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