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