Home | History | Annotate | Download | only in net
      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      */
     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      */
     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      */
     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      */
     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      */
     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      */
     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
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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