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.UnknownHostException;
38 
39 /**
40  * Collection of utilities for the network stack.
41  */
42 public class NetworkStackUtils {
43     private static final String TAG = "NetworkStackUtils";
44 
45     /**
46      * A list of captive portal detection specifications used in addition to the fallback URLs.
47      * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
48      * by "@@,@@".
49      */
50     public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
51             "captive_portal_fallback_probe_specs";
52 
53     /**
54      * A comma separated list of URLs used for captive portal detection in addition to the
55      * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
56      */
57     public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
58             "captive_portal_other_fallback_urls";
59 
60     /**
61      * A comma separated list of URLs used for captive portal detection in addition to the HTTP url
62      * associated with the CAPTIVE_PORTAL_HTTP_URL settings.
63      */
64     public static final String CAPTIVE_PORTAL_OTHER_HTTP_URLS = "captive_portal_other_http_urls";
65 
66     /**
67      * A comma separated list of URLs used for network validation. in addition to the HTTPS url
68      * associated with the CAPTIVE_PORTAL_HTTPS_URL settings.
69      */
70     public static final String CAPTIVE_PORTAL_OTHER_HTTPS_URLS = "captive_portal_other_https_urls";
71 
72     /**
73      * Which User-Agent string to use in the header of the captive portal detection probes.
74      * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
75      */
76     public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
77 
78     /**
79      * Whether to use HTTPS for network validation. This is enabled by default and the setting
80      * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
81      * don't actually use HTTPS, but it's consistent with the other settings.
82      */
83     public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
84 
85     /**
86      * The URL used for HTTPS captive portal detection upon a new connection.
87      * A 204 response code from the server is used for validation.
88      */
89     public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
90 
91     /**
92      * The URL used for HTTP captive portal detection upon a new connection.
93      * A 204 response code from the server is used for validation.
94      */
95     public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
96 
97     /**
98      * The URL used for fallback HTTP captive portal detection when previous HTTP
99      * and HTTPS captive portal detection attemps did not return a conclusive answer.
100      */
101     public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
102 
103     /**
104      * What to do when connecting a network that presents a captive portal.
105      * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
106      *
107      * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
108      */
109     public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
110 
111     /**
112      * Don't attempt to detect captive portals.
113      */
114     public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
115 
116     /**
117      * When detecting a captive portal, display a notification that
118      * prompts the user to sign in.
119      */
120     public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
121 
122     /**
123      * When detecting a captive portal, immediately disconnect from the
124      * network and do not reconnect to that network in the future.
125      */
126     public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
127 
128     /**
129      * DNS probe timeout for network validation. Enough for 3 DNS queries 5 seconds apart.
130      */
131     public static final int DEFAULT_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT = 12500;
132 
133     /**
134      * List of fallback probe specs to use for detecting captive portals. This is an alternative to
135      * fallback URLs that provides more flexibility on detection rules. Empty, so unused by default.
136      */
137     public static final String[] DEFAULT_CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
138             new String[] {};
139 
140     /**
141      * The default list of HTTP URLs to use for detecting captive portals.
142      */
143     public static final String[] DEFAULT_CAPTIVE_PORTAL_HTTP_URLS =
144             new String [] {"http://connectivitycheck.gstatic.com/generate_204"};
145 
146     /**
147      * The default list of HTTPS URLs for network validation, to use for confirming internet
148      * connectivity.
149      */
150     public static final String[] DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS =
151             new String [] {"https://www.google.com/generate_204"};
152 
153     /**
154      * Minimum module version at which to enable the DHCP Rapid Commit option.
155      */
156     public static final String DHCP_RAPID_COMMIT_VERSION = "dhcp_rapid_commit_version";
157 
158     /**
159      * Minimum module version at which to enable the IP address conflict detection feature.
160      */
161     public static final String DHCP_IP_CONFLICT_DETECT_VERSION = "dhcp_ip_conflict_detect_version";
162 
163     /**
164      * Minimum module version at which to enable slow DHCP retransmission approach in renew/rebind
165      * state suggested in RFC2131 section 4.4.5.
166      */
167     public static final String DHCP_SLOW_RETRANSMISSION_VERSION =
168             "dhcp_slow_retransmission_version";
169 
170     /**
171      * Experiment flag to enable considering DNS probes returning private IP addresses as failed
172      * when attempting to detect captive portals.
173      *
174      * This flag is enabled if !=0 and less than the module APK version.
175      */
176     public static final String DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION =
177             "dns_probe_private_ip_no_internet";
178 
179     /**
180      * Experiment flag to enable validation metrics sent by NetworkMonitor.
181      *
182      * Metrics are sent by default. They can be disabled by setting the flag to a number greater
183      * than the APK version (for example 999999999).
184      * @see DeviceConfigUtils#isFeatureEnabled(Context, String, String, boolean)
185      */
186     public static final String VALIDATION_METRICS_VERSION = "validation_metrics_version";
187 
188     /**
189      * Experiment flag to enable sending Gratuitous APR and Gratuitous Neighbor Advertisement for
190      * all assigned IPv4 and IPv6 GUAs after completing L2 roaming.
191      */
192     public static final String IPCLIENT_GARP_NA_ROAMING_VERSION =
193             "ipclient_garp_na_roaming_version";
194 
195     /**
196      * Experiment flag to enable "mcast_resolicit" neighbor parameter in IpReachabilityMonitor,
197      * set it to 3 by default.
198      */
199     public static final String IP_REACHABILITY_MCAST_RESOLICIT_VERSION =
200             "ip_reachability_mcast_resolicit_version";
201 
202     /**
203      * Experiment flag to attempt to ignore the on-link IPv6 DNS server which fails to respond to
204      * address resolution.
205      */
206     public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DNS_SERVER_VERSION =
207             "ip_reachability_ignore_incompleted_ipv6_dns_server_version";
208 
209     /**
210      * Experiment flag to attempt to ignore the IPv6 default router which fails to respond to
211      * address resolution.
212      */
213     public static final String IP_REACHABILITY_IGNORE_INCOMPLETE_IPV6_DEFAULT_ROUTER_VERSION =
214             "ip_reachability_ignore_incompleted_ipv6_default_router_version";
215 
216     /**
217      * Experiment flag to treat router MAC address changes as a failure only on roam.
218      */
219     public static final String IP_REACHABILITY_ROUTER_MAC_CHANGE_FAILURE_ONLY_AFTER_ROAM_VERSION =
220             "ip_reachability_router_mac_change_failure_only_after_roam_version";
221 
222     /**
223      * Experiment flag to ignore all NUD failures from kernel organic.
224      */
225     public static final String IP_REACHABILITY_IGNORE_ORGANIC_NUD_FAILURE_VERSION =
226             "ip_reachability_ignore_organic_nud_failure_version";
227 
228     /**
229      * Experiment flag to ignore all NUD failures from the neighbor that has never ever entered the
230      * reachable state.
231      */
232     public static final String IP_REACHABILITY_IGNORE_NEVER_REACHABLE_NEIGHBOR_VERSION =
233             "ip_reachability_ignore_never_reachable_neighbor_version";
234 
235     /**
236      * Experiment flag to enable DHCPv6 Prefix Delegation(RFC8415) in IpClient.
237      */
238     public static final String IPCLIENT_DHCPV6_PREFIX_DELEGATION_VERSION =
239             "ipclient_dhcpv6_prefix_delegation_version";
240 
241     /**
242      * Experiment flag to enable new ra filter.
243      */
244     public static final String APF_NEW_RA_FILTER_VERSION = "apf_new_ra_filter_version";
245 
246     /**
247      * Experiment flag to enable the feature of polling counters in Apf.
248      */
249     public static final String APF_POLLING_COUNTERS_VERSION = "apf_polling_counters_version";
250 
251     /**
252      * Experiment flag to enable the feature of ignoring any individual RA section with lifetime
253      * below accept_ra_min_lft sysctl.
254      */
255     public static final String IPCLIENT_IGNORE_LOW_RA_LIFETIME_VERSION =
256             "ipclient_ignore_low_ra_lifetime_version";
257 
258     /**
259      * Feature flag to send private DNS resolution queries and probes on a background thread.
260      */
261     public static final String NETWORKMONITOR_ASYNC_PRIVDNS_RESOLUTION =
262             "networkmonitor_async_privdns_resolution";
263 
264     /**
265      * Experiment flag to populate the IP link address lifetime such as deprecationTime and
266      * expirationtTime.
267      */
268     public static final String IPCLIENT_POPULATE_LINK_ADDRESS_LIFETIME_VERSION =
269             "ipclient_populate_link_address_lifetime_version";
270 
271     /**
272      * Experiment flag to support parsing PIO P flag(DHCPv6-PD preferred).
273      */
274     public static final String IPCLIENT_DHCPV6_PD_PREFERRED_FLAG_VERSION =
275             "ipclient_dhcpv6_pd_preferred_flag_version";
276 
277     /**** BEGIN Feature Kill Switch Flags ****/
278 
279     /**
280      * Kill switch flag to disable the feature of handle light doze mode in Apf.
281      */
282     public static final String APF_HANDLE_LIGHT_DOZE_FORCE_DISABLE =
283             "apf_handle_light_doze_force_disable";
284 
285     /**
286      * Kill switch flag to disable the feature of skipping Tcp socket info polling when light
287      * doze mode is enabled.
288      */
289     public static final String SKIP_TCP_POLL_IN_LIGHT_DOZE = "skip_tcp_poll_in_light_doze_mode";
290 
291     /**
292      * Experiment flag to enable the feature of re-evaluate when network resumes.
293      */
294     public static final String REEVALUATE_WHEN_RESUME = "reevaluate_when_resume";
295 
296     /**
297      * Kill switch flag to disable the feature of ignoring Tcp socket info for uids which
298      * networking are blocked.
299      */
300     public static final String IGNORE_TCP_INFO_FOR_BLOCKED_UIDS =
301             "ignore_tcp_info_for_blocked_uids";
302 
303     /**
304      * Kill switch flag to disable the feature of handle arp offload in Apf.
305      */
306     public static final String APF_HANDLE_ARP_OFFLOAD_FORCE_DISABLE =
307             "apf_handle_arp_offload_force_disable";
308 
309     static {
310         System.loadLibrary("networkstackutilsjni");
311     }
312 
313     /**
314      * Convert IPv6 multicast address to ethernet multicast address in network order.
315      */
ipv6MulticastToEthernetMulticast(@onNull final Inet6Address addr)316     public static MacAddress ipv6MulticastToEthernetMulticast(@NonNull final Inet6Address addr) {
317         final byte[] etherMulticast = new byte[6];
318         final byte[] ipv6Multicast = addr.getAddress();
319         etherMulticast[0] = (byte) 0x33;
320         etherMulticast[1] = (byte) 0x33;
321         etherMulticast[2] = ipv6Multicast[12];
322         etherMulticast[3] = ipv6Multicast[13];
323         etherMulticast[4] = ipv6Multicast[14];
324         etherMulticast[5] = ipv6Multicast[15];
325         return MacAddress.fromBytes(etherMulticast);
326     }
327 
328     /**
329      * Convert IPv6 unicast or anycast address to solicited node multicast address
330      * per RFC4291 section 2.7.1.
331      */
332     @Nullable
ipv6AddressToSolicitedNodeMulticast( @onNull final Inet6Address addr)333     public static Inet6Address ipv6AddressToSolicitedNodeMulticast(
334             @NonNull final Inet6Address addr) {
335         final byte[] address = new byte[16];
336         address[0] = (byte) 0xFF;
337         address[1] = (byte) 0x02;
338         address[11] = (byte) 0x01;
339         address[12] = (byte) 0xFF;
340         address[13] = addr.getAddress()[13];
341         address[14] = addr.getAddress()[14];
342         address[15] = addr.getAddress()[15];
343         try {
344             return (Inet6Address) InetAddress.getByAddress(address);
345         } catch (UnknownHostException e) {
346             Log.e(TAG, "Invalid host IP address " + addr.getHostAddress(), e);
347             return null;
348         }
349     }
350 
351     /**
352      * Check whether a link address is IPv6 global preferred unicast address.
353      */
isIPv6GUA(@onNull final LinkAddress address)354     public static boolean isIPv6GUA(@NonNull final LinkAddress address) {
355         return address.isIpv6() && address.isGlobalPreferred();
356     }
357 
358     /**
359      * Convert 48bits MAC address to 64bits link-layer address(EUI64).
360      *     1. insert the 0xFFFE in the middle of mac address
361      *     2. flip the 7th bit(universal/local) of the first byte.
362      */
macAddressToEui64(@onNull final MacAddress hwAddr)363     public static byte[] macAddressToEui64(@NonNull final MacAddress hwAddr) {
364         final byte[] eui64 = new byte[8];
365         final byte[] mac48 = hwAddr.toByteArray();
366         System.arraycopy(mac48 /* src */, 0 /* srcPos */, eui64 /* dest */, 0 /* destPos */,
367                 3 /* length */);
368         eui64[3] = (byte) 0xFF;
369         eui64[4] = (byte) 0xFE;
370         System.arraycopy(mac48 /* src */, 3 /* srcPos */, eui64 /* dest */, 5 /* destPos */,
371                 3 /* length */);
372         eui64[0] = (byte) (eui64[0] ^ 0x02); // flip 7th bit
373         return eui64;
374     }
375 
376     /**
377      * Generate an IPv6 address based on the given prefix(/64) and stable interface
378      * identifier(EUI64).
379      */
380     @Nullable
createInet6AddressFromEui64(@onNull final IpPrefix prefix, @NonNull final byte[] eui64)381     public static Inet6Address createInet6AddressFromEui64(@NonNull final IpPrefix prefix,
382             @NonNull final byte[] eui64) {
383         if (prefix.getPrefixLength() > 64) {
384             Log.e(TAG, "Invalid IPv6 prefix length " + prefix.getPrefixLength());
385             return null;
386         }
387         final byte[] address = new byte[16];
388         System.arraycopy(prefix.getRawAddress() /* src */, 0 /* srcPos */, address /* dest */,
389                 0 /* destPos*/, 8 /* length */);
390         System.arraycopy(eui64 /* src */, 0 /* srcPos */, address /* dest */, 8 /* destPos */,
391                 eui64.length);
392         try {
393             return (Inet6Address) InetAddress.getByAddress(address);
394         } catch (UnknownHostException e) {
395             Log.e(TAG, "Invalid IPv6 address " + HexDump.toHexString(address), e);
396             return null;
397         }
398     }
399 
400     /**
401      * Attaches a socket filter that accepts DHCP packets to the given socket.
402      */
attachDhcpFilter(FileDescriptor fd)403     public static native void attachDhcpFilter(FileDescriptor fd) throws ErrnoException;
404 
405     /**
406      * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
407      * @param fd the socket's {@link FileDescriptor}.
408      */
attachRaFilter(FileDescriptor fd)409     public static native void attachRaFilter(FileDescriptor fd) throws ErrnoException;
410 
411     /**
412      * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
413      *
414      * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
415      *
416      * @param fd the socket's {@link FileDescriptor}.
417      */
attachControlPacketFilter(FileDescriptor fd)418     public static native void attachControlPacketFilter(FileDescriptor fd) throws ErrnoException;
419 
420     /**
421      * Add an entry into the ARP cache.
422      */
addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr, String ifname, FileDescriptor fd)423     public static void addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr,
424             String ifname, FileDescriptor fd) throws IOException {
425         addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
426     }
427 
addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname, FileDescriptor fd)428     private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
429             FileDescriptor fd) throws IOException;
430 
431 }
432