1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import static android.net.RouteInfo.RTN_THROW;
20 import static android.net.RouteInfo.RTN_UNICAST;
21 import static android.net.RouteInfo.RTN_UNREACHABLE;
22 
23 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
24 import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
25 
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNotEquals;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32 
33 import android.compat.testing.PlatformCompatChangeRule;
34 import android.net.LinkProperties.ProvisioningChange;
35 import android.net.connectivity.ConnectivityCompatChanges;
36 import android.os.Build;
37 import android.system.OsConstants;
38 import android.util.ArraySet;
39 
40 import androidx.test.filters.SmallTest;
41 import androidx.test.runner.AndroidJUnit4;
42 
43 import com.android.modules.utils.build.SdkLevel;
44 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
45 import com.android.testutils.ConnectivityModuleTest;
46 import com.android.testutils.DevSdkIgnoreRule;
47 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
48 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
49 import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk31;
50 
51 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
52 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
53 
54 import org.junit.Rule;
55 import org.junit.Test;
56 import org.junit.rules.RuleChain;
57 import org.junit.runner.RunWith;
58 
59 import java.net.Inet4Address;
60 import java.net.Inet6Address;
61 import java.net.InetAddress;
62 import java.util.Arrays;
63 import java.util.Collection;
64 import java.util.Collections;
65 import java.util.List;
66 import java.util.Set;
67 
68 @RunWith(AndroidJUnit4.class)
69 @SmallTest
70 @ConnectivityModuleTest
71 public class LinkPropertiesTest {
72     // Use a RuleChain to explicitly specify the order of rules. DevSdkIgnoreRule must run before
73     // PlatformCompatChange rule, because otherwise tests with that should be skipped when targeting
74     // target SDK 33 will still attempt to override compat changes (which on user builds will crash)
75     // before being skipped.
76     @Rule
77     public final RuleChain chain = RuleChain.outerRule(
78             new DevSdkIgnoreRule()).around(new PlatformCompatChangeRule());
79 
80     private static final InetAddress ADDRV4 = address("75.208.6.1");
81     private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
82     private static final InetAddress DNS1 = address("75.208.7.1");
83     private static final InetAddress DNS2 = address("69.78.7.1");
84     private static final InetAddress DNS6 = address("2001:4860:4860::8888");
85     private static final InetAddress PRIVDNS1 = address("1.1.1.1");
86     private static final InetAddress PRIVDNS2 = address("1.0.0.1");
87     private static final InetAddress PRIVDNS6 = address("2606:4700:4700::1111");
88     private static final InetAddress PCSCFV4 = address("10.77.25.37");
89     private static final InetAddress PCSCFV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:1");
90     private static final InetAddress GATEWAY1 = address("75.208.8.1");
91     private static final InetAddress GATEWAY2 = address("69.78.8.1");
92     private static final InetAddress GATEWAY61 = address("fe80::6:0000:613");
93     private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
94     private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
95     private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
96     private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1");
97     private static final String NAME = "qmi0";
98     private static final String DOMAINS = "google.com";
99     private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
100     private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576";
101     private static final int MTU = 1500;
102     private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
103     private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
104     private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
105     private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
106 
107     // CaptivePortalData cannot be in a constant as it does not exist on Q.
108     // The test runner also crashes when scanning for tests if it is a return type.
getCaptivePortalData()109     private static Object getCaptivePortalData() {
110         return new CaptivePortalData.Builder()
111                 .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
112     }
113 
address(String addrString)114     private static InetAddress address(String addrString) {
115         return InetAddresses.parseNumericAddress(addrString);
116     }
117 
checkEmpty(final LinkProperties lp)118     private void checkEmpty(final LinkProperties lp) {
119         assertEquals(0, lp.getAllInterfaceNames().size());
120         assertEquals(0, lp.getAllAddresses().size());
121         assertEquals(0, lp.getDnsServers().size());
122         assertEquals(0, lp.getValidatedPrivateDnsServers().size());
123         assertEquals(0, lp.getPcscfServers().size());
124         assertEquals(0, lp.getAllRoutes().size());
125         assertEquals(0, lp.getAllLinkAddresses().size());
126         assertEquals(0, lp.getStackedLinks().size());
127         assertEquals(0, lp.getMtu());
128         assertNull(lp.getPrivateDnsServerName());
129         assertNull(lp.getDomains());
130         assertNull(lp.getHttpProxy());
131         assertNull(lp.getTcpBufferSizes());
132         assertNull(lp.getNat64Prefix());
133         assertFalse(lp.isProvisioned());
134         assertFalse(lp.isIpv4Provisioned());
135         assertFalse(lp.isIpv6Provisioned());
136         assertFalse(lp.isPrivateDnsActive());
137         assertNull(lp.getDhcpServerAddress());
138         assertFalse(lp.isWakeOnLanSupported());
139         assertNull(lp.getCaptivePortalApiUrl());
140         assertNull(lp.getCaptivePortalData());
141     }
142 
makeTestObject()143     private LinkProperties makeTestObject() {
144         final LinkProperties lp = new LinkProperties();
145         lp.setInterfaceName(NAME);
146         lp.addLinkAddress(LINKADDRV4);
147         lp.addLinkAddress(LINKADDRV6);
148         lp.addDnsServer(DNS1);
149         lp.addDnsServer(DNS2);
150         lp.addValidatedPrivateDnsServer(PRIVDNS1);
151         lp.addValidatedPrivateDnsServer(PRIVDNS2);
152         lp.setUsePrivateDns(true);
153         lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
154         lp.addPcscfServer(PCSCFV6);
155         lp.setDomains(DOMAINS);
156         lp.addRoute(new RouteInfo(GATEWAY1));
157         lp.addRoute(new RouteInfo(GATEWAY2));
158         lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
159         lp.setMtu(MTU);
160         lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
161         lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
162         lp.setDhcpServerAddress(DHCPSERVER);
163         lp.setWakeOnLanSupported(true);
164         lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
165         lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
166         return lp;
167     }
168 
assertLinkPropertiesEqual(LinkProperties source, LinkProperties target)169     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
170         // Check implementation of equals(), element by element.
171         assertTrue(source.isIdenticalInterfaceName(target));
172         assertTrue(target.isIdenticalInterfaceName(source));
173 
174         assertTrue(source.isIdenticalAddresses(target));
175         assertTrue(target.isIdenticalAddresses(source));
176 
177         assertTrue(source.isIdenticalDnses(target));
178         assertTrue(target.isIdenticalDnses(source));
179 
180         assertTrue(source.isIdenticalPrivateDns(target));
181         assertTrue(target.isIdenticalPrivateDns(source));
182 
183         assertTrue(source.isIdenticalValidatedPrivateDnses(target));
184         assertTrue(target.isIdenticalValidatedPrivateDnses(source));
185 
186         assertTrue(source.isIdenticalPcscfs(target));
187         assertTrue(target.isIdenticalPcscfs(source));
188 
189         assertTrue(source.isIdenticalRoutes(target));
190         assertTrue(target.isIdenticalRoutes(source));
191 
192         assertTrue(source.isIdenticalHttpProxy(target));
193         assertTrue(target.isIdenticalHttpProxy(source));
194 
195         assertTrue(source.isIdenticalStackedLinks(target));
196         assertTrue(target.isIdenticalStackedLinks(source));
197 
198         assertTrue(source.isIdenticalMtu(target));
199         assertTrue(target.isIdenticalMtu(source));
200 
201         assertTrue(source.isIdenticalTcpBufferSizes(target));
202         assertTrue(target.isIdenticalTcpBufferSizes(source));
203 
204         assertTrue(source.isIdenticalDhcpServerAddress(target));
205         assertTrue(source.isIdenticalDhcpServerAddress(source));
206 
207         assertTrue(source.isIdenticalWakeOnLan(target));
208         assertTrue(target.isIdenticalWakeOnLan(source));
209 
210         assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
211         assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
212 
213         assertTrue(source.isIdenticalCaptivePortalData(target));
214         assertTrue(target.isIdenticalCaptivePortalData(source));
215 
216         // Check result of equals().
217         assertTrue(source.equals(target));
218         assertTrue(target.equals(source));
219 
220         // Check hashCode.
221         assertEquals(source.hashCode(), target.hashCode());
222     }
223 
224     @Test
testEqualsNull()225     public void testEqualsNull() {
226         LinkProperties source = new LinkProperties();
227         LinkProperties target = new LinkProperties();
228 
229         assertFalse(source == target);
230         assertLinkPropertiesEqual(source, target);
231     }
232 
233     @Test
testEqualsSameOrder()234     public void testEqualsSameOrder() throws Exception {
235         LinkProperties source = new LinkProperties();
236         source.setInterfaceName(NAME);
237         // set 2 link addresses
238         source.addLinkAddress(LINKADDRV4);
239         source.addLinkAddress(LINKADDRV6);
240         // set 2 dnses
241         source.addDnsServer(DNS1);
242         source.addDnsServer(DNS2);
243         // set 1 pcscf
244         source.addPcscfServer(PCSCFV6);
245         // set 2 gateways
246         source.addRoute(new RouteInfo(GATEWAY1));
247         source.addRoute(new RouteInfo(GATEWAY2));
248         source.setMtu(MTU);
249 
250         LinkProperties target = new LinkProperties();
251 
252         // All fields are same
253         target.setInterfaceName(NAME);
254         target.addLinkAddress(LINKADDRV4);
255         target.addLinkAddress(LINKADDRV6);
256         target.addDnsServer(DNS1);
257         target.addDnsServer(DNS2);
258         target.addPcscfServer(PCSCFV6);
259         target.addRoute(new RouteInfo(GATEWAY1));
260         target.addRoute(new RouteInfo(GATEWAY2));
261         target.setMtu(MTU);
262 
263         assertLinkPropertiesEqual(source, target);
264 
265         target.clear();
266         // change Interface Name
267         target.setInterfaceName("qmi1");
268         target.addLinkAddress(LINKADDRV4);
269         target.addLinkAddress(LINKADDRV6);
270         target.addDnsServer(DNS1);
271         target.addDnsServer(DNS2);
272         target.addPcscfServer(PCSCFV6);
273         target.addRoute(new RouteInfo(GATEWAY1));
274         target.addRoute(new RouteInfo(GATEWAY2));
275         target.setMtu(MTU);
276         assertFalse(source.equals(target));
277 
278         target.clear();
279         target.setInterfaceName(NAME);
280         // change link addresses
281         target.addLinkAddress(new LinkAddress(address("75.208.6.2"), 32));
282         target.addLinkAddress(LINKADDRV6);
283         target.addDnsServer(DNS1);
284         target.addDnsServer(DNS2);
285         target.addPcscfServer(PCSCFV6);
286         target.addRoute(new RouteInfo(GATEWAY1));
287         target.addRoute(new RouteInfo(GATEWAY2));
288         target.setMtu(MTU);
289         assertFalse(source.equals(target));
290 
291         target.clear();
292         target.setInterfaceName(NAME);
293         target.addLinkAddress(LINKADDRV4);
294         target.addLinkAddress(LINKADDRV6);
295         // change dnses
296         target.addDnsServer(address("75.208.7.2"));
297         target.addDnsServer(DNS2);
298         target.addPcscfServer(PCSCFV6);
299         target.addRoute(new RouteInfo(GATEWAY1));
300         target.addRoute(new RouteInfo(GATEWAY2));
301         target.setMtu(MTU);
302         assertFalse(source.equals(target));
303 
304         target.clear();
305         target.setInterfaceName(NAME);
306         target.addLinkAddress(LINKADDRV4);
307         target.addLinkAddress(LINKADDRV6);
308         target.addDnsServer(address("75.208.7.2"));
309         target.addDnsServer(DNS2);
310         // change pcscf
311         target.addPcscfServer(address("2001::1"));
312         target.addRoute(new RouteInfo(GATEWAY1));
313         target.addRoute(new RouteInfo(GATEWAY2));
314         target.setMtu(MTU);
315         assertFalse(source.equals(target));
316 
317         target.clear();
318         target.setInterfaceName(NAME);
319         target.addLinkAddress(LINKADDRV4);
320         target.addLinkAddress(LINKADDRV6);
321         target.addDnsServer(DNS1);
322         target.addDnsServer(DNS2);
323         // change gateway
324         target.addRoute(new RouteInfo(address("75.208.8.2")));
325         target.setMtu(MTU);
326         target.addRoute(new RouteInfo(GATEWAY2));
327         assertFalse(source.equals(target));
328 
329         target.clear();
330         target.setInterfaceName(NAME);
331         target.addLinkAddress(LINKADDRV4);
332         target.addLinkAddress(LINKADDRV6);
333         target.addDnsServer(DNS1);
334         target.addDnsServer(DNS2);
335         target.addRoute(new RouteInfo(GATEWAY1));
336         target.addRoute(new RouteInfo(GATEWAY2));
337         // change mtu
338         target.setMtu(1440);
339         assertFalse(source.equals(target));
340     }
341 
342     @Test
testEqualsDifferentOrder()343     public void testEqualsDifferentOrder() throws Exception {
344         LinkProperties source = new LinkProperties();
345         source.setInterfaceName(NAME);
346         // set 2 link addresses
347         source.addLinkAddress(LINKADDRV4);
348         source.addLinkAddress(LINKADDRV6);
349         // set 2 dnses
350         source.addDnsServer(DNS1);
351         source.addDnsServer(DNS2);
352         // set 2 gateways
353         source.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
354         source.addRoute(new RouteInfo(GATEWAY2));
355         source.setMtu(MTU);
356 
357         LinkProperties target = new LinkProperties();
358         // Exchange order
359         target.setInterfaceName(NAME);
360         target.addLinkAddress(LINKADDRV6);
361         target.addLinkAddress(LINKADDRV4);
362         target.addDnsServer(DNS2);
363         target.addDnsServer(DNS1);
364         target.addRoute(new RouteInfo(GATEWAY2));
365         target.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
366         target.setMtu(MTU);
367 
368         assertLinkPropertiesEqual(source, target);
369     }
370 
371     @Test
testEqualsDuplicated()372     public void testEqualsDuplicated() throws Exception {
373         LinkProperties source = new LinkProperties();
374         // set 3 link addresses, eg, [A, A, B]
375         source.addLinkAddress(LINKADDRV4);
376         source.addLinkAddress(LINKADDRV4);
377         source.addLinkAddress(LINKADDRV6);
378 
379         LinkProperties target = new LinkProperties();
380         // set 3 link addresses, eg, [A, B, B]
381         target.addLinkAddress(LINKADDRV4);
382         target.addLinkAddress(LINKADDRV6);
383         target.addLinkAddress(LINKADDRV6);
384 
385         assertLinkPropertiesEqual(source, target);
386     }
387 
assertAllRoutesHaveInterface(String iface, LinkProperties lp)388     private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
389         for (RouteInfo r : lp.getRoutes()) {
390             assertEquals(iface, r.getInterface());
391         }
392     }
393 
assertAllRoutesNotHaveInterface(String iface, LinkProperties lp)394     private void assertAllRoutesNotHaveInterface(String iface, LinkProperties lp) {
395         for (RouteInfo r : lp.getRoutes()) {
396             assertNotEquals(iface, r.getInterface());
397         }
398     }
399 
400     @Test
testRouteInterfaces()401     public void testRouteInterfaces() {
402         LinkAddress prefix1 = new LinkAddress(address("2001:db8:1::"), 48);
403         LinkAddress prefix2 = new LinkAddress(address("2001:db8:2::"), 48);
404         InetAddress address = ADDRV6;
405 
406         // Add a route with no interface to a LinkProperties with no interface. No errors.
407         LinkProperties lp = new LinkProperties();
408         RouteInfo r = new RouteInfo(prefix1, address, null);
409         assertTrue(lp.addRoute(r));
410         assertEquals(1, lp.getRoutes().size());
411         assertAllRoutesHaveInterface(null, lp);
412 
413         // Adding the same route twice has no effect.
414         assertFalse(lp.addRoute(r));
415         assertEquals(1, lp.getRoutes().size());
416 
417         // Add a route with an interface. Expect an exception.
418         r = new RouteInfo(prefix2, address, "wlan0");
419         try {
420           lp.addRoute(r);
421           fail("Adding wlan0 route to LP with no interface, expect exception");
422         } catch (IllegalArgumentException expected) {}
423 
424         // Change the interface name. All the routes should change their interface name too.
425         lp.setInterfaceName("rmnet0");
426         assertAllRoutesHaveInterface("rmnet0", lp);
427         assertAllRoutesNotHaveInterface(null, lp);
428         assertAllRoutesNotHaveInterface("wlan0", lp);
429 
430         // Now add a route with the wrong interface. This causes an exception too.
431         try {
432           lp.addRoute(r);
433           fail("Adding wlan0 route to rmnet0 LP, expect exception");
434         } catch (IllegalArgumentException expected) {}
435 
436         // If the interface name matches, the route is added.
437         r = new RouteInfo(prefix2, null, "wlan0");
438         lp.setInterfaceName("wlan0");
439         lp.addRoute(r);
440         assertEquals(2, lp.getRoutes().size());
441         assertAllRoutesHaveInterface("wlan0", lp);
442         assertAllRoutesNotHaveInterface("rmnet0", lp);
443 
444         // Routes with null interfaces are converted to wlan0.
445         r = RouteInfo.makeHostRoute(ADDRV6, null);
446         lp.addRoute(r);
447         assertEquals(3, lp.getRoutes().size());
448         assertAllRoutesHaveInterface("wlan0", lp);
449 
450         // Check routes are updated correctly when calling setInterfaceName.
451         LinkProperties lp2 = new LinkProperties(lp);
452         assertAllRoutesHaveInterface("wlan0", lp2);
453         final CompareResult<RouteInfo> cr1 =
454                 new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
455         assertEquals(0, cr1.added.size());
456         assertEquals(0, cr1.removed.size());
457 
458         lp2.setInterfaceName("p2p0");
459         assertAllRoutesHaveInterface("p2p0", lp2);
460         assertAllRoutesNotHaveInterface("wlan0", lp2);
461         final CompareResult<RouteInfo> cr2 =
462                 new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
463         assertEquals(3, cr2.added.size());
464         assertEquals(3, cr2.removed.size());
465 
466         // Remove route with incorrect interface, no route removed.
467         lp.removeRoute(new RouteInfo(prefix2, null, null));
468         assertEquals(3, lp.getRoutes().size());
469 
470         // Check remove works when interface is correct.
471         lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
472         assertEquals(2, lp.getRoutes().size());
473         assertAllRoutesHaveInterface("wlan0", lp);
474         assertAllRoutesNotHaveInterface("p2p0", lp);
475     }
476 
477     @Test
testStackedInterfaces()478     public void testStackedInterfaces() {
479         LinkProperties rmnet0 = new LinkProperties();
480         rmnet0.setInterfaceName("rmnet0");
481         rmnet0.addLinkAddress(LINKADDRV6);
482 
483         LinkProperties clat4 = new LinkProperties();
484         clat4.setInterfaceName("clat4");
485         clat4.addLinkAddress(LINKADDRV4);
486 
487         assertEquals(0, rmnet0.getStackedLinks().size());
488         assertEquals(1, rmnet0.getAddresses().size());
489         assertEquals(1, rmnet0.getLinkAddresses().size());
490         assertEquals(1, rmnet0.getAllAddresses().size());
491         assertEquals(1, rmnet0.getAllLinkAddresses().size());
492         assertEquals(1, rmnet0.getAllInterfaceNames().size());
493         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
494 
495         rmnet0.addStackedLink(clat4);
496         assertEquals(1, rmnet0.getStackedLinks().size());
497         assertEquals(1, rmnet0.getAddresses().size());
498         assertEquals(1, rmnet0.getLinkAddresses().size());
499         assertEquals(2, rmnet0.getAllAddresses().size());
500         assertEquals(2, rmnet0.getAllLinkAddresses().size());
501         assertEquals(2, rmnet0.getAllInterfaceNames().size());
502         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
503         assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
504 
505         rmnet0.addStackedLink(clat4);
506         assertEquals(1, rmnet0.getStackedLinks().size());
507         assertEquals(1, rmnet0.getAddresses().size());
508         assertEquals(1, rmnet0.getLinkAddresses().size());
509         assertEquals(2, rmnet0.getAllAddresses().size());
510         assertEquals(2, rmnet0.getAllLinkAddresses().size());
511         assertEquals(2, rmnet0.getAllInterfaceNames().size());
512         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
513         assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
514 
515         assertEquals(0, clat4.getStackedLinks().size());
516 
517         // Modify an item in the returned collection to see what happens.
518         for (LinkProperties link : rmnet0.getStackedLinks()) {
519             if (link.getInterfaceName().equals("clat4")) {
520                link.setInterfaceName("newname");
521             }
522         }
523         for (LinkProperties link : rmnet0.getStackedLinks()) {
524             assertFalse("newname".equals(link.getInterfaceName()));
525         }
526 
527         assertTrue(rmnet0.removeStackedLink("clat4"));
528         assertEquals(0, rmnet0.getStackedLinks().size());
529         assertEquals(1, rmnet0.getAddresses().size());
530         assertEquals(1, rmnet0.getLinkAddresses().size());
531         assertEquals(1, rmnet0.getAllAddresses().size());
532         assertEquals(1, rmnet0.getAllLinkAddresses().size());
533         assertEquals(1, rmnet0.getAllInterfaceNames().size());
534         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
535 
536         assertFalse(rmnet0.removeStackedLink("clat4"));
537     }
538 
getFirstLinkAddress(LinkProperties lp)539     private LinkAddress getFirstLinkAddress(LinkProperties lp) {
540         return lp.getLinkAddresses().iterator().next();
541     }
542 
543     @Test
testAddressMethods()544     public void testAddressMethods() {
545         LinkProperties lp = new LinkProperties();
546 
547         // No addresses.
548         assertFalse(lp.hasIpv4Address());
549         assertFalse(lp.hasGlobalIpv6Address());
550 
551         // Addresses on stacked links don't count.
552         LinkProperties stacked = new LinkProperties();
553         stacked.setInterfaceName("stacked");
554         lp.addStackedLink(stacked);
555         stacked.addLinkAddress(LINKADDRV4);
556         stacked.addLinkAddress(LINKADDRV6);
557         assertTrue(stacked.hasIpv4Address());
558         assertTrue(stacked.hasGlobalIpv6Address());
559         assertFalse(lp.hasIpv4Address());
560         assertFalse(lp.hasGlobalIpv6Address());
561         lp.removeStackedLink("stacked");
562         assertFalse(lp.hasIpv4Address());
563         assertFalse(lp.hasGlobalIpv6Address());
564 
565         // Addresses on the base link.
566         // Check the return values of hasIpvXAddress and ensure the add/remove methods return true
567         // iff something changes.
568         assertEquals(0, lp.getLinkAddresses().size());
569         assertTrue(lp.addLinkAddress(LINKADDRV6));
570         assertEquals(1, lp.getLinkAddresses().size());
571         assertFalse(lp.hasIpv4Address());
572         assertTrue(lp.hasGlobalIpv6Address());
573 
574         assertTrue(lp.removeLinkAddress(LINKADDRV6));
575         assertEquals(0, lp.getLinkAddresses().size());
576 
577         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
578         assertEquals(1, lp.getLinkAddresses().size());
579         assertFalse(lp.hasGlobalIpv6Address());
580 
581         assertTrue(lp.addLinkAddress(LINKADDRV4));
582         assertEquals(2, lp.getLinkAddresses().size());
583         assertTrue(lp.hasIpv4Address());
584         assertFalse(lp.hasGlobalIpv6Address());
585 
586         assertTrue(lp.addLinkAddress(LINKADDRV6));
587         assertEquals(3, lp.getLinkAddresses().size());
588         assertTrue(lp.hasIpv4Address());
589         assertTrue(lp.hasGlobalIpv6Address());
590 
591         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
592         assertEquals(2, lp.getLinkAddresses().size());
593         assertTrue(lp.hasIpv4Address());
594         assertTrue(lp.hasGlobalIpv6Address());
595 
596         // Adding an address twice has no effect.
597         // Removing an address that's not present has no effect.
598         assertFalse(lp.addLinkAddress(LINKADDRV4));
599         assertEquals(2, lp.getLinkAddresses().size());
600         assertTrue(lp.hasIpv4Address());
601         assertTrue(lp.removeLinkAddress(LINKADDRV4));
602         assertEquals(1, lp.getLinkAddresses().size());
603         assertFalse(lp.hasIpv4Address());
604         assertFalse(lp.removeLinkAddress(LINKADDRV4));
605         assertEquals(1, lp.getLinkAddresses().size());
606 
607         // Adding an address that's already present but with different properties causes the
608         // existing address to be updated and returns true.
609         // Start with only LINKADDRV6.
610         assertEquals(1, lp.getLinkAddresses().size());
611         assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
612 
613         // Create a LinkAddress object for the same address, but with different flags.
614         LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
615                 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
616         assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
617         assertFalse(deprecated.equals(LINKADDRV6));
618 
619         // Check that adding it updates the existing address instead of adding a new one.
620         assertTrue(lp.addLinkAddress(deprecated));
621         assertEquals(1, lp.getLinkAddresses().size());
622         assertEquals(deprecated, getFirstLinkAddress(lp));
623         assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
624 
625         // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
626         assertTrue(lp.removeLinkAddress(LINKADDRV6));
627         assertEquals(0, lp.getLinkAddresses().size());
628     }
629 
630     @Test
testLinkAddresses()631     public void testLinkAddresses() {
632         final LinkProperties lp = new LinkProperties();
633         lp.addLinkAddress(LINKADDRV4);
634         lp.addLinkAddress(LINKADDRV6);
635 
636         final LinkProperties lp2 = new LinkProperties();
637         lp2.addLinkAddress(LINKADDRV6);
638 
639         final LinkProperties lp3 = new LinkProperties();
640         final List<LinkAddress> linkAddresses = Arrays.asList(LINKADDRV4);
641         lp3.setLinkAddresses(linkAddresses);
642 
643         assertFalse(lp.equals(lp2));
644         assertFalse(lp2.equals(lp3));
645 
646         lp.removeLinkAddress(LINKADDRV4);
647         assertTrue(lp.equals(lp2));
648 
649         lp2.setLinkAddresses(lp3.getLinkAddresses());
650         assertTrue(lp2.equals(lp3));
651     }
652 
653     @Test
testNat64Prefix()654     public void testNat64Prefix() throws Exception {
655         LinkProperties lp = new LinkProperties();
656         lp.addLinkAddress(LINKADDRV4);
657         lp.addLinkAddress(LINKADDRV6);
658 
659         assertNull(lp.getNat64Prefix());
660 
661         IpPrefix p = new IpPrefix("64:ff9b::/96");
662         lp.setNat64Prefix(p);
663         assertEquals(p, lp.getNat64Prefix());
664 
665         p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
666         lp.setNat64Prefix(p);
667         assertEquals(p, lp.getNat64Prefix());
668 
669         p = new IpPrefix("2001:db8:a:b:1:2::/80");
670         try {
671             lp.setNat64Prefix(p);
672         } catch (IllegalArgumentException expected) {
673         }
674 
675         p = new IpPrefix("64:ff9b::/64");
676         try {
677             lp.setNat64Prefix(p);
678         } catch (IllegalArgumentException expected) {
679         }
680 
681         assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
682 
683         lp.setNat64Prefix(null);
684         assertNull(lp.getNat64Prefix());
685     }
686 
687     @Test
testIsProvisioned()688     public void testIsProvisioned() {
689         LinkProperties lp4 = new LinkProperties();
690         assertFalse("v4only:empty", lp4.isProvisioned());
691         lp4.addLinkAddress(LINKADDRV4);
692         assertFalse("v4only:addr-only", lp4.isProvisioned());
693         lp4.addDnsServer(DNS1);
694         assertFalse("v4only:addr+dns", lp4.isProvisioned());
695         lp4.addRoute(new RouteInfo(GATEWAY1));
696         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
697         assertTrue("v4only:addr+dns+route", lp4.isIpv4Provisioned());
698         assertFalse("v4only:addr+dns+route", lp4.isIpv6Provisioned());
699 
700         LinkProperties lp6 = new LinkProperties();
701         assertFalse("v6only:empty", lp6.isProvisioned());
702         lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
703         assertFalse("v6only:fe80-only", lp6.isProvisioned());
704         lp6.addDnsServer(DNS6);
705         assertFalse("v6only:fe80+dns", lp6.isProvisioned());
706         lp6.addRoute(new RouteInfo(GATEWAY61));
707         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
708         lp6.addLinkAddress(LINKADDRV6);
709         assertTrue("v6only:fe80+global+dns+route", lp6.isIpv6Provisioned());
710         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
711         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
712         assertFalse("v6only:global+dns+route", lp6.isIpv4Provisioned());
713         assertTrue("v6only:global+dns+route", lp6.isIpv6Provisioned());
714         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
715 
716         LinkProperties lp46 = new LinkProperties();
717         lp46.addLinkAddress(LINKADDRV4);
718         lp46.addLinkAddress(LINKADDRV6);
719         lp46.addDnsServer(DNS1);
720         lp46.addDnsServer(DNS6);
721         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
722         lp46.addRoute(new RouteInfo(GATEWAY1));
723         assertTrue("dualstack:v4-provisioned", lp46.isIpv4Provisioned());
724         assertFalse("dualstack:v4-provisioned", lp46.isIpv6Provisioned());
725         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
726         lp46.addRoute(new RouteInfo(GATEWAY61));
727         assertTrue("dualstack:both-provisioned", lp46.isIpv4Provisioned());
728         assertTrue("dualstack:both-provisioned", lp46.isIpv6Provisioned());
729         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
730 
731         // A link with an IPv6 address and default route, but IPv4 DNS server.
732         LinkProperties mixed = new LinkProperties();
733         mixed.addLinkAddress(LINKADDRV6);
734         mixed.addDnsServer(DNS1);
735         mixed.addRoute(new RouteInfo(GATEWAY61));
736         assertFalse("mixed:addr6+route6+dns4", mixed.isIpv4Provisioned());
737         assertFalse("mixed:addr6+route6+dns4", mixed.isIpv6Provisioned());
738         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
739     }
740 
741     @Test
testCompareProvisioning()742     public void testCompareProvisioning() {
743         LinkProperties v4lp = new LinkProperties();
744         v4lp.addLinkAddress(LINKADDRV4);
745         v4lp.addRoute(new RouteInfo(GATEWAY1));
746         v4lp.addDnsServer(DNS1);
747         assertTrue(v4lp.isProvisioned());
748 
749         LinkProperties v4r = new LinkProperties(v4lp);
750         v4r.removeDnsServer(DNS1);
751         assertFalse(v4r.isProvisioned());
752 
753         assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
754                 LinkProperties.compareProvisioning(v4r, v4r));
755         assertEquals(ProvisioningChange.LOST_PROVISIONING,
756                 LinkProperties.compareProvisioning(v4lp, v4r));
757         assertEquals(ProvisioningChange.GAINED_PROVISIONING,
758                 LinkProperties.compareProvisioning(v4r, v4lp));
759         assertEquals(ProvisioningChange.STILL_PROVISIONED,
760                 LinkProperties.compareProvisioning(v4lp, v4lp));
761 
762         // Check that losing IPv4 provisioning on a dualstack network is
763         // seen as a total loss of provisioning.
764         LinkProperties v6lp = new LinkProperties();
765         v6lp.addLinkAddress(LINKADDRV6);
766         v6lp.addRoute(new RouteInfo(GATEWAY61));
767         v6lp.addDnsServer(DNS6);
768         assertFalse(v6lp.isIpv4Provisioned());
769         assertTrue(v6lp.isIpv6Provisioned());
770         assertTrue(v6lp.isProvisioned());
771 
772         LinkProperties v46lp = new LinkProperties(v6lp);
773         v46lp.addLinkAddress(LINKADDRV4);
774         v46lp.addRoute(new RouteInfo(GATEWAY1));
775         v46lp.addDnsServer(DNS1);
776         assertTrue(v46lp.isIpv4Provisioned());
777         assertTrue(v46lp.isIpv6Provisioned());
778         assertTrue(v46lp.isProvisioned());
779 
780         assertEquals(ProvisioningChange.STILL_PROVISIONED,
781                 LinkProperties.compareProvisioning(v4lp, v46lp));
782         assertEquals(ProvisioningChange.STILL_PROVISIONED,
783                 LinkProperties.compareProvisioning(v6lp, v46lp));
784         assertEquals(ProvisioningChange.LOST_PROVISIONING,
785                 LinkProperties.compareProvisioning(v46lp, v6lp));
786         assertEquals(ProvisioningChange.LOST_PROVISIONING,
787                 LinkProperties.compareProvisioning(v46lp, v4lp));
788 
789         // Check that losing and gaining a secondary router does not change
790         // the provisioning status.
791         LinkProperties v6lp2 = new LinkProperties(v6lp);
792         v6lp2.addRoute(new RouteInfo(GATEWAY62));
793         assertTrue(v6lp2.isProvisioned());
794 
795         assertEquals(ProvisioningChange.STILL_PROVISIONED,
796                 LinkProperties.compareProvisioning(v6lp2, v6lp));
797         assertEquals(ProvisioningChange.STILL_PROVISIONED,
798                 LinkProperties.compareProvisioning(v6lp, v6lp2));
799     }
800 
801     @Test
testIsReachable()802     public void testIsReachable() {
803         final LinkProperties v4lp = new LinkProperties();
804         assertFalse(v4lp.isReachable(DNS1));
805         assertFalse(v4lp.isReachable(DNS2));
806 
807         // Add an on-link route, making the on-link DNS server reachable,
808         // but there is still no IPv4 address.
809         assertTrue(v4lp.addRoute(new RouteInfo(new IpPrefix(address("75.208.0.0"), 16))));
810         assertFalse(v4lp.isReachable(DNS1));
811         assertFalse(v4lp.isReachable(DNS2));
812 
813         // Adding an IPv4 address (right now, any IPv4 address) means we use
814         // the routes to compute likely reachability.
815         assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
816         assertTrue(v4lp.isReachable(DNS1));
817         assertFalse(v4lp.isReachable(DNS2));
818 
819         // Adding a default route makes the off-link DNS server reachable.
820         assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
821         assertTrue(v4lp.isReachable(DNS1));
822         assertTrue(v4lp.isReachable(DNS2));
823 
824         final LinkProperties v6lp = new LinkProperties();
825         final InetAddress kLinkLocalDns = address("fe80::6:1");
826         final InetAddress kLinkLocalDnsWithScope = address("fe80::6:2%43");
827         final InetAddress kOnLinkDns = address("2001:db8:85a3::53");
828         assertFalse(v6lp.isReachable(kLinkLocalDns));
829         assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
830         assertFalse(v6lp.isReachable(kOnLinkDns));
831         assertFalse(v6lp.isReachable(DNS6));
832 
833         // Add a link-local route, making the link-local DNS servers reachable. Because
834         // we assume the presence of an IPv6 link-local address, link-local DNS servers
835         // are considered reachable, but only those with a non-zero scope identifier.
836         assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("fe80::"), 64))));
837         assertFalse(v6lp.isReachable(kLinkLocalDns));
838         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
839         assertFalse(v6lp.isReachable(kOnLinkDns));
840         assertFalse(v6lp.isReachable(DNS6));
841 
842         // Add a link-local address--nothing changes.
843         assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
844         assertFalse(v6lp.isReachable(kLinkLocalDns));
845         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
846         assertFalse(v6lp.isReachable(kOnLinkDns));
847         assertFalse(v6lp.isReachable(DNS6));
848 
849         // Add a global route on link, but no global address yet. DNS servers reachable
850         // via a route that doesn't require a gateway: give them the benefit of the
851         // doubt and hope the link-local source address suffices for communication.
852         assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("2001:db8:85a3::"), 64))));
853         assertFalse(v6lp.isReachable(kLinkLocalDns));
854         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
855         assertTrue(v6lp.isReachable(kOnLinkDns));
856         assertFalse(v6lp.isReachable(DNS6));
857 
858         // Add a global address; the on-link global address DNS server is (still)
859         // presumed reachable.
860         assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
861         assertFalse(v6lp.isReachable(kLinkLocalDns));
862         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
863         assertTrue(v6lp.isReachable(kOnLinkDns));
864         assertFalse(v6lp.isReachable(DNS6));
865 
866         // Adding a default route makes the off-link DNS server reachable.
867         assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
868         assertFalse(v6lp.isReachable(kLinkLocalDns));
869         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
870         assertTrue(v6lp.isReachable(kOnLinkDns));
871         assertTrue(v6lp.isReachable(DNS6));
872 
873         // Check isReachable on stacked links. This requires that the source IP address be assigned
874         // on the interface returned by the route lookup.
875         LinkProperties stacked = new LinkProperties();
876 
877         // Can't add a stacked link without an interface name.
878         stacked.setInterfaceName("v4-test0");
879         v6lp.addStackedLink(stacked);
880 
881         InetAddress stackedAddress = address("192.0.0.4");
882         LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
883         assertFalse(v6lp.isReachable(stackedAddress));
884         stacked.addLinkAddress(stackedLinkAddress);
885         assertFalse(v6lp.isReachable(stackedAddress));
886         stacked.addRoute(new RouteInfo(stackedLinkAddress));
887         assertTrue(stacked.isReachable(stackedAddress));
888         assertTrue(v6lp.isReachable(stackedAddress));
889 
890         assertFalse(v6lp.isReachable(DNS1));
891         stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
892         assertTrue(v6lp.isReachable(DNS1));
893     }
894 
895     @Test
testLinkPropertiesEnsureDirectlyConnectedRoutes()896     public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
897         // IPv4 case: no route added initially
898         LinkProperties rmnet0 = new LinkProperties();
899         rmnet0.setInterfaceName("rmnet0");
900         rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
901         RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
902                 rmnet0.getInterfaceName());
903 
904         // Since no routes is added explicitly, getAllRoutes() should return empty.
905         assertTrue(rmnet0.getAllRoutes().isEmpty());
906         rmnet0.ensureDirectlyConnectedRoutes();
907         // ensureDirectlyConnectedRoutes() should have added the missing local route.
908         assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
909 
910         // IPv4 case: both direct and default routes added initially
911         LinkProperties rmnet1 = new LinkProperties();
912         rmnet1.setInterfaceName("rmnet1");
913         rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
914         RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, address("10.0.0.1"),
915                 rmnet1.getInterfaceName());
916         RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
917                 rmnet1.getInterfaceName());
918         rmnet1.addRoute(defaultRoute1);
919         rmnet1.addRoute(directRoute1);
920 
921         // Check added routes
922         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
923         // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
924         // route is already part of the configuration.
925         rmnet1.ensureDirectlyConnectedRoutes();
926         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
927 
928         // IPv6 case: only default routes added initially
929         LinkProperties rmnet2 = new LinkProperties();
930         rmnet2.setInterfaceName("rmnet2");
931         rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
932         rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
933         RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, address("2001:db8::1"),
934                 rmnet2.getInterfaceName());
935         RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
936                 rmnet2.getInterfaceName());
937         RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
938                 rmnet2.getInterfaceName());
939         rmnet2.addRoute(defaultRoute2);
940 
941         assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
942         rmnet2.ensureDirectlyConnectedRoutes();
943         assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
944                 rmnet2.getAllRoutes());
945 
946         // Corner case: no interface name
947         LinkProperties rmnet3 = new LinkProperties();
948         rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
949         RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
950                 rmnet3.getInterfaceName());
951 
952         assertTrue(rmnet3.getAllRoutes().isEmpty());
953         rmnet3.ensureDirectlyConnectedRoutes();
954         assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
955     }
956 
assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual)957     private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
958         Set<RouteInfo> expectedSet = new ArraySet<>(expected);
959         Set<RouteInfo> actualSet = new ArraySet<>(actual);
960         // Duplicated entries in actual routes are considered failures
961         assertEquals(actual.size(), actualSet.size());
962 
963         assertEquals(expectedSet, actualSet);
964     }
965 
makeLinkPropertiesForParceling()966     private static LinkProperties makeLinkPropertiesForParceling() {
967         LinkProperties source = new LinkProperties();
968         source.setInterfaceName(NAME);
969 
970         source.addLinkAddress(LINKADDRV4);
971         source.addLinkAddress(LINKADDRV6);
972 
973         source.addDnsServer(DNS1);
974         source.addDnsServer(DNS2);
975         source.addDnsServer(GATEWAY62);
976 
977         source.addPcscfServer(TESTIPV4ADDR);
978         source.addPcscfServer(TESTIPV6ADDR);
979 
980         source.setUsePrivateDns(true);
981         source.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
982 
983         source.setDomains(DOMAINS);
984 
985         source.addRoute(new RouteInfo(GATEWAY1));
986         source.addRoute(new RouteInfo(GATEWAY2));
987 
988         source.addValidatedPrivateDnsServer(DNS6);
989         source.addValidatedPrivateDnsServer(GATEWAY61);
990         source.addValidatedPrivateDnsServer(TESTIPV6ADDR);
991 
992         source.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
993 
994         source.setMtu(MTU);
995 
996         source.setTcpBufferSizes(TCP_BUFFER_SIZES);
997 
998         source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
999 
1000         final LinkProperties stacked = new LinkProperties();
1001         stacked.setInterfaceName("test-stacked");
1002         source.addStackedLink(stacked);
1003 
1004         return source;
1005     }
1006 
1007     @Test @IgnoreAfter(Build.VERSION_CODES.Q)
testLinkPropertiesParcelable_Q()1008     public void testLinkPropertiesParcelable_Q() throws Exception {
1009         final LinkProperties source = makeLinkPropertiesForParceling();
1010         assertParcelingIsLossless(source);
1011     }
1012 
1013     @Test
testLinkPropertiesParcelable()1014     public void testLinkPropertiesParcelable() throws Exception {
1015         final LinkProperties source = makeLinkPropertiesForParceling();
1016 
1017         source.setWakeOnLanSupported(true);
1018         source.setCaptivePortalApiUrl(CAPPORT_API_URL);
1019         source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
1020         source.setDhcpServerAddress((Inet4Address) GATEWAY1);
1021         assertParcelingIsLossless(new LinkProperties(source, true /* parcelSensitiveFields */));
1022 
1023         // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
1024         final LinkProperties sanitized = new LinkProperties(source);
1025         sanitized.setCaptivePortalApiUrl(null);
1026         sanitized.setCaptivePortalData(null);
1027         assertEquals(sanitized, parcelingRoundTrip(source));
1028     }
1029 
1030     // Parceling of the scope was broken until Q-QPR2
1031     @Test
testLinkLocalDnsServerParceling()1032     public void testLinkLocalDnsServerParceling() throws Exception {
1033         final String strAddress = "fe80::1%lo";
1034         final LinkProperties lp = new LinkProperties();
1035         lp.addDnsServer(address(strAddress));
1036         final LinkProperties unparceled = parcelingRoundTrip(lp);
1037         // Inet6Address#equals does not test for the scope id
1038         assertEquals(strAddress, unparceled.getDnsServers().get(0).getHostAddress());
1039     }
1040 
1041     @Test
testParcelUninitialized()1042     public void testParcelUninitialized() throws Exception {
1043         LinkProperties empty = new LinkProperties();
1044         assertParcelingIsLossless(empty);
1045     }
1046 
1047     @Test
testConstructor()1048     public void testConstructor() {
1049         LinkProperties lp = new LinkProperties();
1050         checkEmpty(lp);
1051         assertLinkPropertiesEqual(lp, new LinkProperties(lp));
1052         assertLinkPropertiesEqual(lp, new LinkProperties());
1053 
1054         lp = makeTestObject();
1055         assertLinkPropertiesEqual(lp, new LinkProperties(lp));
1056     }
1057 
1058     @Test
testDnsServers()1059     public void testDnsServers() {
1060         final LinkProperties lp = new LinkProperties();
1061         final List<InetAddress> dnsServers = Arrays.asList(DNS1, DNS2);
1062         lp.setDnsServers(dnsServers);
1063         assertEquals(2, lp.getDnsServers().size());
1064         assertEquals(DNS1, lp.getDnsServers().get(0));
1065         assertEquals(DNS2, lp.getDnsServers().get(1));
1066 
1067         lp.removeDnsServer(DNS1);
1068         assertEquals(1, lp.getDnsServers().size());
1069         assertEquals(DNS2, lp.getDnsServers().get(0));
1070 
1071         lp.addDnsServer(DNS6);
1072         assertEquals(2, lp.getDnsServers().size());
1073         assertEquals(DNS2, lp.getDnsServers().get(0));
1074         assertEquals(DNS6, lp.getDnsServers().get(1));
1075     }
1076 
1077     @Test
testValidatedPrivateDnsServers()1078     public void testValidatedPrivateDnsServers() {
1079         final LinkProperties lp = new LinkProperties();
1080         final List<InetAddress> privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2);
1081         lp.setValidatedPrivateDnsServers(privDnsServers);
1082         assertEquals(2, lp.getValidatedPrivateDnsServers().size());
1083         assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0));
1084         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1));
1085 
1086         lp.removeValidatedPrivateDnsServer(PRIVDNS1);
1087         assertEquals(1, lp.getValidatedPrivateDnsServers().size());
1088         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
1089 
1090         lp.addValidatedPrivateDnsServer(PRIVDNS6);
1091         assertEquals(2, lp.getValidatedPrivateDnsServers().size());
1092         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
1093         assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1));
1094     }
1095 
1096     @Test
testPcscfServers()1097     public void testPcscfServers() {
1098         final LinkProperties lp = new LinkProperties();
1099         final List<InetAddress> pcscfServers = Arrays.asList(PCSCFV4);
1100         lp.setPcscfServers(pcscfServers);
1101         assertEquals(1, lp.getPcscfServers().size());
1102         assertEquals(PCSCFV4, lp.getPcscfServers().get(0));
1103 
1104         lp.removePcscfServer(PCSCFV4);
1105         assertEquals(0, lp.getPcscfServers().size());
1106 
1107         lp.addPcscfServer(PCSCFV6);
1108         assertEquals(1, lp.getPcscfServers().size());
1109         assertEquals(PCSCFV6, lp.getPcscfServers().get(0));
1110     }
1111 
1112     @Test
testTcpBufferSizes()1113     public void testTcpBufferSizes() {
1114         final LinkProperties lp = makeTestObject();
1115         assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes());
1116 
1117         lp.setTcpBufferSizes(null);
1118         assertNull(lp.getTcpBufferSizes());
1119     }
1120 
1121     @Test
testHasIpv6DefaultRoute()1122     public void testHasIpv6DefaultRoute() {
1123         final LinkProperties lp = makeTestObject();
1124         assertFalse(lp.hasIPv6DefaultRoute());
1125 
1126         lp.addRoute(new RouteInfo(GATEWAY61));
1127         assertTrue(lp.hasIPv6DefaultRoute());
1128     }
1129 
1130     @Test
testHttpProxy()1131     public void testHttpProxy() {
1132         final LinkProperties lp = makeTestObject();
1133         assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888)));
1134     }
1135 
1136     @Test
testPrivateDnsServerName()1137     public void testPrivateDnsServerName() {
1138         final LinkProperties lp = makeTestObject();
1139         assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName());
1140 
1141         lp.setPrivateDnsServerName(null);
1142         assertNull(lp.getPrivateDnsServerName());
1143     }
1144 
1145     @Test
testUsePrivateDns()1146     public void testUsePrivateDns() {
1147         final LinkProperties lp = makeTestObject();
1148         assertTrue(lp.isPrivateDnsActive());
1149 
1150         lp.clear();
1151         assertFalse(lp.isPrivateDnsActive());
1152     }
1153 
1154     @Test
testDhcpServerAddress()1155     public void testDhcpServerAddress() {
1156         final LinkProperties lp = makeTestObject();
1157         assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
1158 
1159         lp.clear();
1160         assertNull(lp.getDhcpServerAddress());
1161     }
1162 
1163     @Test
testWakeOnLanSupported()1164     public void testWakeOnLanSupported() {
1165         final LinkProperties lp = makeTestObject();
1166         assertTrue(lp.isWakeOnLanSupported());
1167 
1168         lp.clear();
1169         assertFalse(lp.isWakeOnLanSupported());
1170     }
1171 
1172     @Test
testCaptivePortalApiUrl()1173     public void testCaptivePortalApiUrl() {
1174         final LinkProperties lp = makeTestObject();
1175         assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
1176 
1177         lp.clear();
1178         assertNull(lp.getCaptivePortalApiUrl());
1179     }
1180 
1181     @Test
testCaptivePortalData()1182     public void testCaptivePortalData() {
1183         final LinkProperties lp = makeTestObject();
1184         assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
1185 
1186         lp.clear();
1187         assertNull(lp.getCaptivePortalData());
1188     }
1189 
makeIpv4LinkProperties()1190     private LinkProperties makeIpv4LinkProperties() {
1191         final LinkProperties linkProperties = new LinkProperties();
1192         linkProperties.setInterfaceName(NAME);
1193         linkProperties.addLinkAddress(LINKADDRV4);
1194         linkProperties.addDnsServer(DNS1);
1195         linkProperties.addRoute(new RouteInfo(GATEWAY1));
1196         linkProperties.addRoute(new RouteInfo(GATEWAY2));
1197         return linkProperties;
1198     }
1199 
makeIpv6LinkProperties()1200     private LinkProperties makeIpv6LinkProperties() {
1201         final LinkProperties linkProperties = new LinkProperties();
1202         linkProperties.setInterfaceName(NAME);
1203         linkProperties.addLinkAddress(LINKADDRV6);
1204         linkProperties.addDnsServer(DNS6);
1205         linkProperties.addRoute(new RouteInfo(GATEWAY61));
1206         linkProperties.addRoute(new RouteInfo(GATEWAY62));
1207         return linkProperties;
1208     }
1209 
1210     @Test
testHasIpv4DefaultRoute()1211     public void testHasIpv4DefaultRoute() {
1212         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1213         assertTrue(Ipv4.hasIpv4DefaultRoute());
1214         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1215         assertFalse(Ipv6.hasIpv4DefaultRoute());
1216     }
1217 
1218     @Test
testHasIpv4DnsServer()1219     public void testHasIpv4DnsServer() {
1220         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1221         assertTrue(Ipv4.hasIpv4DnsServer());
1222         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1223         assertFalse(Ipv6.hasIpv4DnsServer());
1224     }
1225 
1226     @Test
testHasIpv6DnsServer()1227     public void testHasIpv6DnsServer() {
1228         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1229         assertFalse(Ipv4.hasIpv6DnsServer());
1230         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1231         assertTrue(Ipv6.hasIpv6DnsServer());
1232     }
1233 
1234     @Test
testHasIpv4UnreachableDefaultRoute()1235     public void testHasIpv4UnreachableDefaultRoute() {
1236         final LinkProperties lp = makeTestObject();
1237         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1238         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1239 
1240         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
1241         assertTrue(lp.hasIpv4UnreachableDefaultRoute());
1242         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1243     }
1244 
1245     @Test
testHasIpv6UnreachableDefaultRoute()1246     public void testHasIpv6UnreachableDefaultRoute() {
1247         final LinkProperties lp = makeTestObject();
1248         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1249         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1250 
1251         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
1252         assertTrue(lp.hasIpv6UnreachableDefaultRoute());
1253         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1254     }
1255 
1256     @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
1257     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
1258     @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
testHasExcludeRoute()1259     public void testHasExcludeRoute() {
1260         LinkProperties lp = new LinkProperties();
1261         lp.setInterfaceName("tun0");
1262         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 24), RTN_UNICAST));
1263         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 0), RTN_UNICAST));
1264         assertFalse(lp.hasExcludeRoute());
1265         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 32), RTN_THROW));
1266         assertTrue(lp.hasExcludeRoute());
1267     }
1268 
1269     @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
1270     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
1271     @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
testRouteAddWithSameKey()1272     public void testRouteAddWithSameKey() throws Exception {
1273         LinkProperties lp = new LinkProperties();
1274         lp.setInterfaceName("wlan0");
1275         final IpPrefix v6 = new IpPrefix("64:ff9b::/96");
1276         lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1280));
1277         assertEquals(1, lp.getRoutes().size());
1278         lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1500));
1279         assertEquals(1, lp.getRoutes().size());
1280         final IpPrefix v4 = new IpPrefix("192.0.2.128/25");
1281         lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_UNICAST, 1460));
1282         assertEquals(2, lp.getRoutes().size());
1283         lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_THROW, 1460));
1284         assertEquals(2, lp.getRoutes().size());
1285     }
1286 
assertExcludeRoutesVisible()1287     private void assertExcludeRoutesVisible() {
1288         final LinkProperties lp = new LinkProperties();
1289         assertEquals(0, lp.getRoutes().size());
1290 
1291         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 31), RTN_UNREACHABLE));
1292         assertEquals(1, lp.getRoutes().size());
1293 
1294         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 127), RTN_THROW));
1295         assertEquals(2, lp.getRoutes().size());
1296 
1297         lp.addRoute(new RouteInfo(GATEWAY1));
1298         assertEquals(3, lp.getRoutes().size());
1299 
1300         lp.addRoute(new RouteInfo(new IpPrefix(DNS6, 127), RTN_UNICAST));
1301         assertEquals(4, lp.getRoutes().size());
1302     }
1303 
assertExcludeRoutesNotVisible()1304     private void assertExcludeRoutesNotVisible() {
1305         final LinkProperties lp = new LinkProperties();
1306         assertEquals(0, lp.getRoutes().size());
1307 
1308         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV4, 31), RTN_UNREACHABLE));
1309         assertEquals(0, lp.getRoutes().size());
1310 
1311         lp.addRoute(new RouteInfo(new IpPrefix(ADDRV6, 127), RTN_THROW));
1312         assertEquals(0, lp.getRoutes().size());
1313 
1314         lp.addRoute(new RouteInfo(GATEWAY1));
1315         assertEquals(1, lp.getRoutes().size());
1316 
1317         lp.addRoute(new RouteInfo(new IpPrefix(DNS6, 127), RTN_UNICAST));
1318         assertEquals(2, lp.getRoutes().size());
1319     }
1320 
checkExcludeRoutesNotVisibleAfterS()1321     private void checkExcludeRoutesNotVisibleAfterS() {
1322         if (!SdkLevel.isAtLeastT()) {
1323             // RTN_THROW routes are visible on R and S when added by the caller (but they are not
1324             // added by the system except for legacy VPN).
1325             // This is uncommon usage but was tested by CTSr12.
1326             assertExcludeRoutesVisible();
1327         } else {
1328             assertExcludeRoutesNotVisible();
1329         }
1330     }
1331 
1332     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
1333     @CtsNetTestCasesMaxTargetSdk31(reason = "Testing behaviour for target SDK 31")
testExcludedRoutesNotVisibleOnTargetSdk31()1334     public void testExcludedRoutesNotVisibleOnTargetSdk31() {
1335         checkExcludeRoutesNotVisibleAfterS();
1336     }
1337 
1338     @Test
testExcludedRoutesVisibleOnTargetSdk33AndAbove()1339     public void testExcludedRoutesVisibleOnTargetSdk33AndAbove() {
1340         assertExcludeRoutesVisible();
1341     }
1342 
1343     @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
1344     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
1345     @EnableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
testExcludedRoutesEnabledByCompatChange()1346     public void testExcludedRoutesEnabledByCompatChange() {
1347         assertExcludeRoutesVisible();
1348     }
1349 
1350     @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2)
1351     @CtsNetTestCasesMaxTargetSdk31(reason = "Compat change cannot be overridden when targeting T+")
1352     @DisableCompatChanges({ConnectivityCompatChanges.EXCLUDED_ROUTES})
testExcludedRoutesDisabledByCompatChange()1353     public void testExcludedRoutesDisabledByCompatChange() {
1354         checkExcludeRoutesNotVisibleAfterS();
1355     }
1356 }
1357