1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.networkstack.tethering; 18 19 import android.net.IpPrefix; 20 import android.net.LinkAddress; 21 import android.net.LinkProperties; 22 import android.net.Network; 23 import android.net.NetworkCapabilities; 24 import android.net.RouteInfo; 25 import android.net.ip.IpServer; 26 import android.net.util.NetworkConstants; 27 import android.util.Log; 28 29 import com.android.net.module.util.SharedLog; 30 31 import java.net.Inet6Address; 32 import java.net.InetAddress; 33 import java.net.UnknownHostException; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.LinkedList; 37 import java.util.Random; 38 39 40 /** 41 * IPv6 tethering is rather different from IPv4 owing to the absence of NAT. 42 * This coordinator is responsible for evaluating the dedicated prefixes 43 * assigned to the device and deciding how to divvy them up among downstream 44 * interfaces. 45 * 46 * @hide 47 */ 48 public class IPv6TetheringCoordinator { 49 private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName(); 50 private static final boolean DBG = false; 51 private static final boolean VDBG = false; 52 53 private static class Downstream { 54 public final IpServer ipServer; 55 public final int mode; // IpServer.STATE_* 56 // Used to append to a ULA /48, constructing a ULA /64 for local use. 57 public final short subnetId; 58 Downstream(IpServer ipServer, int mode, short subnetId)59 Downstream(IpServer ipServer, int mode, short subnetId) { 60 this.ipServer = ipServer; 61 this.mode = mode; 62 this.subnetId = subnetId; 63 } 64 } 65 66 private final ArrayList<IpServer> mNotifyList; 67 private final SharedLog mLog; 68 // NOTE: mActiveDownstreams is a list and not a hash data structure because 69 // we keep active downstreams in arrival order. This is done so /64s can 70 // be parceled out on a "first come, first served" basis and a /64 used by 71 // a downstream that is no longer active can be redistributed to any next 72 // waiting active downstream (again, in arrival order). 73 private final LinkedList<Downstream> mActiveDownstreams; 74 private final byte[] mUniqueLocalPrefix; 75 private short mNextSubnetId; 76 private UpstreamNetworkState mUpstreamNetworkState; 77 IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log)78 public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) { 79 mNotifyList = notifyList; 80 mLog = log.forSubComponent(TAG); 81 mActiveDownstreams = new LinkedList<>(); 82 mUniqueLocalPrefix = generateUniqueLocalPrefix(); 83 mNextSubnetId = 0; 84 } 85 86 /** Add active downstream to ipv6 tethering candidate list. */ addActiveDownstream(IpServer downstream, int mode)87 public void addActiveDownstream(IpServer downstream, int mode) { 88 if (findDownstream(downstream) == null) { 89 // Adding a new downstream appends it to the list. Adding a 90 // downstream a second time without first removing it has no effect. 91 // We never change the mode of a downstream except by first removing 92 // it and then re-adding it (with its new mode specified); 93 if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) { 94 // Make sure subnet IDs are always positive. They are appended 95 // to a ULA /48 to make a ULA /64 for local use. 96 mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1); 97 } 98 updateIPv6TetheringInterfaces(); 99 } 100 } 101 102 /** Remove downstream from ipv6 tethering candidate list. */ removeActiveDownstream(IpServer downstream)103 public void removeActiveDownstream(IpServer downstream) { 104 stopIPv6TetheringOn(downstream); 105 if (mActiveDownstreams.remove(findDownstream(downstream))) { 106 updateIPv6TetheringInterfaces(); 107 } 108 109 // When tethering is stopping we can reset the subnet counter. 110 if (mNotifyList.isEmpty()) { 111 if (!mActiveDownstreams.isEmpty()) { 112 Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty."); 113 } 114 mNextSubnetId = 0; 115 } 116 } 117 118 /** 119 * Call when UpstreamNetworkState may be changed. 120 * If upstream has ipv6 for tethering, update this new UpstreamNetworkState 121 * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces. 122 */ updateUpstreamNetworkState(UpstreamNetworkState ns)123 public void updateUpstreamNetworkState(UpstreamNetworkState ns) { 124 if (VDBG) { 125 Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); 126 } 127 if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) { 128 stopIPv6TetheringOnAllInterfaces(); 129 setUpstreamNetworkState(null); 130 return; 131 } 132 133 if (mUpstreamNetworkState != null 134 && !ns.network.equals(mUpstreamNetworkState.network)) { 135 stopIPv6TetheringOnAllInterfaces(); 136 } 137 138 setUpstreamNetworkState(ns); 139 updateIPv6TetheringInterfaces(); 140 } 141 stopIPv6TetheringOnAllInterfaces()142 private void stopIPv6TetheringOnAllInterfaces() { 143 for (IpServer ipServer : mNotifyList) { 144 stopIPv6TetheringOn(ipServer); 145 } 146 } 147 setUpstreamNetworkState(UpstreamNetworkState ns)148 private void setUpstreamNetworkState(UpstreamNetworkState ns) { 149 if (ns == null) { 150 mUpstreamNetworkState = null; 151 } else { 152 // Make a deep copy of the parts we need. 153 mUpstreamNetworkState = new UpstreamNetworkState( 154 new LinkProperties(ns.linkProperties), 155 new NetworkCapabilities(ns.networkCapabilities), 156 new Network(ns.network)); 157 } 158 159 mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState)); 160 } 161 updateIPv6TetheringInterfaces()162 private void updateIPv6TetheringInterfaces() { 163 for (IpServer ipServer : mNotifyList) { 164 final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer); 165 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, getTtlAdjustment(), 0, lp); 166 break; 167 } 168 } 169 getTtlAdjustment()170 private int getTtlAdjustment() { 171 if (mUpstreamNetworkState == null || mUpstreamNetworkState.networkCapabilities == null) { 172 return 0; 173 } 174 175 // If upstream is cellular, set the TTL in Router Advertisements to "network-set TTL" - 1 176 // for carrier requirement. 177 if (mUpstreamNetworkState.networkCapabilities.hasTransport( 178 NetworkCapabilities.TRANSPORT_CELLULAR)) { 179 return -1; 180 } 181 182 // For other non-cellular upstream, set TTL as "network-set TTL" + 1 to preventing arbitrary 183 // distinction between tethered and untethered traffic. 184 return 1; 185 } 186 getInterfaceIPv6LinkProperties(IpServer ipServer)187 private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) { 188 final Downstream ds = findDownstream(ipServer); 189 if (ds == null) return null; 190 191 if (ds.mode == IpServer.STATE_LOCAL_ONLY) { 192 // Build a Unique Locally-assigned Prefix configuration. 193 return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId); 194 } 195 196 // This downstream is in IpServer.STATE_TETHERED mode. 197 if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) { 198 return null; 199 } 200 201 // NOTE: Here, in future, we would have policies to decide how to divvy 202 // up the available dedicated prefixes among downstream interfaces. 203 // At this time we have no such mechanism--we only support tethering 204 // IPv6 toward the oldest (first requested) active downstream. 205 206 final Downstream currentActive = mActiveDownstreams.peek(); 207 if (currentActive != null && currentActive.ipServer == ipServer) { 208 final LinkProperties lp = getIPv6OnlyLinkProperties( 209 mUpstreamNetworkState.linkProperties); 210 if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) { 211 return lp; 212 } 213 } 214 215 return null; 216 } 217 findDownstream(IpServer ipServer)218 Downstream findDownstream(IpServer ipServer) { 219 for (Downstream ds : mActiveDownstreams) { 220 if (ds.ipServer == ipServer) return ds; 221 } 222 return null; 223 } 224 getIPv6OnlyLinkProperties(LinkProperties lp)225 private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) { 226 final LinkProperties v6only = new LinkProperties(); 227 if (lp == null) { 228 return v6only; 229 } 230 231 // NOTE: At this time we don't copy over any information about any 232 // stacked links. No current stacked link configuration has IPv6. 233 234 v6only.setInterfaceName(lp.getInterfaceName()); 235 236 v6only.setMtu(lp.getMtu()); 237 238 for (LinkAddress linkAddr : lp.getLinkAddresses()) { 239 if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) { 240 v6only.addLinkAddress(linkAddr); 241 } 242 } 243 244 for (RouteInfo routeInfo : lp.getRoutes()) { 245 final IpPrefix destination = routeInfo.getDestination(); 246 if ((destination.getAddress() instanceof Inet6Address) 247 && (destination.getPrefixLength() <= 64)) { 248 v6only.addRoute(routeInfo); 249 } 250 } 251 252 for (InetAddress dnsServer : lp.getDnsServers()) { 253 if (isIPv6GlobalAddress(dnsServer)) { 254 // For now we include ULAs. 255 v6only.addDnsServer(dnsServer); 256 } 257 } 258 259 v6only.setDomains(lp.getDomains()); 260 261 return v6only; 262 } 263 264 // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we 265 // announce our own IPv6 address as DNS server. isIPv6GlobalAddress(InetAddress ip)266 private static boolean isIPv6GlobalAddress(InetAddress ip) { 267 return (ip instanceof Inet6Address) 268 && !ip.isAnyLocalAddress() 269 && !ip.isLoopbackAddress() 270 && !ip.isLinkLocalAddress() 271 && !ip.isSiteLocalAddress() 272 && !ip.isMulticastAddress(); 273 } 274 getUniqueLocalConfig(byte[] ulp, short subnetId)275 private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) { 276 final LinkProperties lp = new LinkProperties(); 277 278 final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48); 279 lp.addRoute(new RouteInfo(local48, null, null, RouteInfo.RTN_UNICAST)); 280 281 final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64); 282 // Because this is a locally-generated ULA, we don't have an upstream 283 // address. But because the downstream IP address management code gets 284 // its prefix from the upstream's IP address, we create a fake one here. 285 lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64)); 286 287 lp.setMtu(NetworkConstants.ETHER_MTU); 288 return lp; 289 } 290 makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen)291 private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) { 292 final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length); 293 bytes[7] = (byte) (subnetId >> 8); 294 bytes[8] = (byte) subnetId; 295 final InetAddress addr; 296 try { 297 addr = InetAddress.getByAddress(bytes); 298 } catch (UnknownHostException e) { 299 throw new IllegalStateException("Invalid address length: " + bytes.length, e); 300 } 301 return new IpPrefix(addr, prefixlen); 302 } 303 304 // Generates a Unique Locally-assigned Prefix: 305 // 306 // https://tools.ietf.org/html/rfc4193#section-3.1 307 // 308 // The result is a /48 that can be used for local-only communications. generateUniqueLocalPrefix()309 private static byte[] generateUniqueLocalPrefix() { 310 final byte[] ulp = new byte[6]; // 6 = 48bits / 8bits/byte 311 (new Random()).nextBytes(ulp); 312 313 final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN); 314 in6addr[0] = (byte) 0xfd; // fc00::/7 and L=1 315 316 return in6addr; 317 } 318 toDebugString(UpstreamNetworkState ns)319 private static String toDebugString(UpstreamNetworkState ns) { 320 if (ns == null) { 321 return "UpstreamNetworkState{null}"; 322 } 323 return ns.toString(); 324 } 325 stopIPv6TetheringOn(IpServer ipServer)326 private static void stopIPv6TetheringOn(IpServer ipServer) { 327 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); 328 } 329 } 330