• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.android.networkstack.util;
18 
19 import android.content.Context;
20 import android.net.IpPrefix;
21 import android.net.LinkAddress;
22 import android.net.MacAddress;
23 import android.system.ErrnoException;
24 import android.util.Log;
25 
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 
29 import com.android.net.module.util.DeviceConfigUtils;
30 import com.android.net.module.util.HexDump;
31 
32 import java.io.FileDescriptor;
33 import java.io.IOException;
34 import java.net.Inet4Address;
35 import java.net.Inet6Address;
36 import java.net.InetAddress;
37 import java.net.SocketException;
38 import java.net.UnknownHostException;
39 
40 /**
41  * Collection of utilities for the network stack.
42  */
43 public class NetworkStackUtils {
44     private static final String TAG = "NetworkStackUtils";
45 
46     /**
47      * A list of captive portal detection specifications used in addition to the fallback URLs.
48      * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
49      * by "@@,@@".
50      */
51     public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
52             "captive_portal_fallback_probe_specs";
53 
54     /**
55      * A comma separated list of URLs used for captive portal detection in addition to the
56      * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
57      */
58     public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
59             "captive_portal_other_fallback_urls";
60 
61     /**
62      * A comma separated list of URLs used for captive portal detection in addition to the HTTP url
63      * associated with the CAPTIVE_PORTAL_HTTP_URL settings.
64      */
65     public static final String CAPTIVE_PORTAL_OTHER_HTTP_URLS = "captive_portal_other_http_urls";
66 
67     /**
68      * A comma separated list of URLs used for network validation. in addition to the HTTPS url
69      * associated with the CAPTIVE_PORTAL_HTTPS_URL settings.
70      */
71     public static final String CAPTIVE_PORTAL_OTHER_HTTPS_URLS = "captive_portal_other_https_urls";
72 
73     /**
74      * Which User-Agent string to use in the header of the captive portal detection probes.
75      * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
76      */
77     public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
78 
79     /**
80      * Whether to use HTTPS for network validation. This is enabled by default and the setting
81      * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
82      * don't actually use HTTPS, but it's consistent with the other settings.
83      */
84     public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
85 
86     /**
87      * The URL used for HTTPS captive portal detection upon a new connection.
88      * A 204 response code from the server is used for validation.
89      */
90     public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
91 
92     /**
93      * The URL used for HTTP captive portal detection upon a new connection.
94      * A 204 response code from the server is used for validation.
95      */
96     public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
97 
98     /**
99      * The URL used for fallback HTTP captive portal detection when previous HTTP
100      * and HTTPS captive portal detection attemps did not return a conclusive answer.
101      */
102     public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
103 
104     /**
105      * What to do when connecting a network that presents a captive portal.
106      * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
107      *
108      * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
109      */
110     public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
111 
112     /**
113      * Don't attempt to detect captive portals.
114      */
115     public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
116 
117     /**
118      * When detecting a captive portal, display a notification that
119      * prompts the user to sign in.
120      */
121     public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
122 
123     /**
124      * When detecting a captive portal, immediately disconnect from the
125      * network and do not reconnect to that network in the future.
126      */
127     public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
128 
129     /**
130      * DNS probe timeout for network validation. Enough for 3 DNS queries 5 seconds apart.
131      */
132     public static final int DEFAULT_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT = 12500;
133 
134     /**
135      * List of fallback probe specs to use for detecting captive portals. This is an alternative to
136      * fallback URLs that provides more flexibility on detection rules. Empty, so unused by default.
137      */
138     public static final String[] DEFAULT_CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
139             new String[] {};
140 
141     /**
142      * The default list of HTTP URLs to use for detecting captive portals.
143      */
144     public static final String[] DEFAULT_CAPTIVE_PORTAL_HTTP_URLS =
145             new String [] {"http://connectivitycheck.gstatic.com/generate_204"};
146 
147     /**
148      * The default list of HTTPS URLs for network validation, to use for confirming internet
149      * connectivity.
150      */
151     public static final String[] DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS =
152             new String [] {"https://www.google.com/generate_204"};
153 
154     /**
155      * @deprecated Considering boolean experiment flag is likely to cause misconfiguration
156      *             particularly when NetworkStack module rolls back to previous version. It's
157      *             much safer to determine whether or not to enable one specific experimental
158      *             feature by comparing flag version with module version.
159      */
160     @Deprecated
161     public static final String DHCP_INIT_REBOOT_ENABLED = "dhcp_init_reboot_enabled";
162 
163     /**
164      * @deprecated See above explanation.
165      */
166     @Deprecated
167     public static final String DHCP_RAPID_COMMIT_ENABLED = "dhcp_rapid_commit_enabled";
168 
169     /**
170      * Minimum module version at which to enable the DHCP INIT-REBOOT state.
171      */
172     public static final String DHCP_INIT_REBOOT_VERSION = "dhcp_init_reboot_version";
173 
174     /**
175      * Minimum module version at which to enable the DHCP Rapid Commit option.
176      */
177     public static final String DHCP_RAPID_COMMIT_VERSION = "dhcp_rapid_commit_version";
178 
179     /**
180      * Minimum module version at which to enable the IP address conflict detection feature.
181      */
182     public static final String DHCP_IP_CONFLICT_DETECT_VERSION = "dhcp_ip_conflict_detect_version";
183 
184     /**
185      * Minimum module version at which to enable the IPv6-Only preferred option.
186      */
187     public static final String DHCP_IPV6_ONLY_PREFERRED_VERSION =
188             "dhcp_ipv6_only_preferred_version";
189 
190     /**
191      * Minimum module version at which to enable slow DHCP retransmission approach in renew/rebind
192      * state suggested in RFC2131 section 4.4.5.
193      */
194     public static final String DHCP_SLOW_RETRANSMISSION_VERSION =
195             "dhcp_slow_retransmission_version";
196 
197     /**
198      * Experiment flag to enable considering DNS probes returning private IP addresses as failed
199      * when attempting to detect captive portals.
200      *
201      * This flag is enabled if !=0 and less than the module APK version.
202      */
203     public static final String DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION =
204             "dns_probe_private_ip_no_internet";
205 
206     /**
207      * Experiment flag to enable validation metrics sent by NetworkMonitor.
208      *
209      * Metrics are sent by default. They can be disabled by setting the flag to a number greater
210      * than the APK version (for example 999999999).
211      * @see DeviceConfigUtils#isFeatureEnabled(Context, String, String, boolean)
212      */
213     public static final String VALIDATION_METRICS_VERSION = "validation_metrics_version";
214 
215     /**
216      * Experiment flag to enable sending gratuitous multicast unsolicited Neighbor Advertisements
217      * to propagate new assigned IPv6 GUA as quickly as possible.
218      */
219     public static final String IPCLIENT_GRATUITOUS_NA_VERSION = "ipclient_gratuitous_na_version";
220 
221     /**
222      * Experiment flag to send multicast NS from the global IPv6 GUA to the solicited-node
223      * multicast address based on the default router's IPv6 link-local address, which helps
224      * flush the first-hop routers' neighbor cache entry for the global IPv6 GUA.
225      */
226     public static final String IPCLIENT_MULTICAST_NS_VERSION = "ipclient_multicast_ns_version";
227 
228     /**
229      * Experiment flag to enable sending Gratuitous APR and Gratuitous Neighbor Advertisement for
230      * all assigned IPv4 and IPv6 GUAs after completing L2 roaming.
231      */
232     public static final String IPCLIENT_GARP_NA_ROAMING_VERSION =
233             "ipclient_garp_na_roaming_version";
234 
235     /**
236      * Experiment flag to enable parsing netlink events from kernel directly instead from netd aidl
237      * interface.
238      */
239     public static final String IPCLIENT_PARSE_NETLINK_EVENTS_VERSION =
240             "ipclient_parse_netlink_events_version";
241 
242     /**
243      * Experiment flag to check if an on-link IPv6 link local DNS is acceptable. The default flag
244      * value is true, just add this flag for A/B testing to see if this fix works as expected via
245      * experiment rollout.
246      */
247     public static final String IPCLIENT_ACCEPT_IPV6_LINK_LOCAL_DNS_VERSION =
248             "ipclient_accept_ipv6_link_local_dns_version";
249 
250     /**
251      * Experiment flag to disable accept_ra parameter when IPv6 provisioning loss happens due to
252      * the default route has gone.
253      */
254     public static final String IPCLIENT_DISABLE_ACCEPT_RA_VERSION = "ipclient_disable_accept_ra";
255 
256     /**
257      * Experiment flag to enable "mcast_resolicit" neighbor parameter in IpReachabilityMonitor,
258      * set it to 3 by default.
259      */
260     public static final String IP_REACHABILITY_MCAST_RESOLICIT_VERSION =
261             "ip_reachability_mcast_resolicit_version";
262 
263     /**
264      * Experiment flag to attempt to ignore the on-link IPv6 DNS server which fails to respond to
265      * address resolution.
266      */
267     public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION =
268             "ip_reachability_ignore_incompleted_ipv6_dns_server_version";
269 
270     /**
271      * Experiment flag to attempt to ignore the IPv6 default router which fails to respond to
272      * address resolution.
273      */
274     public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION =
275             "ip_reachability_ignore_incompleted_ipv6_default_router_version";
276 
277     /**
278      * Experiment flag to use the RA lifetime calculation fix in aosp/2276160. It can be disabled
279      * if OEM finds additional battery usage and want to use the old buggy behavior again.
280      */
281     public static final String APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION =
282             "apf_use_ra_lifetime_calculation_fix_version";
283 
284     static {
285         System.loadLibrary("networkstackutilsjni");
286     }
287 
288     /**
289      * Convert IPv6 multicast address to ethernet multicast address in network order.
290      */
ipv6MulticastToEthernetMulticast(@onNull final Inet6Address addr)291     public static MacAddress ipv6MulticastToEthernetMulticast(@NonNull final Inet6Address addr) {
292         final byte[] etherMulticast = new byte[6];
293         final byte[] ipv6Multicast = addr.getAddress();
294         etherMulticast[0] = (byte) 0x33;
295         etherMulticast[1] = (byte) 0x33;
296         etherMulticast[2] = ipv6Multicast[12];
297         etherMulticast[3] = ipv6Multicast[13];
298         etherMulticast[4] = ipv6Multicast[14];
299         etherMulticast[5] = ipv6Multicast[15];
300         return MacAddress.fromBytes(etherMulticast);
301     }
302 
303     /**
304      * Convert IPv6 unicast or anycast address to solicited node multicast address
305      * per RFC4291 section 2.7.1.
306      */
307     @Nullable
ipv6AddressToSolicitedNodeMulticast( @onNull final Inet6Address addr)308     public static Inet6Address ipv6AddressToSolicitedNodeMulticast(
309             @NonNull final Inet6Address addr) {
310         final byte[] address = new byte[16];
311         address[0] = (byte) 0xFF;
312         address[1] = (byte) 0x02;
313         address[11] = (byte) 0x01;
314         address[12] = (byte) 0xFF;
315         address[13] = addr.getAddress()[13];
316         address[14] = addr.getAddress()[14];
317         address[15] = addr.getAddress()[15];
318         try {
319             return (Inet6Address) InetAddress.getByAddress(address);
320         } catch (UnknownHostException e) {
321             Log.e(TAG, "Invalid host IP address " + addr.getHostAddress(), e);
322             return null;
323         }
324     }
325 
326     /**
327      * Check whether a link address is IPv6 global preferred unicast address.
328      */
isIPv6GUA(@onNull final LinkAddress address)329     public static boolean isIPv6GUA(@NonNull final LinkAddress address) {
330         return address.isIpv6() && address.isGlobalPreferred();
331     }
332 
333     /**
334      * Convert 48bits MAC address to 64bits link-layer address(EUI64).
335      *     1. insert the 0xFFFE in the middle of mac address
336      *     2. flip the 7th bit(universal/local) of the first byte.
337      */
macAddressToEui64(@onNull final MacAddress hwAddr)338     public static byte[] macAddressToEui64(@NonNull final MacAddress hwAddr) {
339         final byte[] eui64 = new byte[8];
340         final byte[] mac48 = hwAddr.toByteArray();
341         System.arraycopy(mac48 /* src */, 0 /* srcPos */, eui64 /* dest */, 0 /* destPos */,
342                 3 /* length */);
343         eui64[3] = (byte) 0xFF;
344         eui64[4] = (byte) 0xFE;
345         System.arraycopy(mac48 /* src */, 3 /* srcPos */, eui64 /* dest */, 5 /* destPos */,
346                 3 /* length */);
347         eui64[0] = (byte) (eui64[0] ^ 0x02); // flip 7th bit
348         return eui64;
349     }
350 
351     /**
352      * Generate an IPv6 address based on the given prefix(/64) and stable interface
353      * identifier(EUI64).
354      */
createInet6AddressFromEui64(@onNull final IpPrefix prefix, @NonNull final byte[] eui64)355     public static Inet6Address createInet6AddressFromEui64(@NonNull final IpPrefix prefix,
356             @NonNull final byte[] eui64) {
357         if (prefix.getPrefixLength() != 64) {
358             Log.e(TAG, "Invalid IPv6 prefix length " + prefix.getPrefixLength());
359             return null;
360         }
361         final byte[] address = new byte[16];
362         System.arraycopy(prefix.getRawAddress() /* src */, 0 /* srcPos */, address /* dest */,
363                 0 /* destPos*/, 8 /* length */);
364         System.arraycopy(eui64 /* src */, 0 /* srcPos */, address /* dest */, 8 /* destPos */,
365                 eui64.length);
366         try {
367             return (Inet6Address) InetAddress.getByAddress(address);
368         } catch (UnknownHostException e) {
369             Log.e(TAG, "Invalid IPv6 address " + HexDump.toHexString(address), e);
370             return null;
371         }
372     }
373 
374     /**
375      * Attaches a socket filter that accepts DHCP packets to the given socket.
376      */
attachDhcpFilter(FileDescriptor fd)377     public static native void attachDhcpFilter(FileDescriptor fd) throws ErrnoException;
378 
379     /**
380      * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
381      * @param fd the socket's {@link FileDescriptor}.
382      * @param packetType the hardware address type, one of ARPHRD_*.
383      */
attachRaFilter(FileDescriptor fd, int packetType)384     public static native void attachRaFilter(FileDescriptor fd, int packetType)
385             throws SocketException;
386 
387     /**
388      * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
389      *
390      * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
391      *
392      * @param fd the socket's {@link FileDescriptor}.
393      * @param packetType the hardware address type, one of ARPHRD_*.
394      */
attachControlPacketFilter(FileDescriptor fd, int packetType)395     public static native void attachControlPacketFilter(FileDescriptor fd, int packetType)
396             throws SocketException;
397 
398     /**
399      * Add an entry into the ARP cache.
400      */
addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr, String ifname, FileDescriptor fd)401     public static void addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr,
402             String ifname, FileDescriptor fd) throws IOException {
403         addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
404     }
405 
addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname, FileDescriptor fd)406     private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
407             FileDescriptor fd) throws IOException;
408 
409 }
410