1 /* 2 * Copyright (C) 2008 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 android.net; 18 19 import static android.system.OsConstants.AF_INET; 20 import static android.system.OsConstants.AF_INET6; 21 22 import android.annotation.NonNull; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.net.shared.Inet4AddressUtils; 25 import android.os.Build; 26 import android.system.ErrnoException; 27 import android.system.Os; 28 import android.util.Log; 29 import android.util.Pair; 30 31 import java.io.FileDescriptor; 32 import java.math.BigInteger; 33 import java.net.Inet4Address; 34 import java.net.InetAddress; 35 import java.net.SocketException; 36 import java.net.UnknownHostException; 37 import java.util.Collection; 38 import java.util.Locale; 39 import java.util.TreeSet; 40 41 /** 42 * Native methods for managing network interfaces. 43 * 44 * {@hide} 45 */ 46 public class NetworkUtils { 47 48 private static final String TAG = "NetworkUtils"; 49 50 /** 51 * Attaches a socket filter that drops all of incoming packets. 52 * @param fd the socket's {@link FileDescriptor}. 53 */ attachDropAllBPFFilter(FileDescriptor fd)54 public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException; 55 56 /** 57 * Detaches a socket filter. 58 * @param fd the socket's {@link FileDescriptor}. 59 */ detachBPFFilter(FileDescriptor fd)60 public static native void detachBPFFilter(FileDescriptor fd) throws SocketException; 61 62 /** 63 * Binds the current process to the network designated by {@code netId}. All sockets created 64 * in the future (and not explicitly bound via a bound {@link SocketFactory} (see 65 * {@link Network#getSocketFactory}) will be bound to this network. Note that if this 66 * {@code Network} ever disconnects all sockets created in this way will cease to work. This 67 * is by design so an application doesn't accidentally use sockets it thinks are still bound to 68 * a particular {@code Network}. Passing NETID_UNSET clears the binding. 69 */ bindProcessToNetwork(int netId)70 public native static boolean bindProcessToNetwork(int netId); 71 72 /** 73 * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if 74 * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. 75 */ getBoundNetworkForProcess()76 public native static int getBoundNetworkForProcess(); 77 78 /** 79 * Binds host resolutions performed by this process to the network designated by {@code netId}. 80 * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears 81 * the binding. 82 * 83 * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). 84 */ 85 @Deprecated bindProcessToNetworkForHostResolution(int netId)86 public native static boolean bindProcessToNetworkForHostResolution(int netId); 87 88 /** 89 * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This 90 * overrides any binding via {@link #bindProcessToNetwork}. 91 * @return 0 on success or negative errno on failure. 92 */ bindSocketToNetwork(int socketfd, int netId)93 public native static int bindSocketToNetwork(int socketfd, int netId); 94 95 /** 96 * Protect {@code fd} from VPN connections. After protecting, data sent through 97 * this socket will go directly to the underlying network, so its traffic will not be 98 * forwarded through the VPN. 99 */ 100 @UnsupportedAppUsage protectFromVpn(FileDescriptor fd)101 public static boolean protectFromVpn(FileDescriptor fd) { 102 return protectFromVpn(fd.getInt$()); 103 } 104 105 /** 106 * Protect {@code socketfd} from VPN connections. After protecting, data sent through 107 * this socket will go directly to the underlying network, so its traffic will not be 108 * forwarded through the VPN. 109 */ protectFromVpn(int socketfd)110 public native static boolean protectFromVpn(int socketfd); 111 112 /** 113 * Determine if {@code uid} can access network designated by {@code netId}. 114 * @return {@code true} if {@code uid} can access network, {@code false} otherwise. 115 */ queryUserAccess(int uid, int netId)116 public native static boolean queryUserAccess(int uid, int netId); 117 118 /** 119 * DNS resolver series jni method. 120 * Issue the query {@code msg} on the network designated by {@code netId}. 121 * {@code flags} is an additional config to control actual querying behavior. 122 * @return a file descriptor to watch for read events 123 */ resNetworkSend( int netId, byte[] msg, int msglen, int flags)124 public static native FileDescriptor resNetworkSend( 125 int netId, byte[] msg, int msglen, int flags) throws ErrnoException; 126 127 /** 128 * DNS resolver series jni method. 129 * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated 130 * with Domain Name {@code dname} on the network designated by {@code netId}. 131 * {@code flags} is an additional config to control actual querying behavior. 132 * @return a file descriptor to watch for read events 133 */ resNetworkQuery( int netId, String dname, int nsClass, int nsType, int flags)134 public static native FileDescriptor resNetworkQuery( 135 int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException; 136 137 /** 138 * DNS resolver series jni method. 139 * Read a result for the query associated with the {@code fd}. 140 * @return DnsResponse containing blob answer and rcode 141 */ resNetworkResult(FileDescriptor fd)142 public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) 143 throws ErrnoException; 144 145 /** 146 * DNS resolver series jni method. 147 * Attempts to cancel the in-progress query associated with the {@code fd}. 148 */ resNetworkCancel(FileDescriptor fd)149 public static native void resNetworkCancel(FileDescriptor fd); 150 151 /** 152 * DNS resolver series jni method. 153 * Attempts to get network which resolver will use if no network is explicitly selected. 154 */ getDnsNetwork()155 public static native Network getDnsNetwork() throws ErrnoException; 156 157 /** 158 * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process. 159 * 160 * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets 161 * and DNS lookups. 162 */ setAllowNetworkingForProcess(boolean allowNetworking)163 public static native void setAllowNetworkingForProcess(boolean allowNetworking); 164 165 /** 166 * Get the tcp repair window associated with the {@code fd}. 167 * 168 * @param fd the tcp socket's {@link FileDescriptor}. 169 * @return a {@link TcpRepairWindow} object indicates tcp window size. 170 */ getTcpRepairWindow(FileDescriptor fd)171 public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd) 172 throws ErrnoException; 173 174 /** 175 * @see Inet4AddressUtils#intToInet4AddressHTL(int) 176 * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)} 177 * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)} 178 */ 179 @Deprecated 180 @UnsupportedAppUsage intToInetAddress(int hostAddress)181 public static InetAddress intToInetAddress(int hostAddress) { 182 return Inet4AddressUtils.intToInet4AddressHTL(hostAddress); 183 } 184 185 /** 186 * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address) 187 * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)} 188 * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)} 189 */ 190 @Deprecated inetAddressToInt(Inet4Address inetAddr)191 public static int inetAddressToInt(Inet4Address inetAddr) 192 throws IllegalArgumentException { 193 return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr); 194 } 195 196 /** 197 * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int) 198 * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)} 199 * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)} 200 */ 201 @Deprecated 202 @UnsupportedAppUsage prefixLengthToNetmaskInt(int prefixLength)203 public static int prefixLengthToNetmaskInt(int prefixLength) 204 throws IllegalArgumentException { 205 return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength); 206 } 207 208 /** 209 * Convert a IPv4 netmask integer to a prefix length 210 * @param netmask as an integer (0xff000000 for a /8 subnet) 211 * @return the network prefix length 212 */ netmaskIntToPrefixLength(int netmask)213 public static int netmaskIntToPrefixLength(int netmask) { 214 return Integer.bitCount(netmask); 215 } 216 217 /** 218 * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. 219 * @param netmask as a {@code Inet4Address}. 220 * @return the network prefix length 221 * @throws IllegalArgumentException the specified netmask was not contiguous. 222 * @hide 223 * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)} 224 */ 225 @UnsupportedAppUsage 226 @Deprecated netmaskToPrefixLength(Inet4Address netmask)227 public static int netmaskToPrefixLength(Inet4Address netmask) { 228 // This is only here because some apps seem to be using it (@UnsupportedAppUsage). 229 return Inet4AddressUtils.netmaskToPrefixLength(netmask); 230 } 231 232 233 /** 234 * Create an InetAddress from a string where the string must be a standard 235 * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure 236 * but it will throw an IllegalArgumentException in that case. 237 * @param addrString 238 * @return the InetAddress 239 * @hide 240 * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible. 241 */ 242 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 243 @Deprecated numericToInetAddress(String addrString)244 public static InetAddress numericToInetAddress(String addrString) 245 throws IllegalArgumentException { 246 return InetAddress.parseNumericAddress(addrString); 247 } 248 249 /** 250 * Masks a raw IP address byte array with the specified prefix length. 251 */ maskRawAddress(byte[] array, int prefixLength)252 public static void maskRawAddress(byte[] array, int prefixLength) { 253 if (prefixLength < 0 || prefixLength > array.length * 8) { 254 throw new RuntimeException("IP address with " + array.length + 255 " bytes has invalid prefix length " + prefixLength); 256 } 257 258 int offset = prefixLength / 8; 259 int remainder = prefixLength % 8; 260 byte mask = (byte)(0xFF << (8 - remainder)); 261 262 if (offset < array.length) array[offset] = (byte)(array[offset] & mask); 263 264 offset++; 265 266 for (; offset < array.length; offset++) { 267 array[offset] = 0; 268 } 269 } 270 271 /** 272 * Get InetAddress masked with prefixLength. Will never return null. 273 * @param address the IP address to mask with 274 * @param prefixLength the prefixLength used to mask the IP 275 */ getNetworkPart(InetAddress address, int prefixLength)276 public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { 277 byte[] array = address.getAddress(); 278 maskRawAddress(array, prefixLength); 279 280 InetAddress netPart = null; 281 try { 282 netPart = InetAddress.getByAddress(array); 283 } catch (UnknownHostException e) { 284 throw new RuntimeException("getNetworkPart error - " + e.toString()); 285 } 286 return netPart; 287 } 288 289 /** 290 * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. 291 */ 292 @UnsupportedAppUsage getImplicitNetmask(Inet4Address address)293 public static int getImplicitNetmask(Inet4Address address) { 294 // Only here because it seems to be used by apps 295 return Inet4AddressUtils.getImplicitNetmask(address); 296 } 297 298 /** 299 * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". 300 * @hide 301 */ parseIpAndMask(String ipAndMaskString)302 public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) { 303 InetAddress address = null; 304 int prefixLength = -1; 305 try { 306 String[] pieces = ipAndMaskString.split("/", 2); 307 prefixLength = Integer.parseInt(pieces[1]); 308 address = InetAddress.parseNumericAddress(pieces[0]); 309 } catch (NullPointerException e) { // Null string. 310 } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. 311 } catch (NumberFormatException e) { // Non-numeric prefix. 312 } catch (IllegalArgumentException e) { // Invalid IP address. 313 } 314 315 if (address == null || prefixLength == -1) { 316 throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); 317 } 318 319 return new Pair<InetAddress, Integer>(address, prefixLength); 320 } 321 322 /** 323 * Convert a 32 char hex string into a Inet6Address. 324 * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be 325 * made into an Inet6Address 326 * @param addrHexString a 32 character hex string representing an IPv6 addr 327 * @return addr an InetAddress representation for the string 328 */ hexToInet6Address(String addrHexString)329 public static InetAddress hexToInet6Address(String addrHexString) 330 throws IllegalArgumentException { 331 try { 332 return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", 333 addrHexString.substring(0,4), addrHexString.substring(4,8), 334 addrHexString.substring(8,12), addrHexString.substring(12,16), 335 addrHexString.substring(16,20), addrHexString.substring(20,24), 336 addrHexString.substring(24,28), addrHexString.substring(28,32))); 337 } catch (Exception e) { 338 Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); 339 throw new IllegalArgumentException(e); 340 } 341 } 342 343 /** 344 * Create a string array of host addresses from a collection of InetAddresses 345 * @param addrs a Collection of InetAddresses 346 * @return an array of Strings containing their host addresses 347 */ makeStrings(Collection<InetAddress> addrs)348 public static String[] makeStrings(Collection<InetAddress> addrs) { 349 String[] result = new String[addrs.size()]; 350 int i = 0; 351 for (InetAddress addr : addrs) { 352 result[i++] = addr.getHostAddress(); 353 } 354 return result; 355 } 356 357 /** 358 * Trim leading zeros from IPv4 address strings 359 * Our base libraries will interpret that as octel.. 360 * Must leave non v4 addresses and host names alone. 361 * For example, 192.168.000.010 -> 192.168.0.10 362 * TODO - fix base libraries and remove this function 363 * @param addr a string representing an ip addr 364 * @return a string propertly trimmed 365 */ 366 @UnsupportedAppUsage trimV4AddrZeros(String addr)367 public static String trimV4AddrZeros(String addr) { 368 if (addr == null) return null; 369 String[] octets = addr.split("\\."); 370 if (octets.length != 4) return addr; 371 StringBuilder builder = new StringBuilder(16); 372 String result = null; 373 for (int i = 0; i < 4; i++) { 374 try { 375 if (octets[i].length() > 3) return addr; 376 builder.append(Integer.parseInt(octets[i])); 377 } catch (NumberFormatException e) { 378 return addr; 379 } 380 if (i < 3) builder.append('.'); 381 } 382 result = builder.toString(); 383 return result; 384 } 385 386 /** 387 * Returns a prefix set without overlaps. 388 * 389 * This expects the src set to be sorted from shorter to longer. Results are undefined 390 * failing this condition. The returned prefix set is sorted in the same order as the 391 * passed set, with the same comparator. 392 */ deduplicatePrefixSet(final TreeSet<IpPrefix> src)393 private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) { 394 final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator()); 395 // Prefixes match addresses that share their upper part up to their length, therefore 396 // the only kind of possible overlap in two prefixes is strict inclusion of the longer 397 // (more restrictive) in the shorter (including equivalence if they have the same 398 // length). 399 // Because prefixes in the src set are sorted from shorter to longer, deduplicating 400 // is done by simply iterating in order, and not adding any longer prefix that is 401 // already covered by a shorter one. 402 newPrefixes: 403 for (IpPrefix newPrefix : src) { 404 for (IpPrefix existingPrefix : dst) { 405 if (existingPrefix.containsPrefix(newPrefix)) { 406 continue newPrefixes; 407 } 408 } 409 dst.add(newPrefix); 410 } 411 return dst; 412 } 413 414 /** 415 * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set. 416 * 417 * Obviously this returns an integral value between 0 and 2**32. 418 * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the 419 * set is not ordered smallest prefix to longer prefix. 420 * 421 * @param prefixes the set of prefixes, ordered by length 422 */ routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes)423 public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) { 424 long routedIPCount = 0; 425 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 426 if (!prefix.isIPv4()) { 427 Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount"); 428 } 429 int rank = 32 - prefix.getPrefixLength(); 430 routedIPCount += 1L << rank; 431 } 432 return routedIPCount; 433 } 434 435 /** 436 * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set. 437 * 438 * This returns a BigInteger between 0 and 2**128. 439 * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the 440 * set is not ordered smallest prefix to longer prefix. 441 */ routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes)442 public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) { 443 BigInteger routedIPCount = BigInteger.ZERO; 444 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 445 if (!prefix.isIPv6()) { 446 Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount"); 447 } 448 int rank = 128 - prefix.getPrefixLength(); 449 routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank)); 450 } 451 return routedIPCount; 452 } 453 454 private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6}; 455 456 /** 457 * Returns true if the hostname is weakly validated. 458 * @param hostname Name of host to validate. 459 * @return True if it's a valid-ish hostname. 460 * 461 * @hide 462 */ isWeaklyValidatedHostname(@onNull String hostname)463 public static boolean isWeaklyValidatedHostname(@NonNull String hostname) { 464 // TODO(b/34953048): Use a validation method that permits more accurate, 465 // but still inexpensive, checking of likely valid DNS hostnames. 466 final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$"; 467 if (!hostname.matches(weakHostnameRegex)) { 468 return false; 469 } 470 471 for (int address_family : ADDRESS_FAMILIES) { 472 if (Os.inet_pton(address_family, hostname) != null) { 473 return false; 474 } 475 } 476 477 return true; 478 } 479 480 /** 481 * Safely multiple a value by a rational. 482 * <p> 483 * Internally it uses integer-based math whenever possible, but switches 484 * over to double-based math if values would overflow. 485 * @hide 486 */ multiplySafeByRational(long value, long num, long den)487 public static long multiplySafeByRational(long value, long num, long den) { 488 if (den == 0) { 489 throw new ArithmeticException("Invalid Denominator"); 490 } 491 long x = value; 492 long y = num; 493 494 // Logic shamelessly borrowed from Math.multiplyExact() 495 long r = x * y; 496 long ax = Math.abs(x); 497 long ay = Math.abs(y); 498 if (((ax | ay) >>> 31 != 0)) { 499 // Some bits greater than 2^31 that might cause overflow 500 // Check the result using the divide operator 501 // and check for the special case of Long.MIN_VALUE * -1 502 if (((y != 0) && (r / y != x)) || 503 (x == Long.MIN_VALUE && y == -1)) { 504 // Use double math to avoid overflowing 505 return (long) (((double) num / den) * value); 506 } 507 } 508 return r / den; 509 } 510 } 511