• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.app.compat.CompatChanges;
23 import android.compat.annotation.ChangeId;
24 import android.compat.annotation.EnabledAfter;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.os.Build;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.text.TextUtils;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.net.module.util.LinkPropertiesUtils;
33 
34 import java.net.Inet4Address;
35 import java.net.Inet6Address;
36 import java.net.InetAddress;
37 import java.net.UnknownHostException;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.Hashtable;
42 import java.util.List;
43 import java.util.Objects;
44 import java.util.StringJoiner;
45 import java.util.stream.Collectors;
46 
47 /**
48  * Describes the properties of a network link.
49  *
50  * A link represents a connection to a network.
51  * It may have multiple addresses and multiple gateways,
52  * multiple dns servers but only one http proxy and one
53  * network interface.
54  *
55  * Note that this is just a holder of data.  Modifying it
56  * does not affect live networks.
57  *
58  */
59 public final class LinkProperties implements Parcelable {
60     /**
61      * The {@link #getRoutes()} now can contain excluded as well as included routes. Use
62      * {@link RouteInfo#getType()} to determine route type.
63      *
64      * @hide
65      */
66     @ChangeId
67     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
68     @VisibleForTesting
69     public static final long EXCLUDED_ROUTES = 186082280;
70 
71     // The interface described by the network link.
72     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
73     private String mIfaceName;
74     private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
75     private final ArrayList<InetAddress> mDnses = new ArrayList<>();
76     // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
77     private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
78     private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
79     private boolean mUsePrivateDns;
80     private String mPrivateDnsServerName;
81     private String mDomains;
82     private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
83     private Inet4Address mDhcpServerAddress;
84     private ProxyInfo mHttpProxy;
85     private int mMtu;
86     // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
87     private String mTcpBufferSizes;
88     private IpPrefix mNat64Prefix;
89     private boolean mWakeOnLanSupported;
90     private Uri mCaptivePortalApiUrl;
91     private CaptivePortalData mCaptivePortalData;
92 
93     /**
94      * Indicates whether parceling should preserve fields that are set based on permissions of
95      * the process receiving the {@link LinkProperties}.
96      */
97     private final transient boolean mParcelSensitiveFields;
98 
99     private static final int MIN_MTU    = 68;
100 
101     private static final int MIN_MTU_V6 = 1280;
102 
103     private static final int MAX_MTU    = 10000;
104 
105     private static final int INET6_ADDR_LENGTH = 16;
106 
107     // Stores the properties of links that are "stacked" above this link.
108     // Indexed by interface name to allow modification and to prevent duplicates being added.
109     private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
110 
111     /**
112      * @hide
113      */
114     @UnsupportedAppUsage(implicitMember =
115             "values()[Landroid/net/LinkProperties$ProvisioningChange;")
116     public enum ProvisioningChange {
117         @UnsupportedAppUsage
118         STILL_NOT_PROVISIONED,
119         @UnsupportedAppUsage
120         LOST_PROVISIONING,
121         @UnsupportedAppUsage
122         GAINED_PROVISIONING,
123         @UnsupportedAppUsage
124         STILL_PROVISIONED,
125     }
126 
127     /**
128      * Compare the provisioning states of two LinkProperties instances.
129      *
130      * @hide
131      */
132     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
compareProvisioning( LinkProperties before, LinkProperties after)133     public static ProvisioningChange compareProvisioning(
134             LinkProperties before, LinkProperties after) {
135         if (before.isProvisioned() && after.isProvisioned()) {
136             // On dual-stack networks, DHCPv4 renewals can occasionally fail.
137             // When this happens, IPv6-reachable services continue to function
138             // normally but IPv4-only services (naturally) fail.
139             //
140             // When an application using an IPv4-only service reports a bad
141             // network condition to the framework, attempts to re-validate
142             // the network succeed (since we support IPv6-only networks) and
143             // nothing is changed.
144             //
145             // For users, this is confusing and unexpected behaviour, and is
146             // not necessarily easy to diagnose.  Therefore, we treat changing
147             // from a dual-stack network to an IPv6-only network equivalent to
148             // a total loss of provisioning.
149             //
150             // For one such example of this, see b/18867306.
151             //
152             // Additionally, losing IPv6 provisioning can result in TCP
153             // connections getting stuck until timeouts fire and other
154             // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
155             // previously dual-stack network is deemed a lost of provisioning.
156             if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
157                     || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
158                 return ProvisioningChange.LOST_PROVISIONING;
159             }
160             return ProvisioningChange.STILL_PROVISIONED;
161         } else if (before.isProvisioned() && !after.isProvisioned()) {
162             return ProvisioningChange.LOST_PROVISIONING;
163         } else if (!before.isProvisioned() && after.isProvisioned()) {
164             return ProvisioningChange.GAINED_PROVISIONING;
165         } else {  // !before.isProvisioned() && !after.isProvisioned()
166             return ProvisioningChange.STILL_NOT_PROVISIONED;
167         }
168     }
169 
170     /**
171      * Constructs a new {@code LinkProperties} with default values.
172      */
LinkProperties()173     public LinkProperties() {
174         mParcelSensitiveFields = false;
175     }
176 
177     /**
178      * @hide
179      */
180     @SystemApi
LinkProperties(@ullable LinkProperties source)181     public LinkProperties(@Nullable LinkProperties source) {
182         this(source, false /* parcelSensitiveFields */);
183     }
184 
185     /**
186      * Create a copy of a {@link LinkProperties} that may preserve fields that were set
187      * based on the permissions of the process that originally received it.
188      *
189      * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
190      * they should not be shared outside of the process that receives them without appropriate
191      * checks.
192      * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
193      * @hide
194      */
195     @SystemApi
LinkProperties(@ullable LinkProperties source, boolean parcelSensitiveFields)196     public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
197         mParcelSensitiveFields = parcelSensitiveFields;
198         if (source == null) return;
199         mIfaceName = source.mIfaceName;
200         mLinkAddresses.addAll(source.mLinkAddresses);
201         mDnses.addAll(source.mDnses);
202         mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
203         mUsePrivateDns = source.mUsePrivateDns;
204         mPrivateDnsServerName = source.mPrivateDnsServerName;
205         mPcscfs.addAll(source.mPcscfs);
206         mDomains = source.mDomains;
207         mRoutes.addAll(source.mRoutes);
208         mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
209         for (LinkProperties l: source.mStackedLinks.values()) {
210             addStackedLink(l);
211         }
212         setMtu(source.mMtu);
213         setDhcpServerAddress(source.getDhcpServerAddress());
214         mTcpBufferSizes = source.mTcpBufferSizes;
215         mNat64Prefix = source.mNat64Prefix;
216         mWakeOnLanSupported = source.mWakeOnLanSupported;
217         mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
218         mCaptivePortalData = source.mCaptivePortalData;
219     }
220 
221     /**
222      * Sets the interface name for this link.  All {@link RouteInfo} already set for this
223      * will have their interface changed to match this new value.
224      *
225      * @param iface The name of the network interface used for this link.
226      */
setInterfaceName(@ullable String iface)227     public void setInterfaceName(@Nullable String iface) {
228         mIfaceName = iface;
229         ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
230         for (RouteInfo route : mRoutes) {
231             newRoutes.add(routeWithInterface(route));
232         }
233         mRoutes = newRoutes;
234     }
235 
236     /**
237      * Gets the interface name for this link.  May be {@code null} if not set.
238      *
239      * @return The interface name set for this link or {@code null}.
240      */
getInterfaceName()241     public @Nullable String getInterfaceName() {
242         return mIfaceName;
243     }
244 
245     /**
246      * @hide
247      */
248     @SystemApi
getAllInterfaceNames()249     public @NonNull List<String> getAllInterfaceNames() {
250         List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
251         if (mIfaceName != null) interfaceNames.add(mIfaceName);
252         for (LinkProperties stacked: mStackedLinks.values()) {
253             interfaceNames.addAll(stacked.getAllInterfaceNames());
254         }
255         return interfaceNames;
256     }
257 
258     /**
259      * Returns all the addresses on this link.  We often think of a link having a single address,
260      * however, particularly with Ipv6 several addresses are typical.  Note that the
261      * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
262      * prefix lengths for each address.  This is a simplified utility alternative to
263      * {@link LinkProperties#getLinkAddresses}.
264      *
265      * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
266      * @hide
267      */
268     @SystemApi
getAddresses()269     public @NonNull List<InetAddress> getAddresses() {
270         final List<InetAddress> addresses = new ArrayList<>();
271         for (LinkAddress linkAddress : mLinkAddresses) {
272             addresses.add(linkAddress.getAddress());
273         }
274         return Collections.unmodifiableList(addresses);
275     }
276 
277     /**
278      * Returns all the addresses on this link and all the links stacked above it.
279      * @hide
280      */
281     @UnsupportedAppUsage
getAllAddresses()282     public @NonNull List<InetAddress> getAllAddresses() {
283         List<InetAddress> addresses = new ArrayList<>();
284         for (LinkAddress linkAddress : mLinkAddresses) {
285             addresses.add(linkAddress.getAddress());
286         }
287         for (LinkProperties stacked: mStackedLinks.values()) {
288             addresses.addAll(stacked.getAllAddresses());
289         }
290         return addresses;
291     }
292 
findLinkAddressIndex(LinkAddress address)293     private int findLinkAddressIndex(LinkAddress address) {
294         for (int i = 0; i < mLinkAddresses.size(); i++) {
295             if (mLinkAddresses.get(i).isSameAddressAs(address)) {
296                 return i;
297             }
298         }
299         return -1;
300     }
301 
302     /**
303      * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
304      * same address/prefix does not already exist.  If it does exist it is replaced.
305      * @param address The {@code LinkAddress} to add.
306      * @return true if {@code address} was added or updated, false otherwise.
307      * @hide
308      */
309     @SystemApi
addLinkAddress(@onNull LinkAddress address)310     public boolean addLinkAddress(@NonNull LinkAddress address) {
311         if (address == null) {
312             return false;
313         }
314         int i = findLinkAddressIndex(address);
315         if (i < 0) {
316             // Address was not present. Add it.
317             mLinkAddresses.add(address);
318             return true;
319         } else if (mLinkAddresses.get(i).equals(address)) {
320             // Address was present and has same properties. Do nothing.
321             return false;
322         } else {
323             // Address was present and has different properties. Update it.
324             mLinkAddresses.set(i, address);
325             return true;
326         }
327     }
328 
329     /**
330      * Removes a {@link LinkAddress} from this {@code LinkProperties}.  Specifically, matches
331      * and {@link LinkAddress} with the same address and prefix.
332      *
333      * @param toRemove A {@link LinkAddress} specifying the address to remove.
334      * @return true if the address was removed, false if it did not exist.
335      * @hide
336      */
337     @SystemApi
removeLinkAddress(@onNull LinkAddress toRemove)338     public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
339         int i = findLinkAddressIndex(toRemove);
340         if (i >= 0) {
341             mLinkAddresses.remove(i);
342             return true;
343         }
344         return false;
345     }
346 
347     /**
348      * Returns all the {@link LinkAddress} on this link.  Typically a link will have
349      * one IPv4 address and one or more IPv6 addresses.
350      *
351      * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
352      */
getLinkAddresses()353     public @NonNull List<LinkAddress> getLinkAddresses() {
354         return Collections.unmodifiableList(mLinkAddresses);
355     }
356 
357     /**
358      * Returns all the addresses on this link and all the links stacked above it.
359      * @hide
360      */
361     @SystemApi
getAllLinkAddresses()362     public @NonNull List<LinkAddress> getAllLinkAddresses() {
363         List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
364         for (LinkProperties stacked: mStackedLinks.values()) {
365             addresses.addAll(stacked.getAllLinkAddresses());
366         }
367         return addresses;
368     }
369 
370     /**
371      * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
372      * the given {@link Collection} of {@link LinkAddress}.
373      *
374      * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
375      *                  object.
376      */
setLinkAddresses(@onNull Collection<LinkAddress> addresses)377     public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
378         mLinkAddresses.clear();
379         for (LinkAddress address: addresses) {
380             addLinkAddress(address);
381         }
382     }
383 
384     /**
385      * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
386      *
387      * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
388      * @return true if the DNS server was added, false if it was already present.
389      * @hide
390      */
391     @SystemApi
addDnsServer(@onNull InetAddress dnsServer)392     public boolean addDnsServer(@NonNull InetAddress dnsServer) {
393         if (dnsServer != null && !mDnses.contains(dnsServer)) {
394             mDnses.add(dnsServer);
395             return true;
396         }
397         return false;
398     }
399 
400     /**
401      * Removes the given {@link InetAddress} from the list of DNS servers.
402      *
403      * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
404      * @return true if the DNS server was removed, false if it did not exist.
405      * @hide
406      */
407     @SystemApi
removeDnsServer(@onNull InetAddress dnsServer)408     public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
409         return mDnses.remove(dnsServer);
410     }
411 
412     /**
413      * Replaces the DNS servers in this {@code LinkProperties} with
414      * the given {@link Collection} of {@link InetAddress} objects.
415      *
416      * @param dnsServers The {@link Collection} of DNS servers to set in this object.
417      */
setDnsServers(@onNull Collection<InetAddress> dnsServers)418     public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
419         mDnses.clear();
420         for (InetAddress dnsServer: dnsServers) {
421             addDnsServer(dnsServer);
422         }
423     }
424 
425     /**
426      * Returns all the {@link InetAddress} for DNS servers on this link.
427      *
428      * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
429      *         this link.
430      */
getDnsServers()431     public @NonNull List<InetAddress> getDnsServers() {
432         return Collections.unmodifiableList(mDnses);
433     }
434 
435     /**
436      * Set whether private DNS is currently in use on this network.
437      *
438      * @param usePrivateDns The private DNS state.
439      * @hide
440      */
441     @SystemApi
setUsePrivateDns(boolean usePrivateDns)442     public void setUsePrivateDns(boolean usePrivateDns) {
443         mUsePrivateDns = usePrivateDns;
444     }
445 
446     /**
447      * Returns whether private DNS is currently in use on this network. When
448      * private DNS is in use, applications must not send unencrypted DNS
449      * queries as doing so could reveal private user information. Furthermore,
450      * if private DNS is in use and {@link #getPrivateDnsServerName} is not
451      * {@code null}, DNS queries must be sent to the specified DNS server.
452      *
453      * @return {@code true} if private DNS is in use, {@code false} otherwise.
454      */
isPrivateDnsActive()455     public boolean isPrivateDnsActive() {
456         return mUsePrivateDns;
457     }
458 
459     /**
460      * Set the name of the private DNS server to which private DNS queries
461      * should be sent when in strict mode. This value should be {@code null}
462      * when private DNS is off or in opportunistic mode.
463      *
464      * @param privateDnsServerName The private DNS server name.
465      * @hide
466      */
467     @SystemApi
setPrivateDnsServerName(@ullable String privateDnsServerName)468     public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
469         mPrivateDnsServerName = privateDnsServerName;
470     }
471 
472     /**
473      * Set DHCP server address.
474      *
475      * @param serverAddress the server address to set.
476      */
setDhcpServerAddress(@ullable Inet4Address serverAddress)477     public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
478         mDhcpServerAddress = serverAddress;
479     }
480 
481      /**
482      * Get DHCP server address
483      *
484      * @return The current DHCP server address.
485      */
getDhcpServerAddress()486     public @Nullable Inet4Address getDhcpServerAddress() {
487         return mDhcpServerAddress;
488     }
489 
490     /**
491      * Returns the private DNS server name that is in use. If not {@code null},
492      * private DNS is in strict mode. In this mode, applications should ensure
493      * that all DNS queries are encrypted and sent to this hostname and that
494      * queries are only sent if the hostname's certificate is valid. If
495      * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private
496      * DNS is in opportunistic mode, and applications should ensure that DNS
497      * queries are encrypted and sent to a DNS server returned by
498      * {@link #getDnsServers}. System DNS will handle each of these cases
499      * correctly, but applications implementing their own DNS lookups must make
500      * sure to follow these requirements.
501      *
502      * @return The private DNS server name.
503      */
getPrivateDnsServerName()504     public @Nullable String getPrivateDnsServerName() {
505         return mPrivateDnsServerName;
506     }
507 
508     /**
509      * Adds the given {@link InetAddress} to the list of validated private DNS servers,
510      * if not present. This is distinct from the server name in that these are actually
511      * resolved addresses.
512      *
513      * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
514      * @return true if the DNS server was added, false if it was already present.
515      * @hide
516      */
addValidatedPrivateDnsServer(@onNull InetAddress dnsServer)517     public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
518         if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
519             mValidatedPrivateDnses.add(dnsServer);
520             return true;
521         }
522         return false;
523     }
524 
525     /**
526      * Removes the given {@link InetAddress} from the list of validated private DNS servers.
527      *
528      * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
529      *        servers.
530      * @return true if the DNS server was removed, false if it did not exist.
531      * @hide
532      */
removeValidatedPrivateDnsServer(@onNull InetAddress dnsServer)533     public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
534         return mValidatedPrivateDnses.remove(dnsServer);
535     }
536 
537     /**
538      * Replaces the validated private DNS servers in this {@code LinkProperties} with
539      * the given {@link Collection} of {@link InetAddress} objects.
540      *
541      * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
542      *        object.
543      * @hide
544      */
545     @SystemApi
setValidatedPrivateDnsServers(@onNull Collection<InetAddress> dnsServers)546     public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
547         mValidatedPrivateDnses.clear();
548         for (InetAddress dnsServer: dnsServers) {
549             addValidatedPrivateDnsServer(dnsServer);
550         }
551     }
552 
553     /**
554      * Returns all the {@link InetAddress} for validated private DNS servers on this link.
555      * These are resolved from the private DNS server name.
556      *
557      * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
558      *         DNS servers on this link.
559      * @hide
560      */
561     @SystemApi
getValidatedPrivateDnsServers()562     public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
563         return Collections.unmodifiableList(mValidatedPrivateDnses);
564     }
565 
566     /**
567      * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
568      *
569      * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
570      * @return true if the PCSCF server was added, false otherwise.
571      * @hide
572      */
573     @SystemApi
addPcscfServer(@onNull InetAddress pcscfServer)574     public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
575         if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
576             mPcscfs.add(pcscfServer);
577             return true;
578         }
579         return false;
580     }
581 
582     /**
583      * Removes the given {@link InetAddress} from the list of PCSCF servers.
584      *
585      * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
586      * @return true if the PCSCF server was removed, false otherwise.
587      * @hide
588      */
removePcscfServer(@onNull InetAddress pcscfServer)589     public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
590         return mPcscfs.remove(pcscfServer);
591     }
592 
593     /**
594      * Replaces the PCSCF servers in this {@code LinkProperties} with
595      * the given {@link Collection} of {@link InetAddress} objects.
596      *
597      * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
598      * @hide
599      */
600     @SystemApi
setPcscfServers(@onNull Collection<InetAddress> pcscfServers)601     public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
602         mPcscfs.clear();
603         for (InetAddress pcscfServer: pcscfServers) {
604             addPcscfServer(pcscfServer);
605         }
606     }
607 
608     /**
609      * Returns all the {@link InetAddress} for PCSCF servers on this link.
610      *
611      * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
612      *         this link.
613      * @hide
614      */
615     @SystemApi
getPcscfServers()616     public @NonNull List<InetAddress> getPcscfServers() {
617         return Collections.unmodifiableList(mPcscfs);
618     }
619 
620     /**
621      * Sets the DNS domain search path used on this link.
622      *
623      * @param domains A {@link String} listing in priority order the comma separated
624      *                domains to search when resolving host names on this link.
625      */
setDomains(@ullable String domains)626     public void setDomains(@Nullable String domains) {
627         mDomains = domains;
628     }
629 
630     /**
631      * Get the DNS domains search path set for this link. May be {@code null} if not set.
632      *
633      * @return A {@link String} containing the comma separated domains to search when resolving host
634      *         names on this link or {@code null}.
635      */
getDomains()636     public @Nullable String getDomains() {
637         return mDomains;
638     }
639 
640     /**
641      * Sets the Maximum Transmission Unit size to use on this link.  This should not be used
642      * unless the system default (1500) is incorrect.  Values less than 68 or greater than
643      * 10000 will be ignored.
644      *
645      * @param mtu The MTU to use for this link.
646      */
setMtu(int mtu)647     public void setMtu(int mtu) {
648         mMtu = mtu;
649     }
650 
651     /**
652      * Gets any non-default MTU size set for this link.  Note that if the default is being used
653      * this will return 0.
654      *
655      * @return The mtu value set for this link.
656      */
getMtu()657     public int getMtu() {
658         return mMtu;
659     }
660 
661     /**
662      * Sets the tcp buffers sizes to be used when this link is the system default.
663      * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
664      *
665      * @param tcpBufferSizes The tcp buffers sizes to use.
666      *
667      * @hide
668      */
669     @SystemApi
setTcpBufferSizes(@ullable String tcpBufferSizes)670     public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
671         mTcpBufferSizes = tcpBufferSizes;
672     }
673 
674     /**
675      * Gets the tcp buffer sizes. May be {@code null} if not set.
676      *
677      * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
678      *
679      * @hide
680      */
681     @SystemApi
getTcpBufferSizes()682     public @Nullable String getTcpBufferSizes() {
683         return mTcpBufferSizes;
684     }
685 
routeWithInterface(RouteInfo route)686     private RouteInfo routeWithInterface(RouteInfo route) {
687         return new RouteInfo(
688             route.getDestination(),
689             route.getGateway(),
690             mIfaceName,
691             route.getType(),
692             route.getMtu());
693     }
694 
findRouteIndexByRouteKey(RouteInfo route)695     private int findRouteIndexByRouteKey(RouteInfo route) {
696         for (int i = 0; i < mRoutes.size(); i++) {
697             if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) {
698                 return i;
699             }
700         }
701         return -1;
702     }
703 
704     /**
705      * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
706      * with the same destination, gateway and interface with different properties
707      * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
708      * interface name set and that differs from the interface set for this
709      * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
710      * The proper course is to add either un-named or properly named {@link RouteInfo}.
711      *
712      * @param route A {@link RouteInfo} to add to this object.
713      * @return {@code true} was added or updated, false otherwise.
714      */
addRoute(@onNull RouteInfo route)715     public boolean addRoute(@NonNull RouteInfo route) {
716         String routeIface = route.getInterface();
717         if (routeIface != null && !routeIface.equals(mIfaceName)) {
718             throw new IllegalArgumentException(
719                     "Route added with non-matching interface: " + routeIface
720                             + " vs. " + mIfaceName);
721         }
722         route = routeWithInterface(route);
723 
724         int i = findRouteIndexByRouteKey(route);
725         if (i == -1) {
726             // Route was not present. Add it.
727             mRoutes.add(route);
728             return true;
729         } else if (mRoutes.get(i).equals(route)) {
730             // Route was present and has same properties. Do nothing.
731             return false;
732         } else {
733             // Route was present and has different properties. Update it.
734             mRoutes.set(i, route);
735             return true;
736         }
737     }
738 
739     /**
740      * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
741      * specify an interface and the interface must match the interface of this
742      * {@code LinkProperties}, or it will not be removed.
743      *
744      * @param route A {@link RouteInfo} specifying the route to remove.
745      * @return {@code true} if the route was removed, {@code false} if it was not present.
746      *
747      * @hide
748      */
749     @SystemApi
removeRoute(@onNull RouteInfo route)750     public boolean removeRoute(@NonNull RouteInfo route) {
751         return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
752     }
753 
754     /**
755      * Returns all the {@link RouteInfo} set on this link.
756      *
757      * Only unicast routes are returned for apps targeting Android S or below.
758      *
759      * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
760      */
getRoutes()761     public @NonNull List<RouteInfo> getRoutes() {
762         if (CompatChanges.isChangeEnabled(EXCLUDED_ROUTES)) {
763             return Collections.unmodifiableList(mRoutes);
764         } else {
765             return Collections.unmodifiableList(getUnicastRoutes());
766         }
767     }
768 
769     /**
770      * Returns all the {@link RouteInfo} of type {@link RouteInfo#RTN_UNICAST} set on this link.
771      */
getUnicastRoutes()772     private @NonNull List<RouteInfo> getUnicastRoutes() {
773         return mRoutes.stream()
774                 .filter(route -> route.getType() == RouteInfo.RTN_UNICAST)
775                 .collect(Collectors.toList());
776     }
777 
778     /**
779      * Make sure this LinkProperties instance contains routes that cover the local subnet
780      * of its link addresses. Add any route that is missing.
781      * @hide
782      */
ensureDirectlyConnectedRoutes()783     public void ensureDirectlyConnectedRoutes() {
784         for (LinkAddress addr : mLinkAddresses) {
785             addRoute(new RouteInfo(addr, null, mIfaceName));
786         }
787     }
788 
789     /**
790      * Returns all the routes on this link and all the links stacked above it.
791      *
792      * Only unicast routes are returned for apps targeting Android S or below.
793      *
794      * @hide
795      */
796     @SystemApi
getAllRoutes()797     public @NonNull List<RouteInfo> getAllRoutes() {
798         final List<RouteInfo> routes = new ArrayList<>(getRoutes());
799         for (LinkProperties stacked: mStackedLinks.values()) {
800             routes.addAll(stacked.getAllRoutes());
801         }
802         return routes;
803     }
804 
805     /**
806      * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
807      * Note that Http Proxies are only a hint - the system recommends their use, but it does
808      * not enforce it and applications may ignore them.
809      *
810      * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
811      */
setHttpProxy(@ullable ProxyInfo proxy)812     public void setHttpProxy(@Nullable ProxyInfo proxy) {
813         mHttpProxy = proxy;
814     }
815 
816     /**
817      * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
818      *
819      * @return The {@link ProxyInfo} set on this link or {@code null}.
820      */
getHttpProxy()821     public @Nullable ProxyInfo getHttpProxy() {
822         return mHttpProxy;
823     }
824 
825     /**
826      * Returns the NAT64 prefix in use on this link, if any.
827      *
828      * @return the NAT64 prefix or {@code null}.
829      */
getNat64Prefix()830     public @Nullable IpPrefix getNat64Prefix() {
831         return mNat64Prefix;
832     }
833 
834     /**
835      * Sets the NAT64 prefix in use on this link.
836      *
837      * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
838      * 128-bit IPv6 address) are supported or {@code null} for no prefix.
839      *
840      * @param prefix the NAT64 prefix.
841      */
setNat64Prefix(@ullable IpPrefix prefix)842     public void setNat64Prefix(@Nullable IpPrefix prefix) {
843         if (prefix != null && prefix.getPrefixLength() != 96) {
844             throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
845         }
846         mNat64Prefix = prefix;  // IpPrefix objects are immutable.
847     }
848 
849     /**
850      * Adds a stacked link.
851      *
852      * If there is already a stacked link with the same interface name as link,
853      * that link is replaced with link. Otherwise, link is added to the list
854      * of stacked links.
855      *
856      * @param link The link to add.
857      * @return true if the link was stacked, false otherwise.
858      * @hide
859      */
860     @UnsupportedAppUsage
addStackedLink(@onNull LinkProperties link)861     public boolean addStackedLink(@NonNull LinkProperties link) {
862         if (link.getInterfaceName() != null) {
863             mStackedLinks.put(link.getInterfaceName(), link);
864             return true;
865         }
866         return false;
867     }
868 
869     /**
870      * Removes a stacked link.
871      *
872      * If there is a stacked link with the given interface name, it is
873      * removed. Otherwise, nothing changes.
874      *
875      * @param iface The interface name of the link to remove.
876      * @return true if the link was removed, false otherwise.
877      * @hide
878      */
removeStackedLink(@onNull String iface)879     public boolean removeStackedLink(@NonNull String iface) {
880         LinkProperties removed = mStackedLinks.remove(iface);
881         return removed != null;
882     }
883 
884     /**
885      * Returns all the links stacked on top of this link.
886      * @hide
887      */
888     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getStackedLinks()889     public @NonNull List<LinkProperties> getStackedLinks() {
890         if (mStackedLinks.isEmpty()) {
891             return Collections.emptyList();
892         }
893         final List<LinkProperties> stacked = new ArrayList<>();
894         for (LinkProperties link : mStackedLinks.values()) {
895             stacked.add(new LinkProperties(link));
896         }
897         return Collections.unmodifiableList(stacked);
898     }
899 
900     /**
901      * Clears this object to its initial state.
902      */
clear()903     public void clear() {
904         if (mParcelSensitiveFields) {
905             throw new UnsupportedOperationException(
906                     "Cannot clear LinkProperties when parcelSensitiveFields is set");
907         }
908 
909         mIfaceName = null;
910         mLinkAddresses.clear();
911         mDnses.clear();
912         mUsePrivateDns = false;
913         mPrivateDnsServerName = null;
914         mPcscfs.clear();
915         mDomains = null;
916         mRoutes.clear();
917         mHttpProxy = null;
918         mStackedLinks.clear();
919         mMtu = 0;
920         mDhcpServerAddress = null;
921         mTcpBufferSizes = null;
922         mNat64Prefix = null;
923         mWakeOnLanSupported = false;
924         mCaptivePortalApiUrl = null;
925         mCaptivePortalData = null;
926     }
927 
928     /**
929      * Implement the Parcelable interface
930      */
describeContents()931     public int describeContents() {
932         return 0;
933     }
934 
935     @Override
toString()936     public String toString() {
937         // Space as a separator, so no need for spaces at start/end of the individual fragments.
938         final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
939 
940         if (mIfaceName != null) {
941             resultJoiner.add("InterfaceName:");
942             resultJoiner.add(mIfaceName);
943         }
944 
945         resultJoiner.add("LinkAddresses: [");
946         if (!mLinkAddresses.isEmpty()) {
947             resultJoiner.add(TextUtils.join(",", mLinkAddresses));
948         }
949         resultJoiner.add("]");
950 
951         resultJoiner.add("DnsAddresses: [");
952         if (!mDnses.isEmpty()) {
953             resultJoiner.add(TextUtils.join(",", mDnses));
954         }
955         resultJoiner.add("]");
956 
957         if (mUsePrivateDns) {
958             resultJoiner.add("UsePrivateDns: true");
959         }
960 
961         if (mPrivateDnsServerName != null) {
962             resultJoiner.add("PrivateDnsServerName:");
963             resultJoiner.add(mPrivateDnsServerName);
964         }
965 
966         if (!mPcscfs.isEmpty()) {
967             resultJoiner.add("PcscfAddresses: [");
968             resultJoiner.add(TextUtils.join(",", mPcscfs));
969             resultJoiner.add("]");
970         }
971 
972         if (!mValidatedPrivateDnses.isEmpty()) {
973             final StringJoiner validatedPrivateDnsesJoiner =
974                     new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
975             for (final InetAddress addr : mValidatedPrivateDnses) {
976                 validatedPrivateDnsesJoiner.add(addr.getHostAddress());
977             }
978             resultJoiner.add(validatedPrivateDnsesJoiner.toString());
979         }
980 
981         resultJoiner.add("Domains:");
982         resultJoiner.add(mDomains);
983 
984         resultJoiner.add("MTU:");
985         resultJoiner.add(Integer.toString(mMtu));
986 
987         if (mWakeOnLanSupported) {
988             resultJoiner.add("WakeOnLanSupported: true");
989         }
990 
991         if (mDhcpServerAddress != null) {
992             resultJoiner.add("ServerAddress:");
993             resultJoiner.add(mDhcpServerAddress.toString());
994         }
995 
996         if (mCaptivePortalApiUrl != null) {
997             resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
998         }
999 
1000         if (mCaptivePortalData != null) {
1001             resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
1002         }
1003 
1004         if (mTcpBufferSizes != null) {
1005             resultJoiner.add("TcpBufferSizes:");
1006             resultJoiner.add(mTcpBufferSizes);
1007         }
1008 
1009         resultJoiner.add("Routes: [");
1010         if (!mRoutes.isEmpty()) {
1011             resultJoiner.add(TextUtils.join(",", mRoutes));
1012         }
1013         resultJoiner.add("]");
1014 
1015         if (mHttpProxy != null) {
1016             resultJoiner.add("HttpProxy:");
1017             resultJoiner.add(mHttpProxy.toString());
1018         }
1019 
1020         if (mNat64Prefix != null) {
1021             resultJoiner.add("Nat64Prefix:");
1022             resultJoiner.add(mNat64Prefix.toString());
1023         }
1024 
1025         final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
1026         if (!stackedLinksValues.isEmpty()) {
1027             final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
1028             for (final LinkProperties lp : stackedLinksValues) {
1029                 stackedLinksJoiner.add("[ " + lp + " ]");
1030             }
1031             resultJoiner.add(stackedLinksJoiner.toString());
1032         }
1033 
1034         return resultJoiner.toString();
1035     }
1036 
1037     /**
1038      * Returns true if this link has an IPv4 address.
1039      *
1040      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1041      * @hide
1042      */
1043     @SystemApi
hasIpv4Address()1044     public boolean hasIpv4Address() {
1045         for (LinkAddress address : mLinkAddresses) {
1046             if (address.getAddress() instanceof Inet4Address) {
1047                 return true;
1048             }
1049         }
1050         return false;
1051     }
1052 
1053     /**
1054      * For backward compatibility.
1055      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1056      * just yet.
1057      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1058      * @hide
1059      */
1060     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasIPv4Address()1061     public boolean hasIPv4Address() {
1062         return hasIpv4Address();
1063     }
1064 
1065     /**
1066      * Returns true if this link or any of its stacked interfaces has an IPv4 address.
1067      *
1068      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
1069      */
hasIpv4AddressOnInterface(String iface)1070     private boolean hasIpv4AddressOnInterface(String iface) {
1071         // mIfaceName can be null.
1072         return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
1073                 || (iface != null && mStackedLinks.containsKey(iface)
1074                         && mStackedLinks.get(iface).hasIpv4Address());
1075     }
1076 
1077     /**
1078      * Returns true if this link has a global preferred IPv6 address.
1079      *
1080      * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
1081      * @hide
1082      */
1083     @SystemApi
hasGlobalIpv6Address()1084     public boolean hasGlobalIpv6Address() {
1085         for (LinkAddress address : mLinkAddresses) {
1086           if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
1087             return true;
1088           }
1089         }
1090         return false;
1091     }
1092 
1093     /**
1094      * Returns true if this link has an IPv4 unreachable default route.
1095      *
1096      * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
1097      * @hide
1098      */
hasIpv4UnreachableDefaultRoute()1099     public boolean hasIpv4UnreachableDefaultRoute() {
1100         for (RouteInfo r : mRoutes) {
1101             if (r.isIPv4UnreachableDefault()) {
1102                 return true;
1103             }
1104         }
1105         return false;
1106     }
1107 
1108     /**
1109      * For backward compatibility.
1110      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1111      * just yet.
1112      * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
1113      * @hide
1114      */
1115     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasGlobalIPv6Address()1116     public boolean hasGlobalIPv6Address() {
1117         return hasGlobalIpv6Address();
1118     }
1119 
1120     /**
1121      * Returns true if this link has an IPv4 default route.
1122      *
1123      * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1124      * @hide
1125      */
1126     @SystemApi
hasIpv4DefaultRoute()1127     public boolean hasIpv4DefaultRoute() {
1128         for (RouteInfo r : mRoutes) {
1129             if (r.isIPv4Default()) {
1130                 return true;
1131             }
1132         }
1133         return false;
1134     }
1135 
1136     /**
1137      * Returns true if this link has an IPv6 unreachable default route.
1138      *
1139      * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
1140      * @hide
1141      */
hasIpv6UnreachableDefaultRoute()1142     public boolean hasIpv6UnreachableDefaultRoute() {
1143         for (RouteInfo r : mRoutes) {
1144             if (r.isIPv6UnreachableDefault()) {
1145                 return true;
1146             }
1147         }
1148         return false;
1149     }
1150 
1151     /**
1152      * For backward compatibility.
1153      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1154      * just yet.
1155      * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
1156      * @hide
1157      */
1158     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasIPv4DefaultRoute()1159     public boolean hasIPv4DefaultRoute() {
1160         return hasIpv4DefaultRoute();
1161     }
1162 
1163     /**
1164      * Returns true if this link has an IPv6 default route.
1165      *
1166      * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1167      * @hide
1168      */
1169     @SystemApi
hasIpv6DefaultRoute()1170     public boolean hasIpv6DefaultRoute() {
1171         for (RouteInfo r : mRoutes) {
1172             if (r.isIPv6Default()) {
1173                 return true;
1174             }
1175         }
1176         return false;
1177     }
1178 
1179     /**
1180      * For backward compatibility.
1181      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1182      * just yet.
1183      * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
1184      * @hide
1185      */
1186     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasIPv6DefaultRoute()1187     public boolean hasIPv6DefaultRoute() {
1188         return hasIpv6DefaultRoute();
1189     }
1190 
1191     /**
1192      * Returns true if this link has an IPv4 DNS server.
1193      *
1194      * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1195      * @hide
1196      */
1197     @SystemApi
hasIpv4DnsServer()1198     public boolean hasIpv4DnsServer() {
1199         for (InetAddress ia : mDnses) {
1200             if (ia instanceof Inet4Address) {
1201                 return true;
1202             }
1203         }
1204         return false;
1205     }
1206 
1207     /**
1208      * For backward compatibility.
1209      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1210      * just yet.
1211      * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
1212      * @hide
1213      */
1214     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasIPv4DnsServer()1215     public boolean hasIPv4DnsServer() {
1216         return hasIpv4DnsServer();
1217     }
1218 
1219     /**
1220      * Returns true if this link has an IPv6 DNS server.
1221      *
1222      * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1223      * @hide
1224      */
1225     @SystemApi
hasIpv6DnsServer()1226     public boolean hasIpv6DnsServer() {
1227         for (InetAddress ia : mDnses) {
1228             if (ia instanceof Inet6Address) {
1229                 return true;
1230             }
1231         }
1232         return false;
1233     }
1234 
1235     /**
1236      * For backward compatibility.
1237      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1238      * just yet.
1239      * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
1240      * @hide
1241      */
1242     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
hasIPv6DnsServer()1243     public boolean hasIPv6DnsServer() {
1244         return hasIpv6DnsServer();
1245     }
1246 
1247     /**
1248      * Returns true if this link has an IPv4 PCSCF server.
1249      *
1250      * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
1251      * @hide
1252      */
hasIpv4PcscfServer()1253     public boolean hasIpv4PcscfServer() {
1254         for (InetAddress ia : mPcscfs) {
1255           if (ia instanceof Inet4Address) {
1256             return true;
1257           }
1258         }
1259         return false;
1260     }
1261 
1262     /**
1263      * Returns true if this link has an IPv6 PCSCF server.
1264      *
1265      * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
1266      * @hide
1267      */
hasIpv6PcscfServer()1268     public boolean hasIpv6PcscfServer() {
1269         for (InetAddress ia : mPcscfs) {
1270           if (ia instanceof Inet6Address) {
1271             return true;
1272           }
1273         }
1274         return false;
1275     }
1276 
1277     /**
1278      * Returns true if this link is provisioned for global IPv4 connectivity.
1279      * This requires an IP address, default route, and DNS server.
1280      *
1281      * @return {@code true} if the link is provisioned, {@code false} otherwise.
1282      * @hide
1283      */
1284     @SystemApi
isIpv4Provisioned()1285     public boolean isIpv4Provisioned() {
1286         return (hasIpv4Address()
1287                 && hasIpv4DefaultRoute()
1288                 && hasIpv4DnsServer());
1289     }
1290 
1291     /**
1292      * Returns true if this link is provisioned for global IPv6 connectivity.
1293      * This requires an IP address, default route, and DNS server.
1294      *
1295      * @return {@code true} if the link is provisioned, {@code false} otherwise.
1296      * @hide
1297      */
1298     @SystemApi
isIpv6Provisioned()1299     public boolean isIpv6Provisioned() {
1300         return (hasGlobalIpv6Address()
1301                 && hasIpv6DefaultRoute()
1302                 && hasIpv6DnsServer());
1303     }
1304 
1305     /**
1306      * For backward compatibility.
1307      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
1308      * just yet.
1309      * @return {@code true} if the link is provisioned, {@code false} otherwise.
1310      * @hide
1311      */
1312     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
isIPv6Provisioned()1313     public boolean isIPv6Provisioned() {
1314         return isIpv6Provisioned();
1315     }
1316 
1317 
1318     /**
1319      * Returns true if this link is provisioned for global connectivity,
1320      * for at least one Internet Protocol family.
1321      *
1322      * @return {@code true} if the link is provisioned, {@code false} otherwise.
1323      * @hide
1324      */
1325     @SystemApi
isProvisioned()1326     public boolean isProvisioned() {
1327         return (isIpv4Provisioned() || isIpv6Provisioned());
1328     }
1329 
1330     /**
1331      * Evaluate whether the {@link InetAddress} is considered reachable.
1332      *
1333      * @return {@code true} if the given {@link InetAddress} is considered reachable,
1334      *         {@code false} otherwise.
1335      * @hide
1336      */
1337     @SystemApi
isReachable(@onNull InetAddress ip)1338     public boolean isReachable(@NonNull InetAddress ip) {
1339         final List<RouteInfo> allRoutes = getAllRoutes();
1340         // If we don't have a route to this IP address, it's not reachable.
1341         final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
1342         if (bestRoute == null) {
1343             return false;
1344         }
1345 
1346         // TODO: better source address evaluation for destination addresses.
1347 
1348         if (ip instanceof Inet4Address) {
1349             // For IPv4, it suffices for now to simply have any address.
1350             return hasIpv4AddressOnInterface(bestRoute.getInterface());
1351         } else if (ip instanceof Inet6Address) {
1352             if (ip.isLinkLocalAddress()) {
1353                 // For now, just make sure link-local destinations have
1354                 // scopedIds set, since transmits will generally fail otherwise.
1355                 // TODO: verify it matches the ifindex of one of the interfaces.
1356                 return (((Inet6Address)ip).getScopeId() != 0);
1357             }  else {
1358                 // For non-link-local destinations check that either the best route
1359                 // is directly connected or that some global preferred address exists.
1360                 // TODO: reconsider all cases (disconnected ULA networks, ...).
1361                 return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
1362             }
1363         }
1364 
1365         return false;
1366     }
1367 
1368     /**
1369      * Returns true if this link has a throw route.
1370      *
1371      * @return {@code true} if there is an exclude route, {@code false} otherwise.
1372      * @hide
1373      */
hasExcludeRoute()1374     public boolean hasExcludeRoute() {
1375         for (RouteInfo r : mRoutes) {
1376             if (r.getType() == RouteInfo.RTN_THROW) {
1377                 return true;
1378             }
1379         }
1380         return false;
1381     }
1382 
1383     /**
1384      * Compares this {@code LinkProperties} interface name against the target
1385      *
1386      * @param target LinkProperties to compare.
1387      * @return {@code true} if both are identical, {@code false} otherwise.
1388      * @hide
1389      */
1390     @UnsupportedAppUsage
isIdenticalInterfaceName(@onNull LinkProperties target)1391     public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
1392         return LinkPropertiesUtils.isIdenticalInterfaceName(target, this);
1393     }
1394 
1395     /**
1396      * Compares this {@code LinkProperties} DHCP server address against the target
1397      *
1398      * @param target LinkProperties to compare.
1399      * @return {@code true} if both are identical, {@code false} otherwise.
1400      * @hide
1401      */
isIdenticalDhcpServerAddress(@onNull LinkProperties target)1402     public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
1403         return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
1404     }
1405 
1406     /**
1407      * Compares this {@code LinkProperties} interface addresses against the target
1408      *
1409      * @param target LinkProperties to compare.
1410      * @return {@code true} if both are identical, {@code false} otherwise.
1411      * @hide
1412      */
1413     @UnsupportedAppUsage
isIdenticalAddresses(@onNull LinkProperties target)1414     public boolean isIdenticalAddresses(@NonNull LinkProperties target) {
1415         return LinkPropertiesUtils.isIdenticalAddresses(target, this);
1416     }
1417 
1418     /**
1419      * Compares this {@code LinkProperties} DNS addresses against the target
1420      *
1421      * @param target LinkProperties to compare.
1422      * @return {@code true} if both are identical, {@code false} otherwise.
1423      * @hide
1424      */
1425     @UnsupportedAppUsage
isIdenticalDnses(@onNull LinkProperties target)1426     public boolean isIdenticalDnses(@NonNull LinkProperties target) {
1427         return LinkPropertiesUtils.isIdenticalDnses(target, this);
1428     }
1429 
1430     /**
1431      * Compares this {@code LinkProperties} private DNS settings against the
1432      * target.
1433      *
1434      * @param target LinkProperties to compare.
1435      * @return {@code true} if both are identical, {@code false} otherwise.
1436      * @hide
1437      */
isIdenticalPrivateDns(@onNull LinkProperties target)1438     public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
1439         return (isPrivateDnsActive() == target.isPrivateDnsActive()
1440                 && TextUtils.equals(getPrivateDnsServerName(),
1441                 target.getPrivateDnsServerName()));
1442     }
1443 
1444     /**
1445      * Compares this {@code LinkProperties} validated private DNS addresses against
1446      * the target
1447      *
1448      * @param target LinkProperties to compare.
1449      * @return {@code true} if both are identical, {@code false} otherwise.
1450      * @hide
1451      */
isIdenticalValidatedPrivateDnses(@onNull LinkProperties target)1452     public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
1453         Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
1454         return (mValidatedPrivateDnses.size() == targetDnses.size())
1455                 ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
1456     }
1457 
1458     /**
1459      * Compares this {@code LinkProperties} PCSCF addresses against the target
1460      *
1461      * @param target LinkProperties to compare.
1462      * @return {@code true} if both are identical, {@code false} otherwise.
1463      * @hide
1464      */
isIdenticalPcscfs(@onNull LinkProperties target)1465     public boolean isIdenticalPcscfs(@NonNull LinkProperties target) {
1466         Collection<InetAddress> targetPcscfs = target.getPcscfServers();
1467         return (mPcscfs.size() == targetPcscfs.size()) ?
1468                     mPcscfs.containsAll(targetPcscfs) : false;
1469     }
1470 
1471     /**
1472      * Compares this {@code LinkProperties} Routes against the target
1473      *
1474      * @param target LinkProperties to compare.
1475      * @return {@code true} if both are identical, {@code false} otherwise.
1476      * @hide
1477      */
1478     @UnsupportedAppUsage
isIdenticalRoutes(@onNull LinkProperties target)1479     public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
1480         return LinkPropertiesUtils.isIdenticalRoutes(target, this);
1481     }
1482 
1483     /**
1484      * Compares this {@code LinkProperties} HttpProxy against the target
1485      *
1486      * @param target LinkProperties to compare.
1487      * @return {@code true} if both are identical, {@code false} otherwise.
1488      * @hide
1489      */
1490     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isIdenticalHttpProxy(@onNull LinkProperties target)1491     public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
1492         return LinkPropertiesUtils.isIdenticalHttpProxy(target, this);
1493     }
1494 
1495     /**
1496      * Compares this {@code LinkProperties} stacked links against the target
1497      *
1498      * @param target LinkProperties to compare.
1499      * @return {@code true} if both are identical, {@code false} otherwise.
1500      * @hide
1501      */
1502     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isIdenticalStackedLinks(@onNull LinkProperties target)1503     public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
1504         if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
1505             return false;
1506         }
1507         for (LinkProperties stacked : mStackedLinks.values()) {
1508             // Hashtable values can never be null.
1509             String iface = stacked.getInterfaceName();
1510             if (!stacked.equals(target.mStackedLinks.get(iface))) {
1511                 return false;
1512             }
1513         }
1514         return true;
1515     }
1516 
1517     /**
1518      * Compares this {@code LinkProperties} MTU against the target
1519      *
1520      * @param target LinkProperties to compare.
1521      * @return {@code true} if both are identical, {@code false} otherwise.
1522      * @hide
1523      */
isIdenticalMtu(@onNull LinkProperties target)1524     public boolean isIdenticalMtu(@NonNull LinkProperties target) {
1525         return getMtu() == target.getMtu();
1526     }
1527 
1528     /**
1529      * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
1530      *
1531      * @param target LinkProperties to compare.
1532      * @return {@code true} if both are identical, {@code false} otherwise.
1533      * @hide
1534      */
isIdenticalTcpBufferSizes(@onNull LinkProperties target)1535     public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
1536         return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
1537     }
1538 
1539     /**
1540      * Compares this {@code LinkProperties} NAT64 prefix against the target.
1541      *
1542      * @param target LinkProperties to compare.
1543      * @return {@code true} if both are identical, {@code false} otherwise.
1544      * @hide
1545      */
isIdenticalNat64Prefix(@onNull LinkProperties target)1546     public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
1547         return Objects.equals(mNat64Prefix, target.mNat64Prefix);
1548     }
1549 
1550     /**
1551      * Compares this {@code LinkProperties} WakeOnLan supported against the target.
1552      *
1553      * @param target LinkProperties to compare.
1554      * @return {@code true} if both are identical, {@code false} otherwise.
1555      * @hide
1556      */
isIdenticalWakeOnLan(LinkProperties target)1557     public boolean isIdenticalWakeOnLan(LinkProperties target) {
1558         return isWakeOnLanSupported() == target.isWakeOnLanSupported();
1559     }
1560 
1561     /**
1562      * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
1563      *
1564      * @param target LinkProperties to compare.
1565      * @return {@code true} if both are identical, {@code false} otherwise.
1566      * @hide
1567      */
isIdenticalCaptivePortalApiUrl(LinkProperties target)1568     public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
1569         return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
1570     }
1571 
1572     /**
1573      * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
1574      *
1575      * @param target LinkProperties to compare.
1576      * @return {@code true} if both are identical, {@code false} otherwise.
1577      * @hide
1578      */
isIdenticalCaptivePortalData(LinkProperties target)1579     public boolean isIdenticalCaptivePortalData(LinkProperties target) {
1580         return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
1581     }
1582 
1583     /**
1584      * Set whether the network interface supports WakeOnLAN
1585      *
1586      * @param supported WakeOnLAN supported value
1587      *
1588      * @hide
1589      */
setWakeOnLanSupported(boolean supported)1590     public void setWakeOnLanSupported(boolean supported) {
1591         mWakeOnLanSupported = supported;
1592     }
1593 
1594     /**
1595      * Returns whether the network interface supports WakeOnLAN
1596      *
1597      * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
1598      */
isWakeOnLanSupported()1599     public boolean isWakeOnLanSupported() {
1600         return mWakeOnLanSupported;
1601     }
1602 
1603     /**
1604      * Set the URL of the captive portal API endpoint to get more information about the network.
1605      * @hide
1606      */
1607     @SystemApi
setCaptivePortalApiUrl(@ullable Uri url)1608     public void setCaptivePortalApiUrl(@Nullable Uri url) {
1609         mCaptivePortalApiUrl = url;
1610     }
1611 
1612     /**
1613      * Get the URL of the captive portal API endpoint to get more information about the network.
1614      *
1615      * <p>This is null unless the application has
1616      * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1617      * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
1618      * the URL.
1619      * @hide
1620      */
1621     @SystemApi
1622     @Nullable
getCaptivePortalApiUrl()1623     public Uri getCaptivePortalApiUrl() {
1624         return mCaptivePortalApiUrl;
1625     }
1626 
1627     /**
1628      * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1629      * @hide
1630      */
1631     @SystemApi
setCaptivePortalData(@ullable CaptivePortalData data)1632     public void setCaptivePortalData(@Nullable CaptivePortalData data) {
1633         mCaptivePortalData = data;
1634     }
1635 
1636     /**
1637      * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
1638      *
1639      * <p>This is null unless the application has
1640      * {@link android.Manifest.permission.NETWORK_SETTINGS} or
1641      * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
1642      * @hide
1643      */
1644     @SystemApi
1645     @Nullable
getCaptivePortalData()1646     public CaptivePortalData getCaptivePortalData() {
1647         return mCaptivePortalData;
1648     }
1649 
1650     /**
1651      * Compares this {@code LinkProperties} instance against the target
1652      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
1653      * all their fields are equal in values.
1654      *
1655      * For collection fields, such as mDnses, containsAll() is used to check
1656      * if two collections contains the same elements, independent of order.
1657      * There are two thoughts regarding containsAll()
1658      * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
1659      * 2. Worst case performance is O(n^2).
1660      *
1661      * @param obj the object to be tested for equality.
1662      * @return {@code true} if both objects are equal, {@code false} otherwise.
1663      */
1664     @Override
equals(@ullable Object obj)1665     public boolean equals(@Nullable Object obj) {
1666         if (this == obj) return true;
1667 
1668         if (!(obj instanceof LinkProperties)) return false;
1669 
1670         LinkProperties target = (LinkProperties) obj;
1671         /*
1672          * This method does not check that stacked interfaces are equal, because
1673          * stacked interfaces are not so much a property of the link as a
1674          * description of connections between links.
1675          */
1676         return isIdenticalInterfaceName(target)
1677                 && isIdenticalAddresses(target)
1678                 && isIdenticalDhcpServerAddress(target)
1679                 && isIdenticalDnses(target)
1680                 && isIdenticalPrivateDns(target)
1681                 && isIdenticalValidatedPrivateDnses(target)
1682                 && isIdenticalPcscfs(target)
1683                 && isIdenticalRoutes(target)
1684                 && isIdenticalHttpProxy(target)
1685                 && isIdenticalStackedLinks(target)
1686                 && isIdenticalMtu(target)
1687                 && isIdenticalTcpBufferSizes(target)
1688                 && isIdenticalNat64Prefix(target)
1689                 && isIdenticalWakeOnLan(target)
1690                 && isIdenticalCaptivePortalApiUrl(target)
1691                 && isIdenticalCaptivePortalData(target);
1692     }
1693 
1694     /**
1695      * Generate hashcode based on significant fields
1696      *
1697      * Equal objects must produce the same hash code, while unequal objects
1698      * may have the same hash codes.
1699      */
1700     @Override
hashCode()1701     public int hashCode() {
1702         return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
1703                 + mLinkAddresses.size() * 31
1704                 + mDnses.size() * 37
1705                 + mValidatedPrivateDnses.size() * 61
1706                 + ((null == mDomains) ? 0 : mDomains.hashCode())
1707                 + mRoutes.size() * 41
1708                 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
1709                 + mStackedLinks.hashCode() * 47)
1710                 + mMtu * 51
1711                 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
1712                 + (mUsePrivateDns ? 57 : 0)
1713                 + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
1714                 + mPcscfs.size() * 67
1715                 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
1716                 + Objects.hash(mNat64Prefix)
1717                 + (mWakeOnLanSupported ? 71 : 0)
1718                 + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
1719     }
1720 
1721     /**
1722      * Implement the Parcelable interface.
1723      */
writeToParcel(Parcel dest, int flags)1724     public void writeToParcel(Parcel dest, int flags) {
1725         dest.writeString(getInterfaceName());
1726         dest.writeInt(mLinkAddresses.size());
1727         for (LinkAddress linkAddress : mLinkAddresses) {
1728             dest.writeParcelable(linkAddress, flags);
1729         }
1730 
1731         writeAddresses(dest, mDnses);
1732         writeAddresses(dest, mValidatedPrivateDnses);
1733         dest.writeBoolean(mUsePrivateDns);
1734         dest.writeString(mPrivateDnsServerName);
1735         writeAddresses(dest, mPcscfs);
1736         dest.writeString(mDomains);
1737         writeAddress(dest, mDhcpServerAddress);
1738         dest.writeInt(mMtu);
1739         dest.writeString(mTcpBufferSizes);
1740         dest.writeInt(mRoutes.size());
1741         for (RouteInfo route : mRoutes) {
1742             dest.writeParcelable(route, flags);
1743         }
1744 
1745         if (mHttpProxy != null) {
1746             dest.writeByte((byte)1);
1747             dest.writeParcelable(mHttpProxy, flags);
1748         } else {
1749             dest.writeByte((byte)0);
1750         }
1751         dest.writeParcelable(mNat64Prefix, 0);
1752 
1753         ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
1754         dest.writeList(stackedLinks);
1755 
1756         dest.writeBoolean(mWakeOnLanSupported);
1757         dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
1758         dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
1759     }
1760 
writeAddresses(@onNull Parcel dest, @NonNull List<InetAddress> list)1761     private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
1762         dest.writeInt(list.size());
1763         for (InetAddress d : list) {
1764             writeAddress(dest, d);
1765         }
1766     }
1767 
writeAddress(@onNull Parcel dest, @Nullable InetAddress addr)1768     private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
1769         byte[] addressBytes = (addr == null ? null : addr.getAddress());
1770         dest.writeByteArray(addressBytes);
1771         if (addr instanceof Inet6Address) {
1772             final Inet6Address v6Addr = (Inet6Address) addr;
1773             final boolean hasScopeId = v6Addr.getScopeId() != 0;
1774             dest.writeBoolean(hasScopeId);
1775             if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
1776         }
1777     }
1778 
1779     @Nullable
readAddress(@onNull Parcel p)1780     private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
1781         final byte[] addr = p.createByteArray();
1782         if (addr == null) return null;
1783 
1784         if (addr.length == INET6_ADDR_LENGTH) {
1785             final boolean hasScopeId = p.readBoolean();
1786             final int scopeId = hasScopeId ? p.readInt() : 0;
1787             return Inet6Address.getByAddress(null /* host */, addr, scopeId);
1788         }
1789 
1790         return InetAddress.getByAddress(addr);
1791     }
1792 
1793     /**
1794      * Implement the Parcelable interface.
1795      */
1796     public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
1797         new Creator<LinkProperties>() {
1798             public LinkProperties createFromParcel(Parcel in) {
1799                 LinkProperties netProp = new LinkProperties();
1800 
1801                 String iface = in.readString();
1802                 if (iface != null) {
1803                     netProp.setInterfaceName(iface);
1804                 }
1805                 int addressCount = in.readInt();
1806                 for (int i = 0; i < addressCount; i++) {
1807                     netProp.addLinkAddress(in.readParcelable(null));
1808                 }
1809                 addressCount = in.readInt();
1810                 for (int i = 0; i < addressCount; i++) {
1811                     try {
1812                         netProp.addDnsServer(readAddress(in));
1813                     } catch (UnknownHostException e) { }
1814                 }
1815                 addressCount = in.readInt();
1816                 for (int i = 0; i < addressCount; i++) {
1817                     try {
1818                         netProp.addValidatedPrivateDnsServer(readAddress(in));
1819                     } catch (UnknownHostException e) { }
1820                 }
1821                 netProp.setUsePrivateDns(in.readBoolean());
1822                 netProp.setPrivateDnsServerName(in.readString());
1823                 addressCount = in.readInt();
1824                 for (int i = 0; i < addressCount; i++) {
1825                     try {
1826                         netProp.addPcscfServer(readAddress(in));
1827                     } catch (UnknownHostException e) { }
1828                 }
1829                 netProp.setDomains(in.readString());
1830                 try {
1831                     netProp.setDhcpServerAddress((Inet4Address) InetAddress
1832                             .getByAddress(in.createByteArray()));
1833                 } catch (UnknownHostException e) { }
1834                 netProp.setMtu(in.readInt());
1835                 netProp.setTcpBufferSizes(in.readString());
1836                 addressCount = in.readInt();
1837                 for (int i = 0; i < addressCount; i++) {
1838                     netProp.addRoute(in.readParcelable(null));
1839                 }
1840                 if (in.readByte() == 1) {
1841                     netProp.setHttpProxy(in.readParcelable(null));
1842                 }
1843                 netProp.setNat64Prefix(in.readParcelable(null));
1844                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
1845                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
1846                 for (LinkProperties stackedLink: stackedLinks) {
1847                     netProp.addStackedLink(stackedLink);
1848                 }
1849                 netProp.setWakeOnLanSupported(in.readBoolean());
1850 
1851                 netProp.setCaptivePortalApiUrl(in.readParcelable(null));
1852                 netProp.setCaptivePortalData(in.readParcelable(null));
1853                 return netProp;
1854             }
1855 
1856             public LinkProperties[] newArray(int size) {
1857                 return new LinkProperties[size];
1858             }
1859         };
1860 
1861     /**
1862      * Check the valid MTU range based on IPv4 or IPv6.
1863      * @hide
1864      */
isValidMtu(int mtu, boolean ipv6)1865     public static boolean isValidMtu(int mtu, boolean ipv6) {
1866         if (ipv6) {
1867             return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
1868         } else {
1869             return mtu >= MIN_MTU && mtu <= MAX_MTU;
1870         }
1871     }
1872 }
1873