1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.net.IpPrefix; 25 import android.net.LinkAddress; 26 import android.net.LinkProperties; 27 import android.net.LinkProperties.CompareResult; 28 import android.net.LinkProperties.ProvisioningChange; 29 import android.net.RouteInfo; 30 import android.os.Parcel; 31 import android.support.test.filters.SmallTest; 32 import android.support.test.runner.AndroidJUnit4; 33 import android.system.OsConstants; 34 import android.util.ArraySet; 35 36 import java.net.InetAddress; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collection; 40 import java.util.Collections; 41 import java.util.List; 42 import java.util.Set; 43 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 47 @RunWith(AndroidJUnit4.class) 48 @SmallTest 49 public class LinkPropertiesTest { 50 private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); 51 private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( 52 "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); 53 private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); 54 private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); 55 private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888"); 56 private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); 57 private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); 58 private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613"); 59 private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222"); 60 private static String NAME = "qmi0"; 61 private static int MTU = 1500; 62 63 private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); 64 private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); 65 private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64"); 66 67 // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method. Address(String addrString)68 private InetAddress Address(String addrString) { 69 return NetworkUtils.numericToInetAddress(addrString); 70 } 71 assertLinkPropertiesEqual(LinkProperties source, LinkProperties target)72 public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) { 73 // Check implementation of equals(), element by element. 74 assertTrue(source.isIdenticalInterfaceName(target)); 75 assertTrue(target.isIdenticalInterfaceName(source)); 76 77 assertTrue(source.isIdenticalAddresses(target)); 78 assertTrue(target.isIdenticalAddresses(source)); 79 80 assertTrue(source.isIdenticalDnses(target)); 81 assertTrue(target.isIdenticalDnses(source)); 82 83 assertTrue(source.isIdenticalPrivateDns(target)); 84 assertTrue(target.isIdenticalPrivateDns(source)); 85 86 assertTrue(source.isIdenticalValidatedPrivateDnses(target)); 87 assertTrue(target.isIdenticalValidatedPrivateDnses(source)); 88 89 assertTrue(source.isIdenticalRoutes(target)); 90 assertTrue(target.isIdenticalRoutes(source)); 91 92 assertTrue(source.isIdenticalHttpProxy(target)); 93 assertTrue(target.isIdenticalHttpProxy(source)); 94 95 assertTrue(source.isIdenticalStackedLinks(target)); 96 assertTrue(target.isIdenticalStackedLinks(source)); 97 98 assertTrue(source.isIdenticalMtu(target)); 99 assertTrue(target.isIdenticalMtu(source)); 100 101 assertTrue(source.isIdenticalTcpBufferSizes(target)); 102 assertTrue(target.isIdenticalTcpBufferSizes(source)); 103 104 // Check result of equals(). 105 assertTrue(source.equals(target)); 106 assertTrue(target.equals(source)); 107 108 // Check hashCode. 109 assertEquals(source.hashCode(), target.hashCode()); 110 } 111 112 @Test testEqualsNull()113 public void testEqualsNull() { 114 LinkProperties source = new LinkProperties(); 115 LinkProperties target = new LinkProperties(); 116 117 assertFalse(source == target); 118 assertLinkPropertiesEqual(source, target); 119 } 120 121 @Test testEqualsSameOrder()122 public void testEqualsSameOrder() throws Exception { 123 LinkProperties source = new LinkProperties(); 124 source.setInterfaceName(NAME); 125 // set 2 link addresses 126 source.addLinkAddress(LINKADDRV4); 127 source.addLinkAddress(LINKADDRV6); 128 // set 2 dnses 129 source.addDnsServer(DNS1); 130 source.addDnsServer(DNS2); 131 // set 2 gateways 132 source.addRoute(new RouteInfo(GATEWAY1)); 133 source.addRoute(new RouteInfo(GATEWAY2)); 134 source.setMtu(MTU); 135 136 LinkProperties target = new LinkProperties(); 137 138 // All fields are same 139 target.setInterfaceName(NAME); 140 target.addLinkAddress(LINKADDRV4); 141 target.addLinkAddress(LINKADDRV6); 142 target.addDnsServer(DNS1); 143 target.addDnsServer(DNS2); 144 target.addRoute(new RouteInfo(GATEWAY1)); 145 target.addRoute(new RouteInfo(GATEWAY2)); 146 target.setMtu(MTU); 147 148 assertLinkPropertiesEqual(source, target); 149 150 target.clear(); 151 // change Interface Name 152 target.setInterfaceName("qmi1"); 153 target.addLinkAddress(LINKADDRV4); 154 target.addLinkAddress(LINKADDRV6); 155 target.addDnsServer(DNS1); 156 target.addDnsServer(DNS2); 157 target.addRoute(new RouteInfo(GATEWAY1)); 158 target.addRoute(new RouteInfo(GATEWAY2)); 159 target.setMtu(MTU); 160 assertFalse(source.equals(target)); 161 162 target.clear(); 163 target.setInterfaceName(NAME); 164 // change link addresses 165 target.addLinkAddress(new LinkAddress( 166 NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); 167 target.addLinkAddress(LINKADDRV6); 168 target.addDnsServer(DNS1); 169 target.addDnsServer(DNS2); 170 target.addRoute(new RouteInfo(GATEWAY1)); 171 target.addRoute(new RouteInfo(GATEWAY2)); 172 target.setMtu(MTU); 173 assertFalse(source.equals(target)); 174 175 target.clear(); 176 target.setInterfaceName(NAME); 177 target.addLinkAddress(LINKADDRV4); 178 target.addLinkAddress(LINKADDRV6); 179 // change dnses 180 target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); 181 target.addDnsServer(DNS2); 182 target.addRoute(new RouteInfo(GATEWAY1)); 183 target.addRoute(new RouteInfo(GATEWAY2)); 184 target.setMtu(MTU); 185 assertFalse(source.equals(target)); 186 187 target.clear(); 188 target.setInterfaceName(NAME); 189 target.addLinkAddress(LINKADDRV4); 190 target.addLinkAddress(LINKADDRV6); 191 target.addDnsServer(DNS1); 192 target.addDnsServer(DNS2); 193 // change gateway 194 target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); 195 target.addRoute(new RouteInfo(GATEWAY2)); 196 target.setMtu(MTU); 197 assertFalse(source.equals(target)); 198 199 target.clear(); 200 target.setInterfaceName(NAME); 201 target.addLinkAddress(LINKADDRV4); 202 target.addLinkAddress(LINKADDRV6); 203 target.addDnsServer(DNS1); 204 target.addDnsServer(DNS2); 205 target.addRoute(new RouteInfo(GATEWAY1)); 206 target.addRoute(new RouteInfo(GATEWAY2)); 207 // change mtu 208 target.setMtu(1440); 209 assertFalse(source.equals(target)); 210 } 211 212 @Test testEqualsDifferentOrder()213 public void testEqualsDifferentOrder() throws Exception { 214 LinkProperties source = new LinkProperties(); 215 source.setInterfaceName(NAME); 216 // set 2 link addresses 217 source.addLinkAddress(LINKADDRV4); 218 source.addLinkAddress(LINKADDRV6); 219 // set 2 dnses 220 source.addDnsServer(DNS1); 221 source.addDnsServer(DNS2); 222 // set 2 gateways 223 source.addRoute(new RouteInfo(GATEWAY1)); 224 source.addRoute(new RouteInfo(GATEWAY2)); 225 source.setMtu(MTU); 226 227 LinkProperties target = new LinkProperties(); 228 // Exchange order 229 target.setInterfaceName(NAME); 230 target.addLinkAddress(LINKADDRV6); 231 target.addLinkAddress(LINKADDRV4); 232 target.addDnsServer(DNS2); 233 target.addDnsServer(DNS1); 234 target.addRoute(new RouteInfo(GATEWAY2)); 235 target.addRoute(new RouteInfo(GATEWAY1)); 236 target.setMtu(MTU); 237 238 assertLinkPropertiesEqual(source, target); 239 } 240 241 @Test testEqualsDuplicated()242 public void testEqualsDuplicated() throws Exception { 243 LinkProperties source = new LinkProperties(); 244 // set 3 link addresses, eg, [A, A, B] 245 source.addLinkAddress(LINKADDRV4); 246 source.addLinkAddress(LINKADDRV4); 247 source.addLinkAddress(LINKADDRV6); 248 249 LinkProperties target = new LinkProperties(); 250 // set 3 link addresses, eg, [A, B, B] 251 target.addLinkAddress(LINKADDRV4); 252 target.addLinkAddress(LINKADDRV6); 253 target.addLinkAddress(LINKADDRV6); 254 255 assertLinkPropertiesEqual(source, target); 256 } 257 assertAllRoutesHaveInterface(String iface, LinkProperties lp)258 private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) { 259 for (RouteInfo r : lp.getRoutes()) { 260 assertEquals(iface, r.getInterface()); 261 } 262 } 263 264 @Test testRouteInterfaces()265 public void testRouteInterfaces() { 266 LinkAddress prefix = new LinkAddress( 267 NetworkUtils.numericToInetAddress("2001:db8::"), 32); 268 InetAddress address = ADDRV6; 269 270 // Add a route with no interface to a LinkProperties with no interface. No errors. 271 LinkProperties lp = new LinkProperties(); 272 RouteInfo r = new RouteInfo(prefix, address, null); 273 assertTrue(lp.addRoute(r)); 274 assertEquals(1, lp.getRoutes().size()); 275 assertAllRoutesHaveInterface(null, lp); 276 277 // Adding the same route twice has no effect. 278 assertFalse(lp.addRoute(r)); 279 assertEquals(1, lp.getRoutes().size()); 280 281 // Add a route with an interface. Expect an exception. 282 r = new RouteInfo(prefix, address, "wlan0"); 283 try { 284 lp.addRoute(r); 285 fail("Adding wlan0 route to LP with no interface, expect exception"); 286 } catch (IllegalArgumentException expected) {} 287 288 // Change the interface name. All the routes should change their interface name too. 289 lp.setInterfaceName("rmnet0"); 290 assertAllRoutesHaveInterface("rmnet0", lp); 291 292 // Now add a route with the wrong interface. This causes an exception too. 293 try { 294 lp.addRoute(r); 295 fail("Adding wlan0 route to rmnet0 LP, expect exception"); 296 } catch (IllegalArgumentException expected) {} 297 298 // If the interface name matches, the route is added. 299 r = new RouteInfo(prefix, null, "wlan0"); 300 lp.setInterfaceName("wlan0"); 301 lp.addRoute(r); 302 assertEquals(2, lp.getRoutes().size()); 303 assertAllRoutesHaveInterface("wlan0", lp); 304 305 // Routes with null interfaces are converted to wlan0. 306 r = RouteInfo.makeHostRoute(ADDRV6, null); 307 lp.addRoute(r); 308 assertEquals(3, lp.getRoutes().size()); 309 assertAllRoutesHaveInterface("wlan0", lp); 310 311 // Check comparisons work. 312 LinkProperties lp2 = new LinkProperties(lp); 313 assertAllRoutesHaveInterface("wlan0", lp); 314 assertEquals(0, lp.compareAllRoutes(lp2).added.size()); 315 assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); 316 317 lp2.setInterfaceName("p2p0"); 318 assertAllRoutesHaveInterface("p2p0", lp2); 319 assertEquals(3, lp.compareAllRoutes(lp2).added.size()); 320 assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); 321 } 322 323 @Test testStackedInterfaces()324 public void testStackedInterfaces() { 325 LinkProperties rmnet0 = new LinkProperties(); 326 rmnet0.setInterfaceName("rmnet0"); 327 rmnet0.addLinkAddress(LINKADDRV6); 328 329 LinkProperties clat4 = new LinkProperties(); 330 clat4.setInterfaceName("clat4"); 331 clat4.addLinkAddress(LINKADDRV4); 332 333 assertEquals(0, rmnet0.getStackedLinks().size()); 334 assertEquals(1, rmnet0.getAddresses().size()); 335 assertEquals(1, rmnet0.getLinkAddresses().size()); 336 assertEquals(1, rmnet0.getAllAddresses().size()); 337 assertEquals(1, rmnet0.getAllLinkAddresses().size()); 338 339 rmnet0.addStackedLink(clat4); 340 assertEquals(1, rmnet0.getStackedLinks().size()); 341 assertEquals(1, rmnet0.getAddresses().size()); 342 assertEquals(1, rmnet0.getLinkAddresses().size()); 343 assertEquals(2, rmnet0.getAllAddresses().size()); 344 assertEquals(2, rmnet0.getAllLinkAddresses().size()); 345 346 rmnet0.addStackedLink(clat4); 347 assertEquals(1, rmnet0.getStackedLinks().size()); 348 assertEquals(1, rmnet0.getAddresses().size()); 349 assertEquals(1, rmnet0.getLinkAddresses().size()); 350 assertEquals(2, rmnet0.getAllAddresses().size()); 351 assertEquals(2, rmnet0.getAllLinkAddresses().size()); 352 353 assertEquals(0, clat4.getStackedLinks().size()); 354 355 // Modify an item in the returned collection to see what happens. 356 for (LinkProperties link : rmnet0.getStackedLinks()) { 357 if (link.getInterfaceName().equals("clat4")) { 358 link.setInterfaceName("newname"); 359 } 360 } 361 for (LinkProperties link : rmnet0.getStackedLinks()) { 362 assertFalse("newname".equals(link.getInterfaceName())); 363 } 364 365 assertTrue(rmnet0.removeStackedLink("clat4")); 366 assertEquals(0, rmnet0.getStackedLinks().size()); 367 assertEquals(1, rmnet0.getAddresses().size()); 368 assertEquals(1, rmnet0.getLinkAddresses().size()); 369 assertEquals(1, rmnet0.getAllAddresses().size()); 370 assertEquals(1, rmnet0.getAllLinkAddresses().size()); 371 372 assertFalse(rmnet0.removeStackedLink("clat4")); 373 } 374 getFirstLinkAddress(LinkProperties lp)375 private LinkAddress getFirstLinkAddress(LinkProperties lp) { 376 return lp.getLinkAddresses().iterator().next(); 377 } 378 379 @Test testAddressMethods()380 public void testAddressMethods() { 381 LinkProperties lp = new LinkProperties(); 382 383 // No addresses. 384 assertFalse(lp.hasIPv4Address()); 385 assertFalse(lp.hasGlobalIPv6Address()); 386 387 // Addresses on stacked links don't count. 388 LinkProperties stacked = new LinkProperties(); 389 stacked.setInterfaceName("stacked"); 390 lp.addStackedLink(stacked); 391 stacked.addLinkAddress(LINKADDRV4); 392 stacked.addLinkAddress(LINKADDRV6); 393 assertTrue(stacked.hasIPv4Address()); 394 assertTrue(stacked.hasGlobalIPv6Address()); 395 assertFalse(lp.hasIPv4Address()); 396 assertFalse(lp.hasGlobalIPv6Address()); 397 lp.removeStackedLink("stacked"); 398 assertFalse(lp.hasIPv4Address()); 399 assertFalse(lp.hasGlobalIPv6Address()); 400 401 // Addresses on the base link. 402 // Check the return values of hasIPvXAddress and ensure the add/remove methods return true 403 // iff something changes. 404 assertEquals(0, lp.getLinkAddresses().size()); 405 assertTrue(lp.addLinkAddress(LINKADDRV6)); 406 assertEquals(1, lp.getLinkAddresses().size()); 407 assertFalse(lp.hasIPv4Address()); 408 assertTrue(lp.hasGlobalIPv6Address()); 409 410 assertTrue(lp.removeLinkAddress(LINKADDRV6)); 411 assertEquals(0, lp.getLinkAddresses().size()); 412 413 assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL)); 414 assertEquals(1, lp.getLinkAddresses().size()); 415 assertFalse(lp.hasGlobalIPv6Address()); 416 417 assertTrue(lp.addLinkAddress(LINKADDRV4)); 418 assertEquals(2, lp.getLinkAddresses().size()); 419 assertTrue(lp.hasIPv4Address()); 420 assertFalse(lp.hasGlobalIPv6Address()); 421 422 assertTrue(lp.addLinkAddress(LINKADDRV6)); 423 assertEquals(3, lp.getLinkAddresses().size()); 424 assertTrue(lp.hasIPv4Address()); 425 assertTrue(lp.hasGlobalIPv6Address()); 426 427 assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL)); 428 assertEquals(2, lp.getLinkAddresses().size()); 429 assertTrue(lp.hasIPv4Address()); 430 assertTrue(lp.hasGlobalIPv6Address()); 431 432 // Adding an address twice has no effect. 433 // Removing an address that's not present has no effect. 434 assertFalse(lp.addLinkAddress(LINKADDRV4)); 435 assertEquals(2, lp.getLinkAddresses().size()); 436 assertTrue(lp.hasIPv4Address()); 437 assertTrue(lp.removeLinkAddress(LINKADDRV4)); 438 assertEquals(1, lp.getLinkAddresses().size()); 439 assertFalse(lp.hasIPv4Address()); 440 assertFalse(lp.removeLinkAddress(LINKADDRV4)); 441 assertEquals(1, lp.getLinkAddresses().size()); 442 443 // Adding an address that's already present but with different properties causes the 444 // existing address to be updated and returns true. 445 // Start with only LINKADDRV6. 446 assertEquals(1, lp.getLinkAddresses().size()); 447 assertEquals(LINKADDRV6, getFirstLinkAddress(lp)); 448 449 // Create a LinkAddress object for the same address, but with different flags. 450 LinkAddress deprecated = new LinkAddress(ADDRV6, 128, 451 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE); 452 assertTrue(deprecated.isSameAddressAs(LINKADDRV6)); 453 assertFalse(deprecated.equals(LINKADDRV6)); 454 455 // Check that adding it updates the existing address instead of adding a new one. 456 assertTrue(lp.addLinkAddress(deprecated)); 457 assertEquals(1, lp.getLinkAddresses().size()); 458 assertEquals(deprecated, getFirstLinkAddress(lp)); 459 assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp))); 460 461 // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties. 462 assertTrue(lp.removeLinkAddress(LINKADDRV6)); 463 assertEquals(0, lp.getLinkAddresses().size()); 464 } 465 466 @Test testSetLinkAddresses()467 public void testSetLinkAddresses() { 468 LinkProperties lp = new LinkProperties(); 469 lp.addLinkAddress(LINKADDRV4); 470 lp.addLinkAddress(LINKADDRV6); 471 472 LinkProperties lp2 = new LinkProperties(); 473 lp2.addLinkAddress(LINKADDRV6); 474 475 assertFalse(lp.equals(lp2)); 476 477 lp2.setLinkAddresses(lp.getLinkAddresses()); 478 assertTrue(lp.equals(lp)); 479 } 480 481 @Test testIsProvisioned()482 public void testIsProvisioned() { 483 LinkProperties lp4 = new LinkProperties(); 484 assertFalse("v4only:empty", lp4.isProvisioned()); 485 lp4.addLinkAddress(LINKADDRV4); 486 assertFalse("v4only:addr-only", lp4.isProvisioned()); 487 lp4.addDnsServer(DNS1); 488 assertFalse("v4only:addr+dns", lp4.isProvisioned()); 489 lp4.addRoute(new RouteInfo(GATEWAY1)); 490 assertTrue("v4only:addr+dns+route", lp4.isProvisioned()); 491 assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned()); 492 assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned()); 493 494 LinkProperties lp6 = new LinkProperties(); 495 assertFalse("v6only:empty", lp6.isProvisioned()); 496 lp6.addLinkAddress(LINKADDRV6LINKLOCAL); 497 assertFalse("v6only:fe80-only", lp6.isProvisioned()); 498 lp6.addDnsServer(DNS6); 499 assertFalse("v6only:fe80+dns", lp6.isProvisioned()); 500 lp6.addRoute(new RouteInfo(GATEWAY61)); 501 assertFalse("v6only:fe80+dns+route", lp6.isProvisioned()); 502 lp6.addLinkAddress(LINKADDRV6); 503 assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned()); 504 assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned()); 505 lp6.removeLinkAddress(LINKADDRV6LINKLOCAL); 506 assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned()); 507 assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned()); 508 assertTrue("v6only:global+dns+route", lp6.isProvisioned()); 509 510 LinkProperties lp46 = new LinkProperties(); 511 lp46.addLinkAddress(LINKADDRV4); 512 lp46.addLinkAddress(LINKADDRV6); 513 lp46.addDnsServer(DNS1); 514 lp46.addDnsServer(DNS6); 515 assertFalse("dualstack:missing-routes", lp46.isProvisioned()); 516 lp46.addRoute(new RouteInfo(GATEWAY1)); 517 assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned()); 518 assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned()); 519 assertTrue("dualstack:v4-provisioned", lp46.isProvisioned()); 520 lp46.addRoute(new RouteInfo(GATEWAY61)); 521 assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned()); 522 assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned()); 523 assertTrue("dualstack:both-provisioned", lp46.isProvisioned()); 524 525 // A link with an IPv6 address and default route, but IPv4 DNS server. 526 LinkProperties mixed = new LinkProperties(); 527 mixed.addLinkAddress(LINKADDRV6); 528 mixed.addDnsServer(DNS1); 529 mixed.addRoute(new RouteInfo(GATEWAY61)); 530 assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned()); 531 assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned()); 532 assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned()); 533 } 534 535 @Test testCompareProvisioning()536 public void testCompareProvisioning() { 537 LinkProperties v4lp = new LinkProperties(); 538 v4lp.addLinkAddress(LINKADDRV4); 539 v4lp.addRoute(new RouteInfo(GATEWAY1)); 540 v4lp.addDnsServer(DNS1); 541 assertTrue(v4lp.isProvisioned()); 542 543 LinkProperties v4r = new LinkProperties(v4lp); 544 v4r.removeDnsServer(DNS1); 545 assertFalse(v4r.isProvisioned()); 546 547 assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED, 548 LinkProperties.compareProvisioning(v4r, v4r)); 549 assertEquals(ProvisioningChange.LOST_PROVISIONING, 550 LinkProperties.compareProvisioning(v4lp, v4r)); 551 assertEquals(ProvisioningChange.GAINED_PROVISIONING, 552 LinkProperties.compareProvisioning(v4r, v4lp)); 553 assertEquals(ProvisioningChange.STILL_PROVISIONED, 554 LinkProperties.compareProvisioning(v4lp, v4lp)); 555 556 // Check that losing IPv4 provisioning on a dualstack network is 557 // seen as a total loss of provisioning. 558 LinkProperties v6lp = new LinkProperties(); 559 v6lp.addLinkAddress(LINKADDRV6); 560 v6lp.addRoute(new RouteInfo(GATEWAY61)); 561 v6lp.addDnsServer(DNS6); 562 assertFalse(v6lp.isIPv4Provisioned()); 563 assertTrue(v6lp.isIPv6Provisioned()); 564 assertTrue(v6lp.isProvisioned()); 565 566 LinkProperties v46lp = new LinkProperties(v6lp); 567 v46lp.addLinkAddress(LINKADDRV4); 568 v46lp.addRoute(new RouteInfo(GATEWAY1)); 569 v46lp.addDnsServer(DNS1); 570 assertTrue(v46lp.isIPv4Provisioned()); 571 assertTrue(v46lp.isIPv6Provisioned()); 572 assertTrue(v46lp.isProvisioned()); 573 574 assertEquals(ProvisioningChange.STILL_PROVISIONED, 575 LinkProperties.compareProvisioning(v4lp, v46lp)); 576 assertEquals(ProvisioningChange.STILL_PROVISIONED, 577 LinkProperties.compareProvisioning(v6lp, v46lp)); 578 assertEquals(ProvisioningChange.LOST_PROVISIONING, 579 LinkProperties.compareProvisioning(v46lp, v6lp)); 580 assertEquals(ProvisioningChange.LOST_PROVISIONING, 581 LinkProperties.compareProvisioning(v46lp, v4lp)); 582 583 // Check that losing and gaining a secondary router does not change 584 // the provisioning status. 585 LinkProperties v6lp2 = new LinkProperties(v6lp); 586 v6lp2.addRoute(new RouteInfo(GATEWAY62)); 587 assertTrue(v6lp2.isProvisioned()); 588 589 assertEquals(ProvisioningChange.STILL_PROVISIONED, 590 LinkProperties.compareProvisioning(v6lp2, v6lp)); 591 assertEquals(ProvisioningChange.STILL_PROVISIONED, 592 LinkProperties.compareProvisioning(v6lp, v6lp2)); 593 } 594 595 @Test testIsReachable()596 public void testIsReachable() { 597 final LinkProperties v4lp = new LinkProperties(); 598 assertFalse(v4lp.isReachable(DNS1)); 599 assertFalse(v4lp.isReachable(DNS2)); 600 601 // Add an on-link route, making the on-link DNS server reachable, 602 // but there is still no IPv4 address. 603 assertTrue(v4lp.addRoute(new RouteInfo( 604 new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16)))); 605 assertFalse(v4lp.isReachable(DNS1)); 606 assertFalse(v4lp.isReachable(DNS2)); 607 608 // Adding an IPv4 address (right now, any IPv4 address) means we use 609 // the routes to compute likely reachability. 610 assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16))); 611 assertTrue(v4lp.isReachable(DNS1)); 612 assertFalse(v4lp.isReachable(DNS2)); 613 614 // Adding a default route makes the off-link DNS server reachable. 615 assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1))); 616 assertTrue(v4lp.isReachable(DNS1)); 617 assertTrue(v4lp.isReachable(DNS2)); 618 619 final LinkProperties v6lp = new LinkProperties(); 620 final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1"); 621 final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43"); 622 final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53"); 623 assertFalse(v6lp.isReachable(kLinkLocalDns)); 624 assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope)); 625 assertFalse(v6lp.isReachable(kOnLinkDns)); 626 assertFalse(v6lp.isReachable(DNS6)); 627 628 // Add a link-local route, making the link-local DNS servers reachable. Because 629 // we assume the presence of an IPv6 link-local address, link-local DNS servers 630 // are considered reachable, but only those with a non-zero scope identifier. 631 assertTrue(v6lp.addRoute(new RouteInfo( 632 new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64)))); 633 assertFalse(v6lp.isReachable(kLinkLocalDns)); 634 assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); 635 assertFalse(v6lp.isReachable(kOnLinkDns)); 636 assertFalse(v6lp.isReachable(DNS6)); 637 638 // Add a link-local address--nothing changes. 639 assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL)); 640 assertFalse(v6lp.isReachable(kLinkLocalDns)); 641 assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); 642 assertFalse(v6lp.isReachable(kOnLinkDns)); 643 assertFalse(v6lp.isReachable(DNS6)); 644 645 // Add a global route on link, but no global address yet. DNS servers reachable 646 // via a route that doesn't require a gateway: give them the benefit of the 647 // doubt and hope the link-local source address suffices for communication. 648 assertTrue(v6lp.addRoute(new RouteInfo( 649 new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64)))); 650 assertFalse(v6lp.isReachable(kLinkLocalDns)); 651 assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); 652 assertTrue(v6lp.isReachable(kOnLinkDns)); 653 assertFalse(v6lp.isReachable(DNS6)); 654 655 // Add a global address; the on-link global address DNS server is (still) 656 // presumed reachable. 657 assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64))); 658 assertFalse(v6lp.isReachable(kLinkLocalDns)); 659 assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); 660 assertTrue(v6lp.isReachable(kOnLinkDns)); 661 assertFalse(v6lp.isReachable(DNS6)); 662 663 // Adding a default route makes the off-link DNS server reachable. 664 assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62))); 665 assertFalse(v6lp.isReachable(kLinkLocalDns)); 666 assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); 667 assertTrue(v6lp.isReachable(kOnLinkDns)); 668 assertTrue(v6lp.isReachable(DNS6)); 669 670 // Check isReachable on stacked links. This requires that the source IP address be assigned 671 // on the interface returned by the route lookup. 672 LinkProperties stacked = new LinkProperties(); 673 674 // Can't add a stacked link without an interface name. 675 stacked.setInterfaceName("v4-test0"); 676 v6lp.addStackedLink(stacked); 677 678 InetAddress stackedAddress = Address("192.0.0.4"); 679 LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32); 680 assertFalse(v6lp.isReachable(stackedAddress)); 681 stacked.addLinkAddress(stackedLinkAddress); 682 assertFalse(v6lp.isReachable(stackedAddress)); 683 stacked.addRoute(new RouteInfo(stackedLinkAddress)); 684 assertTrue(stacked.isReachable(stackedAddress)); 685 assertTrue(v6lp.isReachable(stackedAddress)); 686 687 assertFalse(v6lp.isReachable(DNS1)); 688 stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress)); 689 assertTrue(v6lp.isReachable(DNS1)); 690 } 691 692 @Test testLinkPropertiesEnsureDirectlyConnectedRoutes()693 public void testLinkPropertiesEnsureDirectlyConnectedRoutes() { 694 // IPv4 case: no route added initially 695 LinkProperties rmnet0 = new LinkProperties(); 696 rmnet0.setInterfaceName("rmnet0"); 697 rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8")); 698 RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null, 699 rmnet0.getInterfaceName()); 700 701 // Since no routes is added explicitly, getAllRoutes() should return empty. 702 assertTrue(rmnet0.getAllRoutes().isEmpty()); 703 rmnet0.ensureDirectlyConnectedRoutes(); 704 // ensureDirectlyConnectedRoutes() should have added the missing local route. 705 assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes()); 706 707 // IPv4 case: both direct and default routes added initially 708 LinkProperties rmnet1 = new LinkProperties(); 709 rmnet1.setInterfaceName("rmnet1"); 710 rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8")); 711 RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, 712 NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName()); 713 RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null, 714 rmnet1.getInterfaceName()); 715 rmnet1.addRoute(defaultRoute1); 716 rmnet1.addRoute(directRoute1); 717 718 // Check added routes 719 assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes()); 720 // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected 721 // route is already part of the configuration. 722 rmnet1.ensureDirectlyConnectedRoutes(); 723 assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes()); 724 725 // IPv6 case: only default routes added initially 726 LinkProperties rmnet2 = new LinkProperties(); 727 rmnet2.setInterfaceName("rmnet2"); 728 rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64")); 729 rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64")); 730 RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, 731 NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName()); 732 RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null, 733 rmnet2.getInterfaceName()); 734 RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null, 735 rmnet2.getInterfaceName()); 736 rmnet2.addRoute(defaultRoute2); 737 738 assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes()); 739 rmnet2.ensureDirectlyConnectedRoutes(); 740 assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2), 741 rmnet2.getAllRoutes()); 742 743 // Corner case: no interface name 744 LinkProperties rmnet3 = new LinkProperties(); 745 rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24")); 746 RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null, 747 rmnet3.getInterfaceName()); 748 749 assertTrue(rmnet3.getAllRoutes().isEmpty()); 750 rmnet3.ensureDirectlyConnectedRoutes(); 751 assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes()); 752 753 } 754 755 @Test testCompareResult()756 public void testCompareResult() { 757 // Either adding or removing items 758 compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1), 759 Arrays.asList(2, 3, 4), new ArrayList<>()); 760 compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4), 761 new ArrayList<>(), Arrays.asList(3, 4)); 762 763 764 // adding and removing items at the same time 765 compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5), 766 Arrays.asList(1), Arrays.asList(5)); 767 compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), 768 Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)); 769 770 // null cases 771 compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>()); 772 compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3)); 773 compareResult(null, null, new ArrayList<>(), new ArrayList<>()); 774 } 775 assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual)776 private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) { 777 Set<RouteInfo> expectedSet = new ArraySet<>(expected); 778 Set<RouteInfo> actualSet = new ArraySet<>(actual); 779 // Duplicated entries in actual routes are considered failures 780 assertEquals(actual.size(), actualSet.size()); 781 782 assertEquals(expectedSet, actualSet); 783 } 784 compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved, List<T> expectAdded)785 private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved, 786 List<T> expectAdded) { 787 CompareResult<T> result = new CompareResult<>(oldItems, newItems); 788 assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added)); 789 assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed))); 790 } 791 792 @Test testLinkPropertiesParcelable()793 public void testLinkPropertiesParcelable() { 794 LinkProperties source = new LinkProperties(); 795 source.setInterfaceName(NAME); 796 // set 2 link addresses 797 source.addLinkAddress(LINKADDRV4); 798 source.addLinkAddress(LINKADDRV6); 799 // set 2 dnses 800 source.addDnsServer(DNS1); 801 source.addDnsServer(DNS2); 802 // set 2 gateways 803 source.addRoute(new RouteInfo(GATEWAY1)); 804 source.addRoute(new RouteInfo(GATEWAY2)); 805 // set 2 validated private dnses 806 source.addValidatedPrivateDnsServer(DNS6); 807 source.addValidatedPrivateDnsServer(GATEWAY61); 808 809 source.setMtu(MTU); 810 811 Parcel p = Parcel.obtain(); 812 source.writeToParcel(p, /* flags */ 0); 813 p.setDataPosition(0); 814 final byte[] marshalled = p.marshall(); 815 p = Parcel.obtain(); 816 p.unmarshall(marshalled, 0, marshalled.length); 817 p.setDataPosition(0); 818 LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p); 819 820 assertEquals(source, dest); 821 } 822 } 823