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