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