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 java.net.InetAddress; 20 import java.net.Inet4Address; 21 import java.net.Inet6Address; 22 import java.net.UnknownHostException; 23 import java.util.Collection; 24 import java.util.Locale; 25 26 import android.os.Parcel; 27 import android.util.Log; 28 import android.util.Pair; 29 30 31 /** 32 * Native methods for managing network interfaces. 33 * 34 * {@hide} 35 */ 36 public class NetworkUtils { 37 38 private static final String TAG = "NetworkUtils"; 39 40 /** Setting bit 0 indicates reseting of IPv4 addresses required */ 41 public static final int RESET_IPV4_ADDRESSES = 0x01; 42 43 /** Setting bit 1 indicates reseting of IPv4 addresses required */ 44 public static final int RESET_IPV6_ADDRESSES = 0x02; 45 46 /** Reset all addresses */ 47 public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES; 48 49 /** 50 * Reset IPv6 or IPv4 sockets that are connected via the named interface. 51 * 52 * @param interfaceName is the interface to reset 53 * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES} 54 */ resetConnections(String interfaceName, int mask)55 public native static int resetConnections(String interfaceName, int mask); 56 57 /** 58 * Start the DHCP client daemon, in order to have it request addresses 59 * for the named interface, and then configure the interface with those 60 * addresses. This call blocks until it obtains a result (either success 61 * or failure) from the daemon. 62 * @param interfaceName the name of the interface to configure 63 * @param dhcpResults if the request succeeds, this object is filled in with 64 * the IP address information. 65 * @return {@code true} for success, {@code false} for failure 66 */ runDhcp(String interfaceName, DhcpResults dhcpResults)67 public native static boolean runDhcp(String interfaceName, DhcpResults dhcpResults); 68 69 /** 70 * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains 71 * a result (either success or failure) from the daemon. 72 * @param interfaceName the name of the interface to configure 73 * @param dhcpResults if the request succeeds, this object is filled in with 74 * the IP address information. 75 * @return {@code true} for success, {@code false} for failure 76 */ runDhcpRenew(String interfaceName, DhcpResults dhcpResults)77 public native static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults); 78 79 /** 80 * Shut down the DHCP client daemon. 81 * @param interfaceName the name of the interface for which the daemon 82 * should be stopped 83 * @return {@code true} for success, {@code false} for failure 84 */ stopDhcp(String interfaceName)85 public native static boolean stopDhcp(String interfaceName); 86 87 /** 88 * Release the current DHCP lease. 89 * @param interfaceName the name of the interface for which the lease should 90 * be released 91 * @return {@code true} for success, {@code false} for failure 92 */ releaseDhcpLease(String interfaceName)93 public native static boolean releaseDhcpLease(String interfaceName); 94 95 /** 96 * Return the last DHCP-related error message that was recorded. 97 * <p/>NOTE: This string is not localized, but currently it is only 98 * used in logging. 99 * @return the most recent error message, if any 100 */ getDhcpError()101 public native static String getDhcpError(); 102 103 /** 104 * Binds the current process to the network designated by {@code netId}. All sockets created 105 * in the future (and not explicitly bound via a bound {@link SocketFactory} (see 106 * {@link Network#getSocketFactory}) will be bound to this network. Note that if this 107 * {@code Network} ever disconnects all sockets created in this way will cease to work. This 108 * is by design so an application doesn't accidentally use sockets it thinks are still bound to 109 * a particular {@code Network}. Passing NETID_UNSET clears the binding. 110 */ bindProcessToNetwork(int netId)111 public native static boolean bindProcessToNetwork(int netId); 112 113 /** 114 * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if 115 * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. 116 */ getNetworkBoundToProcess()117 public native static int getNetworkBoundToProcess(); 118 119 /** 120 * Binds host resolutions performed by this process to the network designated by {@code netId}. 121 * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears 122 * the binding. 123 * 124 * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). 125 */ bindProcessToNetworkForHostResolution(int netId)126 public native static boolean bindProcessToNetworkForHostResolution(int netId); 127 128 /** 129 * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This 130 * overrides any binding via {@link #bindProcessToNetwork}. 131 * @return 0 on success or negative errno on failure. 132 */ bindSocketToNetwork(int socketfd, int netId)133 public native static int bindSocketToNetwork(int socketfd, int netId); 134 135 /** 136 * Protect {@code socketfd} from VPN connections. After protecting, data sent through 137 * this socket will go directly to the underlying network, so its traffic will not be 138 * forwarded through the VPN. 139 */ protectFromVpn(int socketfd)140 public native static boolean protectFromVpn(int socketfd); 141 142 /** 143 * Convert a IPv4 address from an integer to an InetAddress. 144 * @param hostAddress an int corresponding to the IPv4 address in network byte order 145 */ intToInetAddress(int hostAddress)146 public static InetAddress intToInetAddress(int hostAddress) { 147 byte[] addressBytes = { (byte)(0xff & hostAddress), 148 (byte)(0xff & (hostAddress >> 8)), 149 (byte)(0xff & (hostAddress >> 16)), 150 (byte)(0xff & (hostAddress >> 24)) }; 151 152 try { 153 return InetAddress.getByAddress(addressBytes); 154 } catch (UnknownHostException e) { 155 throw new AssertionError(); 156 } 157 } 158 159 /** 160 * Convert a IPv4 address from an InetAddress to an integer 161 * @param inetAddr is an InetAddress corresponding to the IPv4 address 162 * @return the IP address as an integer in network byte order 163 */ inetAddressToInt(Inet4Address inetAddr)164 public static int inetAddressToInt(Inet4Address inetAddr) 165 throws IllegalArgumentException { 166 byte [] addr = inetAddr.getAddress(); 167 return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) | 168 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff); 169 } 170 171 /** 172 * Convert a network prefix length to an IPv4 netmask integer 173 * @param prefixLength 174 * @return the IPv4 netmask as an integer in network byte order 175 */ prefixLengthToNetmaskInt(int prefixLength)176 public static int prefixLengthToNetmaskInt(int prefixLength) 177 throws IllegalArgumentException { 178 if (prefixLength < 0 || prefixLength > 32) { 179 throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); 180 } 181 int value = 0xffffffff << (32 - prefixLength); 182 return Integer.reverseBytes(value); 183 } 184 185 /** 186 * Convert a IPv4 netmask integer to a prefix length 187 * @param netmask as an integer in network byte order 188 * @return the network prefix length 189 */ netmaskIntToPrefixLength(int netmask)190 public static int netmaskIntToPrefixLength(int netmask) { 191 return Integer.bitCount(netmask); 192 } 193 194 /** 195 * Create an InetAddress from a string where the string must be a standard 196 * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure 197 * but it will throw an IllegalArgumentException in that case. 198 * @param addrString 199 * @return the InetAddress 200 * @hide 201 */ numericToInetAddress(String addrString)202 public static InetAddress numericToInetAddress(String addrString) 203 throws IllegalArgumentException { 204 return InetAddress.parseNumericAddress(addrString); 205 } 206 207 /** 208 * Writes an InetAddress to a parcel. The address may be null. This is likely faster than 209 * calling writeSerializable. 210 */ parcelInetAddress(Parcel parcel, InetAddress address, int flags)211 protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { 212 byte[] addressArray = (address != null) ? address.getAddress() : null; 213 parcel.writeByteArray(addressArray); 214 } 215 216 /** 217 * Reads an InetAddress from a parcel. Returns null if the address that was written was null 218 * or if the data is invalid. 219 */ unparcelInetAddress(Parcel in)220 protected static InetAddress unparcelInetAddress(Parcel in) { 221 byte[] addressArray = in.createByteArray(); 222 if (addressArray == null) { 223 return null; 224 } 225 try { 226 return InetAddress.getByAddress(addressArray); 227 } catch (UnknownHostException e) { 228 return null; 229 } 230 } 231 232 233 /** 234 * Masks a raw IP address byte array with the specified prefix length. 235 */ maskRawAddress(byte[] array, int prefixLength)236 public static void maskRawAddress(byte[] array, int prefixLength) { 237 if (prefixLength < 0 || prefixLength > array.length * 8) { 238 throw new RuntimeException("IP address with " + array.length + 239 " bytes has invalid prefix length " + prefixLength); 240 } 241 242 int offset = prefixLength / 8; 243 int remainder = prefixLength % 8; 244 byte mask = (byte)(0xFF << (8 - remainder)); 245 246 if (offset < array.length) array[offset] = (byte)(array[offset] & mask); 247 248 offset++; 249 250 for (; offset < array.length; offset++) { 251 array[offset] = 0; 252 } 253 } 254 255 /** 256 * Get InetAddress masked with prefixLength. Will never return null. 257 * @param address the IP address to mask with 258 * @param prefixLength the prefixLength used to mask the IP 259 */ getNetworkPart(InetAddress address, int prefixLength)260 public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { 261 byte[] array = address.getAddress(); 262 maskRawAddress(array, prefixLength); 263 264 InetAddress netPart = null; 265 try { 266 netPart = InetAddress.getByAddress(array); 267 } catch (UnknownHostException e) { 268 throw new RuntimeException("getNetworkPart error - " + e.toString()); 269 } 270 return netPart; 271 } 272 273 /** 274 * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64". 275 * @hide 276 */ parseIpAndMask(String ipAndMaskString)277 public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) { 278 InetAddress address = null; 279 int prefixLength = -1; 280 try { 281 String[] pieces = ipAndMaskString.split("/", 2); 282 prefixLength = Integer.parseInt(pieces[1]); 283 address = InetAddress.parseNumericAddress(pieces[0]); 284 } catch (NullPointerException e) { // Null string. 285 } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. 286 } catch (NumberFormatException e) { // Non-numeric prefix. 287 } catch (IllegalArgumentException e) { // Invalid IP address. 288 } 289 290 if (address == null || prefixLength == -1) { 291 throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString); 292 } 293 294 return new Pair<InetAddress, Integer>(address, prefixLength); 295 } 296 297 /** 298 * Check if IP address type is consistent between two InetAddress. 299 * @return true if both are the same type. False otherwise. 300 */ addressTypeMatches(InetAddress left, InetAddress right)301 public static boolean addressTypeMatches(InetAddress left, InetAddress right) { 302 return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || 303 ((left instanceof Inet6Address) && (right instanceof Inet6Address))); 304 } 305 306 /** 307 * Convert a 32 char hex string into a Inet6Address. 308 * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be 309 * made into an Inet6Address 310 * @param addrHexString a 32 character hex string representing an IPv6 addr 311 * @return addr an InetAddress representation for the string 312 */ hexToInet6Address(String addrHexString)313 public static InetAddress hexToInet6Address(String addrHexString) 314 throws IllegalArgumentException { 315 try { 316 return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", 317 addrHexString.substring(0,4), addrHexString.substring(4,8), 318 addrHexString.substring(8,12), addrHexString.substring(12,16), 319 addrHexString.substring(16,20), addrHexString.substring(20,24), 320 addrHexString.substring(24,28), addrHexString.substring(28,32))); 321 } catch (Exception e) { 322 Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); 323 throw new IllegalArgumentException(e); 324 } 325 } 326 327 /** 328 * Create a string array of host addresses from a collection of InetAddresses 329 * @param addrs a Collection of InetAddresses 330 * @return an array of Strings containing their host addresses 331 */ makeStrings(Collection<InetAddress> addrs)332 public static String[] makeStrings(Collection<InetAddress> addrs) { 333 String[] result = new String[addrs.size()]; 334 int i = 0; 335 for (InetAddress addr : addrs) { 336 result[i++] = addr.getHostAddress(); 337 } 338 return result; 339 } 340 341 /** 342 * Trim leading zeros from IPv4 address strings 343 * Our base libraries will interpret that as octel.. 344 * Must leave non v4 addresses and host names alone. 345 * For example, 192.168.000.010 -> 192.168.0.10 346 * TODO - fix base libraries and remove this function 347 * @param addr a string representing an ip addr 348 * @return a string propertly trimmed 349 */ trimV4AddrZeros(String addr)350 public static String trimV4AddrZeros(String addr) { 351 if (addr == null) return null; 352 String[] octets = addr.split("\\."); 353 if (octets.length != 4) return addr; 354 StringBuilder builder = new StringBuilder(16); 355 String result = null; 356 for (int i = 0; i < 4; i++) { 357 try { 358 if (octets[i].length() > 3) return addr; 359 builder.append(Integer.parseInt(octets[i])); 360 } catch (NumberFormatException e) { 361 return addr; 362 } 363 if (i < 3) builder.append('.'); 364 } 365 result = builder.toString(); 366 return result; 367 } 368 } 369