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.os.Parcel; 22 import android.os.Parcelable; 23 import android.text.TextUtils; 24 25 import java.net.Inet4Address; 26 import java.net.Inet6Address; 27 import java.net.InetAddress; 28 import java.net.UnknownHostException; 29 import java.util.ArrayList; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Hashtable; 33 import java.util.List; 34 import java.util.Objects; 35 36 /** 37 * Describes the properties of a network link. 38 * 39 * A link represents a connection to a network. 40 * It may have multiple addresses and multiple gateways, 41 * multiple dns servers but only one http proxy and one 42 * network interface. 43 * 44 * Note that this is just a holder of data. Modifying it 45 * does not affect live networks. 46 * 47 */ 48 public final class LinkProperties implements Parcelable { 49 // The interface described by the network link. 50 private String mIfaceName; 51 private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>(); 52 private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>(); 53 private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<InetAddress>(); 54 private boolean mUsePrivateDns; 55 private String mPrivateDnsServerName; 56 private String mDomains; 57 private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); 58 private ProxyInfo mHttpProxy; 59 private int mMtu; 60 // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" 61 private String mTcpBufferSizes; 62 63 private static final int MIN_MTU = 68; 64 private static final int MIN_MTU_V6 = 1280; 65 private static final int MAX_MTU = 10000; 66 67 // Stores the properties of links that are "stacked" above this link. 68 // Indexed by interface name to allow modification and to prevent duplicates being added. 69 private Hashtable<String, LinkProperties> mStackedLinks = 70 new Hashtable<String, LinkProperties>(); 71 72 /** 73 * @hide 74 */ 75 public static class CompareResult<T> { 76 public final List<T> removed = new ArrayList<T>(); 77 public final List<T> added = new ArrayList<T>(); 78 CompareResult()79 public CompareResult() {} 80 CompareResult(Collection<T> oldItems, Collection<T> newItems)81 public CompareResult(Collection<T> oldItems, Collection<T> newItems) { 82 if (oldItems != null) { 83 removed.addAll(oldItems); 84 } 85 if (newItems != null) { 86 for (T newItem : newItems) { 87 if (!removed.remove(newItem)) { 88 added.add(newItem); 89 } 90 } 91 } 92 } 93 94 @Override toString()95 public String toString() { 96 String retVal = "removed=["; 97 for (T addr : removed) retVal += addr.toString() + ","; 98 retVal += "] added=["; 99 for (T addr : added) retVal += addr.toString() + ","; 100 retVal += "]"; 101 return retVal; 102 } 103 } 104 105 /** 106 * @hide 107 */ 108 public enum ProvisioningChange { 109 STILL_NOT_PROVISIONED, 110 LOST_PROVISIONING, 111 GAINED_PROVISIONING, 112 STILL_PROVISIONED, 113 } 114 115 /** 116 * Compare the provisioning states of two LinkProperties instances. 117 * 118 * @hide 119 */ compareProvisioning( LinkProperties before, LinkProperties after)120 public static ProvisioningChange compareProvisioning( 121 LinkProperties before, LinkProperties after) { 122 if (before.isProvisioned() && after.isProvisioned()) { 123 // On dualstack networks, DHCPv4 renewals can occasionally fail. 124 // When this happens, IPv6-reachable services continue to function 125 // normally but IPv4-only services (naturally) fail. 126 // 127 // When an application using an IPv4-only service reports a bad 128 // network condition to the framework, attempts to re-validate 129 // the network succeed (since we support IPv6-only networks) and 130 // nothing is changed. 131 // 132 // For users, this is confusing and unexpected behaviour, and is 133 // not necessarily easy to diagnose. Therefore, we treat changing 134 // from a dualstack network to an IPv6-only network equivalent to 135 // a total loss of provisioning. 136 // 137 // For one such example of this, see b/18867306. 138 // 139 // Additionally, losing IPv6 provisioning can result in TCP 140 // connections getting stuck until timeouts fire and other 141 // baffling failures. Therefore, loss of either IPv4 or IPv6 on a 142 // previously dualstack network is deemed a lost of provisioning. 143 if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) || 144 (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) { 145 return ProvisioningChange.LOST_PROVISIONING; 146 } 147 return ProvisioningChange.STILL_PROVISIONED; 148 } else if (before.isProvisioned() && !after.isProvisioned()) { 149 return ProvisioningChange.LOST_PROVISIONING; 150 } else if (!before.isProvisioned() && after.isProvisioned()) { 151 return ProvisioningChange.GAINED_PROVISIONING; 152 } else { // !before.isProvisioned() && !after.isProvisioned() 153 return ProvisioningChange.STILL_NOT_PROVISIONED; 154 } 155 } 156 157 /** 158 * @hide 159 */ LinkProperties()160 public LinkProperties() { 161 } 162 163 /** 164 * @hide 165 */ LinkProperties(LinkProperties source)166 public LinkProperties(LinkProperties source) { 167 if (source != null) { 168 mIfaceName = source.getInterfaceName(); 169 for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); 170 for (InetAddress i : source.getDnsServers()) mDnses.add(i); 171 for (InetAddress i : source.getValidatedPrivateDnsServers()) { 172 mValidatedPrivateDnses.add(i); 173 } 174 mUsePrivateDns = source.mUsePrivateDns; 175 mPrivateDnsServerName = source.mPrivateDnsServerName; 176 mDomains = source.getDomains(); 177 for (RouteInfo r : source.getRoutes()) mRoutes.add(r); 178 mHttpProxy = (source.getHttpProxy() == null) ? 179 null : new ProxyInfo(source.getHttpProxy()); 180 for (LinkProperties l: source.mStackedLinks.values()) { 181 addStackedLink(l); 182 } 183 setMtu(source.getMtu()); 184 mTcpBufferSizes = source.mTcpBufferSizes; 185 } 186 } 187 188 /** 189 * Sets the interface name for this link. All {@link RouteInfo} already set for this 190 * will have their interface changed to match this new value. 191 * 192 * @param iface The name of the network interface used for this link. 193 * @hide 194 */ setInterfaceName(String iface)195 public void setInterfaceName(String iface) { 196 mIfaceName = iface; 197 ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size()); 198 for (RouteInfo route : mRoutes) { 199 newRoutes.add(routeWithInterface(route)); 200 } 201 mRoutes = newRoutes; 202 } 203 204 /** 205 * Gets the interface name for this link. May be {@code null} if not set. 206 * 207 * @return The interface name set for this link or {@code null}. 208 */ getInterfaceName()209 public @Nullable String getInterfaceName() { 210 return mIfaceName; 211 } 212 213 /** 214 * @hide 215 */ getAllInterfaceNames()216 public List<String> getAllInterfaceNames() { 217 List<String> interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1); 218 if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); 219 for (LinkProperties stacked: mStackedLinks.values()) { 220 interfaceNames.addAll(stacked.getAllInterfaceNames()); 221 } 222 return interfaceNames; 223 } 224 225 /** 226 * Returns all the addresses on this link. We often think of a link having a single address, 227 * however, particularly with Ipv6 several addresses are typical. Note that the 228 * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include 229 * prefix lengths for each address. This is a simplified utility alternative to 230 * {@link LinkProperties#getLinkAddresses}. 231 * 232 * @return An umodifiable {@link List} of {@link InetAddress} for this link. 233 * @hide 234 */ getAddresses()235 public List<InetAddress> getAddresses() { 236 List<InetAddress> addresses = new ArrayList<InetAddress>(); 237 for (LinkAddress linkAddress : mLinkAddresses) { 238 addresses.add(linkAddress.getAddress()); 239 } 240 return Collections.unmodifiableList(addresses); 241 } 242 243 /** 244 * Returns all the addresses on this link and all the links stacked above it. 245 * @hide 246 */ getAllAddresses()247 public List<InetAddress> getAllAddresses() { 248 List<InetAddress> addresses = new ArrayList<InetAddress>(); 249 for (LinkAddress linkAddress : mLinkAddresses) { 250 addresses.add(linkAddress.getAddress()); 251 } 252 for (LinkProperties stacked: mStackedLinks.values()) { 253 addresses.addAll(stacked.getAllAddresses()); 254 } 255 return addresses; 256 } 257 findLinkAddressIndex(LinkAddress address)258 private int findLinkAddressIndex(LinkAddress address) { 259 for (int i = 0; i < mLinkAddresses.size(); i++) { 260 if (mLinkAddresses.get(i).isSameAddressAs(address)) { 261 return i; 262 } 263 } 264 return -1; 265 } 266 267 /** 268 * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the 269 * same address/prefix does not already exist. If it does exist it is replaced. 270 * @param address The {@code LinkAddress} to add. 271 * @return true if {@code address} was added or updated, false otherwise. 272 * @hide 273 */ addLinkAddress(LinkAddress address)274 public boolean addLinkAddress(LinkAddress address) { 275 if (address == null) { 276 return false; 277 } 278 int i = findLinkAddressIndex(address); 279 if (i < 0) { 280 // Address was not present. Add it. 281 mLinkAddresses.add(address); 282 return true; 283 } else if (mLinkAddresses.get(i).equals(address)) { 284 // Address was present and has same properties. Do nothing. 285 return false; 286 } else { 287 // Address was present and has different properties. Update it. 288 mLinkAddresses.set(i, address); 289 return true; 290 } 291 } 292 293 /** 294 * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches 295 * and {@link LinkAddress} with the same address and prefix. 296 * 297 * @param toRemove A {@link LinkAddress} specifying the address to remove. 298 * @return true if the address was removed, false if it did not exist. 299 * @hide 300 */ removeLinkAddress(LinkAddress toRemove)301 public boolean removeLinkAddress(LinkAddress toRemove) { 302 int i = findLinkAddressIndex(toRemove); 303 if (i >= 0) { 304 mLinkAddresses.remove(i); 305 return true; 306 } 307 return false; 308 } 309 310 /** 311 * Returns all the {@link LinkAddress} on this link. Typically a link will have 312 * one IPv4 address and one or more IPv6 addresses. 313 * 314 * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. 315 */ getLinkAddresses()316 public List<LinkAddress> getLinkAddresses() { 317 return Collections.unmodifiableList(mLinkAddresses); 318 } 319 320 /** 321 * Returns all the addresses on this link and all the links stacked above it. 322 * @hide 323 */ getAllLinkAddresses()324 public List<LinkAddress> getAllLinkAddresses() { 325 List<LinkAddress> addresses = new ArrayList<LinkAddress>(); 326 addresses.addAll(mLinkAddresses); 327 for (LinkProperties stacked: mStackedLinks.values()) { 328 addresses.addAll(stacked.getAllLinkAddresses()); 329 } 330 return addresses; 331 } 332 333 /** 334 * Replaces the {@link LinkAddress} in this {@code LinkProperties} with 335 * the given {@link Collection} of {@link LinkAddress}. 336 * 337 * @param addresses The {@link Collection} of {@link LinkAddress} to set in this 338 * object. 339 * @hide 340 */ setLinkAddresses(Collection<LinkAddress> addresses)341 public void setLinkAddresses(Collection<LinkAddress> addresses) { 342 mLinkAddresses.clear(); 343 for (LinkAddress address: addresses) { 344 addLinkAddress(address); 345 } 346 } 347 348 /** 349 * Adds the given {@link InetAddress} to the list of DNS servers, if not present. 350 * 351 * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. 352 * @return true if the DNS server was added, false if it was already present. 353 * @hide 354 */ addDnsServer(InetAddress dnsServer)355 public boolean addDnsServer(InetAddress dnsServer) { 356 if (dnsServer != null && !mDnses.contains(dnsServer)) { 357 mDnses.add(dnsServer); 358 return true; 359 } 360 return false; 361 } 362 363 /** 364 * Removes the given {@link InetAddress} from the list of DNS servers. 365 * 366 * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers. 367 * @return true if the DNS server was removed, false if it did not exist. 368 * @hide 369 */ removeDnsServer(InetAddress dnsServer)370 public boolean removeDnsServer(InetAddress dnsServer) { 371 if (dnsServer != null) { 372 return mDnses.remove(dnsServer); 373 } 374 return false; 375 } 376 377 /** 378 * Replaces the DNS servers in this {@code LinkProperties} with 379 * the given {@link Collection} of {@link InetAddress} objects. 380 * 381 * @param dnsServers The {@link Collection} of DNS servers to set in this object. 382 * @hide 383 */ setDnsServers(Collection<InetAddress> dnsServers)384 public void setDnsServers(Collection<InetAddress> dnsServers) { 385 mDnses.clear(); 386 for (InetAddress dnsServer: dnsServers) { 387 addDnsServer(dnsServer); 388 } 389 } 390 391 /** 392 * Returns all the {@link InetAddress} for DNS servers on this link. 393 * 394 * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on 395 * this link. 396 */ getDnsServers()397 public List<InetAddress> getDnsServers() { 398 return Collections.unmodifiableList(mDnses); 399 } 400 401 /** 402 * Set whether private DNS is currently in use on this network. 403 * 404 * @param usePrivateDns The private DNS state. 405 * @hide 406 */ setUsePrivateDns(boolean usePrivateDns)407 public void setUsePrivateDns(boolean usePrivateDns) { 408 mUsePrivateDns = usePrivateDns; 409 } 410 411 /** 412 * Returns whether private DNS is currently in use on this network. When 413 * private DNS is in use, applications must not send unencrypted DNS 414 * queries as doing so could reveal private user information. Furthermore, 415 * if private DNS is in use and {@link #getPrivateDnsServerName} is not 416 * {@code null}, DNS queries must be sent to the specified DNS server. 417 * 418 * @return {@code true} if private DNS is in use, {@code false} otherwise. 419 */ isPrivateDnsActive()420 public boolean isPrivateDnsActive() { 421 return mUsePrivateDns; 422 } 423 424 /** 425 * Set the name of the private DNS server to which private DNS queries 426 * should be sent when in strict mode. This value should be {@code null} 427 * when private DNS is off or in opportunistic mode. 428 * 429 * @param privateDnsServerName The private DNS server name. 430 * @hide 431 */ setPrivateDnsServerName(@ullable String privateDnsServerName)432 public void setPrivateDnsServerName(@Nullable String privateDnsServerName) { 433 mPrivateDnsServerName = privateDnsServerName; 434 } 435 436 /** 437 * Returns the private DNS server name that is in use. If not {@code null}, 438 * private DNS is in strict mode. In this mode, applications should ensure 439 * that all DNS queries are encrypted and sent to this hostname and that 440 * queries are only sent if the hostname's certificate is valid. If 441 * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private 442 * DNS is in opportunistic mode, and applications should ensure that DNS 443 * queries are encrypted and sent to a DNS server returned by 444 * {@link #getDnsServers}. System DNS will handle each of these cases 445 * correctly, but applications implementing their own DNS lookups must make 446 * sure to follow these requirements. 447 * 448 * @return The private DNS server name. 449 */ getPrivateDnsServerName()450 public @Nullable String getPrivateDnsServerName() { 451 return mPrivateDnsServerName; 452 } 453 454 /** 455 * Adds the given {@link InetAddress} to the list of validated private DNS servers, 456 * if not present. This is distinct from the server name in that these are actually 457 * resolved addresses. 458 * 459 * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers. 460 * @return true if the DNS server was added, false if it was already present. 461 * @hide 462 */ addValidatedPrivateDnsServer(InetAddress dnsServer)463 public boolean addValidatedPrivateDnsServer(InetAddress dnsServer) { 464 if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) { 465 mValidatedPrivateDnses.add(dnsServer); 466 return true; 467 } 468 return false; 469 } 470 471 /** 472 * Removes the given {@link InetAddress} from the list of validated private DNS servers. 473 * 474 * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS 475 * servers. 476 * @return true if the DNS server was removed, false if it did not exist. 477 * @hide 478 */ removeValidatedPrivateDnsServer(InetAddress dnsServer)479 public boolean removeValidatedPrivateDnsServer(InetAddress dnsServer) { 480 if (dnsServer != null) { 481 return mValidatedPrivateDnses.remove(dnsServer); 482 } 483 return false; 484 } 485 486 /** 487 * Replaces the validated private DNS servers in this {@code LinkProperties} with 488 * the given {@link Collection} of {@link InetAddress} objects. 489 * 490 * @param dnsServers The {@link Collection} of validated private DNS servers to set in this 491 * object. 492 * @hide 493 */ setValidatedPrivateDnsServers(Collection<InetAddress> dnsServers)494 public void setValidatedPrivateDnsServers(Collection<InetAddress> dnsServers) { 495 mValidatedPrivateDnses.clear(); 496 for (InetAddress dnsServer: dnsServers) { 497 addValidatedPrivateDnsServer(dnsServer); 498 } 499 } 500 501 /** 502 * Returns all the {@link InetAddress} for validated private DNS servers on this link. 503 * These are resolved from the private DNS server name. 504 * 505 * @return An umodifiable {@link List} of {@link InetAddress} for validated private 506 * DNS servers on this link. 507 * @hide 508 */ getValidatedPrivateDnsServers()509 public List<InetAddress> getValidatedPrivateDnsServers() { 510 return Collections.unmodifiableList(mValidatedPrivateDnses); 511 } 512 513 /** 514 * Sets the DNS domain search path used on this link. 515 * 516 * @param domains A {@link String} listing in priority order the comma separated 517 * domains to search when resolving host names on this link. 518 * @hide 519 */ setDomains(String domains)520 public void setDomains(String domains) { 521 mDomains = domains; 522 } 523 524 /** 525 * Get the DNS domains search path set for this link. 526 * 527 * @return A {@link String} containing the comma separated domains to search when resolving 528 * host names on this link. 529 */ getDomains()530 public String getDomains() { 531 return mDomains; 532 } 533 534 /** 535 * Sets the Maximum Transmission Unit size to use on this link. This should not be used 536 * unless the system default (1500) is incorrect. Values less than 68 or greater than 537 * 10000 will be ignored. 538 * 539 * @param mtu The MTU to use for this link. 540 * @hide 541 */ setMtu(int mtu)542 public void setMtu(int mtu) { 543 mMtu = mtu; 544 } 545 546 /** 547 * Gets any non-default MTU size set for this link. Note that if the default is being used 548 * this will return 0. 549 * 550 * @return The mtu value set for this link. 551 * @hide 552 */ getMtu()553 public int getMtu() { 554 return mMtu; 555 } 556 557 /** 558 * Sets the tcp buffers sizes to be used when this link is the system default. 559 * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max". 560 * 561 * @param tcpBufferSizes The tcp buffers sizes to use. 562 * 563 * @hide 564 */ setTcpBufferSizes(String tcpBufferSizes)565 public void setTcpBufferSizes(String tcpBufferSizes) { 566 mTcpBufferSizes = tcpBufferSizes; 567 } 568 569 /** 570 * Gets the tcp buffer sizes. 571 * 572 * @return the tcp buffer sizes to use when this link is the system default. 573 * 574 * @hide 575 */ getTcpBufferSizes()576 public String getTcpBufferSizes() { 577 return mTcpBufferSizes; 578 } 579 routeWithInterface(RouteInfo route)580 private RouteInfo routeWithInterface(RouteInfo route) { 581 return new RouteInfo( 582 route.getDestination(), 583 route.getGateway(), 584 mIfaceName, 585 route.getType()); 586 } 587 588 /** 589 * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the 590 * {@link RouteInfo} had an interface name set and that differs from the interface set for this 591 * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The proper 592 * course is to add either un-named or properly named {@link RouteInfo}. 593 * 594 * @param route A {@link RouteInfo} to add to this object. 595 * @return {@code false} if the route was already present, {@code true} if it was added. 596 * 597 * @hide 598 */ addRoute(RouteInfo route)599 public boolean addRoute(RouteInfo route) { 600 if (route != null) { 601 String routeIface = route.getInterface(); 602 if (routeIface != null && !routeIface.equals(mIfaceName)) { 603 throw new IllegalArgumentException( 604 "Route added with non-matching interface: " + routeIface + 605 " vs. " + mIfaceName); 606 } 607 route = routeWithInterface(route); 608 if (!mRoutes.contains(route)) { 609 mRoutes.add(route); 610 return true; 611 } 612 } 613 return false; 614 } 615 616 /** 617 * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must 618 * specify an interface and the interface must match the interface of this 619 * {@code LinkProperties}, or it will not be removed. 620 * 621 * @return {@code true} if the route was removed, {@code false} if it was not present. 622 * 623 * @hide 624 */ removeRoute(RouteInfo route)625 public boolean removeRoute(RouteInfo route) { 626 return route != null && 627 Objects.equals(mIfaceName, route.getInterface()) && 628 mRoutes.remove(route); 629 } 630 631 /** 632 * Returns all the {@link RouteInfo} set on this link. 633 * 634 * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. 635 */ getRoutes()636 public List<RouteInfo> getRoutes() { 637 return Collections.unmodifiableList(mRoutes); 638 } 639 640 /** 641 * Make sure this LinkProperties instance contains routes that cover the local subnet 642 * of its link addresses. Add any route that is missing. 643 * @hide 644 */ ensureDirectlyConnectedRoutes()645 public void ensureDirectlyConnectedRoutes() { 646 for (LinkAddress addr: mLinkAddresses) { 647 addRoute(new RouteInfo(addr, null, mIfaceName)); 648 } 649 } 650 651 /** 652 * Returns all the routes on this link and all the links stacked above it. 653 * @hide 654 */ getAllRoutes()655 public List<RouteInfo> getAllRoutes() { 656 List<RouteInfo> routes = new ArrayList<>(); 657 routes.addAll(mRoutes); 658 for (LinkProperties stacked: mStackedLinks.values()) { 659 routes.addAll(stacked.getAllRoutes()); 660 } 661 return routes; 662 } 663 664 /** 665 * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. 666 * Note that Http Proxies are only a hint - the system recommends their use, but it does 667 * not enforce it and applications may ignore them. 668 * 669 * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link. 670 * @hide 671 */ setHttpProxy(ProxyInfo proxy)672 public void setHttpProxy(ProxyInfo proxy) { 673 mHttpProxy = proxy; 674 } 675 676 /** 677 * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. 678 * 679 * @return The {@link ProxyInfo} set on this link 680 */ getHttpProxy()681 public ProxyInfo getHttpProxy() { 682 return mHttpProxy; 683 } 684 685 /** 686 * Adds a stacked link. 687 * 688 * If there is already a stacked link with the same interfacename as link, 689 * that link is replaced with link. Otherwise, link is added to the list 690 * of stacked links. If link is null, nothing changes. 691 * 692 * @param link The link to add. 693 * @return true if the link was stacked, false otherwise. 694 * @hide 695 */ addStackedLink(LinkProperties link)696 public boolean addStackedLink(LinkProperties link) { 697 if (link != null && link.getInterfaceName() != null) { 698 mStackedLinks.put(link.getInterfaceName(), link); 699 return true; 700 } 701 return false; 702 } 703 704 /** 705 * Removes a stacked link. 706 * 707 * If there is a stacked link with the given interface name, it is 708 * removed. Otherwise, nothing changes. 709 * 710 * @param iface The interface name of the link to remove. 711 * @return true if the link was removed, false otherwise. 712 * @hide 713 */ removeStackedLink(String iface)714 public boolean removeStackedLink(String iface) { 715 if (iface != null) { 716 LinkProperties removed = mStackedLinks.remove(iface); 717 return removed != null; 718 } 719 return false; 720 } 721 722 /** 723 * Returns all the links stacked on top of this link. 724 * @hide 725 */ getStackedLinks()726 public @NonNull List<LinkProperties> getStackedLinks() { 727 if (mStackedLinks.isEmpty()) { 728 return Collections.EMPTY_LIST; 729 } 730 List<LinkProperties> stacked = new ArrayList<LinkProperties>(); 731 for (LinkProperties link : mStackedLinks.values()) { 732 stacked.add(new LinkProperties(link)); 733 } 734 return Collections.unmodifiableList(stacked); 735 } 736 737 /** 738 * Clears this object to its initial state. 739 * @hide 740 */ clear()741 public void clear() { 742 mIfaceName = null; 743 mLinkAddresses.clear(); 744 mDnses.clear(); 745 mUsePrivateDns = false; 746 mPrivateDnsServerName = null; 747 mDomains = null; 748 mRoutes.clear(); 749 mHttpProxy = null; 750 mStackedLinks.clear(); 751 mMtu = 0; 752 mTcpBufferSizes = null; 753 } 754 755 /** 756 * Implement the Parcelable interface 757 */ describeContents()758 public int describeContents() { 759 return 0; 760 } 761 762 @Override toString()763 public String toString() { 764 String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); 765 766 String linkAddresses = "LinkAddresses: ["; 767 for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ","; 768 linkAddresses += "] "; 769 770 String dns = "DnsAddresses: ["; 771 for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; 772 dns += "] "; 773 774 String usePrivateDns = "UsePrivateDns: " + mUsePrivateDns + " "; 775 776 String privateDnsServerName = ""; 777 if (privateDnsServerName != null) { 778 privateDnsServerName = "PrivateDnsServerName: " + mPrivateDnsServerName + " "; 779 } 780 781 String validatedPrivateDns = ""; 782 if (!mValidatedPrivateDnses.isEmpty()) { 783 validatedPrivateDns = "ValidatedPrivateDnsAddresses: ["; 784 for (InetAddress addr : mValidatedPrivateDnses) { 785 validatedPrivateDns += addr.getHostAddress() + ","; 786 } 787 validatedPrivateDns += "] "; 788 } 789 790 String domainName = "Domains: " + mDomains; 791 792 String mtu = " MTU: " + mMtu; 793 794 String tcpBuffSizes = ""; 795 if (mTcpBufferSizes != null) { 796 tcpBuffSizes = " TcpBufferSizes: " + mTcpBufferSizes; 797 } 798 799 String routes = " Routes: ["; 800 for (RouteInfo route : mRoutes) routes += route.toString() + ","; 801 routes += "] "; 802 String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " "); 803 804 String stacked = ""; 805 if (mStackedLinks.values().size() > 0) { 806 stacked += " Stacked: ["; 807 for (LinkProperties link: mStackedLinks.values()) { 808 stacked += " [" + link.toString() + " ],"; 809 } 810 stacked += "] "; 811 } 812 return "{" + ifaceName + linkAddresses + routes + dns + usePrivateDns 813 + privateDnsServerName + domainName + mtu + tcpBuffSizes + proxy 814 + stacked + "}"; 815 } 816 817 /** 818 * Returns true if this link has an IPv4 address. 819 * 820 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 821 * @hide 822 */ hasIPv4Address()823 public boolean hasIPv4Address() { 824 for (LinkAddress address : mLinkAddresses) { 825 if (address.getAddress() instanceof Inet4Address) { 826 return true; 827 } 828 } 829 return false; 830 } 831 832 /** 833 * Returns true if this link or any of its stacked interfaces has an IPv4 address. 834 * 835 * @return {@code true} if there is an IPv4 address, {@code false} otherwise. 836 */ hasIPv4AddressOnInterface(String iface)837 private boolean hasIPv4AddressOnInterface(String iface) { 838 // mIfaceName can be null. 839 return (Objects.equals(iface, mIfaceName) && hasIPv4Address()) || 840 (iface != null && mStackedLinks.containsKey(iface) && 841 mStackedLinks.get(iface).hasIPv4Address()); 842 } 843 844 /** 845 * Returns true if this link has a global preferred IPv6 address. 846 * 847 * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. 848 * @hide 849 */ hasGlobalIPv6Address()850 public boolean hasGlobalIPv6Address() { 851 for (LinkAddress address : mLinkAddresses) { 852 if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) { 853 return true; 854 } 855 } 856 return false; 857 } 858 859 /** 860 * Returns true if this link has an IPv4 default route. 861 * 862 * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. 863 * @hide 864 */ hasIPv4DefaultRoute()865 public boolean hasIPv4DefaultRoute() { 866 for (RouteInfo r : mRoutes) { 867 if (r.isIPv4Default()) { 868 return true; 869 } 870 } 871 return false; 872 } 873 874 /** 875 * Returns true if this link has an IPv6 default route. 876 * 877 * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. 878 * @hide 879 */ hasIPv6DefaultRoute()880 public boolean hasIPv6DefaultRoute() { 881 for (RouteInfo r : mRoutes) { 882 if (r.isIPv6Default()) { 883 return true; 884 } 885 } 886 return false; 887 } 888 889 /** 890 * Returns true if this link has an IPv4 DNS server. 891 * 892 * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. 893 * @hide 894 */ hasIPv4DnsServer()895 public boolean hasIPv4DnsServer() { 896 for (InetAddress ia : mDnses) { 897 if (ia instanceof Inet4Address) { 898 return true; 899 } 900 } 901 return false; 902 } 903 904 /** 905 * Returns true if this link has an IPv6 DNS server. 906 * 907 * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. 908 * @hide 909 */ hasIPv6DnsServer()910 public boolean hasIPv6DnsServer() { 911 for (InetAddress ia : mDnses) { 912 if (ia instanceof Inet6Address) { 913 return true; 914 } 915 } 916 return false; 917 } 918 919 /** 920 * Returns true if this link is provisioned for global IPv4 connectivity. 921 * This requires an IP address, default route, and DNS server. 922 * 923 * @return {@code true} if the link is provisioned, {@code false} otherwise. 924 * @hide 925 */ isIPv4Provisioned()926 public boolean isIPv4Provisioned() { 927 return (hasIPv4Address() && 928 hasIPv4DefaultRoute() && 929 hasIPv4DnsServer()); 930 } 931 932 /** 933 * Returns true if this link is provisioned for global IPv6 connectivity. 934 * This requires an IP address, default route, and DNS server. 935 * 936 * @return {@code true} if the link is provisioned, {@code false} otherwise. 937 * @hide 938 */ isIPv6Provisioned()939 public boolean isIPv6Provisioned() { 940 return (hasGlobalIPv6Address() && 941 hasIPv6DefaultRoute() && 942 hasIPv6DnsServer()); 943 } 944 945 /** 946 * Returns true if this link is provisioned for global connectivity, 947 * for at least one Internet Protocol family. 948 * 949 * @return {@code true} if the link is provisioned, {@code false} otherwise. 950 * @hide 951 */ isProvisioned()952 public boolean isProvisioned() { 953 return (isIPv4Provisioned() || isIPv6Provisioned()); 954 } 955 956 /** 957 * Evaluate whether the {@link InetAddress} is considered reachable. 958 * 959 * @return {@code true} if the given {@link InetAddress} is considered reachable, 960 * {@code false} otherwise. 961 * @hide 962 */ isReachable(InetAddress ip)963 public boolean isReachable(InetAddress ip) { 964 final List<RouteInfo> allRoutes = getAllRoutes(); 965 // If we don't have a route to this IP address, it's not reachable. 966 final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip); 967 if (bestRoute == null) { 968 return false; 969 } 970 971 // TODO: better source address evaluation for destination addresses. 972 973 if (ip instanceof Inet4Address) { 974 // For IPv4, it suffices for now to simply have any address. 975 return hasIPv4AddressOnInterface(bestRoute.getInterface()); 976 } else if (ip instanceof Inet6Address) { 977 if (ip.isLinkLocalAddress()) { 978 // For now, just make sure link-local destinations have 979 // scopedIds set, since transmits will generally fail otherwise. 980 // TODO: verify it matches the ifindex of one of the interfaces. 981 return (((Inet6Address)ip).getScopeId() != 0); 982 } else { 983 // For non-link-local destinations check that either the best route 984 // is directly connected or that some global preferred address exists. 985 // TODO: reconsider all cases (disconnected ULA networks, ...). 986 return (!bestRoute.hasGateway() || hasGlobalIPv6Address()); 987 } 988 } 989 990 return false; 991 } 992 993 /** 994 * Compares this {@code LinkProperties} interface name against the target 995 * 996 * @param target LinkProperties to compare. 997 * @return {@code true} if both are identical, {@code false} otherwise. 998 * @hide 999 */ isIdenticalInterfaceName(LinkProperties target)1000 public boolean isIdenticalInterfaceName(LinkProperties target) { 1001 return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); 1002 } 1003 1004 /** 1005 * Compares this {@code LinkProperties} interface addresses against the target 1006 * 1007 * @param target LinkProperties to compare. 1008 * @return {@code true} if both are identical, {@code false} otherwise. 1009 * @hide 1010 */ isIdenticalAddresses(LinkProperties target)1011 public boolean isIdenticalAddresses(LinkProperties target) { 1012 Collection<InetAddress> targetAddresses = target.getAddresses(); 1013 Collection<InetAddress> sourceAddresses = getAddresses(); 1014 return (sourceAddresses.size() == targetAddresses.size()) ? 1015 sourceAddresses.containsAll(targetAddresses) : false; 1016 } 1017 1018 /** 1019 * Compares this {@code LinkProperties} DNS addresses against the target 1020 * 1021 * @param target LinkProperties to compare. 1022 * @return {@code true} if both are identical, {@code false} otherwise. 1023 * @hide 1024 */ isIdenticalDnses(LinkProperties target)1025 public boolean isIdenticalDnses(LinkProperties target) { 1026 Collection<InetAddress> targetDnses = target.getDnsServers(); 1027 String targetDomains = target.getDomains(); 1028 if (mDomains == null) { 1029 if (targetDomains != null) return false; 1030 } else { 1031 if (mDomains.equals(targetDomains) == false) return false; 1032 } 1033 return (mDnses.size() == targetDnses.size()) ? 1034 mDnses.containsAll(targetDnses) : false; 1035 } 1036 1037 /** 1038 * Compares this {@code LinkProperties} private DNS settings against the 1039 * target. 1040 * 1041 * @param target LinkProperties to compare. 1042 * @return {@code true} if both are identical, {@code false} otherwise. 1043 * @hide 1044 */ isIdenticalPrivateDns(LinkProperties target)1045 public boolean isIdenticalPrivateDns(LinkProperties target) { 1046 return (isPrivateDnsActive() == target.isPrivateDnsActive() 1047 && TextUtils.equals(getPrivateDnsServerName(), 1048 target.getPrivateDnsServerName())); 1049 } 1050 1051 /** 1052 * Compares this {@code LinkProperties} validated private DNS addresses against 1053 * the target 1054 * 1055 * @param target LinkProperties to compare. 1056 * @return {@code true} if both are identical, {@code false} otherwise. 1057 * @hide 1058 */ isIdenticalValidatedPrivateDnses(LinkProperties target)1059 public boolean isIdenticalValidatedPrivateDnses(LinkProperties target) { 1060 Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers(); 1061 return (mValidatedPrivateDnses.size() == targetDnses.size()) 1062 ? mValidatedPrivateDnses.containsAll(targetDnses) : false; 1063 } 1064 1065 /** 1066 * Compares this {@code LinkProperties} Routes against the target 1067 * 1068 * @param target LinkProperties to compare. 1069 * @return {@code true} if both are identical, {@code false} otherwise. 1070 * @hide 1071 */ isIdenticalRoutes(LinkProperties target)1072 public boolean isIdenticalRoutes(LinkProperties target) { 1073 Collection<RouteInfo> targetRoutes = target.getRoutes(); 1074 return (mRoutes.size() == targetRoutes.size()) ? 1075 mRoutes.containsAll(targetRoutes) : false; 1076 } 1077 1078 /** 1079 * Compares this {@code LinkProperties} HttpProxy against the target 1080 * 1081 * @param target LinkProperties to compare. 1082 * @return {@code true} if both are identical, {@code false} otherwise. 1083 * @hide 1084 */ isIdenticalHttpProxy(LinkProperties target)1085 public boolean isIdenticalHttpProxy(LinkProperties target) { 1086 return getHttpProxy() == null ? target.getHttpProxy() == null : 1087 getHttpProxy().equals(target.getHttpProxy()); 1088 } 1089 1090 /** 1091 * Compares this {@code LinkProperties} stacked links against the target 1092 * 1093 * @param target LinkProperties to compare. 1094 * @return {@code true} if both are identical, {@code false} otherwise. 1095 * @hide 1096 */ isIdenticalStackedLinks(LinkProperties target)1097 public boolean isIdenticalStackedLinks(LinkProperties target) { 1098 if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { 1099 return false; 1100 } 1101 for (LinkProperties stacked : mStackedLinks.values()) { 1102 // Hashtable values can never be null. 1103 String iface = stacked.getInterfaceName(); 1104 if (!stacked.equals(target.mStackedLinks.get(iface))) { 1105 return false; 1106 } 1107 } 1108 return true; 1109 } 1110 1111 /** 1112 * Compares this {@code LinkProperties} MTU against the target 1113 * 1114 * @param target LinkProperties to compare. 1115 * @return {@code true} if both are identical, {@code false} otherwise. 1116 * @hide 1117 */ isIdenticalMtu(LinkProperties target)1118 public boolean isIdenticalMtu(LinkProperties target) { 1119 return getMtu() == target.getMtu(); 1120 } 1121 1122 /** 1123 * Compares this {@code LinkProperties} Tcp buffer sizes against the target. 1124 * 1125 * @param target LinkProperties to compare. 1126 * @return {@code true} if both are identical, {@code false} otherwise. 1127 * @hide 1128 */ isIdenticalTcpBufferSizes(LinkProperties target)1129 public boolean isIdenticalTcpBufferSizes(LinkProperties target) { 1130 return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes); 1131 } 1132 1133 @Override 1134 /** 1135 * Compares this {@code LinkProperties} instance against the target 1136 * LinkProperties in {@code obj}. Two LinkPropertieses are equal if 1137 * all their fields are equal in values. 1138 * 1139 * For collection fields, such as mDnses, containsAll() is used to check 1140 * if two collections contains the same elements, independent of order. 1141 * There are two thoughts regarding containsAll() 1142 * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. 1143 * 2. Worst case performance is O(n^2). 1144 * 1145 * @param obj the object to be tested for equality. 1146 * @return {@code true} if both objects are equal, {@code false} otherwise. 1147 */ equals(Object obj)1148 public boolean equals(Object obj) { 1149 if (this == obj) return true; 1150 1151 if (!(obj instanceof LinkProperties)) return false; 1152 1153 LinkProperties target = (LinkProperties) obj; 1154 /** 1155 * This method does not check that stacked interfaces are equal, because 1156 * stacked interfaces are not so much a property of the link as a 1157 * description of connections between links. 1158 */ 1159 return isIdenticalInterfaceName(target) 1160 && isIdenticalAddresses(target) 1161 && isIdenticalDnses(target) 1162 && isIdenticalPrivateDns(target) 1163 && isIdenticalValidatedPrivateDnses(target) 1164 && isIdenticalRoutes(target) 1165 && isIdenticalHttpProxy(target) 1166 && isIdenticalStackedLinks(target) 1167 && isIdenticalMtu(target) 1168 && isIdenticalTcpBufferSizes(target); 1169 } 1170 1171 /** 1172 * Compares the addresses in this LinkProperties with another 1173 * LinkProperties, examining only addresses on the base link. 1174 * 1175 * @param target a LinkProperties with the new list of addresses 1176 * @return the differences between the addresses. 1177 * @hide 1178 */ compareAddresses(LinkProperties target)1179 public CompareResult<LinkAddress> compareAddresses(LinkProperties target) { 1180 /* 1181 * Duplicate the LinkAddresses into removed, we will be removing 1182 * address which are common between mLinkAddresses and target 1183 * leaving the addresses that are different. And address which 1184 * are in target but not in mLinkAddresses are placed in the 1185 * addedAddresses. 1186 */ 1187 return new CompareResult<>(mLinkAddresses, 1188 target != null ? target.getLinkAddresses() : null); 1189 } 1190 1191 /** 1192 * Compares the DNS addresses in this LinkProperties with another 1193 * LinkProperties, examining only DNS addresses on the base link. 1194 * 1195 * @param target a LinkProperties with the new list of dns addresses 1196 * @return the differences between the DNS addresses. 1197 * @hide 1198 */ compareDnses(LinkProperties target)1199 public CompareResult<InetAddress> compareDnses(LinkProperties target) { 1200 /* 1201 * Duplicate the InetAddresses into removed, we will be removing 1202 * dns address which are common between mDnses and target 1203 * leaving the addresses that are different. And dns address which 1204 * are in target but not in mDnses are placed in the 1205 * addedAddresses. 1206 */ 1207 return new CompareResult<>(mDnses, target != null ? target.getDnsServers() : null); 1208 } 1209 1210 /** 1211 * Compares the validated private DNS addresses in this LinkProperties with another 1212 * LinkProperties. 1213 * 1214 * @param target a LinkProperties with the new list of validated private dns addresses 1215 * @return the differences between the DNS addresses. 1216 * @hide 1217 */ compareValidatedPrivateDnses(LinkProperties target)1218 public CompareResult<InetAddress> compareValidatedPrivateDnses(LinkProperties target) { 1219 return new CompareResult<>(mValidatedPrivateDnses, 1220 target != null ? target.getValidatedPrivateDnsServers() : null); 1221 } 1222 1223 /** 1224 * Compares all routes in this LinkProperties with another LinkProperties, 1225 * examining both the the base link and all stacked links. 1226 * 1227 * @param target a LinkProperties with the new list of routes 1228 * @return the differences between the routes. 1229 * @hide 1230 */ compareAllRoutes(LinkProperties target)1231 public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) { 1232 /* 1233 * Duplicate the RouteInfos into removed, we will be removing 1234 * routes which are common between mRoutes and target 1235 * leaving the routes that are different. And route address which 1236 * are in target but not in mRoutes are placed in added. 1237 */ 1238 return new CompareResult<>(getAllRoutes(), target != null ? target.getAllRoutes() : null); 1239 } 1240 1241 /** 1242 * Compares all interface names in this LinkProperties with another 1243 * LinkProperties, examining both the the base link and all stacked links. 1244 * 1245 * @param target a LinkProperties with the new list of interface names 1246 * @return the differences between the interface names. 1247 * @hide 1248 */ compareAllInterfaceNames(LinkProperties target)1249 public CompareResult<String> compareAllInterfaceNames(LinkProperties target) { 1250 /* 1251 * Duplicate the interface names into removed, we will be removing 1252 * interface names which are common between this and target 1253 * leaving the interface names that are different. And interface names which 1254 * are in target but not in this are placed in added. 1255 */ 1256 return new CompareResult<>(getAllInterfaceNames(), 1257 target != null ? target.getAllInterfaceNames() : null); 1258 } 1259 1260 1261 @Override 1262 /** 1263 * generate hashcode based on significant fields 1264 * Equal objects must produce the same hash code, while unequal objects 1265 * may have the same hash codes. 1266 */ hashCode()1267 public int hashCode() { 1268 return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() 1269 + mLinkAddresses.size() * 31 1270 + mDnses.size() * 37 1271 + mValidatedPrivateDnses.size() * 61 1272 + ((null == mDomains) ? 0 : mDomains.hashCode()) 1273 + mRoutes.size() * 41 1274 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) 1275 + mStackedLinks.hashCode() * 47) 1276 + mMtu * 51 1277 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode()) 1278 + (mUsePrivateDns ? 57 : 0) 1279 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode()); 1280 } 1281 1282 /** 1283 * Implement the Parcelable interface. 1284 */ writeToParcel(Parcel dest, int flags)1285 public void writeToParcel(Parcel dest, int flags) { 1286 dest.writeString(getInterfaceName()); 1287 dest.writeInt(mLinkAddresses.size()); 1288 for (LinkAddress linkAddress : mLinkAddresses) { 1289 dest.writeParcelable(linkAddress, flags); 1290 } 1291 1292 dest.writeInt(mDnses.size()); 1293 for (InetAddress d : mDnses) { 1294 dest.writeByteArray(d.getAddress()); 1295 } 1296 dest.writeInt(mValidatedPrivateDnses.size()); 1297 for (InetAddress d : mValidatedPrivateDnses) { 1298 dest.writeByteArray(d.getAddress()); 1299 } 1300 dest.writeBoolean(mUsePrivateDns); 1301 dest.writeString(mPrivateDnsServerName); 1302 dest.writeString(mDomains); 1303 dest.writeInt(mMtu); 1304 dest.writeString(mTcpBufferSizes); 1305 dest.writeInt(mRoutes.size()); 1306 for (RouteInfo route : mRoutes) { 1307 dest.writeParcelable(route, flags); 1308 } 1309 1310 if (mHttpProxy != null) { 1311 dest.writeByte((byte)1); 1312 dest.writeParcelable(mHttpProxy, flags); 1313 } else { 1314 dest.writeByte((byte)0); 1315 } 1316 ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values()); 1317 dest.writeList(stackedLinks); 1318 } 1319 1320 /** 1321 * Implement the Parcelable interface. 1322 */ 1323 public static final Creator<LinkProperties> CREATOR = 1324 new Creator<LinkProperties>() { 1325 public LinkProperties createFromParcel(Parcel in) { 1326 LinkProperties netProp = new LinkProperties(); 1327 1328 String iface = in.readString(); 1329 if (iface != null) { 1330 netProp.setInterfaceName(iface); 1331 } 1332 int addressCount = in.readInt(); 1333 for (int i = 0; i < addressCount; i++) { 1334 netProp.addLinkAddress((LinkAddress) in.readParcelable(null)); 1335 } 1336 addressCount = in.readInt(); 1337 for (int i = 0; i < addressCount; i++) { 1338 try { 1339 netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray())); 1340 } catch (UnknownHostException e) { } 1341 } 1342 addressCount = in.readInt(); 1343 for (int i = 0; i < addressCount; i++) { 1344 try { 1345 netProp.addValidatedPrivateDnsServer( 1346 InetAddress.getByAddress(in.createByteArray())); 1347 } catch (UnknownHostException e) { } 1348 } 1349 netProp.setUsePrivateDns(in.readBoolean()); 1350 netProp.setPrivateDnsServerName(in.readString()); 1351 netProp.setDomains(in.readString()); 1352 netProp.setMtu(in.readInt()); 1353 netProp.setTcpBufferSizes(in.readString()); 1354 addressCount = in.readInt(); 1355 for (int i = 0; i < addressCount; i++) { 1356 netProp.addRoute((RouteInfo) in.readParcelable(null)); 1357 } 1358 if (in.readByte() == 1) { 1359 netProp.setHttpProxy((ProxyInfo) in.readParcelable(null)); 1360 } 1361 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>(); 1362 in.readList(stackedLinks, LinkProperties.class.getClassLoader()); 1363 for (LinkProperties stackedLink: stackedLinks) { 1364 netProp.addStackedLink(stackedLink); 1365 } 1366 return netProp; 1367 } 1368 1369 public LinkProperties[] newArray(int size) { 1370 return new LinkProperties[size]; 1371 } 1372 }; 1373 1374 /** 1375 * Check the valid MTU range based on IPv4 or IPv6. 1376 * @hide 1377 */ isValidMtu(int mtu, boolean ipv6)1378 public static boolean isValidMtu(int mtu, boolean ipv6) { 1379 if (ipv6) { 1380 if (mtu >= MIN_MTU_V6 && mtu <= MAX_MTU) return true; 1381 } else { 1382 if (mtu >= MIN_MTU && mtu <= MAX_MTU) return true; 1383 } 1384 return false; 1385 } 1386 } 1387