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