• 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.net.ConnectivityManager.NETID_UNSET;
20 
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.Build;
23 import android.system.ErrnoException;
24 import android.util.Log;
25 import android.util.Pair;
26 
27 import com.android.net.module.util.Inet4AddressUtils;
28 
29 import java.io.FileDescriptor;
30 import java.math.BigInteger;
31 import java.net.Inet4Address;
32 import java.net.Inet6Address;
33 import java.net.InetAddress;
34 import java.net.SocketException;
35 import java.net.UnknownHostException;
36 import java.util.Locale;
37 import java.util.TreeSet;
38 
39 /**
40  * Native methods for managing network interfaces.
41  *
42  * {@hide}
43  */
44 public class NetworkUtils {
45     static {
46         System.loadLibrary("framework-connectivity-jni");
47     }
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 
bindProcessToNetworkHandle(long netHandle)63     private static native boolean bindProcessToNetworkHandle(long netHandle);
64 
65     /**
66      * Binds the current process to the network designated by {@code netId}.  All sockets created
67      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
68      * {@link Network#getSocketFactory}) will be bound to this network.  Note that if this
69      * {@code Network} ever disconnects all sockets created in this way will cease to work.  This
70      * is by design so an application doesn't accidentally use sockets it thinks are still bound to
71      * a particular {@code Network}.  Passing NETID_UNSET clears the binding.
72      */
bindProcessToNetwork(int netId)73     public static boolean bindProcessToNetwork(int netId) {
74         return bindProcessToNetworkHandle(new Network(netId).getNetworkHandle());
75     }
76 
getBoundNetworkHandleForProcess()77     private static native long getBoundNetworkHandleForProcess();
78 
79     /**
80      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
81      * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
82      */
getBoundNetworkForProcess()83     public static int getBoundNetworkForProcess() {
84         final long netHandle = getBoundNetworkHandleForProcess();
85         return netHandle == 0L ? NETID_UNSET : Network.fromNetworkHandle(netHandle).getNetId();
86     }
87 
88     /**
89      * Binds host resolutions performed by this process to the network designated by {@code netId}.
90      * {@link #bindProcessToNetwork} takes precedence over this setting.  Passing NETID_UNSET clears
91      * the binding.
92      *
93      * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
94      */
95     @Deprecated
bindProcessToNetworkForHostResolution(int netId)96     public native static boolean bindProcessToNetworkForHostResolution(int netId);
97 
bindSocketToNetworkHandle(FileDescriptor fd, long netHandle)98     private static native int bindSocketToNetworkHandle(FileDescriptor fd, long netHandle);
99 
100     /**
101      * Explicitly binds {@code fd} to the network designated by {@code netId}.  This
102      * overrides any binding via {@link #bindProcessToNetwork}.
103      * @return 0 on success or negative errno on failure.
104      */
bindSocketToNetwork(FileDescriptor fd, int netId)105     public static int bindSocketToNetwork(FileDescriptor fd, int netId) {
106         return bindSocketToNetworkHandle(fd, new Network(netId).getNetworkHandle());
107     }
108 
109     /**
110      * Determine if {@code uid} can access network designated by {@code netId}.
111      * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
112      */
queryUserAccess(int uid, int netId)113     public static boolean queryUserAccess(int uid, int netId) {
114         // TODO (b/183485986): remove this method
115         return false;
116     }
117 
resNetworkSend( long netHandle, byte[] msg, int msglen, int flags)118     private static native FileDescriptor resNetworkSend(
119             long netHandle, byte[] msg, int msglen, int flags) throws ErrnoException;
120 
121     /**
122      * DNS resolver series jni method.
123      * Issue the query {@code msg} on the network designated by {@code netId}.
124      * {@code flags} is an additional config to control actual querying behavior.
125      * @return a file descriptor to watch for read events
126      */
resNetworkSend( int netId, byte[] msg, int msglen, int flags)127     public static FileDescriptor resNetworkSend(
128             int netId, byte[] msg, int msglen, int flags) throws ErrnoException {
129         return resNetworkSend(new Network(netId).getNetworkHandle(), msg, msglen, flags);
130     }
131 
resNetworkQuery( long netHandle, String dname, int nsClass, int nsType, int flags)132     private static native FileDescriptor resNetworkQuery(
133             long netHandle, String dname, int nsClass, int nsType, 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 FileDescriptor resNetworkQuery(
143             int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException {
144         return resNetworkQuery(new Network(netId).getNetworkHandle(), dname, nsClass, nsType,
145                 flags);
146     }
147 
148     /**
149      * DNS resolver series jni method.
150      * Read a result for the query associated with the {@code fd}.
151      * @return DnsResponse containing blob answer and rcode
152      */
resNetworkResult(FileDescriptor fd)153     public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
154             throws ErrnoException;
155 
156     /**
157      * DNS resolver series jni method.
158      * Attempts to cancel the in-progress query associated with the {@code fd}.
159      */
resNetworkCancel(FileDescriptor fd)160     public static native void resNetworkCancel(FileDescriptor fd);
161 
162     /**
163      * DNS resolver series jni method.
164      * Attempts to get network which resolver will use if no network is explicitly selected.
165      */
getDnsNetwork()166     public static native Network getDnsNetwork() throws ErrnoException;
167 
168     /**
169      * Get the tcp repair window associated with the {@code fd}.
170      *
171      * @param fd the tcp socket's {@link FileDescriptor}.
172      * @return a {@link TcpRepairWindow} object indicates tcp window size.
173      */
getTcpRepairWindow(FileDescriptor fd)174     public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd)
175             throws ErrnoException;
176 
177     /**
178      * @see Inet4AddressUtils#intToInet4AddressHTL(int)
179      * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
180      *             or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
181      */
182     @Deprecated
183     @UnsupportedAppUsage
intToInetAddress(int hostAddress)184     public static InetAddress intToInetAddress(int hostAddress) {
185         return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
186     }
187 
188     /**
189      * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
190      * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
191      *             or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
192      */
193     @Deprecated
inetAddressToInt(Inet4Address inetAddr)194     public static int inetAddressToInt(Inet4Address inetAddr)
195             throws IllegalArgumentException {
196         return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
197     }
198 
199     /**
200      * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
201      * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
202      *             or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
203      */
204     @Deprecated
205     @UnsupportedAppUsage
prefixLengthToNetmaskInt(int prefixLength)206     public static int prefixLengthToNetmaskInt(int prefixLength)
207             throws IllegalArgumentException {
208         return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
209     }
210 
211     /**
212      * Convert a IPv4 netmask integer to a prefix length
213      * @param netmask as an integer (0xff000000 for a /8 subnet)
214      * @return the network prefix length
215      */
netmaskIntToPrefixLength(int netmask)216     public static int netmaskIntToPrefixLength(int netmask) {
217         return Integer.bitCount(netmask);
218     }
219 
220     /**
221      * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
222      * @param netmask as a {@code Inet4Address}.
223      * @return the network prefix length
224      * @throws IllegalArgumentException the specified netmask was not contiguous.
225      * @hide
226      * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
227      */
228     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
229     @Deprecated
netmaskToPrefixLength(Inet4Address netmask)230     public static int netmaskToPrefixLength(Inet4Address netmask) {
231         // This is only here because some apps seem to be using it (@UnsupportedAppUsage).
232         return Inet4AddressUtils.netmaskToPrefixLength(netmask);
233     }
234 
235 
236     /**
237      * Create an InetAddress from a string where the string must be a standard
238      * representation of a V4 or V6 address.  Avoids doing a DNS lookup on failure
239      * but it will throw an IllegalArgumentException in that case.
240      * @param addrString
241      * @return the InetAddress
242      * @hide
243      * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible.
244      */
245     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
246     @Deprecated
numericToInetAddress(String addrString)247     public static InetAddress numericToInetAddress(String addrString)
248             throws IllegalArgumentException {
249         return InetAddresses.parseNumericAddress(addrString);
250     }
251 
252     /**
253      * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
254      */
255     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getImplicitNetmask(Inet4Address address)256     public static int getImplicitNetmask(Inet4Address address) {
257         // Only here because it seems to be used by apps
258         return Inet4AddressUtils.getImplicitNetmask(address);
259     }
260 
261     /**
262      * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
263      * @hide
264      */
parseIpAndMask(String ipAndMaskString)265     public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
266         InetAddress address = null;
267         int prefixLength = -1;
268         try {
269             String[] pieces = ipAndMaskString.split("/", 2);
270             prefixLength = Integer.parseInt(pieces[1]);
271             address = InetAddresses.parseNumericAddress(pieces[0]);
272         } catch (NullPointerException e) {            // Null string.
273         } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
274         } catch (NumberFormatException e) {           // Non-numeric prefix.
275         } catch (IllegalArgumentException e) {        // Invalid IP address.
276         }
277 
278         if (address == null || prefixLength == -1) {
279             throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
280         }
281 
282         return new Pair<InetAddress, Integer>(address, prefixLength);
283     }
284 
285     /**
286      * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
287      * @hide
288      *
289      * @deprecated This method is used only for IpPrefix and LinkAddress. Since Android S, use
290      *             {@link #parseIpAndMask(String)}, if possible.
291      */
292     @Deprecated
legacyParseIpAndMask(String ipAndMaskString)293     public static Pair<InetAddress, Integer> legacyParseIpAndMask(String ipAndMaskString) {
294         InetAddress address = null;
295         int prefixLength = -1;
296         try {
297             String[] pieces = ipAndMaskString.split("/", 2);
298             prefixLength = Integer.parseInt(pieces[1]);
299             if (pieces[0] == null || pieces[0].isEmpty()) {
300                 final byte[] bytes = new byte[16];
301                 bytes[15] = 1;
302                 return new Pair<InetAddress, Integer>(Inet6Address.getByAddress(
303                         "ip6-localhost"/* host */, bytes, 0 /* scope_id */), prefixLength);
304             }
305 
306             if (pieces[0].startsWith("[")
307                     && pieces[0].endsWith("]")
308                     && pieces[0].indexOf(':') != -1) {
309                 pieces[0] = pieces[0].substring(1, pieces[0].length() - 1);
310             }
311             address = InetAddresses.parseNumericAddress(pieces[0]);
312         } catch (NullPointerException e) {            // Null string.
313         } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
314         } catch (NumberFormatException e) {           // Non-numeric prefix.
315         } catch (IllegalArgumentException e) {        // Invalid IP address.
316         } catch (UnknownHostException e) {            // IP address length is illegal
317         }
318 
319         if (address == null || prefixLength == -1) {
320             throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
321         }
322 
323         return new Pair<InetAddress, Integer>(address, prefixLength);
324     }
325 
326     /**
327      * Convert a 32 char hex string into a Inet6Address.
328      * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
329      * made into an Inet6Address
330      * @param addrHexString a 32 character hex string representing an IPv6 addr
331      * @return addr an InetAddress representation for the string
332      */
hexToInet6Address(String addrHexString)333     public static InetAddress hexToInet6Address(String addrHexString)
334             throws IllegalArgumentException {
335         try {
336             return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
337                     addrHexString.substring(0,4),   addrHexString.substring(4,8),
338                     addrHexString.substring(8,12),  addrHexString.substring(12,16),
339                     addrHexString.substring(16,20), addrHexString.substring(20,24),
340                     addrHexString.substring(24,28), addrHexString.substring(28,32)));
341         } catch (Exception e) {
342             Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
343             throw new IllegalArgumentException(e);
344         }
345     }
346 
347     /**
348      * Trim leading zeros from IPv4 address strings
349      * Our base libraries will interpret that as octel..
350      * Must leave non v4 addresses and host names alone.
351      * For example, 192.168.000.010 -> 192.168.0.10
352      * TODO - fix base libraries and remove this function
353      * @param addr a string representing an ip addr
354      * @return a string propertly trimmed
355      */
356     @UnsupportedAppUsage
trimV4AddrZeros(String addr)357     public static String trimV4AddrZeros(String addr) {
358         return Inet4AddressUtils.trimAddressZeros(addr);
359     }
360 
361     /**
362      * Returns a prefix set without overlaps.
363      *
364      * This expects the src set to be sorted from shorter to longer. Results are undefined
365      * failing this condition. The returned prefix set is sorted in the same order as the
366      * passed set, with the same comparator.
367      */
deduplicatePrefixSet(final TreeSet<IpPrefix> src)368     private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
369         final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
370         // Prefixes match addresses that share their upper part up to their length, therefore
371         // the only kind of possible overlap in two prefixes is strict inclusion of the longer
372         // (more restrictive) in the shorter (including equivalence if they have the same
373         // length).
374         // Because prefixes in the src set are sorted from shorter to longer, deduplicating
375         // is done by simply iterating in order, and not adding any longer prefix that is
376         // already covered by a shorter one.
377         newPrefixes:
378         for (IpPrefix newPrefix : src) {
379             for (IpPrefix existingPrefix : dst) {
380                 if (existingPrefix.containsPrefix(newPrefix)) {
381                     continue newPrefixes;
382                 }
383             }
384             dst.add(newPrefix);
385         }
386         return dst;
387     }
388 
389     /**
390      * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
391      *
392      * Obviously this returns an integral value between 0 and 2**32.
393      * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
394      * set is not ordered smallest prefix to longer prefix.
395      *
396      * @param prefixes the set of prefixes, ordered by length
397      */
routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes)398     public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
399         long routedIPCount = 0;
400         for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
401             if (!prefix.isIPv4()) {
402                 Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
403             }
404             int rank = 32 - prefix.getPrefixLength();
405             routedIPCount += 1L << rank;
406         }
407         return routedIPCount;
408     }
409 
410     /**
411      * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
412      *
413      * This returns a BigInteger between 0 and 2**128.
414      * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
415      * set is not ordered smallest prefix to longer prefix.
416      */
routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes)417     public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
418         BigInteger routedIPCount = BigInteger.ZERO;
419         for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
420             if (!prefix.isIPv6()) {
421                 Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
422             }
423             int rank = 128 - prefix.getPrefixLength();
424             routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
425         }
426         return routedIPCount;
427     }
428 
429 }
430