1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import android.net.LinkProperties;
20 import android.net.RouteInfo;
21 import android.system.OsConstants;
22 import android.test.suitebuilder.annotation.SmallTest;
23 import junit.framework.TestCase;
24 
25 import java.net.InetAddress;
26 import java.util.ArrayList;
27 
28 public class LinkPropertiesTest extends TestCase {
29     private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
30     private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
31             "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
32     private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
33     private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
34     private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
35     private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
36     private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
37     private static InetAddress GATEWAY6 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
38     private static String NAME = "qmi0";
39     private static int MTU = 1500;
40 
41     private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
42     private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
43     private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
44 
assertLinkPropertiesEqual(LinkProperties source, LinkProperties target)45     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
46         // Check implementation of equals(), element by element.
47         assertTrue(source.isIdenticalInterfaceName(target));
48         assertTrue(target.isIdenticalInterfaceName(source));
49 
50         assertTrue(source.isIdenticalAddresses(target));
51         assertTrue(target.isIdenticalAddresses(source));
52 
53         assertTrue(source.isIdenticalDnses(target));
54         assertTrue(target.isIdenticalDnses(source));
55 
56         assertTrue(source.isIdenticalRoutes(target));
57         assertTrue(target.isIdenticalRoutes(source));
58 
59         assertTrue(source.isIdenticalHttpProxy(target));
60         assertTrue(target.isIdenticalHttpProxy(source));
61 
62         assertTrue(source.isIdenticalStackedLinks(target));
63         assertTrue(target.isIdenticalStackedLinks(source));
64 
65         assertTrue(source.isIdenticalMtu(target));
66         assertTrue(target.isIdenticalMtu(source));
67 
68         // Check result of equals().
69         assertTrue(source.equals(target));
70         assertTrue(target.equals(source));
71 
72         // Check hashCode.
73         assertEquals(source.hashCode(), target.hashCode());
74     }
75 
76     @SmallTest
testEqualsNull()77     public void testEqualsNull() {
78         LinkProperties source = new LinkProperties();
79         LinkProperties target = new LinkProperties();
80 
81         assertFalse(source == target);
82         assertLinkPropertiesEqual(source, target);
83     }
84 
85     @SmallTest
testEqualsSameOrder()86     public void testEqualsSameOrder() {
87         try {
88             LinkProperties source = new LinkProperties();
89             source.setInterfaceName(NAME);
90             // set 2 link addresses
91             source.addLinkAddress(LINKADDRV4);
92             source.addLinkAddress(LINKADDRV6);
93             // set 2 dnses
94             source.addDnsServer(DNS1);
95             source.addDnsServer(DNS2);
96             // set 2 gateways
97             source.addRoute(new RouteInfo(GATEWAY1));
98             source.addRoute(new RouteInfo(GATEWAY2));
99             source.setMtu(MTU);
100 
101             LinkProperties target = new LinkProperties();
102 
103             // All fields are same
104             target.setInterfaceName(NAME);
105             target.addLinkAddress(LINKADDRV4);
106             target.addLinkAddress(LINKADDRV6);
107             target.addDnsServer(DNS1);
108             target.addDnsServer(DNS2);
109             target.addRoute(new RouteInfo(GATEWAY1));
110             target.addRoute(new RouteInfo(GATEWAY2));
111             target.setMtu(MTU);
112 
113             assertLinkPropertiesEqual(source, target);
114 
115             target.clear();
116             // change Interface Name
117             target.setInterfaceName("qmi1");
118             target.addLinkAddress(LINKADDRV4);
119             target.addLinkAddress(LINKADDRV6);
120             target.addDnsServer(DNS1);
121             target.addDnsServer(DNS2);
122             target.addRoute(new RouteInfo(GATEWAY1));
123             target.addRoute(new RouteInfo(GATEWAY2));
124             target.setMtu(MTU);
125             assertFalse(source.equals(target));
126 
127             target.clear();
128             target.setInterfaceName(NAME);
129             // change link addresses
130             target.addLinkAddress(new LinkAddress(
131                     NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
132             target.addLinkAddress(LINKADDRV6);
133             target.addDnsServer(DNS1);
134             target.addDnsServer(DNS2);
135             target.addRoute(new RouteInfo(GATEWAY1));
136             target.addRoute(new RouteInfo(GATEWAY2));
137             target.setMtu(MTU);
138             assertFalse(source.equals(target));
139 
140             target.clear();
141             target.setInterfaceName(NAME);
142             target.addLinkAddress(LINKADDRV4);
143             target.addLinkAddress(LINKADDRV6);
144             // change dnses
145             target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
146             target.addDnsServer(DNS2);
147             target.addRoute(new RouteInfo(GATEWAY1));
148             target.addRoute(new RouteInfo(GATEWAY2));
149             target.setMtu(MTU);
150             assertFalse(source.equals(target));
151 
152             target.clear();
153             target.setInterfaceName(NAME);
154             target.addLinkAddress(LINKADDRV4);
155             target.addLinkAddress(LINKADDRV6);
156             target.addDnsServer(DNS1);
157             target.addDnsServer(DNS2);
158             // change gateway
159             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
160             target.addRoute(new RouteInfo(GATEWAY2));
161             target.setMtu(MTU);
162             assertFalse(source.equals(target));
163 
164             target.clear();
165             target.setInterfaceName(NAME);
166             target.addLinkAddress(LINKADDRV4);
167             target.addLinkAddress(LINKADDRV6);
168             target.addDnsServer(DNS1);
169             target.addDnsServer(DNS2);
170             target.addRoute(new RouteInfo(GATEWAY1));
171             target.addRoute(new RouteInfo(GATEWAY2));
172             // change mtu
173             target.setMtu(1440);
174             assertFalse(source.equals(target));
175 
176         } catch (Exception e) {
177             throw new RuntimeException(e.toString());
178             //fail();
179         }
180     }
181 
182     @SmallTest
testEqualsDifferentOrder()183     public void testEqualsDifferentOrder() {
184         try {
185             LinkProperties source = new LinkProperties();
186             source.setInterfaceName(NAME);
187             // set 2 link addresses
188             source.addLinkAddress(LINKADDRV4);
189             source.addLinkAddress(LINKADDRV6);
190             // set 2 dnses
191             source.addDnsServer(DNS1);
192             source.addDnsServer(DNS2);
193             // set 2 gateways
194             source.addRoute(new RouteInfo(GATEWAY1));
195             source.addRoute(new RouteInfo(GATEWAY2));
196             source.setMtu(MTU);
197 
198             LinkProperties target = new LinkProperties();
199             // Exchange order
200             target.setInterfaceName(NAME);
201             target.addLinkAddress(LINKADDRV6);
202             target.addLinkAddress(LINKADDRV4);
203             target.addDnsServer(DNS2);
204             target.addDnsServer(DNS1);
205             target.addRoute(new RouteInfo(GATEWAY2));
206             target.addRoute(new RouteInfo(GATEWAY1));
207             target.setMtu(MTU);
208 
209             assertLinkPropertiesEqual(source, target);
210         } catch (Exception e) {
211             fail();
212         }
213     }
214 
215     @SmallTest
testEqualsDuplicated()216     public void testEqualsDuplicated() {
217         try {
218             LinkProperties source = new LinkProperties();
219             // set 3 link addresses, eg, [A, A, B]
220             source.addLinkAddress(LINKADDRV4);
221             source.addLinkAddress(LINKADDRV4);
222             source.addLinkAddress(LINKADDRV6);
223 
224             LinkProperties target = new LinkProperties();
225             // set 3 link addresses, eg, [A, B, B]
226             target.addLinkAddress(LINKADDRV4);
227             target.addLinkAddress(LINKADDRV6);
228             target.addLinkAddress(LINKADDRV6);
229 
230             assertLinkPropertiesEqual(source, target);
231         } catch (Exception e) {
232             fail();
233         }
234     }
235 
assertAllRoutesHaveInterface(String iface, LinkProperties lp)236     private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
237         for (RouteInfo r : lp.getRoutes()) {
238             assertEquals(iface, r.getInterface());
239         }
240     }
241 
242     @SmallTest
testRouteInterfaces()243     public void testRouteInterfaces() {
244         LinkAddress prefix = new LinkAddress(
245             NetworkUtils.numericToInetAddress("2001:db8::"), 32);
246         InetAddress address = ADDRV6;
247 
248         // Add a route with no interface to a LinkProperties with no interface. No errors.
249         LinkProperties lp = new LinkProperties();
250         RouteInfo r = new RouteInfo(prefix, address, null);
251         assertTrue(lp.addRoute(r));
252         assertEquals(1, lp.getRoutes().size());
253         assertAllRoutesHaveInterface(null, lp);
254 
255         // Adding the same route twice has no effect.
256         assertFalse(lp.addRoute(r));
257         assertEquals(1, lp.getRoutes().size());
258 
259         // Add a route with an interface. Expect an exception.
260         r = new RouteInfo(prefix, address, "wlan0");
261         try {
262           lp.addRoute(r);
263           fail("Adding wlan0 route to LP with no interface, expect exception");
264         } catch (IllegalArgumentException expected) {}
265 
266         // Change the interface name. All the routes should change their interface name too.
267         lp.setInterfaceName("rmnet0");
268         assertAllRoutesHaveInterface("rmnet0", lp);
269 
270         // Now add a route with the wrong interface. This causes an exception too.
271         try {
272           lp.addRoute(r);
273           fail("Adding wlan0 route to rmnet0 LP, expect exception");
274         } catch (IllegalArgumentException expected) {}
275 
276         // If the interface name matches, the route is added.
277         r = new RouteInfo(prefix, null, "wlan0");
278         lp.setInterfaceName("wlan0");
279         lp.addRoute(r);
280         assertEquals(2, lp.getRoutes().size());
281         assertAllRoutesHaveInterface("wlan0", lp);
282 
283         // Routes with null interfaces are converted to wlan0.
284         r = RouteInfo.makeHostRoute(ADDRV6, null);
285         lp.addRoute(r);
286         assertEquals(3, lp.getRoutes().size());
287         assertAllRoutesHaveInterface("wlan0", lp);
288 
289         // Check comparisons work.
290         LinkProperties lp2 = new LinkProperties(lp);
291         assertAllRoutesHaveInterface("wlan0", lp);
292         assertEquals(0, lp.compareAllRoutes(lp2).added.size());
293         assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
294 
295         lp2.setInterfaceName("p2p0");
296         assertAllRoutesHaveInterface("p2p0", lp2);
297         assertEquals(3, lp.compareAllRoutes(lp2).added.size());
298         assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
299     }
300 
301     @SmallTest
testStackedInterfaces()302     public void testStackedInterfaces() {
303         LinkProperties rmnet0 = new LinkProperties();
304         rmnet0.setInterfaceName("rmnet0");
305         rmnet0.addLinkAddress(LINKADDRV6);
306 
307         LinkProperties clat4 = new LinkProperties();
308         clat4.setInterfaceName("clat4");
309         clat4.addLinkAddress(LINKADDRV4);
310 
311         assertEquals(0, rmnet0.getStackedLinks().size());
312         assertEquals(1, rmnet0.getAddresses().size());
313         assertEquals(1, rmnet0.getLinkAddresses().size());
314         assertEquals(1, rmnet0.getAllAddresses().size());
315         assertEquals(1, rmnet0.getAllLinkAddresses().size());
316 
317         rmnet0.addStackedLink(clat4);
318         assertEquals(1, rmnet0.getStackedLinks().size());
319         assertEquals(1, rmnet0.getAddresses().size());
320         assertEquals(1, rmnet0.getLinkAddresses().size());
321         assertEquals(2, rmnet0.getAllAddresses().size());
322         assertEquals(2, rmnet0.getAllLinkAddresses().size());
323 
324         rmnet0.addStackedLink(clat4);
325         assertEquals(1, rmnet0.getStackedLinks().size());
326         assertEquals(1, rmnet0.getAddresses().size());
327         assertEquals(1, rmnet0.getLinkAddresses().size());
328         assertEquals(2, rmnet0.getAllAddresses().size());
329         assertEquals(2, rmnet0.getAllLinkAddresses().size());
330 
331         assertEquals(0, clat4.getStackedLinks().size());
332 
333         // Modify an item in the returned collection to see what happens.
334         for (LinkProperties link : rmnet0.getStackedLinks()) {
335             if (link.getInterfaceName().equals("clat4")) {
336                link.setInterfaceName("newname");
337             }
338         }
339         for (LinkProperties link : rmnet0.getStackedLinks()) {
340             assertFalse("newname".equals(link.getInterfaceName()));
341         }
342 
343         assertTrue(rmnet0.removeStackedLink("clat4"));
344         assertEquals(0, rmnet0.getStackedLinks().size());
345         assertEquals(1, rmnet0.getAddresses().size());
346         assertEquals(1, rmnet0.getLinkAddresses().size());
347         assertEquals(1, rmnet0.getAllAddresses().size());
348         assertEquals(1, rmnet0.getAllLinkAddresses().size());
349 
350         assertFalse(rmnet0.removeStackedLink("clat4"));
351     }
352 
getFirstLinkAddress(LinkProperties lp)353     private LinkAddress getFirstLinkAddress(LinkProperties lp) {
354         return lp.getLinkAddresses().iterator().next();
355     }
356 
357     @SmallTest
testAddressMethods()358     public void testAddressMethods() {
359         LinkProperties lp = new LinkProperties();
360 
361         // No addresses.
362         assertFalse(lp.hasIPv4Address());
363         assertFalse(lp.hasGlobalIPv6Address());
364 
365         // Addresses on stacked links don't count.
366         LinkProperties stacked = new LinkProperties();
367         stacked.setInterfaceName("stacked");
368         lp.addStackedLink(stacked);
369         stacked.addLinkAddress(LINKADDRV4);
370         stacked.addLinkAddress(LINKADDRV6);
371         assertTrue(stacked.hasIPv4Address());
372         assertTrue(stacked.hasGlobalIPv6Address());
373         assertFalse(lp.hasIPv4Address());
374         assertFalse(lp.hasGlobalIPv6Address());
375         lp.removeStackedLink("stacked");
376         assertFalse(lp.hasIPv4Address());
377         assertFalse(lp.hasGlobalIPv6Address());
378 
379         // Addresses on the base link.
380         // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
381         // iff something changes.
382         assertEquals(0, lp.getLinkAddresses().size());
383         assertTrue(lp.addLinkAddress(LINKADDRV6));
384         assertEquals(1, lp.getLinkAddresses().size());
385         assertFalse(lp.hasIPv4Address());
386         assertTrue(lp.hasGlobalIPv6Address());
387 
388         assertTrue(lp.removeLinkAddress(LINKADDRV6));
389         assertEquals(0, lp.getLinkAddresses().size());
390 
391         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
392         assertEquals(1, lp.getLinkAddresses().size());
393         assertFalse(lp.hasGlobalIPv6Address());
394 
395         assertTrue(lp.addLinkAddress(LINKADDRV4));
396         assertEquals(2, lp.getLinkAddresses().size());
397         assertTrue(lp.hasIPv4Address());
398         assertFalse(lp.hasGlobalIPv6Address());
399 
400         assertTrue(lp.addLinkAddress(LINKADDRV6));
401         assertEquals(3, lp.getLinkAddresses().size());
402         assertTrue(lp.hasIPv4Address());
403         assertTrue(lp.hasGlobalIPv6Address());
404 
405         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
406         assertEquals(2, lp.getLinkAddresses().size());
407         assertTrue(lp.hasIPv4Address());
408         assertTrue(lp.hasGlobalIPv6Address());
409 
410         // Adding an address twice has no effect.
411         // Removing an address that's not present has no effect.
412         assertFalse(lp.addLinkAddress(LINKADDRV4));
413         assertEquals(2, lp.getLinkAddresses().size());
414         assertTrue(lp.hasIPv4Address());
415         assertTrue(lp.removeLinkAddress(LINKADDRV4));
416         assertEquals(1, lp.getLinkAddresses().size());
417         assertFalse(lp.hasIPv4Address());
418         assertFalse(lp.removeLinkAddress(LINKADDRV4));
419         assertEquals(1, lp.getLinkAddresses().size());
420 
421         // Adding an address that's already present but with different properties causes the
422         // existing address to be updated and returns true.
423         // Start with only LINKADDRV6.
424         assertEquals(1, lp.getLinkAddresses().size());
425         assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
426 
427         // Create a LinkAddress object for the same address, but with different flags.
428         LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
429                 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
430         assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
431         assertFalse(deprecated.equals(LINKADDRV6));
432 
433         // Check that adding it updates the existing address instead of adding a new one.
434         assertTrue(lp.addLinkAddress(deprecated));
435         assertEquals(1, lp.getLinkAddresses().size());
436         assertEquals(deprecated, getFirstLinkAddress(lp));
437         assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
438 
439         // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
440         assertTrue(lp.removeLinkAddress(LINKADDRV6));
441         assertEquals(0, lp.getLinkAddresses().size());
442     }
443 
444     @SmallTest
testSetLinkAddresses()445     public void testSetLinkAddresses() {
446         LinkProperties lp = new LinkProperties();
447         lp.addLinkAddress(LINKADDRV4);
448         lp.addLinkAddress(LINKADDRV6);
449 
450         LinkProperties lp2 = new LinkProperties();
451         lp2.addLinkAddress(LINKADDRV6);
452 
453         assertFalse(lp.equals(lp2));
454 
455         lp2.setLinkAddresses(lp.getLinkAddresses());
456         assertTrue(lp.equals(lp));
457     }
458 
459     @SmallTest
testIsProvisioned()460     public void testIsProvisioned() {
461         LinkProperties lp4 = new LinkProperties();
462         assertFalse("v4only:empty", lp4.isProvisioned());
463         lp4.addLinkAddress(LINKADDRV4);
464         assertFalse("v4only:addr-only", lp4.isProvisioned());
465         lp4.addDnsServer(DNS1);
466         assertFalse("v4only:addr+dns", lp4.isProvisioned());
467         lp4.addRoute(new RouteInfo(GATEWAY1));
468         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
469 
470         LinkProperties lp6 = new LinkProperties();
471         assertFalse("v6only:empty", lp6.isProvisioned());
472         lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
473         assertFalse("v6only:fe80-only", lp6.isProvisioned());
474         lp6.addDnsServer(DNS6);
475         assertFalse("v6only:fe80+dns", lp6.isProvisioned());
476         lp6.addRoute(new RouteInfo(GATEWAY6));
477         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
478         lp6.addLinkAddress(LINKADDRV6);
479         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
480         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
481         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
482 
483         LinkProperties lp46 = new LinkProperties();
484         lp46.addLinkAddress(LINKADDRV4);
485         lp46.addLinkAddress(LINKADDRV6);
486         lp46.addDnsServer(DNS1);
487         lp46.addDnsServer(DNS6);
488         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
489         lp46.addRoute(new RouteInfo(GATEWAY1));
490         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
491         lp6.addRoute(new RouteInfo(GATEWAY6));
492         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
493 
494         // A link with an IPv6 address and default route, but IPv4 DNS server.
495         LinkProperties mixed = new LinkProperties();
496         mixed.addLinkAddress(LINKADDRV6);
497         mixed.addDnsServer(DNS1);
498         mixed.addRoute(new RouteInfo(GATEWAY6));
499         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
500     }
501 }
502