1 /* 2 * Copyright (C) 2020 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 package com.android.networkstack.tethering; 17 18 import static android.net.NetworkCapabilities.TRANSPORT_VPN; 19 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL; 20 import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL; 21 import static android.net.TetheringManager.TETHERING_BLUETOOTH; 22 import static android.net.TetheringManager.TETHERING_WIFI_P2P; 23 24 import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; 25 import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; 26 import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; 27 import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix; 28 29 import static java.util.Arrays.asList; 30 31 import android.content.Context; 32 import android.net.ConnectivityManager; 33 import android.net.IpPrefix; 34 import android.net.LinkAddress; 35 import android.net.Network; 36 import android.net.ip.IpServer; 37 import android.util.ArrayMap; 38 import android.util.ArraySet; 39 40 import androidx.annotation.NonNull; 41 import androidx.annotation.Nullable; 42 43 import com.android.internal.annotations.VisibleForTesting; 44 import com.android.internal.util.IndentingPrintWriter; 45 46 import java.net.Inet4Address; 47 import java.net.InetAddress; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.HashSet; 51 import java.util.List; 52 import java.util.Random; 53 import java.util.Set; 54 55 /** 56 * This class coordinate IP addresses conflict problem. 57 * 58 * Tethering downstream IP addresses may conflict with network assigned addresses. This 59 * coordinator is responsible for recording all of network assigned addresses and dispatched 60 * free address to downstream interfaces. 61 * 62 * This class is not thread-safe and should be accessed on the same tethering internal thread. 63 * @hide 64 */ 65 public class PrivateAddressCoordinator { 66 public static final int PREFIX_LENGTH = 24; 67 68 // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream 69 // address may be requested before coordinator get current upstream notification. To ensure 70 // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared 71 // when tethering is down. Instead tethering would remove all deprecated upstreams from 72 // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams(). 73 private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap; 74 private final ArraySet<IpServer> mDownstreams; 75 private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24"; 76 private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24"; 77 private final List<IpPrefix> mTetheringPrefixes; 78 private final ConnectivityManager mConnectivityMgr; 79 private final TetheringConfiguration mConfig; 80 // keyed by downstream type(TetheringManager.TETHERING_*). 81 private final ArrayMap<AddressKey, LinkAddress> mCachedAddresses; 82 PrivateAddressCoordinator(Context context, TetheringConfiguration config)83 public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { 84 mDownstreams = new ArraySet<>(); 85 mUpstreamPrefixMap = new ArrayMap<>(); 86 mConnectivityMgr = (ConnectivityManager) context.getSystemService( 87 Context.CONNECTIVITY_SERVICE); 88 mConfig = config; 89 mCachedAddresses = new ArrayMap<AddressKey, LinkAddress>(); 90 // Reserved static addresses for bluetooth and wifi p2p. 91 mCachedAddresses.put(new AddressKey(TETHERING_BLUETOOTH, CONNECTIVITY_SCOPE_GLOBAL), 92 new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); 93 mCachedAddresses.put(new AddressKey(TETHERING_WIFI_P2P, CONNECTIVITY_SCOPE_LOCAL), 94 new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); 95 96 mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16"), 97 new IpPrefix("172.16.0.0/12"), new IpPrefix("10.0.0.0/8"))); 98 } 99 100 /** 101 * Record a new upstream IpPrefix which may conflict with tethering downstreams. 102 * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called, 103 * UpstreamNetworkState must have an already populated LinkProperties. 104 */ updateUpstreamPrefix(final UpstreamNetworkState ns)105 public void updateUpstreamPrefix(final UpstreamNetworkState ns) { 106 // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null, 107 // but just checking to be sure. 108 if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) { 109 removeUpstreamPrefix(ns.network); 110 return; 111 } 112 113 final ArrayList<IpPrefix> ipv4Prefixes = getIpv4Prefixes( 114 ns.linkProperties.getAllLinkAddresses()); 115 if (ipv4Prefixes.isEmpty()) { 116 removeUpstreamPrefix(ns.network); 117 return; 118 } 119 120 mUpstreamPrefixMap.put(ns.network, ipv4Prefixes); 121 handleMaybePrefixConflict(ipv4Prefixes); 122 } 123 getIpv4Prefixes(final List<LinkAddress> linkAddresses)124 private ArrayList<IpPrefix> getIpv4Prefixes(final List<LinkAddress> linkAddresses) { 125 final ArrayList<IpPrefix> list = new ArrayList<>(); 126 for (LinkAddress address : linkAddresses) { 127 if (!address.isIpv4()) continue; 128 129 list.add(asIpPrefix(address)); 130 } 131 132 return list; 133 } 134 handleMaybePrefixConflict(final List<IpPrefix> prefixes)135 private void handleMaybePrefixConflict(final List<IpPrefix> prefixes) { 136 for (IpServer downstream : mDownstreams) { 137 final IpPrefix target = getDownstreamPrefix(downstream); 138 139 for (IpPrefix source : prefixes) { 140 if (isConflictPrefix(source, target)) { 141 downstream.sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); 142 break; 143 } 144 } 145 } 146 } 147 148 /** Remove IpPrefix records corresponding to input network. */ removeUpstreamPrefix(final Network network)149 public void removeUpstreamPrefix(final Network network) { 150 mUpstreamPrefixMap.remove(network); 151 } 152 153 /** 154 * Maybe remove deprecated upstream records, this would be called once tethering started without 155 * any exiting tethered downstream. 156 */ maybeRemoveDeprecatedUpstreams()157 public void maybeRemoveDeprecatedUpstreams() { 158 if (mUpstreamPrefixMap.isEmpty()) return; 159 160 // Remove all upstreams that are no longer valid networks 161 final Set<Network> toBeRemoved = new HashSet<>(mUpstreamPrefixMap.keySet()); 162 toBeRemoved.removeAll(asList(mConnectivityMgr.getAllNetworks())); 163 164 mUpstreamPrefixMap.removeAll(toBeRemoved); 165 } 166 167 /** 168 * Pick a random available address and mark its prefix as in use for the provided IpServer, 169 * returns null if there is no available address. 170 */ 171 @Nullable requestDownstreamAddress(final IpServer ipServer, final int scope, boolean useLastAddress)172 public LinkAddress requestDownstreamAddress(final IpServer ipServer, final int scope, 173 boolean useLastAddress) { 174 if (mConfig.shouldEnableWifiP2pDedicatedIp() 175 && ipServer.interfaceType() == TETHERING_WIFI_P2P) { 176 return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS); 177 } 178 179 final AddressKey addrKey = new AddressKey(ipServer.interfaceType(), scope); 180 // This ensures that tethering isn't started on 2 different interfaces with the same type. 181 // Once tethering could support multiple interface with the same type, 182 // TetheringSoftApCallback would need to handle it among others. 183 final LinkAddress cachedAddress = mCachedAddresses.get(addrKey); 184 if (useLastAddress && cachedAddress != null 185 && !isConflictWithUpstream(asIpPrefix(cachedAddress))) { 186 mDownstreams.add(ipServer); 187 return cachedAddress; 188 } 189 190 for (IpPrefix prefixRange : mTetheringPrefixes) { 191 final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); 192 if (newAddress != null) { 193 mDownstreams.add(ipServer); 194 mCachedAddresses.put(addrKey, newAddress); 195 return newAddress; 196 } 197 } 198 199 // No available address. 200 return null; 201 } 202 getPrefixBaseAddress(final IpPrefix prefix)203 private int getPrefixBaseAddress(final IpPrefix prefix) { 204 return inet4AddressToIntHTH((Inet4Address) prefix.getAddress()); 205 } 206 207 /** 208 * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes. 209 * If yes, return one of them. 210 */ getConflictPrefix(final IpPrefix prefix)211 private IpPrefix getConflictPrefix(final IpPrefix prefix) { 212 final IpPrefix upstream = getConflictWithUpstream(prefix); 213 if (upstream != null) return upstream; 214 215 return getInUseDownstreamPrefix(prefix); 216 } 217 218 // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the 219 // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix 220 // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is 221 // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0). 222 // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as 223 // selected random sub address later. getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask)224 private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) { 225 final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength()); 226 // The largest offset within the prefix assignment block that still conflicts with 227 // conflictPrefix. 228 final int maxConflict = 229 (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask; 230 231 final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); 232 // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than 233 // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix. 234 // There is no need to mask the result with PREFIX_LENGTH bits because this is done by 235 // findAvailablePrefixFromRange when it constructs the prefix. 236 return maxConflict + (1 << (32 - PREFIX_LENGTH)); 237 } 238 chooseDownstreamAddress(final IpPrefix prefixRange)239 private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) { 240 // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12). 241 final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength()); 242 243 // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12). 244 final int baseAddress = getPrefixBaseAddress(prefixRange); 245 246 // The subnet mask corresponding to PREFIX_LENGTH. 247 final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); 248 249 // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH. 250 // This may not be the prefix of the address returned by this method: 251 // - If it is already in use, the method will return an address in another prefix. 252 // - If all prefixes within prefixRange are in use, the method will return null. For 253 // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in 254 // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00. 255 // 256 // prefixRangeMask is required to ensure no wrapping. For example, consider: 257 // - prefixRange 127.0.0.0/8 258 // - randomPrefixStart 127.255.255.0 259 // - A conflicting prefix of 127.255.254.0/23 260 // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which 261 // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix 262 // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648 263 // is less than 127.0.0.0 = 0x7f000000 = 2130706432. 264 // 265 // Additionally, it makes debug output easier to read by making the numbers smaller. 266 final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask; 267 268 // A random offset within the prefix. Used to determine the local address once the prefix 269 // is selected. It does not result in an IPv4 address ending in .0, .1, or .255 270 // For a PREFIX_LENGTH of 255, this is a number between 2 and 254. 271 final int subAddress = getSanitizedSubAddr(~prefixMask); 272 273 // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block, 274 // such that the prefix does not conflict with any upstream. 275 IpPrefix downstreamPrefix = findAvailablePrefixFromRange( 276 randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask); 277 if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress); 278 279 // If that failed, do the same, but between 0 and randomPrefixStart. 280 downstreamPrefix = findAvailablePrefixFromRange( 281 0, randomPrefixStart, baseAddress, prefixRangeMask); 282 283 return getLinkAddress(downstreamPrefix, subAddress); 284 } 285 getLinkAddress(final IpPrefix prefix, final int subAddress)286 private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) { 287 if (prefix == null) return null; 288 289 final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress); 290 return new LinkAddress(address, PREFIX_LENGTH); 291 } 292 findAvailablePrefixFromRange(final int start, final int end, final int baseAddress, final int prefixRangeMask)293 private IpPrefix findAvailablePrefixFromRange(final int start, final int end, 294 final int baseAddress, final int prefixRangeMask) { 295 int newSubPrefix = start; 296 while (newSubPrefix < end) { 297 final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix); 298 final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH); 299 300 final IpPrefix conflictPrefix = getConflictPrefix(prefix); 301 302 if (conflictPrefix == null) return prefix; 303 304 newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask); 305 } 306 307 return null; 308 } 309 310 /** Get random int which could be used to generate random address. */ 311 @VisibleForTesting getRandomInt()312 public int getRandomInt() { 313 return (new Random()).nextInt(); 314 } 315 316 /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */ getSanitizedSubAddr(final int subAddrMask)317 private int getSanitizedSubAddr(final int subAddrMask) { 318 final int randomSubAddr = getRandomInt() & subAddrMask; 319 // If prefix length > 30, the selecting speace would be less than 4 which may be hard to 320 // avoid 3 consecutive address. 321 if (PREFIX_LENGTH > 30) return randomSubAddr; 322 323 // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering 324 // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer 325 // than 24 326 final int candidate = randomSubAddr & 0xff; 327 if (candidate == 0 || candidate == 1 || candidate == 255) { 328 return (randomSubAddr & 0xfffffffc) + 2; 329 } 330 331 return randomSubAddr; 332 } 333 334 /** Release downstream record for IpServer. */ releaseDownstream(final IpServer ipServer)335 public void releaseDownstream(final IpServer ipServer) { 336 mDownstreams.remove(ipServer); 337 } 338 339 /** Clear current upstream prefixes records. */ clearUpstreamPrefixes()340 public void clearUpstreamPrefixes() { 341 mUpstreamPrefixMap.clear(); 342 } 343 getConflictWithUpstream(final IpPrefix prefix)344 private IpPrefix getConflictWithUpstream(final IpPrefix prefix) { 345 for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { 346 final List<IpPrefix> list = mUpstreamPrefixMap.valueAt(i); 347 for (IpPrefix upstream : list) { 348 if (isConflictPrefix(prefix, upstream)) return upstream; 349 } 350 } 351 return null; 352 } 353 isConflictWithUpstream(final IpPrefix prefix)354 private boolean isConflictWithUpstream(final IpPrefix prefix) { 355 return getConflictWithUpstream(prefix) != null; 356 } 357 isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2)358 private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) { 359 if (prefix2.getPrefixLength() < prefix1.getPrefixLength()) { 360 return prefix2.contains(prefix1.getAddress()); 361 } 362 363 return prefix1.contains(prefix2.getAddress()); 364 } 365 366 // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last 367 // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p). getInUseDownstreamPrefix(final IpPrefix prefix)368 private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) { 369 for (int i = 0; i < mCachedAddresses.size(); i++) { 370 final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i)); 371 if (isConflictPrefix(prefix, downstream)) return downstream; 372 } 373 374 // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include 375 // in mCachedAddresses. 376 for (IpServer downstream : mDownstreams) { 377 final IpPrefix target = getDownstreamPrefix(downstream); 378 379 if (isConflictPrefix(prefix, target)) return target; 380 } 381 382 return null; 383 } 384 385 @NonNull getDownstreamPrefix(final IpServer downstream)386 private IpPrefix getDownstreamPrefix(final IpServer downstream) { 387 final LinkAddress address = downstream.getAddress(); 388 389 return asIpPrefix(address); 390 } 391 392 private static class AddressKey { 393 private final int mTetheringType; 394 private final int mScope; 395 AddressKey(int type, int scope)396 private AddressKey(int type, int scope) { 397 mTetheringType = type; 398 mScope = scope; 399 } 400 401 @Override hashCode()402 public int hashCode() { 403 return (mTetheringType << 16) + mScope; 404 } 405 406 @Override equals(@ullable Object obj)407 public boolean equals(@Nullable Object obj) { 408 if (!(obj instanceof AddressKey)) return false; 409 final AddressKey other = (AddressKey) obj; 410 411 return mTetheringType == other.mTetheringType && mScope == other.mScope; 412 } 413 414 @Override toString()415 public String toString() { 416 return "AddressKey(" + mTetheringType + ", " + mScope + ")"; 417 } 418 } 419 dump(final IndentingPrintWriter pw)420 void dump(final IndentingPrintWriter pw) { 421 pw.println("mTetheringPrefixes:"); 422 pw.increaseIndent(); 423 for (IpPrefix prefix : mTetheringPrefixes) { 424 pw.println(prefix); 425 } 426 pw.decreaseIndent(); 427 428 pw.println("mUpstreamPrefixMap:"); 429 pw.increaseIndent(); 430 for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { 431 pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i)); 432 } 433 pw.decreaseIndent(); 434 435 pw.println("mDownstreams:"); 436 pw.increaseIndent(); 437 for (IpServer ipServer : mDownstreams) { 438 pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress()); 439 } 440 pw.decreaseIndent(); 441 442 pw.println("mCachedAddresses:"); 443 pw.increaseIndent(); 444 for (int i = 0; i < mCachedAddresses.size(); i++) { 445 pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i)); 446 } 447 pw.decreaseIndent(); 448 } 449 } 450