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.ParcelUtilsKt.assertParcelSane;
24 import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
25 import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNotEquals;
30 import static org.junit.Assert.assertNull;
31 import static org.junit.Assert.assertTrue;
32 import static org.junit.Assert.fail;
33 
34 import android.net.LinkProperties.ProvisioningChange;
35 import android.net.util.LinkPropertiesUtils.CompareResult;
36 import android.os.Build;
37 import android.system.OsConstants;
38 import android.util.ArraySet;
39 
40 import androidx.core.os.BuildCompat;
41 import androidx.test.filters.SmallTest;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import com.android.testutils.DevSdkIgnoreRule;
45 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
46 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
47 
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 
52 import java.net.Inet4Address;
53 import java.net.Inet6Address;
54 import java.net.InetAddress;
55 import java.util.ArrayList;
56 import java.util.Arrays;
57 import java.util.Collection;
58 import java.util.Collections;
59 import java.util.List;
60 import java.util.Set;
61 
62 @RunWith(AndroidJUnit4.class)
63 @SmallTest
64 public class LinkPropertiesTest {
65     @Rule
66     public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
67 
68     private static final InetAddress ADDRV4 = address("75.208.6.1");
69     private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
70     private static final InetAddress DNS1 = address("75.208.7.1");
71     private static final InetAddress DNS2 = address("69.78.7.1");
72     private static final InetAddress DNS6 = address("2001:4860:4860::8888");
73     private static final InetAddress PRIVDNS1 = address("1.1.1.1");
74     private static final InetAddress PRIVDNS2 = address("1.0.0.1");
75     private static final InetAddress PRIVDNS6 = address("2606:4700:4700::1111");
76     private static final InetAddress PCSCFV4 = address("10.77.25.37");
77     private static final InetAddress PCSCFV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:1");
78     private static final InetAddress GATEWAY1 = address("75.208.8.1");
79     private static final InetAddress GATEWAY2 = address("69.78.8.1");
80     private static final InetAddress GATEWAY61 = address("fe80::6:0000:613");
81     private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
82     private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
83     private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
84     private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1");
85     private static final String NAME = "qmi0";
86     private static final String DOMAINS = "google.com";
87     private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
88     private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576";
89     private static final int MTU = 1500;
90     private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
91     private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
92     private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
93     private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
94 
95     // CaptivePortalData cannot be in a constant as it does not exist on Q.
96     // The test runner also crashes when scanning for tests if it is a return type.
getCaptivePortalData()97     private static Object getCaptivePortalData() {
98         return new CaptivePortalData.Builder()
99                 .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
100     }
101 
address(String addrString)102     private static InetAddress address(String addrString) {
103         return InetAddresses.parseNumericAddress(addrString);
104     }
105 
isAtLeastR()106     private static boolean isAtLeastR() {
107         // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
108         return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
109     }
110 
checkEmpty(final LinkProperties lp)111     private void checkEmpty(final LinkProperties lp) {
112         assertEquals(0, lp.getAllInterfaceNames().size());
113         assertEquals(0, lp.getAllAddresses().size());
114         assertEquals(0, lp.getDnsServers().size());
115         assertEquals(0, lp.getValidatedPrivateDnsServers().size());
116         assertEquals(0, lp.getPcscfServers().size());
117         assertEquals(0, lp.getAllRoutes().size());
118         assertEquals(0, lp.getAllLinkAddresses().size());
119         assertEquals(0, lp.getStackedLinks().size());
120         assertEquals(0, lp.getMtu());
121         assertNull(lp.getPrivateDnsServerName());
122         assertNull(lp.getDomains());
123         assertNull(lp.getHttpProxy());
124         assertNull(lp.getTcpBufferSizes());
125         assertNull(lp.getNat64Prefix());
126         assertFalse(lp.isProvisioned());
127         assertFalse(lp.isIpv4Provisioned());
128         assertFalse(lp.isIpv6Provisioned());
129         assertFalse(lp.isPrivateDnsActive());
130 
131         if (isAtLeastR()) {
132             assertNull(lp.getDhcpServerAddress());
133             assertFalse(lp.isWakeOnLanSupported());
134             assertNull(lp.getCaptivePortalApiUrl());
135             assertNull(lp.getCaptivePortalData());
136         }
137     }
138 
makeTestObject()139     private LinkProperties makeTestObject() {
140         final LinkProperties lp = new LinkProperties();
141         lp.setInterfaceName(NAME);
142         lp.addLinkAddress(LINKADDRV4);
143         lp.addLinkAddress(LINKADDRV6);
144         lp.addDnsServer(DNS1);
145         lp.addDnsServer(DNS2);
146         lp.addValidatedPrivateDnsServer(PRIVDNS1);
147         lp.addValidatedPrivateDnsServer(PRIVDNS2);
148         lp.setUsePrivateDns(true);
149         lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
150         lp.addPcscfServer(PCSCFV6);
151         lp.setDomains(DOMAINS);
152         lp.addRoute(new RouteInfo(GATEWAY1));
153         lp.addRoute(new RouteInfo(GATEWAY2));
154         lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
155         lp.setMtu(MTU);
156         lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
157         lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
158         if (isAtLeastR()) {
159             lp.setDhcpServerAddress(DHCPSERVER);
160             lp.setWakeOnLanSupported(true);
161             lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
162             lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
163         }
164         return lp;
165     }
166 
assertLinkPropertiesEqual(LinkProperties source, LinkProperties target)167     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
168         // Check implementation of equals(), element by element.
169         assertTrue(source.isIdenticalInterfaceName(target));
170         assertTrue(target.isIdenticalInterfaceName(source));
171 
172         assertTrue(source.isIdenticalAddresses(target));
173         assertTrue(target.isIdenticalAddresses(source));
174 
175         assertTrue(source.isIdenticalDnses(target));
176         assertTrue(target.isIdenticalDnses(source));
177 
178         assertTrue(source.isIdenticalPrivateDns(target));
179         assertTrue(target.isIdenticalPrivateDns(source));
180 
181         assertTrue(source.isIdenticalValidatedPrivateDnses(target));
182         assertTrue(target.isIdenticalValidatedPrivateDnses(source));
183 
184         assertTrue(source.isIdenticalPcscfs(target));
185         assertTrue(target.isIdenticalPcscfs(source));
186 
187         assertTrue(source.isIdenticalRoutes(target));
188         assertTrue(target.isIdenticalRoutes(source));
189 
190         assertTrue(source.isIdenticalHttpProxy(target));
191         assertTrue(target.isIdenticalHttpProxy(source));
192 
193         assertTrue(source.isIdenticalStackedLinks(target));
194         assertTrue(target.isIdenticalStackedLinks(source));
195 
196         assertTrue(source.isIdenticalMtu(target));
197         assertTrue(target.isIdenticalMtu(source));
198 
199         assertTrue(source.isIdenticalTcpBufferSizes(target));
200         assertTrue(target.isIdenticalTcpBufferSizes(source));
201 
202         if (isAtLeastR()) {
203             assertTrue(source.isIdenticalDhcpServerAddress(target));
204             assertTrue(source.isIdenticalDhcpServerAddress(source));
205 
206             assertTrue(source.isIdenticalWakeOnLan(target));
207             assertTrue(target.isIdenticalWakeOnLan(source));
208 
209             assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
210             assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
211 
212             assertTrue(source.isIdenticalCaptivePortalData(target));
213             assertTrue(target.isIdenticalCaptivePortalData(source));
214         }
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 comparisons work.
451         LinkProperties lp2 = new LinkProperties(lp);
452         assertAllRoutesHaveInterface("wlan0", lp2);
453         // LinkProperties#compareAllRoutes exists both in R and before R, but the return type
454         // changed in R, so a test compiled with the R version of LinkProperties cannot run on Q.
455         if (isAtLeastR()) {
456             assertEquals(0, lp.compareAllRoutes(lp2).added.size());
457             assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
458         }
459 
460         lp2.setInterfaceName("p2p0");
461         assertAllRoutesHaveInterface("p2p0", lp2);
462         assertAllRoutesNotHaveInterface("wlan0", lp2);
463         if (isAtLeastR()) {
464             assertEquals(3, lp.compareAllRoutes(lp2).added.size());
465             assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
466         }
467 
468         // Remove route with incorrect interface, no route removed.
469         lp.removeRoute(new RouteInfo(prefix2, null, null));
470         assertEquals(3, lp.getRoutes().size());
471 
472         // Check remove works when interface is correct.
473         lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
474         assertEquals(2, lp.getRoutes().size());
475         assertAllRoutesHaveInterface("wlan0", lp);
476         assertAllRoutesNotHaveInterface("p2p0", lp);
477     }
478 
479     @Test
testStackedInterfaces()480     public void testStackedInterfaces() {
481         LinkProperties rmnet0 = new LinkProperties();
482         rmnet0.setInterfaceName("rmnet0");
483         rmnet0.addLinkAddress(LINKADDRV6);
484 
485         LinkProperties clat4 = new LinkProperties();
486         clat4.setInterfaceName("clat4");
487         clat4.addLinkAddress(LINKADDRV4);
488 
489         assertEquals(0, rmnet0.getStackedLinks().size());
490         assertEquals(1, rmnet0.getAddresses().size());
491         assertEquals(1, rmnet0.getLinkAddresses().size());
492         assertEquals(1, rmnet0.getAllAddresses().size());
493         assertEquals(1, rmnet0.getAllLinkAddresses().size());
494         assertEquals(1, rmnet0.getAllInterfaceNames().size());
495         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
496 
497         rmnet0.addStackedLink(clat4);
498         assertEquals(1, rmnet0.getStackedLinks().size());
499         assertEquals(1, rmnet0.getAddresses().size());
500         assertEquals(1, rmnet0.getLinkAddresses().size());
501         assertEquals(2, rmnet0.getAllAddresses().size());
502         assertEquals(2, rmnet0.getAllLinkAddresses().size());
503         assertEquals(2, rmnet0.getAllInterfaceNames().size());
504         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
505         assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
506 
507         rmnet0.addStackedLink(clat4);
508         assertEquals(1, rmnet0.getStackedLinks().size());
509         assertEquals(1, rmnet0.getAddresses().size());
510         assertEquals(1, rmnet0.getLinkAddresses().size());
511         assertEquals(2, rmnet0.getAllAddresses().size());
512         assertEquals(2, rmnet0.getAllLinkAddresses().size());
513         assertEquals(2, rmnet0.getAllInterfaceNames().size());
514         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
515         assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
516 
517         assertEquals(0, clat4.getStackedLinks().size());
518 
519         // Modify an item in the returned collection to see what happens.
520         for (LinkProperties link : rmnet0.getStackedLinks()) {
521             if (link.getInterfaceName().equals("clat4")) {
522                link.setInterfaceName("newname");
523             }
524         }
525         for (LinkProperties link : rmnet0.getStackedLinks()) {
526             assertFalse("newname".equals(link.getInterfaceName()));
527         }
528 
529         assertTrue(rmnet0.removeStackedLink("clat4"));
530         assertEquals(0, rmnet0.getStackedLinks().size());
531         assertEquals(1, rmnet0.getAddresses().size());
532         assertEquals(1, rmnet0.getLinkAddresses().size());
533         assertEquals(1, rmnet0.getAllAddresses().size());
534         assertEquals(1, rmnet0.getAllLinkAddresses().size());
535         assertEquals(1, rmnet0.getAllInterfaceNames().size());
536         assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
537 
538         assertFalse(rmnet0.removeStackedLink("clat4"));
539     }
540 
getFirstLinkAddress(LinkProperties lp)541     private LinkAddress getFirstLinkAddress(LinkProperties lp) {
542         return lp.getLinkAddresses().iterator().next();
543     }
544 
545     @Test
testAddressMethods()546     public void testAddressMethods() {
547         LinkProperties lp = new LinkProperties();
548 
549         // No addresses.
550         assertFalse(lp.hasIpv4Address());
551         assertFalse(lp.hasGlobalIpv6Address());
552 
553         // Addresses on stacked links don't count.
554         LinkProperties stacked = new LinkProperties();
555         stacked.setInterfaceName("stacked");
556         lp.addStackedLink(stacked);
557         stacked.addLinkAddress(LINKADDRV4);
558         stacked.addLinkAddress(LINKADDRV6);
559         assertTrue(stacked.hasIpv4Address());
560         assertTrue(stacked.hasGlobalIpv6Address());
561         assertFalse(lp.hasIpv4Address());
562         assertFalse(lp.hasGlobalIpv6Address());
563         lp.removeStackedLink("stacked");
564         assertFalse(lp.hasIpv4Address());
565         assertFalse(lp.hasGlobalIpv6Address());
566 
567         // Addresses on the base link.
568         // Check the return values of hasIpvXAddress and ensure the add/remove methods return true
569         // iff something changes.
570         assertEquals(0, lp.getLinkAddresses().size());
571         assertTrue(lp.addLinkAddress(LINKADDRV6));
572         assertEquals(1, lp.getLinkAddresses().size());
573         assertFalse(lp.hasIpv4Address());
574         assertTrue(lp.hasGlobalIpv6Address());
575 
576         assertTrue(lp.removeLinkAddress(LINKADDRV6));
577         assertEquals(0, lp.getLinkAddresses().size());
578 
579         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
580         assertEquals(1, lp.getLinkAddresses().size());
581         assertFalse(lp.hasGlobalIpv6Address());
582 
583         assertTrue(lp.addLinkAddress(LINKADDRV4));
584         assertEquals(2, lp.getLinkAddresses().size());
585         assertTrue(lp.hasIpv4Address());
586         assertFalse(lp.hasGlobalIpv6Address());
587 
588         assertTrue(lp.addLinkAddress(LINKADDRV6));
589         assertEquals(3, lp.getLinkAddresses().size());
590         assertTrue(lp.hasIpv4Address());
591         assertTrue(lp.hasGlobalIpv6Address());
592 
593         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
594         assertEquals(2, lp.getLinkAddresses().size());
595         assertTrue(lp.hasIpv4Address());
596         assertTrue(lp.hasGlobalIpv6Address());
597 
598         // Adding an address twice has no effect.
599         // Removing an address that's not present has no effect.
600         assertFalse(lp.addLinkAddress(LINKADDRV4));
601         assertEquals(2, lp.getLinkAddresses().size());
602         assertTrue(lp.hasIpv4Address());
603         assertTrue(lp.removeLinkAddress(LINKADDRV4));
604         assertEquals(1, lp.getLinkAddresses().size());
605         assertFalse(lp.hasIpv4Address());
606         assertFalse(lp.removeLinkAddress(LINKADDRV4));
607         assertEquals(1, lp.getLinkAddresses().size());
608 
609         // Adding an address that's already present but with different properties causes the
610         // existing address to be updated and returns true.
611         // Start with only LINKADDRV6.
612         assertEquals(1, lp.getLinkAddresses().size());
613         assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
614 
615         // Create a LinkAddress object for the same address, but with different flags.
616         LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
617                 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
618         assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
619         assertFalse(deprecated.equals(LINKADDRV6));
620 
621         // Check that adding it updates the existing address instead of adding a new one.
622         assertTrue(lp.addLinkAddress(deprecated));
623         assertEquals(1, lp.getLinkAddresses().size());
624         assertEquals(deprecated, getFirstLinkAddress(lp));
625         assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
626 
627         // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
628         assertTrue(lp.removeLinkAddress(LINKADDRV6));
629         assertEquals(0, lp.getLinkAddresses().size());
630     }
631 
632     @Test
testLinkAddresses()633     public void testLinkAddresses() {
634         final LinkProperties lp = new LinkProperties();
635         lp.addLinkAddress(LINKADDRV4);
636         lp.addLinkAddress(LINKADDRV6);
637 
638         final LinkProperties lp2 = new LinkProperties();
639         lp2.addLinkAddress(LINKADDRV6);
640 
641         final LinkProperties lp3 = new LinkProperties();
642         final List<LinkAddress> linkAddresses = Arrays.asList(LINKADDRV4);
643         lp3.setLinkAddresses(linkAddresses);
644 
645         assertFalse(lp.equals(lp2));
646         assertFalse(lp2.equals(lp3));
647 
648         lp.removeLinkAddress(LINKADDRV4);
649         assertTrue(lp.equals(lp2));
650 
651         lp2.setLinkAddresses(lp3.getLinkAddresses());
652         assertTrue(lp2.equals(lp3));
653     }
654 
655     @Test
testNat64Prefix()656     public void testNat64Prefix() throws Exception {
657         LinkProperties lp = new LinkProperties();
658         lp.addLinkAddress(LINKADDRV4);
659         lp.addLinkAddress(LINKADDRV6);
660 
661         assertNull(lp.getNat64Prefix());
662 
663         IpPrefix p = new IpPrefix("64:ff9b::/96");
664         lp.setNat64Prefix(p);
665         assertEquals(p, lp.getNat64Prefix());
666 
667         p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
668         lp.setNat64Prefix(p);
669         assertEquals(p, lp.getNat64Prefix());
670 
671         p = new IpPrefix("2001:db8:a:b:1:2::/80");
672         try {
673             lp.setNat64Prefix(p);
674         } catch (IllegalArgumentException expected) {
675         }
676 
677         p = new IpPrefix("64:ff9b::/64");
678         try {
679             lp.setNat64Prefix(p);
680         } catch (IllegalArgumentException expected) {
681         }
682 
683         assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
684 
685         lp.setNat64Prefix(null);
686         assertNull(lp.getNat64Prefix());
687     }
688 
689     @Test
testIsProvisioned()690     public void testIsProvisioned() {
691         LinkProperties lp4 = new LinkProperties();
692         assertFalse("v4only:empty", lp4.isProvisioned());
693         lp4.addLinkAddress(LINKADDRV4);
694         assertFalse("v4only:addr-only", lp4.isProvisioned());
695         lp4.addDnsServer(DNS1);
696         assertFalse("v4only:addr+dns", lp4.isProvisioned());
697         lp4.addRoute(new RouteInfo(GATEWAY1));
698         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
699         assertTrue("v4only:addr+dns+route", lp4.isIpv4Provisioned());
700         assertFalse("v4only:addr+dns+route", lp4.isIpv6Provisioned());
701 
702         LinkProperties lp6 = new LinkProperties();
703         assertFalse("v6only:empty", lp6.isProvisioned());
704         lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
705         assertFalse("v6only:fe80-only", lp6.isProvisioned());
706         lp6.addDnsServer(DNS6);
707         assertFalse("v6only:fe80+dns", lp6.isProvisioned());
708         lp6.addRoute(new RouteInfo(GATEWAY61));
709         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
710         lp6.addLinkAddress(LINKADDRV6);
711         assertTrue("v6only:fe80+global+dns+route", lp6.isIpv6Provisioned());
712         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
713         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
714         assertFalse("v6only:global+dns+route", lp6.isIpv4Provisioned());
715         assertTrue("v6only:global+dns+route", lp6.isIpv6Provisioned());
716         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
717 
718         LinkProperties lp46 = new LinkProperties();
719         lp46.addLinkAddress(LINKADDRV4);
720         lp46.addLinkAddress(LINKADDRV6);
721         lp46.addDnsServer(DNS1);
722         lp46.addDnsServer(DNS6);
723         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
724         lp46.addRoute(new RouteInfo(GATEWAY1));
725         assertTrue("dualstack:v4-provisioned", lp46.isIpv4Provisioned());
726         assertFalse("dualstack:v4-provisioned", lp46.isIpv6Provisioned());
727         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
728         lp46.addRoute(new RouteInfo(GATEWAY61));
729         assertTrue("dualstack:both-provisioned", lp46.isIpv4Provisioned());
730         assertTrue("dualstack:both-provisioned", lp46.isIpv6Provisioned());
731         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
732 
733         // A link with an IPv6 address and default route, but IPv4 DNS server.
734         LinkProperties mixed = new LinkProperties();
735         mixed.addLinkAddress(LINKADDRV6);
736         mixed.addDnsServer(DNS1);
737         mixed.addRoute(new RouteInfo(GATEWAY61));
738         assertFalse("mixed:addr6+route6+dns4", mixed.isIpv4Provisioned());
739         assertFalse("mixed:addr6+route6+dns4", mixed.isIpv6Provisioned());
740         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
741     }
742 
743     @Test
testCompareProvisioning()744     public void testCompareProvisioning() {
745         LinkProperties v4lp = new LinkProperties();
746         v4lp.addLinkAddress(LINKADDRV4);
747         v4lp.addRoute(new RouteInfo(GATEWAY1));
748         v4lp.addDnsServer(DNS1);
749         assertTrue(v4lp.isProvisioned());
750 
751         LinkProperties v4r = new LinkProperties(v4lp);
752         v4r.removeDnsServer(DNS1);
753         assertFalse(v4r.isProvisioned());
754 
755         assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
756                 LinkProperties.compareProvisioning(v4r, v4r));
757         assertEquals(ProvisioningChange.LOST_PROVISIONING,
758                 LinkProperties.compareProvisioning(v4lp, v4r));
759         assertEquals(ProvisioningChange.GAINED_PROVISIONING,
760                 LinkProperties.compareProvisioning(v4r, v4lp));
761         assertEquals(ProvisioningChange.STILL_PROVISIONED,
762                 LinkProperties.compareProvisioning(v4lp, v4lp));
763 
764         // Check that losing IPv4 provisioning on a dualstack network is
765         // seen as a total loss of provisioning.
766         LinkProperties v6lp = new LinkProperties();
767         v6lp.addLinkAddress(LINKADDRV6);
768         v6lp.addRoute(new RouteInfo(GATEWAY61));
769         v6lp.addDnsServer(DNS6);
770         assertFalse(v6lp.isIpv4Provisioned());
771         assertTrue(v6lp.isIpv6Provisioned());
772         assertTrue(v6lp.isProvisioned());
773 
774         LinkProperties v46lp = new LinkProperties(v6lp);
775         v46lp.addLinkAddress(LINKADDRV4);
776         v46lp.addRoute(new RouteInfo(GATEWAY1));
777         v46lp.addDnsServer(DNS1);
778         assertTrue(v46lp.isIpv4Provisioned());
779         assertTrue(v46lp.isIpv6Provisioned());
780         assertTrue(v46lp.isProvisioned());
781 
782         assertEquals(ProvisioningChange.STILL_PROVISIONED,
783                 LinkProperties.compareProvisioning(v4lp, v46lp));
784         assertEquals(ProvisioningChange.STILL_PROVISIONED,
785                 LinkProperties.compareProvisioning(v6lp, v46lp));
786         assertEquals(ProvisioningChange.LOST_PROVISIONING,
787                 LinkProperties.compareProvisioning(v46lp, v6lp));
788         assertEquals(ProvisioningChange.LOST_PROVISIONING,
789                 LinkProperties.compareProvisioning(v46lp, v4lp));
790 
791         // Check that losing and gaining a secondary router does not change
792         // the provisioning status.
793         LinkProperties v6lp2 = new LinkProperties(v6lp);
794         v6lp2.addRoute(new RouteInfo(GATEWAY62));
795         assertTrue(v6lp2.isProvisioned());
796 
797         assertEquals(ProvisioningChange.STILL_PROVISIONED,
798                 LinkProperties.compareProvisioning(v6lp2, v6lp));
799         assertEquals(ProvisioningChange.STILL_PROVISIONED,
800                 LinkProperties.compareProvisioning(v6lp, v6lp2));
801     }
802 
803     @Test
testIsReachable()804     public void testIsReachable() {
805         final LinkProperties v4lp = new LinkProperties();
806         assertFalse(v4lp.isReachable(DNS1));
807         assertFalse(v4lp.isReachable(DNS2));
808 
809         // Add an on-link route, making the on-link DNS server reachable,
810         // but there is still no IPv4 address.
811         assertTrue(v4lp.addRoute(new RouteInfo(new IpPrefix(address("75.208.0.0"), 16))));
812         assertFalse(v4lp.isReachable(DNS1));
813         assertFalse(v4lp.isReachable(DNS2));
814 
815         // Adding an IPv4 address (right now, any IPv4 address) means we use
816         // the routes to compute likely reachability.
817         assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
818         assertTrue(v4lp.isReachable(DNS1));
819         assertFalse(v4lp.isReachable(DNS2));
820 
821         // Adding a default route makes the off-link DNS server reachable.
822         assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
823         assertTrue(v4lp.isReachable(DNS1));
824         assertTrue(v4lp.isReachable(DNS2));
825 
826         final LinkProperties v6lp = new LinkProperties();
827         final InetAddress kLinkLocalDns = address("fe80::6:1");
828         final InetAddress kLinkLocalDnsWithScope = address("fe80::6:2%43");
829         final InetAddress kOnLinkDns = address("2001:db8:85a3::53");
830         assertFalse(v6lp.isReachable(kLinkLocalDns));
831         assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
832         assertFalse(v6lp.isReachable(kOnLinkDns));
833         assertFalse(v6lp.isReachable(DNS6));
834 
835         // Add a link-local route, making the link-local DNS servers reachable. Because
836         // we assume the presence of an IPv6 link-local address, link-local DNS servers
837         // are considered reachable, but only those with a non-zero scope identifier.
838         assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("fe80::"), 64))));
839         assertFalse(v6lp.isReachable(kLinkLocalDns));
840         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
841         assertFalse(v6lp.isReachable(kOnLinkDns));
842         assertFalse(v6lp.isReachable(DNS6));
843 
844         // Add a link-local address--nothing changes.
845         assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
846         assertFalse(v6lp.isReachable(kLinkLocalDns));
847         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
848         assertFalse(v6lp.isReachable(kOnLinkDns));
849         assertFalse(v6lp.isReachable(DNS6));
850 
851         // Add a global route on link, but no global address yet. DNS servers reachable
852         // via a route that doesn't require a gateway: give them the benefit of the
853         // doubt and hope the link-local source address suffices for communication.
854         assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("2001:db8:85a3::"), 64))));
855         assertFalse(v6lp.isReachable(kLinkLocalDns));
856         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
857         assertTrue(v6lp.isReachable(kOnLinkDns));
858         assertFalse(v6lp.isReachable(DNS6));
859 
860         // Add a global address; the on-link global address DNS server is (still)
861         // presumed reachable.
862         assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
863         assertFalse(v6lp.isReachable(kLinkLocalDns));
864         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
865         assertTrue(v6lp.isReachable(kOnLinkDns));
866         assertFalse(v6lp.isReachable(DNS6));
867 
868         // Adding a default route makes the off-link DNS server reachable.
869         assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
870         assertFalse(v6lp.isReachable(kLinkLocalDns));
871         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
872         assertTrue(v6lp.isReachable(kOnLinkDns));
873         assertTrue(v6lp.isReachable(DNS6));
874 
875         // Check isReachable on stacked links. This requires that the source IP address be assigned
876         // on the interface returned by the route lookup.
877         LinkProperties stacked = new LinkProperties();
878 
879         // Can't add a stacked link without an interface name.
880         stacked.setInterfaceName("v4-test0");
881         v6lp.addStackedLink(stacked);
882 
883         InetAddress stackedAddress = address("192.0.0.4");
884         LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
885         assertFalse(v6lp.isReachable(stackedAddress));
886         stacked.addLinkAddress(stackedLinkAddress);
887         assertFalse(v6lp.isReachable(stackedAddress));
888         stacked.addRoute(new RouteInfo(stackedLinkAddress));
889         assertTrue(stacked.isReachable(stackedAddress));
890         assertTrue(v6lp.isReachable(stackedAddress));
891 
892         assertFalse(v6lp.isReachable(DNS1));
893         stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
894         assertTrue(v6lp.isReachable(DNS1));
895     }
896 
897     @Test
testLinkPropertiesEnsureDirectlyConnectedRoutes()898     public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
899         // IPv4 case: no route added initially
900         LinkProperties rmnet0 = new LinkProperties();
901         rmnet0.setInterfaceName("rmnet0");
902         rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
903         RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
904                 rmnet0.getInterfaceName());
905 
906         // Since no routes is added explicitly, getAllRoutes() should return empty.
907         assertTrue(rmnet0.getAllRoutes().isEmpty());
908         rmnet0.ensureDirectlyConnectedRoutes();
909         // ensureDirectlyConnectedRoutes() should have added the missing local route.
910         assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
911 
912         // IPv4 case: both direct and default routes added initially
913         LinkProperties rmnet1 = new LinkProperties();
914         rmnet1.setInterfaceName("rmnet1");
915         rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
916         RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, address("10.0.0.1"),
917                 rmnet1.getInterfaceName());
918         RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
919                 rmnet1.getInterfaceName());
920         rmnet1.addRoute(defaultRoute1);
921         rmnet1.addRoute(directRoute1);
922 
923         // Check added routes
924         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
925         // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
926         // route is already part of the configuration.
927         rmnet1.ensureDirectlyConnectedRoutes();
928         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
929 
930         // IPv6 case: only default routes added initially
931         LinkProperties rmnet2 = new LinkProperties();
932         rmnet2.setInterfaceName("rmnet2");
933         rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
934         rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
935         RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, address("2001:db8::1"),
936                 rmnet2.getInterfaceName());
937         RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
938                 rmnet2.getInterfaceName());
939         RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
940                 rmnet2.getInterfaceName());
941         rmnet2.addRoute(defaultRoute2);
942 
943         assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
944         rmnet2.ensureDirectlyConnectedRoutes();
945         assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
946                 rmnet2.getAllRoutes());
947 
948         // Corner case: no interface name
949         LinkProperties rmnet3 = new LinkProperties();
950         rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
951         RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
952                 rmnet3.getInterfaceName());
953 
954         assertTrue(rmnet3.getAllRoutes().isEmpty());
955         rmnet3.ensureDirectlyConnectedRoutes();
956         assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
957 
958     }
959 
960     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testCompareResult()961     public void testCompareResult() {
962         // Either adding or removing items
963         compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
964                 Arrays.asList(2, 3, 4), new ArrayList<>());
965         compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
966                 new ArrayList<>(), Arrays.asList(3, 4));
967 
968 
969         // adding and removing items at the same time
970         compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
971                 Arrays.asList(1), Arrays.asList(5));
972         compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
973                 Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
974 
975         // null cases
976         compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
977         compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
978         compareResult(null, null, new ArrayList<>(), new ArrayList<>());
979     }
980 
assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual)981     private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
982         Set<RouteInfo> expectedSet = new ArraySet<>(expected);
983         Set<RouteInfo> actualSet = new ArraySet<>(actual);
984         // Duplicated entries in actual routes are considered failures
985         assertEquals(actual.size(), actualSet.size());
986 
987         assertEquals(expectedSet, actualSet);
988     }
989 
compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved, List<T> expectAdded)990     private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
991             List<T> expectAdded) {
992         CompareResult<T> result = new CompareResult<>(oldItems, newItems);
993         assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
994         assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
995     }
996 
makeLinkPropertiesForParceling()997     private static LinkProperties makeLinkPropertiesForParceling() {
998         LinkProperties source = new LinkProperties();
999         source.setInterfaceName(NAME);
1000 
1001         source.addLinkAddress(LINKADDRV4);
1002         source.addLinkAddress(LINKADDRV6);
1003 
1004         source.addDnsServer(DNS1);
1005         source.addDnsServer(DNS2);
1006         source.addDnsServer(GATEWAY62);
1007 
1008         source.addPcscfServer(TESTIPV4ADDR);
1009         source.addPcscfServer(TESTIPV6ADDR);
1010 
1011         source.setUsePrivateDns(true);
1012         source.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
1013 
1014         source.setDomains(DOMAINS);
1015 
1016         source.addRoute(new RouteInfo(GATEWAY1));
1017         source.addRoute(new RouteInfo(GATEWAY2));
1018 
1019         source.addValidatedPrivateDnsServer(DNS6);
1020         source.addValidatedPrivateDnsServer(GATEWAY61);
1021         source.addValidatedPrivateDnsServer(TESTIPV6ADDR);
1022 
1023         source.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
1024 
1025         source.setMtu(MTU);
1026 
1027         source.setTcpBufferSizes(TCP_BUFFER_SIZES);
1028 
1029         source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
1030 
1031         final LinkProperties stacked = new LinkProperties();
1032         stacked.setInterfaceName("test-stacked");
1033         source.addStackedLink(stacked);
1034 
1035         return source;
1036     }
1037 
1038     @Test @IgnoreAfter(Build.VERSION_CODES.Q)
testLinkPropertiesParcelable_Q()1039     public void testLinkPropertiesParcelable_Q() throws Exception {
1040         final LinkProperties source = makeLinkPropertiesForParceling();
1041         assertParcelSane(source, 14 /* fieldCount */);
1042     }
1043 
1044     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testLinkPropertiesParcelable()1045     public void testLinkPropertiesParcelable() throws Exception {
1046         final LinkProperties source = makeLinkPropertiesForParceling();
1047 
1048         source.setWakeOnLanSupported(true);
1049         source.setCaptivePortalApiUrl(CAPPORT_API_URL);
1050         source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
1051         source.setDhcpServerAddress((Inet4Address) GATEWAY1);
1052         assertParcelSane(new LinkProperties(source, true /* parcelSensitiveFields */),
1053                 18 /* fieldCount */);
1054 
1055         // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
1056         final LinkProperties sanitized = new LinkProperties(source);
1057         sanitized.setCaptivePortalApiUrl(null);
1058         sanitized.setCaptivePortalData(null);
1059         assertEquals(sanitized, parcelingRoundTrip(source));
1060     }
1061 
1062     // Parceling of the scope was broken until Q-QPR2
1063     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testLinkLocalDnsServerParceling()1064     public void testLinkLocalDnsServerParceling() throws Exception {
1065         final String strAddress = "fe80::1%lo";
1066         final LinkProperties lp = new LinkProperties();
1067         lp.addDnsServer(address(strAddress));
1068         final LinkProperties unparceled = parcelingRoundTrip(lp);
1069         // Inet6Address#equals does not test for the scope id
1070         assertEquals(strAddress, unparceled.getDnsServers().get(0).getHostAddress());
1071     }
1072 
1073     @Test
testParcelUninitialized()1074     public void testParcelUninitialized() throws Exception {
1075         LinkProperties empty = new LinkProperties();
1076         assertParcelingIsLossless(empty);
1077     }
1078 
1079     @Test
testConstructor()1080     public void testConstructor() {
1081         LinkProperties lp = new LinkProperties();
1082         checkEmpty(lp);
1083         assertLinkPropertiesEqual(lp, new LinkProperties(lp));
1084         assertLinkPropertiesEqual(lp, new LinkProperties());
1085 
1086         lp = makeTestObject();
1087         assertLinkPropertiesEqual(lp, new LinkProperties(lp));
1088     }
1089 
1090     @Test
testDnsServers()1091     public void testDnsServers() {
1092         final LinkProperties lp = new LinkProperties();
1093         final List<InetAddress> dnsServers = Arrays.asList(DNS1, DNS2);
1094         lp.setDnsServers(dnsServers);
1095         assertEquals(2, lp.getDnsServers().size());
1096         assertEquals(DNS1, lp.getDnsServers().get(0));
1097         assertEquals(DNS2, lp.getDnsServers().get(1));
1098 
1099         lp.removeDnsServer(DNS1);
1100         assertEquals(1, lp.getDnsServers().size());
1101         assertEquals(DNS2, lp.getDnsServers().get(0));
1102 
1103         lp.addDnsServer(DNS6);
1104         assertEquals(2, lp.getDnsServers().size());
1105         assertEquals(DNS2, lp.getDnsServers().get(0));
1106         assertEquals(DNS6, lp.getDnsServers().get(1));
1107     }
1108 
1109     @Test
testValidatedPrivateDnsServers()1110     public void testValidatedPrivateDnsServers() {
1111         final LinkProperties lp = new LinkProperties();
1112         final List<InetAddress> privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2);
1113         lp.setValidatedPrivateDnsServers(privDnsServers);
1114         assertEquals(2, lp.getValidatedPrivateDnsServers().size());
1115         assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0));
1116         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1));
1117 
1118         lp.removeValidatedPrivateDnsServer(PRIVDNS1);
1119         assertEquals(1, lp.getValidatedPrivateDnsServers().size());
1120         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
1121 
1122         lp.addValidatedPrivateDnsServer(PRIVDNS6);
1123         assertEquals(2, lp.getValidatedPrivateDnsServers().size());
1124         assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
1125         assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1));
1126     }
1127 
1128     @Test
testPcscfServers()1129     public void testPcscfServers() {
1130         final LinkProperties lp = new LinkProperties();
1131         final List<InetAddress> pcscfServers = Arrays.asList(PCSCFV4);
1132         lp.setPcscfServers(pcscfServers);
1133         assertEquals(1, lp.getPcscfServers().size());
1134         assertEquals(PCSCFV4, lp.getPcscfServers().get(0));
1135 
1136         lp.removePcscfServer(PCSCFV4);
1137         assertEquals(0, lp.getPcscfServers().size());
1138 
1139         lp.addPcscfServer(PCSCFV6);
1140         assertEquals(1, lp.getPcscfServers().size());
1141         assertEquals(PCSCFV6, lp.getPcscfServers().get(0));
1142     }
1143 
1144     @Test
testTcpBufferSizes()1145     public void testTcpBufferSizes() {
1146         final LinkProperties lp = makeTestObject();
1147         assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes());
1148 
1149         lp.setTcpBufferSizes(null);
1150         assertNull(lp.getTcpBufferSizes());
1151     }
1152 
1153     @Test
testHasIpv6DefaultRoute()1154     public void testHasIpv6DefaultRoute() {
1155         final LinkProperties lp = makeTestObject();
1156         assertFalse(lp.hasIPv6DefaultRoute());
1157 
1158         lp.addRoute(new RouteInfo(GATEWAY61));
1159         assertTrue(lp.hasIPv6DefaultRoute());
1160     }
1161 
1162     @Test
testHttpProxy()1163     public void testHttpProxy() {
1164         final LinkProperties lp = makeTestObject();
1165         assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888)));
1166     }
1167 
1168     @Test
testPrivateDnsServerName()1169     public void testPrivateDnsServerName() {
1170         final LinkProperties lp = makeTestObject();
1171         assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName());
1172 
1173         lp.setPrivateDnsServerName(null);
1174         assertNull(lp.getPrivateDnsServerName());
1175     }
1176 
1177     @Test
testUsePrivateDns()1178     public void testUsePrivateDns() {
1179         final LinkProperties lp = makeTestObject();
1180         assertTrue(lp.isPrivateDnsActive());
1181 
1182         lp.clear();
1183         assertFalse(lp.isPrivateDnsActive());
1184     }
1185 
1186     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testDhcpServerAddress()1187     public void testDhcpServerAddress() {
1188         final LinkProperties lp = makeTestObject();
1189         assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
1190 
1191         lp.clear();
1192         assertNull(lp.getDhcpServerAddress());
1193     }
1194 
1195     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testWakeOnLanSupported()1196     public void testWakeOnLanSupported() {
1197         final LinkProperties lp = makeTestObject();
1198         assertTrue(lp.isWakeOnLanSupported());
1199 
1200         lp.clear();
1201         assertFalse(lp.isWakeOnLanSupported());
1202     }
1203 
1204     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testCaptivePortalApiUrl()1205     public void testCaptivePortalApiUrl() {
1206         final LinkProperties lp = makeTestObject();
1207         assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
1208 
1209         lp.clear();
1210         assertNull(lp.getCaptivePortalApiUrl());
1211     }
1212 
1213     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testCaptivePortalData()1214     public void testCaptivePortalData() {
1215         final LinkProperties lp = makeTestObject();
1216         assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
1217 
1218         lp.clear();
1219         assertNull(lp.getCaptivePortalData());
1220     }
1221 
makeIpv4LinkProperties()1222     private LinkProperties makeIpv4LinkProperties() {
1223         final LinkProperties linkProperties = new LinkProperties();
1224         linkProperties.setInterfaceName(NAME);
1225         linkProperties.addLinkAddress(LINKADDRV4);
1226         linkProperties.addDnsServer(DNS1);
1227         linkProperties.addRoute(new RouteInfo(GATEWAY1));
1228         linkProperties.addRoute(new RouteInfo(GATEWAY2));
1229         return linkProperties;
1230     }
1231 
makeIpv6LinkProperties()1232     private LinkProperties makeIpv6LinkProperties() {
1233         final LinkProperties linkProperties = new LinkProperties();
1234         linkProperties.setInterfaceName(NAME);
1235         linkProperties.addLinkAddress(LINKADDRV6);
1236         linkProperties.addDnsServer(DNS6);
1237         linkProperties.addRoute(new RouteInfo(GATEWAY61));
1238         linkProperties.addRoute(new RouteInfo(GATEWAY62));
1239         return linkProperties;
1240     }
1241 
1242     @Test
testHasIpv4DefaultRoute()1243     public void testHasIpv4DefaultRoute() {
1244         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1245         assertTrue(Ipv4.hasIpv4DefaultRoute());
1246         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1247         assertFalse(Ipv6.hasIpv4DefaultRoute());
1248     }
1249 
1250     @Test
testHasIpv4DnsServer()1251     public void testHasIpv4DnsServer() {
1252         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1253         assertTrue(Ipv4.hasIpv4DnsServer());
1254         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1255         assertFalse(Ipv6.hasIpv4DnsServer());
1256     }
1257 
1258     @Test
testHasIpv6DnsServer()1259     public void testHasIpv6DnsServer() {
1260         final LinkProperties Ipv4 = makeIpv4LinkProperties();
1261         assertFalse(Ipv4.hasIpv6DnsServer());
1262         final LinkProperties Ipv6 = makeIpv6LinkProperties();
1263         assertTrue(Ipv6.hasIpv6DnsServer());
1264     }
1265 
1266     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testHasIpv4UnreachableDefaultRoute()1267     public void testHasIpv4UnreachableDefaultRoute() {
1268         final LinkProperties lp = makeTestObject();
1269         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1270         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1271 
1272         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
1273         assertTrue(lp.hasIpv4UnreachableDefaultRoute());
1274         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1275     }
1276 
1277     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testHasIpv6UnreachableDefaultRoute()1278     public void testHasIpv6UnreachableDefaultRoute() {
1279         final LinkProperties lp = makeTestObject();
1280         assertFalse(lp.hasIpv6UnreachableDefaultRoute());
1281         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1282 
1283         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
1284         assertTrue(lp.hasIpv6UnreachableDefaultRoute());
1285         assertFalse(lp.hasIpv4UnreachableDefaultRoute());
1286     }
1287 
1288     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
testRouteAddWithSameKey()1289     public void testRouteAddWithSameKey() throws Exception {
1290         LinkProperties lp = new LinkProperties();
1291         lp.setInterfaceName("wlan0");
1292         final IpPrefix v6 = new IpPrefix("64:ff9b::/96");
1293         lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1280));
1294         assertEquals(1, lp.getRoutes().size());
1295         lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1500));
1296         assertEquals(1, lp.getRoutes().size());
1297         final IpPrefix v4 = new IpPrefix("192.0.2.128/25");
1298         lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_UNICAST, 1460));
1299         assertEquals(2, lp.getRoutes().size());
1300         lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_THROW, 1460));
1301         assertEquals(2, lp.getRoutes().size());
1302     }
1303 }
1304