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