Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2013 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.system.OsConstants.IFA_F_DADFAILED;
     20 import static android.system.OsConstants.IFA_F_DEPRECATED;
     21 import static android.system.OsConstants.IFA_F_OPTIMISTIC;
     22 import static android.system.OsConstants.IFA_F_PERMANENT;
     23 import static android.system.OsConstants.IFA_F_TEMPORARY;
     24 import static android.system.OsConstants.IFA_F_TENTATIVE;
     25 import static android.system.OsConstants.RT_SCOPE_HOST;
     26 import static android.system.OsConstants.RT_SCOPE_LINK;
     27 import static android.system.OsConstants.RT_SCOPE_SITE;
     28 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
     29 import static org.junit.Assert.assertEquals;
     30 import static org.junit.Assert.assertFalse;
     31 import static org.junit.Assert.assertNotEquals;
     32 import static org.junit.Assert.assertNotNull;
     33 import static org.junit.Assert.assertTrue;
     34 import static org.junit.Assert.fail;
     35 
     36 import java.net.Inet4Address;
     37 import java.net.Inet6Address;
     38 import java.net.InetAddress;
     39 import java.net.InterfaceAddress;
     40 import java.net.NetworkInterface;
     41 import java.net.SocketException;
     42 import java.util.Arrays;
     43 import java.util.Collections;
     44 import java.util.Comparator;
     45 import java.util.List;
     46 
     47 import android.os.Parcel;
     48 import android.support.test.filters.SmallTest;
     49 import android.support.test.runner.AndroidJUnit4;
     50 
     51 import org.junit.runner.RunWith;
     52 import org.junit.Test;
     53 
     54 @RunWith(AndroidJUnit4.class)
     55 @SmallTest
     56 public class LinkAddressTest {
     57 
     58     private static final String V4 = "192.0.2.1";
     59     private static final String V6 = "2001:db8::1";
     60     private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
     61     private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
     62 
     63     @Test
     64     public void testConstants() {
     65         // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
     66         assertNotEquals(0, RT_SCOPE_HOST);
     67         assertNotEquals(0, RT_SCOPE_LINK);
     68         assertNotEquals(0, RT_SCOPE_SITE);
     69 
     70         assertNotEquals(0, IFA_F_DEPRECATED);
     71         assertNotEquals(0, IFA_F_PERMANENT);
     72         assertNotEquals(0, IFA_F_TENTATIVE);
     73     }
     74 
     75     @Test
     76     public void testConstructors() throws SocketException {
     77         LinkAddress address;
     78 
     79         // Valid addresses work as expected.
     80         address = new LinkAddress(V4_ADDRESS, 25);
     81         assertEquals(V4_ADDRESS, address.getAddress());
     82         assertEquals(25, address.getPrefixLength());
     83         assertEquals(0, address.getFlags());
     84         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
     85         assertTrue(address.isIPv4());
     86 
     87         address = new LinkAddress(V6_ADDRESS, 127);
     88         assertEquals(V6_ADDRESS, address.getAddress());
     89         assertEquals(127, address.getPrefixLength());
     90         assertEquals(0, address.getFlags());
     91         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
     92         assertTrue(address.isIPv6());
     93 
     94         // Nonsensical flags/scopes or combinations thereof are acceptable.
     95         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
     96         assertEquals(V6_ADDRESS, address.getAddress());
     97         assertEquals(64, address.getPrefixLength());
     98         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
     99         assertEquals(RT_SCOPE_LINK, address.getScope());
    100         assertTrue(address.isIPv6());
    101 
    102         address = new LinkAddress(V4 + "/23", 123, 456);
    103         assertEquals(V4_ADDRESS, address.getAddress());
    104         assertEquals(23, address.getPrefixLength());
    105         assertEquals(123, address.getFlags());
    106         assertEquals(456, address.getScope());
    107         assertTrue(address.isIPv4());
    108 
    109         // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
    110         List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
    111 
    112         // We expect to find 127.0.0.1/8 and ::1/128, in any order.
    113         LinkAddress ipv4Loopback, ipv6Loopback;
    114         assertEquals(2, addrs.size());
    115         if (addrs.get(0).getAddress() instanceof Inet4Address) {
    116             ipv4Loopback = new LinkAddress(addrs.get(0));
    117             ipv6Loopback = new LinkAddress(addrs.get(1));
    118         } else {
    119             ipv4Loopback = new LinkAddress(addrs.get(1));
    120             ipv6Loopback = new LinkAddress(addrs.get(0));
    121         }
    122 
    123         assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
    124         assertEquals(8, ipv4Loopback.getPrefixLength());
    125 
    126         assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
    127         assertEquals(128, ipv6Loopback.getPrefixLength());
    128 
    129         // Null addresses are rejected.
    130         try {
    131             address = new LinkAddress(null, 24);
    132             fail("Null InetAddress should cause IllegalArgumentException");
    133         } catch(IllegalArgumentException expected) {}
    134 
    135         try {
    136             address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
    137             fail("Null string should cause IllegalArgumentException");
    138         } catch(IllegalArgumentException expected) {}
    139 
    140         try {
    141             address = new LinkAddress((InterfaceAddress) null);
    142             fail("Null string should cause NullPointerException");
    143         } catch(NullPointerException expected) {}
    144 
    145         // Invalid prefix lengths are rejected.
    146         try {
    147             address = new LinkAddress(V4_ADDRESS, -1);
    148             fail("Negative IPv4 prefix length should cause IllegalArgumentException");
    149         } catch(IllegalArgumentException expected) {}
    150 
    151         try {
    152             address = new LinkAddress(V6_ADDRESS, -1);
    153             fail("Negative IPv6 prefix length should cause IllegalArgumentException");
    154         } catch(IllegalArgumentException expected) {}
    155 
    156         try {
    157             address = new LinkAddress(V4_ADDRESS, 33);
    158             fail("/33 IPv4 prefix length should cause IllegalArgumentException");
    159         } catch(IllegalArgumentException expected) {}
    160 
    161         try {
    162             address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
    163             fail("/33 IPv4 prefix length should cause IllegalArgumentException");
    164         } catch(IllegalArgumentException expected) {}
    165 
    166 
    167         try {
    168             address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
    169             fail("/129 IPv6 prefix length should cause IllegalArgumentException");
    170         } catch(IllegalArgumentException expected) {}
    171 
    172         try {
    173             address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
    174             fail("/129 IPv6 prefix length should cause IllegalArgumentException");
    175         } catch(IllegalArgumentException expected) {}
    176 
    177         // Multicast addresses are rejected.
    178         try {
    179             address = new LinkAddress("224.0.0.2/32");
    180             fail("IPv4 multicast address should cause IllegalArgumentException");
    181         } catch(IllegalArgumentException expected) {}
    182 
    183         try {
    184             address = new LinkAddress("ff02::1/128");
    185             fail("IPv6 multicast address should cause IllegalArgumentException");
    186         } catch(IllegalArgumentException expected) {}
    187     }
    188 
    189     @Test
    190     public void testAddressScopes() {
    191         assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
    192         assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
    193 
    194         assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
    195         assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
    196         assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
    197         assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
    198 
    199         assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
    200 
    201         assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
    202         assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
    203         assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
    204         assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
    205     }
    206 
    207     private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
    208         assertTrue(l1 + " unexpectedly does not have same address as " + l2,
    209                 l1.isSameAddressAs(l2));
    210         assertTrue(l2 + " unexpectedly does not have same address as " + l1,
    211                 l2.isSameAddressAs(l1));
    212     }
    213 
    214     private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
    215         assertFalse(l1 + " unexpectedly has same address as " + l2,
    216                 l1.isSameAddressAs(l2));
    217         assertFalse(l2 + " unexpectedly has same address as " + l1,
    218                 l1.isSameAddressAs(l2));
    219     }
    220 
    221     private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) {
    222         assertTrue(l1 + " unexpectedly not equal to " + l2, l1.equals(l2));
    223         assertTrue(l2 + " unexpectedly not equal to " + l1, l2.equals(l1));
    224         assertEquals(l1.hashCode(), l2.hashCode());
    225     }
    226 
    227     private void assertLinkAddressesNotEqual(LinkAddress l1, LinkAddress l2) {
    228         assertFalse(l1 + " unexpectedly equal to " + l2, l1.equals(l2));
    229         assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
    230     }
    231 
    232     @Test
    233     public void testEqualsAndSameAddressAs() {
    234         LinkAddress l1, l2, l3;
    235 
    236         l1 = new LinkAddress("2001:db8::1/64");
    237         l2 = new LinkAddress("2001:db8::1/64");
    238         assertLinkAddressesEqual(l1, l2);
    239         assertIsSameAddressAs(l1, l2);
    240 
    241         l2 = new LinkAddress("2001:db8::1/65");
    242         assertLinkAddressesNotEqual(l1, l2);
    243         assertIsNotSameAddressAs(l1, l2);
    244 
    245         l2 = new LinkAddress("2001:db8::2/64");
    246         assertLinkAddressesNotEqual(l1, l2);
    247         assertIsNotSameAddressAs(l1, l2);
    248 
    249 
    250         l1 = new LinkAddress("192.0.2.1/24");
    251         l2 = new LinkAddress("192.0.2.1/24");
    252         assertLinkAddressesEqual(l1, l2);
    253         assertIsSameAddressAs(l1, l2);
    254 
    255         l2 = new LinkAddress("192.0.2.1/23");
    256         assertLinkAddressesNotEqual(l1, l2);
    257         assertIsNotSameAddressAs(l1, l2);
    258 
    259         l2 = new LinkAddress("192.0.2.2/24");
    260         assertLinkAddressesNotEqual(l1, l2);
    261         assertIsNotSameAddressAs(l1, l2);
    262 
    263 
    264         // Check equals() and isSameAddressAs() on identical addresses with different flags.
    265         l1 = new LinkAddress(V6_ADDRESS, 64);
    266         l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
    267         assertLinkAddressesEqual(l1, l2);
    268         assertIsSameAddressAs(l1, l2);
    269 
    270         l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
    271         assertLinkAddressesNotEqual(l1, l2);
    272         assertIsSameAddressAs(l1, l2);
    273 
    274         // Check equals() and isSameAddressAs() on identical addresses with different scope.
    275         l1 = new LinkAddress(V4_ADDRESS, 24);
    276         l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
    277         assertLinkAddressesEqual(l1, l2);
    278         assertIsSameAddressAs(l1, l2);
    279 
    280         l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
    281         assertLinkAddressesNotEqual(l1, l2);
    282         assertIsSameAddressAs(l1, l2);
    283 
    284         // Addresses with the same start or end bytes aren't equal between families.
    285         l1 = new LinkAddress("32.1.13.184/24");
    286         l2 = new LinkAddress("2001:db8::1/24");
    287         l3 = new LinkAddress("::2001:db8/24");
    288 
    289         byte[] ipv4Bytes = l1.getAddress().getAddress();
    290         byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
    291         byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
    292         assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
    293         assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
    294 
    295         assertLinkAddressesNotEqual(l1, l2);
    296         assertIsNotSameAddressAs(l1, l2);
    297 
    298         assertLinkAddressesNotEqual(l1, l3);
    299         assertIsNotSameAddressAs(l1, l3);
    300 
    301         // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
    302         // TODO: Investigate fixing this.
    303         String addressString = V4 + "/24";
    304         l1 = new LinkAddress(addressString);
    305         l2 = new LinkAddress("::ffff:" + addressString);
    306         assertLinkAddressesEqual(l1, l2);
    307         assertIsSameAddressAs(l1, l2);
    308     }
    309 
    310     @Test
    311     public void testHashCode() {
    312         LinkAddress l1, l2;
    313 
    314         l1 = new LinkAddress(V4_ADDRESS, 23);
    315         l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
    316         assertNotEquals(l1.hashCode(), l2.hashCode());
    317 
    318         l1 = new LinkAddress(V6_ADDRESS, 128);
    319         l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
    320         assertNotEquals(l1.hashCode(), l2.hashCode());
    321     }
    322 
    323     private LinkAddress passThroughParcel(LinkAddress l) {
    324         Parcel p = Parcel.obtain();
    325         LinkAddress l2 = null;
    326         try {
    327             l.writeToParcel(p, 0);
    328             p.setDataPosition(0);
    329             l2 = LinkAddress.CREATOR.createFromParcel(p);
    330         } finally {
    331             p.recycle();
    332         }
    333         assertNotNull(l2);
    334         return l2;
    335     }
    336 
    337     private void assertParcelingIsLossless(LinkAddress l) {
    338       LinkAddress l2 = passThroughParcel(l);
    339       assertEquals(l, l2);
    340     }
    341 
    342     @Test
    343     public void testParceling() {
    344         LinkAddress l;
    345 
    346         l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
    347         assertParcelingIsLossless(l);
    348 
    349         l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
    350         assertParcelingIsLossless(l);
    351     }
    352 
    353     private void assertGlobalPreferred(LinkAddress l, String msg) {
    354         assertTrue(msg, l.isGlobalPreferred());
    355     }
    356 
    357     private void assertNotGlobalPreferred(LinkAddress l, String msg) {
    358         assertFalse(msg, l.isGlobalPreferred());
    359     }
    360 
    361     @Test
    362     public void testIsGlobalPreferred() {
    363         LinkAddress l;
    364 
    365         l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE);
    366         assertGlobalPreferred(l, "v4,global,noflags");
    367 
    368         l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE);
    369         assertGlobalPreferred(l, "v4-rfc1918,global,noflags");
    370 
    371         l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE);
    372         assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags");
    373 
    374         l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST);
    375         assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags");
    376 
    377         l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
    378         assertGlobalPreferred(l, "v6,global,noflags");
    379 
    380         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
    381         assertGlobalPreferred(l, "v6,global,permanent");
    382 
    383         // IPv6 ULAs are not acceptable "global preferred" addresses.
    384         l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE);
    385         assertNotGlobalPreferred(l, "v6,ula1,noflags");
    386 
    387         l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE);
    388         assertNotGlobalPreferred(l, "v6,ula2,noflags");
    389 
    390         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE);
    391         assertGlobalPreferred(l, "v6,global,tempaddr");
    392 
    393         l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED),
    394                             RT_SCOPE_UNIVERSE);
    395         assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed");
    396 
    397         l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED),
    398                             RT_SCOPE_UNIVERSE);
    399         assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated");
    400 
    401         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE);
    402         assertNotGlobalPreferred(l, "v6,site-local,tempaddr");
    403 
    404         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK);
    405         assertNotGlobalPreferred(l, "v6,link-local,tempaddr");
    406 
    407         l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST);
    408         assertNotGlobalPreferred(l, "v6,node-local,tempaddr");
    409 
    410         l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST);
    411         assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent");
    412 
    413         l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE),
    414                             RT_SCOPE_UNIVERSE);
    415         assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative");
    416 
    417         l = new LinkAddress(V6_ADDRESS, 64,
    418                             (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
    419                             RT_SCOPE_UNIVERSE);
    420         assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
    421     }
    422 }
    423