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.server.connectivity.tethering; 18 19 import android.net.ConnectivityManager; 20 import android.net.IpPrefix; 21 import android.net.LinkAddress; 22 import android.net.LinkProperties; 23 import android.net.Network; 24 import android.net.NetworkCapabilities; 25 import android.net.NetworkState; 26 import android.net.RouteInfo; 27 import android.net.util.NetworkConstants; 28 import android.net.util.SharedLog; 29 import android.util.Log; 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.HashMap; 37 import java.util.LinkedList; 38 import java.util.Random; 39 40 41 /** 42 * IPv6 tethering is rather different from IPv4 owing to the absence of NAT. 43 * This coordinator is responsible for evaluating the dedicated prefixes 44 * assigned to the device and deciding how to divvy them up among downstream 45 * interfaces. 46 * 47 * @hide 48 */ 49 public class IPv6TetheringCoordinator { 50 private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName(); 51 private static final boolean DBG = false; 52 private static final boolean VDBG = false; 53 54 private static class Downstream { 55 public final TetherInterfaceStateMachine tism; 56 public final int mode; // IControlsTethering.STATE_* 57 // Used to append to a ULA /48, constructing a ULA /64 for local use. 58 public final short subnetId; 59 Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId)60 Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) { 61 this.tism = tism; 62 this.mode = mode; 63 this.subnetId = subnetId; 64 } 65 } 66 67 private final ArrayList<TetherInterfaceStateMachine> mNotifyList; 68 private final SharedLog mLog; 69 // NOTE: mActiveDownstreams is a list and not a hash data structure because 70 // we keep active downstreams in arrival order. This is done so /64s can 71 // be parceled out on a "first come, first served" basis and a /64 used by 72 // a downstream that is no longer active can be redistributed to any next 73 // waiting active downstream (again, in arrival order). 74 private final LinkedList<Downstream> mActiveDownstreams; 75 private final byte[] mUniqueLocalPrefix; 76 private short mNextSubnetId; 77 private NetworkState mUpstreamNetworkState; 78 IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList, SharedLog log)79 public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList, 80 SharedLog log) { 81 mNotifyList = notifyList; 82 mLog = log.forSubComponent(TAG); 83 mActiveDownstreams = new LinkedList<>(); 84 mUniqueLocalPrefix = generateUniqueLocalPrefix(); 85 mNextSubnetId = 0; 86 } 87 addActiveDownstream(TetherInterfaceStateMachine downstream, int mode)88 public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) { 89 if (findDownstream(downstream) == null) { 90 // Adding a new downstream appends it to the list. Adding a 91 // downstream a second time without first removing it has no effect. 92 // We never change the mode of a downstream except by first removing 93 // it and then re-adding it (with its new mode specified); 94 if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) { 95 // Make sure subnet IDs are always positive. They are appended 96 // to a ULA /48 to make a ULA /64 for local use. 97 mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1); 98 } 99 updateIPv6TetheringInterfaces(); 100 } 101 } 102 removeActiveDownstream(TetherInterfaceStateMachine downstream)103 public void removeActiveDownstream(TetherInterfaceStateMachine 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 updateUpstreamNetworkState(NetworkState ns)118 public void updateUpstreamNetworkState(NetworkState ns) { 119 if (VDBG) { 120 Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); 121 } 122 if (!canTetherIPv6(ns, mLog)) { 123 stopIPv6TetheringOnAllInterfaces(); 124 setUpstreamNetworkState(null); 125 return; 126 } 127 128 if (mUpstreamNetworkState != null && 129 !ns.network.equals(mUpstreamNetworkState.network)) { 130 stopIPv6TetheringOnAllInterfaces(); 131 } 132 133 setUpstreamNetworkState(ns); 134 updateIPv6TetheringInterfaces(); 135 } 136 stopIPv6TetheringOnAllInterfaces()137 private void stopIPv6TetheringOnAllInterfaces() { 138 for (TetherInterfaceStateMachine sm : mNotifyList) { 139 stopIPv6TetheringOn(sm); 140 } 141 } 142 setUpstreamNetworkState(NetworkState ns)143 private void setUpstreamNetworkState(NetworkState ns) { 144 if (ns == null) { 145 mUpstreamNetworkState = null; 146 } else { 147 // Make a deep copy of the parts we need. 148 mUpstreamNetworkState = new NetworkState( 149 null, 150 new LinkProperties(ns.linkProperties), 151 new NetworkCapabilities(ns.networkCapabilities), 152 new Network(ns.network), 153 null, 154 null); 155 } 156 157 mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState)); 158 } 159 updateIPv6TetheringInterfaces()160 private void updateIPv6TetheringInterfaces() { 161 for (TetherInterfaceStateMachine sm : mNotifyList) { 162 final LinkProperties lp = getInterfaceIPv6LinkProperties(sm); 163 sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); 164 break; 165 } 166 } 167 getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm)168 private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) { 169 if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) { 170 // TODO: Figure out IPv6 support on PAN interfaces. 171 return null; 172 } 173 174 final Downstream ds = findDownstream(sm); 175 if (ds == null) return null; 176 177 if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) { 178 // Build a Unique Locally-assigned Prefix configuration. 179 return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId); 180 } 181 182 // This downstream is in IControlsTethering.STATE_TETHERED mode. 183 if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) { 184 return null; 185 } 186 187 // NOTE: Here, in future, we would have policies to decide how to divvy 188 // up the available dedicated prefixes among downstream interfaces. 189 // At this time we have no such mechanism--we only support tethering 190 // IPv6 toward the oldest (first requested) active downstream. 191 192 final Downstream currentActive = mActiveDownstreams.peek(); 193 if (currentActive != null && currentActive.tism == sm) { 194 final LinkProperties lp = getIPv6OnlyLinkProperties( 195 mUpstreamNetworkState.linkProperties); 196 if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) { 197 return lp; 198 } 199 } 200 201 return null; 202 } 203 findDownstream(TetherInterfaceStateMachine tism)204 Downstream findDownstream(TetherInterfaceStateMachine tism) { 205 for (Downstream ds : mActiveDownstreams) { 206 if (ds.tism == tism) return ds; 207 } 208 return null; 209 } 210 canTetherIPv6(NetworkState ns, SharedLog sharedLog)211 private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) { 212 // Broadly speaking: 213 // 214 // [1] does the upstream have an IPv6 default route? 215 // 216 // and 217 // 218 // [2] does the upstream have one or more global IPv6 /64s 219 // dedicated to this device? 220 // 221 // In lieu of Prefix Delegation and other evaluation of whether a 222 // prefix may or may not be dedicated to this device, for now just 223 // check whether the upstream is TRANSPORT_CELLULAR. This works 224 // because "[t]he 3GPP network allocates each default bearer a unique 225 // /64 prefix", per RFC 6459, Section 5.2. 226 227 final boolean canTether = 228 (ns != null) && (ns.network != null) && 229 (ns.linkProperties != null) && (ns.networkCapabilities != null) && 230 // At least one upstream DNS server: 231 ns.linkProperties.isProvisioned() && 232 // Minimal amount of IPv6 provisioning: 233 ns.linkProperties.hasIPv6DefaultRoute() && 234 ns.linkProperties.hasGlobalIPv6Address() && 235 // Temporary approximation of "dedicated prefix": 236 ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); 237 238 // For now, we do not support separate IPv4 and IPv6 upstreams (e.g. 239 // tethering with 464xlat involved). TODO: Rectify this shortcoming, 240 // likely by calling NetworkManagementService#startInterfaceForwarding() 241 // for all upstream interfaces. 242 RouteInfo v4default = null; 243 RouteInfo v6default = null; 244 if (canTether) { 245 for (RouteInfo r : ns.linkProperties.getAllRoutes()) { 246 if (r.isIPv4Default()) { 247 v4default = r; 248 } else if (r.isIPv6Default()) { 249 v6default = r; 250 } 251 252 if (v4default != null && v6default != null) { 253 break; 254 } 255 } 256 } 257 258 final boolean supportedConfiguration = 259 (v4default != null) && (v6default != null) && 260 (v4default.getInterface() != null) && 261 v4default.getInterface().equals(v6default.getInterface()); 262 263 final boolean outcome = canTether && supportedConfiguration; 264 265 if (ns == null) { 266 sharedLog.log("No available upstream."); 267 } else { 268 sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s", 269 (outcome ? "available" : "not available"), toDebugString(ns))); 270 } 271 272 return outcome; 273 } 274 getIPv6OnlyLinkProperties(LinkProperties lp)275 private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) { 276 final LinkProperties v6only = new LinkProperties(); 277 if (lp == null) { 278 return v6only; 279 } 280 281 // NOTE: At this time we don't copy over any information about any 282 // stacked links. No current stacked link configuration has IPv6. 283 284 v6only.setInterfaceName(lp.getInterfaceName()); 285 286 v6only.setMtu(lp.getMtu()); 287 288 for (LinkAddress linkAddr : lp.getLinkAddresses()) { 289 if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) { 290 v6only.addLinkAddress(linkAddr); 291 } 292 } 293 294 for (RouteInfo routeInfo : lp.getRoutes()) { 295 final IpPrefix destination = routeInfo.getDestination(); 296 if ((destination.getAddress() instanceof Inet6Address) && 297 (destination.getPrefixLength() <= 64)) { 298 v6only.addRoute(routeInfo); 299 } 300 } 301 302 for (InetAddress dnsServer : lp.getDnsServers()) { 303 if (isIPv6GlobalAddress(dnsServer)) { 304 // For now we include ULAs. 305 v6only.addDnsServer(dnsServer); 306 } 307 } 308 309 v6only.setDomains(lp.getDomains()); 310 311 return v6only; 312 } 313 314 // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we 315 // announce our own IPv6 address as DNS server. isIPv6GlobalAddress(InetAddress ip)316 private static boolean isIPv6GlobalAddress(InetAddress ip) { 317 return (ip instanceof Inet6Address) && 318 !ip.isAnyLocalAddress() && 319 !ip.isLoopbackAddress() && 320 !ip.isLinkLocalAddress() && 321 !ip.isSiteLocalAddress() && 322 !ip.isMulticastAddress(); 323 } 324 getUniqueLocalConfig(byte[] ulp, short subnetId)325 private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) { 326 final LinkProperties lp = new LinkProperties(); 327 328 final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48); 329 lp.addRoute(new RouteInfo(local48, null, null)); 330 331 final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64); 332 // Because this is a locally-generated ULA, we don't have an upstream 333 // address. But because the downstream IP address management code gets 334 // its prefix from the upstream's IP address, we create a fake one here. 335 lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64)); 336 337 lp.setMtu(NetworkConstants.ETHER_MTU); 338 return lp; 339 } 340 makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen)341 private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) { 342 final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length); 343 bytes[7] = (byte) (subnetId >> 8); 344 bytes[8] = (byte) subnetId; 345 return new IpPrefix(bytes, prefixlen); 346 } 347 348 // Generates a Unique Locally-assigned Prefix: 349 // 350 // https://tools.ietf.org/html/rfc4193#section-3.1 351 // 352 // The result is a /48 that can be used for local-only communications. generateUniqueLocalPrefix()353 private static byte[] generateUniqueLocalPrefix() { 354 final byte[] ulp = new byte[6]; // 6 = 48bits / 8bits/byte 355 (new Random()).nextBytes(ulp); 356 357 final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN); 358 in6addr[0] = (byte) 0xfd; // fc00::/7 and L=1 359 360 return in6addr; 361 } 362 toDebugString(NetworkState ns)363 private static String toDebugString(NetworkState ns) { 364 if (ns == null) { 365 return "NetworkState{null}"; 366 } 367 return String.format("NetworkState{%s, %s, %s}", 368 ns.network, 369 ns.networkCapabilities, 370 ns.linkProperties); 371 } 372 stopIPv6TetheringOn(TetherInterfaceStateMachine sm)373 private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) { 374 sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null); 375 } 376 } 377