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 java.net.Inet4Address; 20 import java.net.Inet6Address; 21 import java.net.InetAddress; 22 import java.net.InterfaceAddress; 23 import java.net.NetworkInterface; 24 import java.net.SocketException; 25 import java.util.Arrays; 26 import java.util.Collections; 27 import java.util.Comparator; 28 import java.util.List; 29 30 import android.net.LinkAddress; 31 import android.os.Parcel; 32 import android.test.AndroidTestCase; 33 import static android.test.MoreAsserts.assertNotEqual; 34 import android.test.suitebuilder.annotation.SmallTest; 35 36 import static android.system.OsConstants.IFA_F_DEPRECATED; 37 import static android.system.OsConstants.IFA_F_PERMANENT; 38 import static android.system.OsConstants.IFA_F_TENTATIVE; 39 import static android.system.OsConstants.RT_SCOPE_HOST; 40 import static android.system.OsConstants.RT_SCOPE_LINK; 41 import static android.system.OsConstants.RT_SCOPE_SITE; 42 import static android.system.OsConstants.RT_SCOPE_UNIVERSE; 43 44 /** 45 * Tests for {@link LinkAddress}. 46 */ 47 public class LinkAddressTest extends AndroidTestCase { 48 49 private static final String V4 = "192.0.2.1"; 50 private static final String V6 = "2001:db8::1"; 51 private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4); 52 private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6); 53 54 public void testConstants() { 55 // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero. 56 assertNotEqual(0, RT_SCOPE_HOST); 57 assertNotEqual(0, RT_SCOPE_LINK); 58 assertNotEqual(0, RT_SCOPE_SITE); 59 60 assertNotEqual(0, IFA_F_DEPRECATED); 61 assertNotEqual(0, IFA_F_PERMANENT); 62 assertNotEqual(0, IFA_F_TENTATIVE); 63 } 64 65 public void testConstructors() throws SocketException { 66 LinkAddress address; 67 68 // Valid addresses work as expected. 69 address = new LinkAddress(V4_ADDRESS, 25); 70 assertEquals(V4_ADDRESS, address.getAddress()); 71 assertEquals(25, address.getPrefixLength()); 72 assertEquals(0, address.getFlags()); 73 assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); 74 75 address = new LinkAddress(V6_ADDRESS, 127); 76 assertEquals(V6_ADDRESS, address.getAddress()); 77 assertEquals(127, address.getPrefixLength()); 78 assertEquals(0, address.getFlags()); 79 assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); 80 81 // Nonsensical flags/scopes or combinations thereof are acceptable. 82 address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK); 83 assertEquals(V6_ADDRESS, address.getAddress()); 84 assertEquals(64, address.getPrefixLength()); 85 assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags()); 86 assertEquals(RT_SCOPE_LINK, address.getScope()); 87 88 address = new LinkAddress(V4 + "/23", 123, 456); 89 assertEquals(V4_ADDRESS, address.getAddress()); 90 assertEquals(23, address.getPrefixLength()); 91 assertEquals(123, address.getFlags()); 92 assertEquals(456, address.getScope()); 93 94 // InterfaceAddress doesn't have a constructor. Fetch some from an interface. 95 List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses(); 96 97 // We expect to find 127.0.0.1/8 and ::1/128, in any order. 98 LinkAddress ipv4Loopback, ipv6Loopback; 99 assertEquals(2, addrs.size()); 100 if (addrs.get(0).getAddress() instanceof Inet4Address) { 101 ipv4Loopback = new LinkAddress(addrs.get(0)); 102 ipv6Loopback = new LinkAddress(addrs.get(1)); 103 } else { 104 ipv4Loopback = new LinkAddress(addrs.get(1)); 105 ipv6Loopback = new LinkAddress(addrs.get(0)); 106 } 107 108 assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress()); 109 assertEquals(8, ipv4Loopback.getPrefixLength()); 110 111 assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress()); 112 assertEquals(128, ipv6Loopback.getPrefixLength()); 113 114 // Null addresses are rejected. 115 try { 116 address = new LinkAddress(null, 24); 117 fail("Null InetAddress should cause IllegalArgumentException"); 118 } catch(IllegalArgumentException expected) {} 119 120 try { 121 address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); 122 fail("Null string should cause IllegalArgumentException"); 123 } catch(IllegalArgumentException expected) {} 124 125 try { 126 address = new LinkAddress((InterfaceAddress) null); 127 fail("Null string should cause NullPointerException"); 128 } catch(NullPointerException expected) {} 129 130 // Invalid prefix lengths are rejected. 131 try { 132 address = new LinkAddress(V4_ADDRESS, -1); 133 fail("Negative IPv4 prefix length should cause IllegalArgumentException"); 134 } catch(IllegalArgumentException expected) {} 135 136 try { 137 address = new LinkAddress(V6_ADDRESS, -1); 138 fail("Negative IPv6 prefix length should cause IllegalArgumentException"); 139 } catch(IllegalArgumentException expected) {} 140 141 try { 142 address = new LinkAddress(V4_ADDRESS, 33); 143 fail("/33 IPv4 prefix length should cause IllegalArgumentException"); 144 } catch(IllegalArgumentException expected) {} 145 146 try { 147 address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); 148 fail("/33 IPv4 prefix length should cause IllegalArgumentException"); 149 } catch(IllegalArgumentException expected) {} 150 151 152 try { 153 address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); 154 fail("/129 IPv6 prefix length should cause IllegalArgumentException"); 155 } catch(IllegalArgumentException expected) {} 156 157 try { 158 address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); 159 fail("/129 IPv6 prefix length should cause IllegalArgumentException"); 160 } catch(IllegalArgumentException expected) {} 161 162 // Multicast addresses are rejected. 163 try { 164 address = new LinkAddress("224.0.0.2/32"); 165 fail("IPv4 multicast address should cause IllegalArgumentException"); 166 } catch(IllegalArgumentException expected) {} 167 168 try { 169 address = new LinkAddress("ff02::1/128"); 170 fail("IPv6 multicast address should cause IllegalArgumentException"); 171 } catch(IllegalArgumentException expected) {} 172 } 173 174 public void testAddressScopes() { 175 assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope()); 176 assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope()); 177 178 assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope()); 179 assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope()); 180 assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope()); 181 assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope()); 182 183 assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope()); 184 185 assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope()); 186 assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope()); 187 assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope()); 188 assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope()); 189 } 190 191 private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) { 192 assertTrue(l1 + " unexpectedly does not have same address as " + l2, 193 l1.isSameAddressAs(l2)); 194 assertTrue(l2 + " unexpectedly does not have same address as " + l1, 195 l2.isSameAddressAs(l1)); 196 } 197 198 private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) { 199 assertFalse(l1 + " unexpectedly has same address as " + l2, 200 l1.isSameAddressAs(l2)); 201 assertFalse(l2 + " unexpectedly has same address as " + l1, 202 l1.isSameAddressAs(l2)); 203 } 204 205 private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) { 206 assertTrue(l1 + " unexpectedly not equal to " + l2, l1.equals(l2)); 207 assertTrue(l2 + " unexpectedly not equal to " + l1, l2.equals(l1)); 208 assertEquals(l1.hashCode(), l2.hashCode()); 209 } 210 211 private void assertLinkAddressesNotEqual(LinkAddress l1, LinkAddress l2) { 212 assertFalse(l1 + " unexpectedly equal to " + l2, l1.equals(l2)); 213 assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1)); 214 } 215 216 public void testEqualsAndSameAddressAs() { 217 LinkAddress l1, l2, l3; 218 219 l1 = new LinkAddress("2001:db8::1/64"); 220 l2 = new LinkAddress("2001:db8::1/64"); 221 assertLinkAddressesEqual(l1, l2); 222 assertIsSameAddressAs(l1, l2); 223 224 l2 = new LinkAddress("2001:db8::1/65"); 225 assertLinkAddressesNotEqual(l1, l2); 226 assertIsNotSameAddressAs(l1, l2); 227 228 l2 = new LinkAddress("2001:db8::2/64"); 229 assertLinkAddressesNotEqual(l1, l2); 230 assertIsNotSameAddressAs(l1, l2); 231 232 233 l1 = new LinkAddress("192.0.2.1/24"); 234 l2 = new LinkAddress("192.0.2.1/24"); 235 assertLinkAddressesEqual(l1, l2); 236 assertIsSameAddressAs(l1, l2); 237 238 l2 = new LinkAddress("192.0.2.1/23"); 239 assertLinkAddressesNotEqual(l1, l2); 240 assertIsNotSameAddressAs(l1, l2); 241 242 l2 = new LinkAddress("192.0.2.2/24"); 243 assertLinkAddressesNotEqual(l1, l2); 244 assertIsNotSameAddressAs(l1, l2); 245 246 247 // Check equals() and isSameAddressAs() on identical addresses with different flags. 248 l1 = new LinkAddress(V6_ADDRESS, 64); 249 l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE); 250 assertLinkAddressesEqual(l1, l2); 251 assertIsSameAddressAs(l1, l2); 252 253 l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE); 254 assertLinkAddressesNotEqual(l1, l2); 255 assertIsSameAddressAs(l1, l2); 256 257 // Check equals() and isSameAddressAs() on identical addresses with different scope. 258 l1 = new LinkAddress(V4_ADDRESS, 24); 259 l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE); 260 assertLinkAddressesEqual(l1, l2); 261 assertIsSameAddressAs(l1, l2); 262 263 l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST); 264 assertLinkAddressesNotEqual(l1, l2); 265 assertIsSameAddressAs(l1, l2); 266 267 // Addresses with the same start or end bytes aren't equal between families. 268 l1 = new LinkAddress("32.1.13.184/24"); 269 l2 = new LinkAddress("2001:db8::1/24"); 270 l3 = new LinkAddress("::2001:db8/24"); 271 272 byte[] ipv4Bytes = l1.getAddress().getAddress(); 273 byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4); 274 byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16); 275 assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes)); 276 assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes)); 277 278 assertLinkAddressesNotEqual(l1, l2); 279 assertIsNotSameAddressAs(l1, l2); 280 281 assertLinkAddressesNotEqual(l1, l3); 282 assertIsNotSameAddressAs(l1, l3); 283 284 // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address. 285 // TODO: Investigate fixing this. 286 String addressString = V4 + "/24"; 287 l1 = new LinkAddress(addressString); 288 l2 = new LinkAddress("::ffff:" + addressString); 289 assertLinkAddressesEqual(l1, l2); 290 assertIsSameAddressAs(l1, l2); 291 } 292 293 public void testHashCode() { 294 LinkAddress l; 295 296 l = new LinkAddress(V4_ADDRESS, 23); 297 assertEquals(-982787, l.hashCode()); 298 299 l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST); 300 assertEquals(-971865, l.hashCode()); 301 302 l = new LinkAddress(V4_ADDRESS, 27); 303 assertEquals(-982743, l.hashCode()); 304 305 l = new LinkAddress(V6_ADDRESS, 64); 306 assertEquals(1076522926, l.hashCode()); 307 308 l = new LinkAddress(V6_ADDRESS, 128); 309 assertEquals(1076523630, l.hashCode()); 310 311 l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE); 312 assertEquals(1076524846, l.hashCode()); 313 } 314 315 private LinkAddress passThroughParcel(LinkAddress l) { 316 Parcel p = Parcel.obtain(); 317 LinkAddress l2 = null; 318 try { 319 l.writeToParcel(p, 0); 320 p.setDataPosition(0); 321 l2 = LinkAddress.CREATOR.createFromParcel(p); 322 } finally { 323 p.recycle(); 324 } 325 assertNotNull(l2); 326 return l2; 327 } 328 329 private void assertParcelingIsLossless(LinkAddress l) { 330 LinkAddress l2 = passThroughParcel(l); 331 assertEquals(l, l2); 332 } 333 334 public void testParceling() { 335 LinkAddress l; 336 337 l = new LinkAddress(V6_ADDRESS, 64, 123, 456); 338 assertParcelingIsLossless(l); 339 340 l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK); 341 assertParcelingIsLossless(l); 342 } 343 } 344