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