• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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