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.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.Inet6Address; 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 * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. 65 * @param fd the socket's {@link FileDescriptor}. 66 * @param ifIndex the interface index. 67 */ setupRaSocket(FileDescriptor fd, int ifIndex)68 public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException; 69 70 /** 71 * Binds the current process to the network designated by {@code netId}. All sockets created 72 * in the future (and not explicitly bound via a bound {@link SocketFactory} (see 73 * {@link Network#getSocketFactory}) will be bound to this network. Note that if this 74 * {@code Network} ever disconnects all sockets created in this way will cease to work. This 75 * is by design so an application doesn't accidentally use sockets it thinks are still bound to 76 * a particular {@code Network}. Passing NETID_UNSET clears the binding. 77 */ bindProcessToNetwork(int netId)78 public native static boolean bindProcessToNetwork(int netId); 79 80 /** 81 * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if 82 * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. 83 */ getBoundNetworkForProcess()84 public native static int getBoundNetworkForProcess(); 85 86 /** 87 * Binds host resolutions performed by this process to the network designated by {@code netId}. 88 * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears 89 * the binding. 90 * 91 * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). 92 */ 93 @Deprecated bindProcessToNetworkForHostResolution(int netId)94 public native static boolean bindProcessToNetworkForHostResolution(int netId); 95 96 /** 97 * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This 98 * overrides any binding via {@link #bindProcessToNetwork}. 99 * @return 0 on success or negative errno on failure. 100 */ bindSocketToNetwork(int socketfd, int netId)101 public native static int bindSocketToNetwork(int socketfd, int netId); 102 103 /** 104 * Protect {@code fd} from VPN connections. After protecting, data sent through 105 * this socket will go directly to the underlying network, so its traffic will not be 106 * forwarded through the VPN. 107 */ 108 @UnsupportedAppUsage protectFromVpn(FileDescriptor fd)109 public static boolean protectFromVpn(FileDescriptor fd) { 110 return protectFromVpn(fd.getInt$()); 111 } 112 113 /** 114 * Protect {@code socketfd} from VPN connections. After protecting, data sent through 115 * this socket will go directly to the underlying network, so its traffic will not be 116 * forwarded through the VPN. 117 */ protectFromVpn(int socketfd)118 public native static boolean protectFromVpn(int socketfd); 119 120 /** 121 * Determine if {@code uid} can access network designated by {@code netId}. 122 * @return {@code true} if {@code uid} can access network, {@code false} otherwise. 123 */ queryUserAccess(int uid, int netId)124 public native static boolean queryUserAccess(int uid, int netId); 125 126 /** 127 * DNS resolver series jni method. 128 * Issue the query {@code msg} on the network designated by {@code netId}. 129 * {@code flags} is an additional config to control actual querying behavior. 130 * @return a file descriptor to watch for read events 131 */ resNetworkSend( int netId, byte[] msg, int msglen, int flags)132 public static native FileDescriptor resNetworkSend( 133 int netId, byte[] msg, int msglen, int flags) throws ErrnoException; 134 135 /** 136 * DNS resolver series jni method. 137 * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated 138 * with Domain Name {@code dname} on the network designated by {@code netId}. 139 * {@code flags} is an additional config to control actual querying behavior. 140 * @return a file descriptor to watch for read events 141 */ resNetworkQuery( int netId, String dname, int nsClass, int nsType, int flags)142 public static native FileDescriptor resNetworkQuery( 143 int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException; 144 145 /** 146 * DNS resolver series jni method. 147 * Read a result for the query associated with the {@code fd}. 148 * @return DnsResponse containing blob answer and rcode 149 */ resNetworkResult(FileDescriptor fd)150 public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) 151 throws ErrnoException; 152 153 /** 154 * DNS resolver series jni method. 155 * Attempts to cancel the in-progress query associated with the {@code fd}. 156 */ resNetworkCancel(FileDescriptor fd)157 public static native void resNetworkCancel(FileDescriptor fd); 158 159 /** 160 * DNS resolver series jni method. 161 * Attempts to get network which resolver will use if no network is explicitly selected. 162 */ getDnsNetwork()163 public static native Network getDnsNetwork() throws ErrnoException; 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 * Check if IP address type is consistent between two InetAddress. 324 * @return true if both are the same type. False otherwise. 325 */ addressTypeMatches(InetAddress left, InetAddress right)326 public static boolean addressTypeMatches(InetAddress left, InetAddress right) { 327 return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || 328 ((left instanceof Inet6Address) && (right instanceof Inet6Address))); 329 } 330 331 /** 332 * Convert a 32 char hex string into a Inet6Address. 333 * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be 334 * made into an Inet6Address 335 * @param addrHexString a 32 character hex string representing an IPv6 addr 336 * @return addr an InetAddress representation for the string 337 */ hexToInet6Address(String addrHexString)338 public static InetAddress hexToInet6Address(String addrHexString) 339 throws IllegalArgumentException { 340 try { 341 return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", 342 addrHexString.substring(0,4), addrHexString.substring(4,8), 343 addrHexString.substring(8,12), addrHexString.substring(12,16), 344 addrHexString.substring(16,20), addrHexString.substring(20,24), 345 addrHexString.substring(24,28), addrHexString.substring(28,32))); 346 } catch (Exception e) { 347 Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); 348 throw new IllegalArgumentException(e); 349 } 350 } 351 352 /** 353 * Create a string array of host addresses from a collection of InetAddresses 354 * @param addrs a Collection of InetAddresses 355 * @return an array of Strings containing their host addresses 356 */ makeStrings(Collection<InetAddress> addrs)357 public static String[] makeStrings(Collection<InetAddress> addrs) { 358 String[] result = new String[addrs.size()]; 359 int i = 0; 360 for (InetAddress addr : addrs) { 361 result[i++] = addr.getHostAddress(); 362 } 363 return result; 364 } 365 366 /** 367 * Trim leading zeros from IPv4 address strings 368 * Our base libraries will interpret that as octel.. 369 * Must leave non v4 addresses and host names alone. 370 * For example, 192.168.000.010 -> 192.168.0.10 371 * TODO - fix base libraries and remove this function 372 * @param addr a string representing an ip addr 373 * @return a string propertly trimmed 374 */ 375 @UnsupportedAppUsage trimV4AddrZeros(String addr)376 public static String trimV4AddrZeros(String addr) { 377 if (addr == null) return null; 378 String[] octets = addr.split("\\."); 379 if (octets.length != 4) return addr; 380 StringBuilder builder = new StringBuilder(16); 381 String result = null; 382 for (int i = 0; i < 4; i++) { 383 try { 384 if (octets[i].length() > 3) return addr; 385 builder.append(Integer.parseInt(octets[i])); 386 } catch (NumberFormatException e) { 387 return addr; 388 } 389 if (i < 3) builder.append('.'); 390 } 391 result = builder.toString(); 392 return result; 393 } 394 395 /** 396 * Returns a prefix set without overlaps. 397 * 398 * This expects the src set to be sorted from shorter to longer. Results are undefined 399 * failing this condition. The returned prefix set is sorted in the same order as the 400 * passed set, with the same comparator. 401 */ deduplicatePrefixSet(final TreeSet<IpPrefix> src)402 private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) { 403 final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator()); 404 // Prefixes match addresses that share their upper part up to their length, therefore 405 // the only kind of possible overlap in two prefixes is strict inclusion of the longer 406 // (more restrictive) in the shorter (including equivalence if they have the same 407 // length). 408 // Because prefixes in the src set are sorted from shorter to longer, deduplicating 409 // is done by simply iterating in order, and not adding any longer prefix that is 410 // already covered by a shorter one. 411 newPrefixes: 412 for (IpPrefix newPrefix : src) { 413 for (IpPrefix existingPrefix : dst) { 414 if (existingPrefix.containsPrefix(newPrefix)) { 415 continue newPrefixes; 416 } 417 } 418 dst.add(newPrefix); 419 } 420 return dst; 421 } 422 423 /** 424 * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set. 425 * 426 * Obviously this returns an integral value between 0 and 2**32. 427 * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the 428 * set is not ordered smallest prefix to longer prefix. 429 * 430 * @param prefixes the set of prefixes, ordered by length 431 */ routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes)432 public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) { 433 long routedIPCount = 0; 434 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 435 if (!prefix.isIPv4()) { 436 Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount"); 437 } 438 int rank = 32 - prefix.getPrefixLength(); 439 routedIPCount += 1L << rank; 440 } 441 return routedIPCount; 442 } 443 444 /** 445 * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set. 446 * 447 * This returns a BigInteger between 0 and 2**128. 448 * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the 449 * set is not ordered smallest prefix to longer prefix. 450 */ routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes)451 public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) { 452 BigInteger routedIPCount = BigInteger.ZERO; 453 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 454 if (!prefix.isIPv6()) { 455 Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount"); 456 } 457 int rank = 128 - prefix.getPrefixLength(); 458 routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank)); 459 } 460 return routedIPCount; 461 } 462 463 private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6}; 464 465 /** 466 * Returns true if the hostname is weakly validated. 467 * @param hostname Name of host to validate. 468 * @return True if it's a valid-ish hostname. 469 * 470 * @hide 471 */ isWeaklyValidatedHostname(@onNull String hostname)472 public static boolean isWeaklyValidatedHostname(@NonNull String hostname) { 473 // TODO(b/34953048): Use a validation method that permits more accurate, 474 // but still inexpensive, checking of likely valid DNS hostnames. 475 final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$"; 476 if (!hostname.matches(weakHostnameRegex)) { 477 return false; 478 } 479 480 for (int address_family : ADDRESS_FAMILIES) { 481 if (Os.inet_pton(address_family, hostname) != null) { 482 return false; 483 } 484 } 485 486 return true; 487 } 488 } 489