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.compat.annotation.UnsupportedAppUsage;
24 import android.os.Build;
25 import android.system.ErrnoException;
26 import android.system.Os;
27 import android.util.Log;
28 import android.util.Pair;
29 
30 import com.android.net.module.util.Inet4AddressUtils;
31 
32 import java.io.FileDescriptor;
33 import java.math.BigInteger;
34 import java.net.Inet4Address;
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      * Binds the current process to the network designated by {@code netId}.  All sockets created
65      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
66      * {@link Network#getSocketFactory}) will be bound to this network.  Note that if this
67      * {@code Network} ever disconnects all sockets created in this way will cease to work.  This
68      * is by design so an application doesn't accidentally use sockets it thinks are still bound to
69      * a particular {@code Network}.  Passing NETID_UNSET clears the binding.
70      */
bindProcessToNetwork(int netId)71     public native static boolean bindProcessToNetwork(int netId);
72 
73     /**
74      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
75      * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
76      */
getBoundNetworkForProcess()77     public native static int getBoundNetworkForProcess();
78 
79     /**
80      * Binds host resolutions performed by this process to the network designated by {@code netId}.
81      * {@link #bindProcessToNetwork} takes precedence over this setting.  Passing NETID_UNSET clears
82      * the binding.
83      *
84      * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
85      */
86     @Deprecated
bindProcessToNetworkForHostResolution(int netId)87     public native static boolean bindProcessToNetworkForHostResolution(int netId);
88 
89     /**
90      * Explicitly binds {@code socketfd} to the network designated by {@code netId}.  This
91      * overrides any binding via {@link #bindProcessToNetwork}.
92      * @return 0 on success or negative errno on failure.
93      */
bindSocketToNetwork(int socketfd, int netId)94     public native static int bindSocketToNetwork(int socketfd, int netId);
95 
96     /**
97      * Protect {@code fd} from VPN connections.  After protecting, data sent through
98      * this socket will go directly to the underlying network, so its traffic will not be
99      * forwarded through the VPN.
100      */
101     @UnsupportedAppUsage
protectFromVpn(FileDescriptor fd)102     public static boolean protectFromVpn(FileDescriptor fd) {
103         return protectFromVpn(fd.getInt$());
104     }
105 
106     /**
107      * Protect {@code socketfd} 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(int socketfd)111     public native static boolean protectFromVpn(int socketfd);
112 
113     /**
114      * Determine if {@code uid} can access network designated by {@code netId}.
115      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
116      */
queryUserAccess(int uid, int netId)117     public native static boolean queryUserAccess(int uid, int netId);
118 
119     /**
120      * DNS resolver series jni method.
121      * Issue the query {@code msg} on the network designated by {@code netId}.
122      * {@code flags} is an additional config to control actual querying behavior.
123      * @return a file descriptor to watch for read events
124      */
resNetworkSend( int netId, byte[] msg, int msglen, int flags)125     public static native FileDescriptor resNetworkSend(
126             int netId, byte[] msg, int msglen, int flags) throws ErrnoException;
127 
128     /**
129      * DNS resolver series jni method.
130      * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated
131      * with Domain Name {@code dname} on the network designated by {@code netId}.
132      * {@code flags} is an additional config to control actual querying behavior.
133      * @return a file descriptor to watch for read events
134      */
resNetworkQuery( int netId, String dname, int nsClass, int nsType, int flags)135     public static native FileDescriptor resNetworkQuery(
136             int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
137 
138     /**
139      * DNS resolver series jni method.
140      * Read a result for the query associated with the {@code fd}.
141      * @return DnsResponse containing blob answer and rcode
142      */
resNetworkResult(FileDescriptor fd)143     public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
144             throws ErrnoException;
145 
146     /**
147      * DNS resolver series jni method.
148      * Attempts to cancel the in-progress query associated with the {@code fd}.
149      */
resNetworkCancel(FileDescriptor fd)150     public static native void resNetworkCancel(FileDescriptor fd);
151 
152     /**
153      * DNS resolver series jni method.
154      * Attempts to get network which resolver will use if no network is explicitly selected.
155      */
getDnsNetwork()156     public static native Network getDnsNetwork() throws ErrnoException;
157 
158     /**
159      * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
160      *
161      * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
162      *                        and DNS lookups.
163      */
setAllowNetworkingForProcess(boolean allowNetworking)164     public static native void setAllowNetworkingForProcess(boolean allowNetworking);
165 
166     /**
167      * Get the tcp repair window associated with the {@code fd}.
168      *
169      * @param fd the tcp socket's {@link FileDescriptor}.
170      * @return a {@link TcpRepairWindow} object indicates tcp window size.
171      */
getTcpRepairWindow(FileDescriptor fd)172     public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd)
173             throws ErrnoException;
174 
175     /**
176      * @see Inet4AddressUtils#intToInet4AddressHTL(int)
177      * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
178      *             or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
179      */
180     @Deprecated
181     @UnsupportedAppUsage
intToInetAddress(int hostAddress)182     public static InetAddress intToInetAddress(int hostAddress) {
183         return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
184     }
185 
186     /**
187      * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
188      * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
189      *             or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
190      */
191     @Deprecated
inetAddressToInt(Inet4Address inetAddr)192     public static int inetAddressToInt(Inet4Address inetAddr)
193             throws IllegalArgumentException {
194         return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
195     }
196 
197     /**
198      * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
199      * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
200      *             or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
201      */
202     @Deprecated
203     @UnsupportedAppUsage
prefixLengthToNetmaskInt(int prefixLength)204     public static int prefixLengthToNetmaskInt(int prefixLength)
205             throws IllegalArgumentException {
206         return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
207     }
208 
209     /**
210      * Convert a IPv4 netmask integer to a prefix length
211      * @param netmask as an integer (0xff000000 for a /8 subnet)
212      * @return the network prefix length
213      */
netmaskIntToPrefixLength(int netmask)214     public static int netmaskIntToPrefixLength(int netmask) {
215         return Integer.bitCount(netmask);
216     }
217 
218     /**
219      * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
220      * @param netmask as a {@code Inet4Address}.
221      * @return the network prefix length
222      * @throws IllegalArgumentException the specified netmask was not contiguous.
223      * @hide
224      * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
225      */
226     @UnsupportedAppUsage
227     @Deprecated
netmaskToPrefixLength(Inet4Address netmask)228     public static int netmaskToPrefixLength(Inet4Address netmask) {
229         // This is only here because some apps seem to be using it (@UnsupportedAppUsage).
230         return Inet4AddressUtils.netmaskToPrefixLength(netmask);
231     }
232 
233 
234     /**
235      * Create an InetAddress from a string where the string must be a standard
236      * representation of a V4 or V6 address.  Avoids doing a DNS lookup on failure
237      * but it will throw an IllegalArgumentException in that case.
238      * @param addrString
239      * @return the InetAddress
240      * @hide
241      * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible.
242      */
243     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
244     @Deprecated
numericToInetAddress(String addrString)245     public static InetAddress numericToInetAddress(String addrString)
246             throws IllegalArgumentException {
247         return InetAddress.parseNumericAddress(addrString);
248     }
249 
250     /**
251      *  Masks a raw IP address byte array with the specified prefix length.
252      */
maskRawAddress(byte[] array, int prefixLength)253     public static void maskRawAddress(byte[] array, int prefixLength) {
254         if (prefixLength < 0 || prefixLength > array.length * 8) {
255             throw new RuntimeException("IP address with " + array.length +
256                     " bytes has invalid prefix length " + prefixLength);
257         }
258 
259         int offset = prefixLength / 8;
260         int remainder = prefixLength % 8;
261         byte mask = (byte)(0xFF << (8 - remainder));
262 
263         if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
264 
265         offset++;
266 
267         for (; offset < array.length; offset++) {
268             array[offset] = 0;
269         }
270     }
271 
272     /**
273      * Get InetAddress masked with prefixLength.  Will never return null.
274      * @param address the IP address to mask with
275      * @param prefixLength the prefixLength used to mask the IP
276      */
getNetworkPart(InetAddress address, int prefixLength)277     public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
278         byte[] array = address.getAddress();
279         maskRawAddress(array, prefixLength);
280 
281         InetAddress netPart = null;
282         try {
283             netPart = InetAddress.getByAddress(array);
284         } catch (UnknownHostException e) {
285             throw new RuntimeException("getNetworkPart error - " + e.toString());
286         }
287         return netPart;
288     }
289 
290     /**
291      * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
292      */
293     @UnsupportedAppUsage
getImplicitNetmask(Inet4Address address)294     public static int getImplicitNetmask(Inet4Address address) {
295         // Only here because it seems to be used by apps
296         return Inet4AddressUtils.getImplicitNetmask(address);
297     }
298 
299     /**
300      * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
301      * @hide
302      */
parseIpAndMask(String ipAndMaskString)303     public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
304         InetAddress address = null;
305         int prefixLength = -1;
306         try {
307             String[] pieces = ipAndMaskString.split("/", 2);
308             prefixLength = Integer.parseInt(pieces[1]);
309             address = InetAddress.parseNumericAddress(pieces[0]);
310         } catch (NullPointerException e) {            // Null string.
311         } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
312         } catch (NumberFormatException e) {           // Non-numeric prefix.
313         } catch (IllegalArgumentException e) {        // Invalid IP address.
314         }
315 
316         if (address == null || prefixLength == -1) {
317             throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
318         }
319 
320         return new Pair<InetAddress, Integer>(address, prefixLength);
321     }
322 
323     /**
324      * Convert a 32 char hex string into a Inet6Address.
325      * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
326      * made into an Inet6Address
327      * @param addrHexString a 32 character hex string representing an IPv6 addr
328      * @return addr an InetAddress representation for the string
329      */
hexToInet6Address(String addrHexString)330     public static InetAddress hexToInet6Address(String addrHexString)
331             throws IllegalArgumentException {
332         try {
333             return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
334                     addrHexString.substring(0,4),   addrHexString.substring(4,8),
335                     addrHexString.substring(8,12),  addrHexString.substring(12,16),
336                     addrHexString.substring(16,20), addrHexString.substring(20,24),
337                     addrHexString.substring(24,28), addrHexString.substring(28,32)));
338         } catch (Exception e) {
339             Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
340             throw new IllegalArgumentException(e);
341         }
342     }
343 
344     /**
345      * Create a string array of host addresses from a collection of InetAddresses
346      * @param addrs a Collection of InetAddresses
347      * @return an array of Strings containing their host addresses
348      */
makeStrings(Collection<InetAddress> addrs)349     public static String[] makeStrings(Collection<InetAddress> addrs) {
350         String[] result = new String[addrs.size()];
351         int i = 0;
352         for (InetAddress addr : addrs) {
353             result[i++] = addr.getHostAddress();
354         }
355         return result;
356     }
357 
358     /**
359      * Trim leading zeros from IPv4 address strings
360      * Our base libraries will interpret that as octel..
361      * Must leave non v4 addresses and host names alone.
362      * For example, 192.168.000.010 -> 192.168.0.10
363      * TODO - fix base libraries and remove this function
364      * @param addr a string representing an ip addr
365      * @return a string propertly trimmed
366      */
367     @UnsupportedAppUsage
trimV4AddrZeros(String addr)368     public static String trimV4AddrZeros(String addr) {
369         if (addr == null) return null;
370         String[] octets = addr.split("\\.");
371         if (octets.length != 4) return addr;
372         StringBuilder builder = new StringBuilder(16);
373         String result = null;
374         for (int i = 0; i < 4; i++) {
375             try {
376                 if (octets[i].length() > 3) return addr;
377                 builder.append(Integer.parseInt(octets[i]));
378             } catch (NumberFormatException e) {
379                 return addr;
380             }
381             if (i < 3) builder.append('.');
382         }
383         result = builder.toString();
384         return result;
385     }
386 
387     /**
388      * Returns a prefix set without overlaps.
389      *
390      * This expects the src set to be sorted from shorter to longer. Results are undefined
391      * failing this condition. The returned prefix set is sorted in the same order as the
392      * passed set, with the same comparator.
393      */
deduplicatePrefixSet(final TreeSet<IpPrefix> src)394     private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
395         final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
396         // Prefixes match addresses that share their upper part up to their length, therefore
397         // the only kind of possible overlap in two prefixes is strict inclusion of the longer
398         // (more restrictive) in the shorter (including equivalence if they have the same
399         // length).
400         // Because prefixes in the src set are sorted from shorter to longer, deduplicating
401         // is done by simply iterating in order, and not adding any longer prefix that is
402         // already covered by a shorter one.
403         newPrefixes:
404         for (IpPrefix newPrefix : src) {
405             for (IpPrefix existingPrefix : dst) {
406                 if (existingPrefix.containsPrefix(newPrefix)) {
407                     continue newPrefixes;
408                 }
409             }
410             dst.add(newPrefix);
411         }
412         return dst;
413     }
414 
415     /**
416      * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
417      *
418      * Obviously this returns an integral value between 0 and 2**32.
419      * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
420      * set is not ordered smallest prefix to longer prefix.
421      *
422      * @param prefixes the set of prefixes, ordered by length
423      */
routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes)424     public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
425         long routedIPCount = 0;
426         for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
427             if (!prefix.isIPv4()) {
428                 Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
429             }
430             int rank = 32 - prefix.getPrefixLength();
431             routedIPCount += 1L << rank;
432         }
433         return routedIPCount;
434     }
435 
436     /**
437      * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
438      *
439      * This returns a BigInteger between 0 and 2**128.
440      * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
441      * set is not ordered smallest prefix to longer prefix.
442      */
routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes)443     public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
444         BigInteger routedIPCount = BigInteger.ZERO;
445         for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
446             if (!prefix.isIPv6()) {
447                 Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
448             }
449             int rank = 128 - prefix.getPrefixLength();
450             routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
451         }
452         return routedIPCount;
453     }
454 
455     private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
456 
457     /**
458      * Returns true if the hostname is weakly validated.
459      * @param hostname Name of host to validate.
460      * @return True if it's a valid-ish hostname.
461      *
462      * @hide
463      */
isWeaklyValidatedHostname(@onNull String hostname)464     public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
465         // TODO(b/34953048): Use a validation method that permits more accurate,
466         // but still inexpensive, checking of likely valid DNS hostnames.
467         final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
468         if (!hostname.matches(weakHostnameRegex)) {
469             return false;
470         }
471 
472         for (int address_family : ADDRESS_FAMILIES) {
473             if (Os.inet_pton(address_family, hostname) != null) {
474                 return false;
475             }
476         }
477 
478         return true;
479     }
480 }
481