• 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 java.io.FileDescriptor;
20 import java.net.InetAddress;
21 import java.net.Inet4Address;
22 import java.net.Inet6Address;
23 import java.net.SocketException;
24 import java.net.UnknownHostException;
25 import java.util.Collection;
26 import java.util.Locale;
27 
28 import android.os.Parcel;
29 import android.util.Log;
30 import android.util.Pair;
31 
32 
33 /**
34  * Native methods for managing network interfaces.
35  *
36  * {@hide}
37  */
38 public class NetworkUtils {
39 
40     private static final String TAG = "NetworkUtils";
41 
42     /**
43      * Attaches a socket filter that accepts DHCP packets to the given socket.
44      */
attachDhcpFilter(FileDescriptor fd)45     public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
46 
47     /**
48      * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
49      * @param fd the socket's {@link FileDescriptor}.
50      * @param packetType the hardware address type, one of ARPHRD_*.
51      */
attachRaFilter(FileDescriptor fd, int packetType)52     public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
53 
54     /**
55      * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
56      * @param fd the socket's {@link FileDescriptor}.
57      * @param ifIndex the interface index.
58      */
setupRaSocket(FileDescriptor fd, int ifIndex)59     public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException;
60 
61     /**
62      * Binds the current process to the network designated by {@code netId}.  All sockets created
63      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
64      * {@link Network#getSocketFactory}) will be bound to this network.  Note that if this
65      * {@code Network} ever disconnects all sockets created in this way will cease to work.  This
66      * is by design so an application doesn't accidentally use sockets it thinks are still bound to
67      * a particular {@code Network}.  Passing NETID_UNSET clears the binding.
68      */
bindProcessToNetwork(int netId)69     public native static boolean bindProcessToNetwork(int netId);
70 
71     /**
72      * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
73      * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
74      */
getBoundNetworkForProcess()75     public native static int getBoundNetworkForProcess();
76 
77     /**
78      * Binds host resolutions performed by this process to the network designated by {@code netId}.
79      * {@link #bindProcessToNetwork} takes precedence over this setting.  Passing NETID_UNSET clears
80      * the binding.
81      *
82      * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
83      */
bindProcessToNetworkForHostResolution(int netId)84     public native static boolean bindProcessToNetworkForHostResolution(int netId);
85 
86     /**
87      * Explicitly binds {@code socketfd} to the network designated by {@code netId}.  This
88      * overrides any binding via {@link #bindProcessToNetwork}.
89      * @return 0 on success or negative errno on failure.
90      */
bindSocketToNetwork(int socketfd, int netId)91     public native static int bindSocketToNetwork(int socketfd, int netId);
92 
93     /**
94      * Protect {@code fd} from VPN connections.  After protecting, data sent through
95      * this socket will go directly to the underlying network, so its traffic will not be
96      * forwarded through the VPN.
97      */
protectFromVpn(FileDescriptor fd)98     public static boolean protectFromVpn(FileDescriptor fd) {
99         return protectFromVpn(fd.getInt$());
100     }
101 
102     /**
103      * Protect {@code socketfd} from VPN connections.  After protecting, data sent through
104      * this socket will go directly to the underlying network, so its traffic will not be
105      * forwarded through the VPN.
106      */
protectFromVpn(int socketfd)107     public native static boolean protectFromVpn(int socketfd);
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 native static boolean queryUserAccess(int uid, int netId);
114 
115     /**
116      * Convert a IPv4 address from an integer to an InetAddress.
117      * @param hostAddress an int corresponding to the IPv4 address in network byte order
118      */
intToInetAddress(int hostAddress)119     public static InetAddress intToInetAddress(int hostAddress) {
120         byte[] addressBytes = { (byte)(0xff & hostAddress),
121                                 (byte)(0xff & (hostAddress >> 8)),
122                                 (byte)(0xff & (hostAddress >> 16)),
123                                 (byte)(0xff & (hostAddress >> 24)) };
124 
125         try {
126            return InetAddress.getByAddress(addressBytes);
127         } catch (UnknownHostException e) {
128            throw new AssertionError();
129         }
130     }
131 
132     /**
133      * Convert a IPv4 address from an InetAddress to an integer
134      * @param inetAddr is an InetAddress corresponding to the IPv4 address
135      * @return the IP address as an integer in network byte order
136      */
inetAddressToInt(Inet4Address inetAddr)137     public static int inetAddressToInt(Inet4Address inetAddr)
138             throws IllegalArgumentException {
139         byte [] addr = inetAddr.getAddress();
140         return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
141                 ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
142     }
143 
144     /**
145      * Convert a network prefix length to an IPv4 netmask integer
146      * @param prefixLength
147      * @return the IPv4 netmask as an integer in network byte order
148      */
prefixLengthToNetmaskInt(int prefixLength)149     public static int prefixLengthToNetmaskInt(int prefixLength)
150             throws IllegalArgumentException {
151         if (prefixLength < 0 || prefixLength > 32) {
152             throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
153         }
154         int value = 0xffffffff << (32 - prefixLength);
155         return Integer.reverseBytes(value);
156     }
157 
158     /**
159      * Convert a IPv4 netmask integer to a prefix length
160      * @param netmask as an integer in network byte order
161      * @return the network prefix length
162      */
netmaskIntToPrefixLength(int netmask)163     public static int netmaskIntToPrefixLength(int netmask) {
164         return Integer.bitCount(netmask);
165     }
166 
167     /**
168      * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
169      * @param netmask as a {@code Inet4Address}.
170      * @return the network prefix length
171      * @throws IllegalArgumentException the specified netmask was not contiguous.
172      * @hide
173      */
netmaskToPrefixLength(Inet4Address netmask)174     public static int netmaskToPrefixLength(Inet4Address netmask) {
175         // inetAddressToInt returns an int in *network* byte order.
176         int i = Integer.reverseBytes(inetAddressToInt(netmask));
177         int prefixLength = Integer.bitCount(i);
178         int trailingZeros = Integer.numberOfTrailingZeros(i);
179         if (trailingZeros != 32 - prefixLength) {
180             throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
181         }
182         return prefixLength;
183     }
184 
185 
186     /**
187      * Create an InetAddress from a string where the string must be a standard
188      * representation of a V4 or V6 address.  Avoids doing a DNS lookup on failure
189      * but it will throw an IllegalArgumentException in that case.
190      * @param addrString
191      * @return the InetAddress
192      * @hide
193      */
numericToInetAddress(String addrString)194     public static InetAddress numericToInetAddress(String addrString)
195             throws IllegalArgumentException {
196         return InetAddress.parseNumericAddress(addrString);
197     }
198 
199     /**
200      * Writes an InetAddress to a parcel. The address may be null. This is likely faster than
201      * calling writeSerializable.
202      */
parcelInetAddress(Parcel parcel, InetAddress address, int flags)203     protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) {
204         byte[] addressArray = (address != null) ? address.getAddress() : null;
205         parcel.writeByteArray(addressArray);
206     }
207 
208     /**
209      * Reads an InetAddress from a parcel. Returns null if the address that was written was null
210      * or if the data is invalid.
211      */
unparcelInetAddress(Parcel in)212     protected static InetAddress unparcelInetAddress(Parcel in) {
213         byte[] addressArray = in.createByteArray();
214         if (addressArray == null) {
215             return null;
216         }
217         try {
218             return InetAddress.getByAddress(addressArray);
219         } catch (UnknownHostException e) {
220             return null;
221         }
222     }
223 
224 
225     /**
226      *  Masks a raw IP address byte array with the specified prefix length.
227      */
maskRawAddress(byte[] array, int prefixLength)228     public static void maskRawAddress(byte[] array, int prefixLength) {
229         if (prefixLength < 0 || prefixLength > array.length * 8) {
230             throw new RuntimeException("IP address with " + array.length +
231                     " bytes has invalid prefix length " + prefixLength);
232         }
233 
234         int offset = prefixLength / 8;
235         int remainder = prefixLength % 8;
236         byte mask = (byte)(0xFF << (8 - remainder));
237 
238         if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
239 
240         offset++;
241 
242         for (; offset < array.length; offset++) {
243             array[offset] = 0;
244         }
245     }
246 
247     /**
248      * Get InetAddress masked with prefixLength.  Will never return null.
249      * @param address the IP address to mask with
250      * @param prefixLength the prefixLength used to mask the IP
251      */
getNetworkPart(InetAddress address, int prefixLength)252     public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
253         byte[] array = address.getAddress();
254         maskRawAddress(array, prefixLength);
255 
256         InetAddress netPart = null;
257         try {
258             netPart = InetAddress.getByAddress(array);
259         } catch (UnknownHostException e) {
260             throw new RuntimeException("getNetworkPart error - " + e.toString());
261         }
262         return netPart;
263     }
264 
265     /**
266      * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
267      */
getImplicitNetmask(Inet4Address address)268     public static int getImplicitNetmask(Inet4Address address) {
269         int firstByte = address.getAddress()[0] & 0xff;  // Convert to an unsigned value.
270         if (firstByte < 128) {
271             return 8;
272         } else if (firstByte < 192) {
273             return 16;
274         } else if (firstByte < 224) {
275             return 24;
276         } else {
277             return 32;  // Will likely not end well for other reasons.
278         }
279     }
280 
281     /**
282      * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
283      * @hide
284      */
parseIpAndMask(String ipAndMaskString)285     public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
286         InetAddress address = null;
287         int prefixLength = -1;
288         try {
289             String[] pieces = ipAndMaskString.split("/", 2);
290             prefixLength = Integer.parseInt(pieces[1]);
291             address = InetAddress.parseNumericAddress(pieces[0]);
292         } catch (NullPointerException e) {            // Null string.
293         } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
294         } catch (NumberFormatException e) {           // Non-numeric prefix.
295         } catch (IllegalArgumentException e) {        // Invalid IP address.
296         }
297 
298         if (address == null || prefixLength == -1) {
299             throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
300         }
301 
302         return new Pair<InetAddress, Integer>(address, prefixLength);
303     }
304 
305     /**
306      * Check if IP address type is consistent between two InetAddress.
307      * @return true if both are the same type.  False otherwise.
308      */
addressTypeMatches(InetAddress left, InetAddress right)309     public static boolean addressTypeMatches(InetAddress left, InetAddress right) {
310         return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) ||
311                 ((left instanceof Inet6Address) && (right instanceof Inet6Address)));
312     }
313 
314     /**
315      * Convert a 32 char hex string into a Inet6Address.
316      * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
317      * made into an Inet6Address
318      * @param addrHexString a 32 character hex string representing an IPv6 addr
319      * @return addr an InetAddress representation for the string
320      */
hexToInet6Address(String addrHexString)321     public static InetAddress hexToInet6Address(String addrHexString)
322             throws IllegalArgumentException {
323         try {
324             return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
325                     addrHexString.substring(0,4),   addrHexString.substring(4,8),
326                     addrHexString.substring(8,12),  addrHexString.substring(12,16),
327                     addrHexString.substring(16,20), addrHexString.substring(20,24),
328                     addrHexString.substring(24,28), addrHexString.substring(28,32)));
329         } catch (Exception e) {
330             Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
331             throw new IllegalArgumentException(e);
332         }
333     }
334 
335     /**
336      * Create a string array of host addresses from a collection of InetAddresses
337      * @param addrs a Collection of InetAddresses
338      * @return an array of Strings containing their host addresses
339      */
makeStrings(Collection<InetAddress> addrs)340     public static String[] makeStrings(Collection<InetAddress> addrs) {
341         String[] result = new String[addrs.size()];
342         int i = 0;
343         for (InetAddress addr : addrs) {
344             result[i++] = addr.getHostAddress();
345         }
346         return result;
347     }
348 
349     /**
350      * Trim leading zeros from IPv4 address strings
351      * Our base libraries will interpret that as octel..
352      * Must leave non v4 addresses and host names alone.
353      * For example, 192.168.000.010 -> 192.168.0.10
354      * TODO - fix base libraries and remove this function
355      * @param addr a string representing an ip addr
356      * @return a string propertly trimmed
357      */
trimV4AddrZeros(String addr)358     public static String trimV4AddrZeros(String addr) {
359         if (addr == null) return null;
360         String[] octets = addr.split("\\.");
361         if (octets.length != 4) return addr;
362         StringBuilder builder = new StringBuilder(16);
363         String result = null;
364         for (int i = 0; i < 4; i++) {
365             try {
366                 if (octets[i].length() > 3) return addr;
367                 builder.append(Integer.parseInt(octets[i]));
368             } catch (NumberFormatException e) {
369                 return addr;
370             }
371             if (i < 3) builder.append('.');
372         }
373         result = builder.toString();
374         return result;
375     }
376 }
377