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