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 android.os.Parcel; 20 import android.util.Log; 21 import android.util.Pair; 22 23 import java.io.FileDescriptor; 24 import java.math.BigInteger; 25 import java.net.Inet4Address; 26 import java.net.Inet6Address; 27 import java.net.InetAddress; 28 import java.net.SocketException; 29 import java.net.UnknownHostException; 30 import java.util.Collection; 31 import java.util.Locale; 32 import java.util.TreeSet; 33 34 /** 35 * Native methods for managing network interfaces. 36 * 37 * {@hide} 38 */ 39 public class NetworkUtils { 40 41 private static final String TAG = "NetworkUtils"; 42 43 /** 44 * Attaches a socket filter that accepts DHCP packets to the given socket. 45 */ attachDhcpFilter(FileDescriptor fd)46 public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException; 47 48 /** 49 * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket. 50 * @param fd the socket's {@link FileDescriptor}. 51 * @param packetType the hardware address type, one of ARPHRD_*. 52 */ attachRaFilter(FileDescriptor fd, int packetType)53 public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException; 54 55 /** 56 * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity. 57 * 58 * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges. 59 * 60 * @param fd the socket's {@link FileDescriptor}. 61 * @param packetType the hardware address type, one of ARPHRD_*. 62 */ attachControlPacketFilter(FileDescriptor fd, int packetType)63 public native static void attachControlPacketFilter(FileDescriptor fd, int packetType) 64 throws SocketException; 65 66 /** 67 * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. 68 * @param fd the socket's {@link FileDescriptor}. 69 * @param ifIndex the interface index. 70 */ setupRaSocket(FileDescriptor fd, int ifIndex)71 public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException; 72 73 /** 74 * Binds the current process to the network designated by {@code netId}. All sockets created 75 * in the future (and not explicitly bound via a bound {@link SocketFactory} (see 76 * {@link Network#getSocketFactory}) will be bound to this network. Note that if this 77 * {@code Network} ever disconnects all sockets created in this way will cease to work. This 78 * is by design so an application doesn't accidentally use sockets it thinks are still bound to 79 * a particular {@code Network}. Passing NETID_UNSET clears the binding. 80 */ bindProcessToNetwork(int netId)81 public native static boolean bindProcessToNetwork(int netId); 82 83 /** 84 * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if 85 * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. 86 */ getBoundNetworkForProcess()87 public native static int getBoundNetworkForProcess(); 88 89 /** 90 * Binds host resolutions performed by this process to the network designated by {@code netId}. 91 * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears 92 * the binding. 93 * 94 * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). 95 */ 96 @Deprecated bindProcessToNetworkForHostResolution(int netId)97 public native static boolean bindProcessToNetworkForHostResolution(int netId); 98 99 /** 100 * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This 101 * overrides any binding via {@link #bindProcessToNetwork}. 102 * @return 0 on success or negative errno on failure. 103 */ bindSocketToNetwork(int socketfd, int netId)104 public native static int bindSocketToNetwork(int socketfd, int netId); 105 106 /** 107 * Protect {@code fd} 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(FileDescriptor fd)111 public static boolean protectFromVpn(FileDescriptor fd) { 112 return protectFromVpn(fd.getInt$()); 113 } 114 115 /** 116 * Protect {@code socketfd} from VPN connections. After protecting, data sent through 117 * this socket will go directly to the underlying network, so its traffic will not be 118 * forwarded through the VPN. 119 */ protectFromVpn(int socketfd)120 public native static boolean protectFromVpn(int socketfd); 121 122 /** 123 * Determine if {@code uid} can access network designated by {@code netId}. 124 * @return {@code true} if {@code uid} can access network, {@code false} otherwise. 125 */ queryUserAccess(int uid, int netId)126 public native static boolean queryUserAccess(int uid, int netId); 127 128 /** 129 * Convert a IPv4 address from an integer to an InetAddress. 130 * @param hostAddress an int corresponding to the IPv4 address in network byte order 131 */ intToInetAddress(int hostAddress)132 public static InetAddress intToInetAddress(int hostAddress) { 133 byte[] addressBytes = { (byte)(0xff & hostAddress), 134 (byte)(0xff & (hostAddress >> 8)), 135 (byte)(0xff & (hostAddress >> 16)), 136 (byte)(0xff & (hostAddress >> 24)) }; 137 138 try { 139 return InetAddress.getByAddress(addressBytes); 140 } catch (UnknownHostException e) { 141 throw new AssertionError(); 142 } 143 } 144 145 /** 146 * Convert a IPv4 address from an InetAddress to an integer 147 * @param inetAddr is an InetAddress corresponding to the IPv4 address 148 * @return the IP address as an integer in network byte order 149 */ inetAddressToInt(Inet4Address inetAddr)150 public static int inetAddressToInt(Inet4Address inetAddr) 151 throws IllegalArgumentException { 152 byte [] addr = inetAddr.getAddress(); 153 return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) | 154 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff); 155 } 156 157 /** 158 * Convert a network prefix length to an IPv4 netmask integer 159 * @param prefixLength 160 * @return the IPv4 netmask as an integer in network byte order 161 */ prefixLengthToNetmaskInt(int prefixLength)162 public static int prefixLengthToNetmaskInt(int prefixLength) 163 throws IllegalArgumentException { 164 if (prefixLength < 0 || prefixLength > 32) { 165 throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); 166 } 167 int value = 0xffffffff << (32 - prefixLength); 168 return Integer.reverseBytes(value); 169 } 170 171 /** 172 * Convert a IPv4 netmask integer to a prefix length 173 * @param netmask as an integer in network byte order 174 * @return the network prefix length 175 */ netmaskIntToPrefixLength(int netmask)176 public static int netmaskIntToPrefixLength(int netmask) { 177 return Integer.bitCount(netmask); 178 } 179 180 /** 181 * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. 182 * @param netmask as a {@code Inet4Address}. 183 * @return the network prefix length 184 * @throws IllegalArgumentException the specified netmask was not contiguous. 185 * @hide 186 */ netmaskToPrefixLength(Inet4Address netmask)187 public static int netmaskToPrefixLength(Inet4Address netmask) { 188 // inetAddressToInt returns an int in *network* byte order. 189 int i = Integer.reverseBytes(inetAddressToInt(netmask)); 190 int prefixLength = Integer.bitCount(i); 191 int trailingZeros = Integer.numberOfTrailingZeros(i); 192 if (trailingZeros != 32 - prefixLength) { 193 throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); 194 } 195 return prefixLength; 196 } 197 198 199 /** 200 * Create an InetAddress from a string where the string must be a standard 201 * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure 202 * but it will throw an IllegalArgumentException in that case. 203 * @param addrString 204 * @return the InetAddress 205 * @hide 206 */ numericToInetAddress(String addrString)207 public static InetAddress numericToInetAddress(String addrString) 208 throws IllegalArgumentException { 209 return InetAddress.parseNumericAddress(addrString); 210 } 211 212 /** 213 * Writes an InetAddress to a parcel. The address may be null. This is likely faster than 214 * calling writeSerializable. 215 */ parcelInetAddress(Parcel parcel, InetAddress address, int flags)216 protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { 217 byte[] addressArray = (address != null) ? address.getAddress() : null; 218 parcel.writeByteArray(addressArray); 219 } 220 221 /** 222 * Reads an InetAddress from a parcel. Returns null if the address that was written was null 223 * or if the data is invalid. 224 */ unparcelInetAddress(Parcel in)225 protected static InetAddress unparcelInetAddress(Parcel in) { 226 byte[] addressArray = in.createByteArray(); 227 if (addressArray == null) { 228 return null; 229 } 230 try { 231 return InetAddress.getByAddress(addressArray); 232 } catch (UnknownHostException e) { 233 return null; 234 } 235 } 236 237 238 /** 239 * Masks a raw IP address byte array with the specified prefix length. 240 */ maskRawAddress(byte[] array, int prefixLength)241 public static void maskRawAddress(byte[] array, int prefixLength) { 242 if (prefixLength < 0 || prefixLength > array.length * 8) { 243 throw new RuntimeException("IP address with " + array.length + 244 " bytes has invalid prefix length " + prefixLength); 245 } 246 247 int offset = prefixLength / 8; 248 int remainder = prefixLength % 8; 249 byte mask = (byte)(0xFF << (8 - remainder)); 250 251 if (offset < array.length) array[offset] = (byte)(array[offset] & mask); 252 253 offset++; 254 255 for (; offset < array.length; offset++) { 256 array[offset] = 0; 257 } 258 } 259 260 /** 261 * Get InetAddress masked with prefixLength. Will never return null. 262 * @param address the IP address to mask with 263 * @param prefixLength the prefixLength used to mask the IP 264 */ getNetworkPart(InetAddress address, int prefixLength)265 public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { 266 byte[] array = address.getAddress(); 267 maskRawAddress(array, prefixLength); 268 269 InetAddress netPart = null; 270 try { 271 netPart = InetAddress.getByAddress(array); 272 } catch (UnknownHostException e) { 273 throw new RuntimeException("getNetworkPart error - " + e.toString()); 274 } 275 return netPart; 276 } 277 278 /** 279 * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. 280 */ getImplicitNetmask(Inet4Address address)281 public static int getImplicitNetmask(Inet4Address address) { 282 int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. 283 if (firstByte < 128) { 284 return 8; 285 } else if (firstByte < 192) { 286 return 16; 287 } else if (firstByte < 224) { 288 return 24; 289 } else { 290 return 32; // Will likely not end well for other reasons. 291 } 292 } 293 294 /** 295 * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". 296 * @hide 297 */ parseIpAndMask(String ipAndMaskString)298 public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) { 299 InetAddress address = null; 300 int prefixLength = -1; 301 try { 302 String[] pieces = ipAndMaskString.split("/", 2); 303 prefixLength = Integer.parseInt(pieces[1]); 304 address = InetAddress.parseNumericAddress(pieces[0]); 305 } catch (NullPointerException e) { // Null string. 306 } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. 307 } catch (NumberFormatException e) { // Non-numeric prefix. 308 } catch (IllegalArgumentException e) { // Invalid IP address. 309 } 310 311 if (address == null || prefixLength == -1) { 312 throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); 313 } 314 315 return new Pair<InetAddress, Integer>(address, prefixLength); 316 } 317 318 /** 319 * Check if IP address type is consistent between two InetAddress. 320 * @return true if both are the same type. False otherwise. 321 */ addressTypeMatches(InetAddress left, InetAddress right)322 public static boolean addressTypeMatches(InetAddress left, InetAddress right) { 323 return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || 324 ((left instanceof Inet6Address) && (right instanceof Inet6Address))); 325 } 326 327 /** 328 * Convert a 32 char hex string into a Inet6Address. 329 * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be 330 * made into an Inet6Address 331 * @param addrHexString a 32 character hex string representing an IPv6 addr 332 * @return addr an InetAddress representation for the string 333 */ hexToInet6Address(String addrHexString)334 public static InetAddress hexToInet6Address(String addrHexString) 335 throws IllegalArgumentException { 336 try { 337 return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", 338 addrHexString.substring(0,4), addrHexString.substring(4,8), 339 addrHexString.substring(8,12), addrHexString.substring(12,16), 340 addrHexString.substring(16,20), addrHexString.substring(20,24), 341 addrHexString.substring(24,28), addrHexString.substring(28,32))); 342 } catch (Exception e) { 343 Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); 344 throw new IllegalArgumentException(e); 345 } 346 } 347 348 /** 349 * Create a string array of host addresses from a collection of InetAddresses 350 * @param addrs a Collection of InetAddresses 351 * @return an array of Strings containing their host addresses 352 */ makeStrings(Collection<InetAddress> addrs)353 public static String[] makeStrings(Collection<InetAddress> addrs) { 354 String[] result = new String[addrs.size()]; 355 int i = 0; 356 for (InetAddress addr : addrs) { 357 result[i++] = addr.getHostAddress(); 358 } 359 return result; 360 } 361 362 /** 363 * Trim leading zeros from IPv4 address strings 364 * Our base libraries will interpret that as octel.. 365 * Must leave non v4 addresses and host names alone. 366 * For example, 192.168.000.010 -> 192.168.0.10 367 * TODO - fix base libraries and remove this function 368 * @param addr a string representing an ip addr 369 * @return a string propertly trimmed 370 */ trimV4AddrZeros(String addr)371 public static String trimV4AddrZeros(String addr) { 372 if (addr == null) return null; 373 String[] octets = addr.split("\\."); 374 if (octets.length != 4) return addr; 375 StringBuilder builder = new StringBuilder(16); 376 String result = null; 377 for (int i = 0; i < 4; i++) { 378 try { 379 if (octets[i].length() > 3) return addr; 380 builder.append(Integer.parseInt(octets[i])); 381 } catch (NumberFormatException e) { 382 return addr; 383 } 384 if (i < 3) builder.append('.'); 385 } 386 result = builder.toString(); 387 return result; 388 } 389 390 /** 391 * Returns a prefix set without overlaps. 392 * 393 * This expects the src set to be sorted from shorter to longer. Results are undefined 394 * failing this condition. The returned prefix set is sorted in the same order as the 395 * passed set, with the same comparator. 396 */ deduplicatePrefixSet(final TreeSet<IpPrefix> src)397 private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) { 398 final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator()); 399 // Prefixes match addresses that share their upper part up to their length, therefore 400 // the only kind of possible overlap in two prefixes is strict inclusion of the longer 401 // (more restrictive) in the shorter (including equivalence if they have the same 402 // length). 403 // Because prefixes in the src set are sorted from shorter to longer, deduplicating 404 // is done by simply iterating in order, and not adding any longer prefix that is 405 // already covered by a shorter one. 406 newPrefixes: 407 for (IpPrefix newPrefix : src) { 408 for (IpPrefix existingPrefix : dst) { 409 if (existingPrefix.containsPrefix(newPrefix)) { 410 continue newPrefixes; 411 } 412 } 413 dst.add(newPrefix); 414 } 415 return dst; 416 } 417 418 /** 419 * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set. 420 * 421 * Obviously this returns an integral value between 0 and 2**32. 422 * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the 423 * set is not ordered smallest prefix to longer prefix. 424 * 425 * @param prefixes the set of prefixes, ordered by length 426 */ routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes)427 public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) { 428 long routedIPCount = 0; 429 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 430 if (!prefix.isIPv4()) { 431 Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount"); 432 } 433 int rank = 32 - prefix.getPrefixLength(); 434 routedIPCount += 1L << rank; 435 } 436 return routedIPCount; 437 } 438 439 /** 440 * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set. 441 * 442 * This returns a BigInteger between 0 and 2**128. 443 * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the 444 * set is not ordered smallest prefix to longer prefix. 445 */ routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes)446 public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) { 447 BigInteger routedIPCount = BigInteger.ZERO; 448 for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) { 449 if (!prefix.isIPv6()) { 450 Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount"); 451 } 452 int rank = 128 - prefix.getPrefixLength(); 453 routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank)); 454 } 455 return routedIPCount; 456 } 457 } 458