1 /* 2 * Copyright (C) 2014 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 com.android.testutils.MiscAsserts.assertEqualBothWays; 20 import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay; 21 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; 22 23 import static org.junit.Assert.assertArrayEquals; 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertNotEquals; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 30 import androidx.test.filters.SmallTest; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import com.android.testutils.ConnectivityModuleTest; 34 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.net.InetAddress; 39 import java.util.Random; 40 41 @RunWith(AndroidJUnit4.class) 42 @SmallTest 43 @ConnectivityModuleTest 44 public class IpPrefixTest { 45 address(String addr)46 private static InetAddress address(String addr) { 47 return InetAddress.parseNumericAddress(addr); 48 } 49 50 // Explicitly cast everything to byte because "error: possible loss of precision". 51 private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4}; 52 private static final byte[] IPV6_BYTES = { 53 (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, 54 (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, 55 (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, 56 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0 57 }; 58 59 @Test testConstructor()60 public void testConstructor() { 61 IpPrefix p; 62 try { 63 p = new IpPrefix((byte[]) null, 9); 64 fail("Expected NullPointerException: null byte array"); 65 } catch (RuntimeException expected) { } 66 67 try { 68 p = new IpPrefix((InetAddress) null, 10); 69 fail("Expected NullPointerException: null InetAddress"); 70 } catch (RuntimeException expected) { } 71 72 try { 73 p = new IpPrefix((String) null); 74 fail("Expected NullPointerException: null String"); 75 } catch (RuntimeException expected) { } 76 77 78 try { 79 byte[] b2 = {1, 2, 3, 4, 5}; 80 p = new IpPrefix(b2, 29); 81 fail("Expected IllegalArgumentException: invalid array length"); 82 } catch (IllegalArgumentException expected) { } 83 84 try { 85 p = new IpPrefix("1.2.3.4"); 86 fail("Expected IllegalArgumentException: no prefix length"); 87 } catch (IllegalArgumentException expected) { } 88 89 try { 90 p = new IpPrefix("1.2.3.4/"); 91 fail("Expected IllegalArgumentException: empty prefix length"); 92 } catch (IllegalArgumentException expected) { } 93 94 try { 95 p = new IpPrefix("foo/32"); 96 fail("Expected IllegalArgumentException: invalid address"); 97 } catch (IllegalArgumentException expected) { } 98 99 try { 100 p = new IpPrefix("1/32"); 101 fail("Expected IllegalArgumentException: deprecated IPv4 format"); 102 } catch (IllegalArgumentException expected) { } 103 104 try { 105 p = new IpPrefix("1.2.3.256/32"); 106 fail("Expected IllegalArgumentException: invalid IPv4 address"); 107 } catch (IllegalArgumentException expected) { } 108 109 try { 110 p = new IpPrefix("foo/32"); 111 fail("Expected IllegalArgumentException: non-address"); 112 } catch (IllegalArgumentException expected) { } 113 114 try { 115 p = new IpPrefix("f00:::/32"); 116 fail("Expected IllegalArgumentException: invalid IPv6 address"); 117 } catch (IllegalArgumentException expected) { } 118 119 p = new IpPrefix("/64"); 120 assertEquals("::/64", p.toString()); 121 122 p = new IpPrefix("/128"); 123 assertEquals("::1/128", p.toString()); 124 125 p = new IpPrefix("[2001:db8::123]/64"); 126 assertEquals("2001:db8::/64", p.toString()); 127 128 p = new IpPrefix(InetAddresses.parseNumericAddress("::128"), 64); 129 assertEquals("::/64", p.toString()); 130 } 131 132 @Test testTruncation()133 public void testTruncation() { 134 IpPrefix p; 135 136 p = new IpPrefix(IPV4_BYTES, 32); 137 assertEquals("192.0.2.4/32", p.toString()); 138 139 p = new IpPrefix(IPV4_BYTES, 29); 140 assertEquals("192.0.2.0/29", p.toString()); 141 142 p = new IpPrefix(IPV4_BYTES, 8); 143 assertEquals("192.0.0.0/8", p.toString()); 144 145 p = new IpPrefix(IPV4_BYTES, 0); 146 assertEquals("0.0.0.0/0", p.toString()); 147 148 try { 149 p = new IpPrefix(IPV4_BYTES, 33); 150 fail("Expected IllegalArgumentException: invalid prefix length"); 151 } catch (RuntimeException expected) { } 152 153 try { 154 p = new IpPrefix(IPV4_BYTES, 128); 155 fail("Expected IllegalArgumentException: invalid prefix length"); 156 } catch (RuntimeException expected) { } 157 158 try { 159 p = new IpPrefix(IPV4_BYTES, -1); 160 fail("Expected IllegalArgumentException: negative prefix length"); 161 } catch (RuntimeException expected) { } 162 163 p = new IpPrefix(IPV6_BYTES, 128); 164 assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString()); 165 166 p = new IpPrefix(IPV6_BYTES, 122); 167 assertEquals("2001:db8:dead:beef:f00::80/122", p.toString()); 168 169 p = new IpPrefix(IPV6_BYTES, 64); 170 assertEquals("2001:db8:dead:beef::/64", p.toString()); 171 172 p = new IpPrefix(IPV6_BYTES, 3); 173 assertEquals("2000::/3", p.toString()); 174 175 p = new IpPrefix(IPV6_BYTES, 0); 176 assertEquals("::/0", p.toString()); 177 178 try { 179 p = new IpPrefix(IPV6_BYTES, -1); 180 fail("Expected IllegalArgumentException: negative prefix length"); 181 } catch (RuntimeException expected) { } 182 183 try { 184 p = new IpPrefix(IPV6_BYTES, 129); 185 fail("Expected IllegalArgumentException: negative prefix length"); 186 } catch (RuntimeException expected) { } 187 188 } 189 190 @Test testEquals()191 public void testEquals() { 192 IpPrefix p1, p2; 193 194 p1 = new IpPrefix("192.0.2.251/23"); 195 p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23); 196 assertEqualBothWays(p1, p2); 197 198 p1 = new IpPrefix("192.0.2.5/23"); 199 assertEqualBothWays(p1, p2); 200 201 p1 = new IpPrefix("192.0.2.5/24"); 202 assertNotEqualEitherWay(p1, p2); 203 204 p1 = new IpPrefix("192.0.4.5/23"); 205 assertNotEqualEitherWay(p1, p2); 206 207 208 p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122"); 209 p2 = new IpPrefix(IPV6_BYTES, 122); 210 assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString()); 211 assertEqualBothWays(p1, p2); 212 213 p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122"); 214 assertEqualBothWays(p1, p2); 215 216 p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123"); 217 assertNotEqualEitherWay(p1, p2); 218 219 p1 = new IpPrefix("2001:db8:dead:beef::/122"); 220 assertNotEqualEitherWay(p1, p2); 221 222 // 192.0.2.4/32 != c000:0204::/32. 223 byte[] ipv6bytes = new byte[16]; 224 System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length); 225 p1 = new IpPrefix(ipv6bytes, 32); 226 assertEqualBothWays(p1, new IpPrefix("c000:0204::/32")); 227 228 p2 = new IpPrefix(IPV4_BYTES, 32); 229 assertNotEqualEitherWay(p1, p2); 230 } 231 232 @Test testContainsInetAddress()233 public void testContainsInetAddress() { 234 IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); 235 assertTrue(p.contains(address("2001:db8:f00::ace:d00c"))); 236 assertTrue(p.contains(address("2001:db8:f00::ace:d00d"))); 237 assertFalse(p.contains(address("2001:db8:f00::ace:d00e"))); 238 assertFalse(p.contains(address("2001:db8:f00::bad:d00d"))); 239 assertFalse(p.contains(address("2001:4868:4860::8888"))); 240 assertFalse(p.contains(address("8.8.8.8"))); 241 242 p = new IpPrefix("192.0.2.0/23"); 243 assertTrue(p.contains(address("192.0.2.43"))); 244 assertTrue(p.contains(address("192.0.3.21"))); 245 assertFalse(p.contains(address("192.0.0.21"))); 246 assertFalse(p.contains(address("8.8.8.8"))); 247 assertFalse(p.contains(address("2001:4868:4860::8888"))); 248 249 IpPrefix ipv6Default = new IpPrefix("::/0"); 250 assertTrue(ipv6Default.contains(address("2001:db8::f00"))); 251 assertFalse(ipv6Default.contains(address("192.0.2.1"))); 252 253 IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0"); 254 assertTrue(ipv4Default.contains(address("255.255.255.255"))); 255 assertTrue(ipv4Default.contains(address("192.0.2.1"))); 256 assertFalse(ipv4Default.contains(address("2001:db8::f00"))); 257 } 258 259 @Test testContainsIpPrefix()260 public void testContainsIpPrefix() { 261 assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0"))); 262 assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0"))); 263 assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8"))); 264 assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24"))); 265 assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23"))); 266 267 assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8"))); 268 assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8"))); 269 assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21"))); 270 assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32"))); 271 272 assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24"))); 273 274 assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32"))); 275 assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8"))); 276 assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15"))); 277 assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8"))); 278 279 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0"))); 280 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1"))); 281 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8"))); 282 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8"))); 283 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64"))); 284 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113"))); 285 assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128"))); 286 287 assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( 288 new IpPrefix("2001:db8:f00::ace:d00d/64"))); 289 assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( 290 new IpPrefix("2001:db8:f00::ace:d00d/120"))); 291 assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( 292 new IpPrefix("2001:db8:f00::ace:d00d/32"))); 293 assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( 294 new IpPrefix("2006:db8:f00::ace:d00d/96"))); 295 296 assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix( 297 new IpPrefix("2001:db8:f00::ace:d00d/128"))); 298 assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix( 299 new IpPrefix("2001:db8:f00::ace:ccaf/110"))); 300 301 assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix( 302 new IpPrefix("2001:db8:f00::ace:d00e/128"))); 303 assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29"))); 304 } 305 306 @Test testHashCode()307 public void testHashCode() { 308 IpPrefix p = new IpPrefix(new byte[4], 0); 309 Random random = new Random(); 310 for (int i = 0; i < 100; i++) { 311 final IpPrefix oldP = p; 312 if (random.nextBoolean()) { 313 // IPv4. 314 byte[] b = new byte[4]; 315 random.nextBytes(b); 316 p = new IpPrefix(b, random.nextInt(33)); 317 } else { 318 // IPv6. 319 byte[] b = new byte[16]; 320 random.nextBytes(b); 321 p = new IpPrefix(b, random.nextInt(129)); 322 } 323 if (p.equals(oldP)) { 324 assertEquals(p.hashCode(), oldP.hashCode()); 325 } 326 if (p.hashCode() != oldP.hashCode()) { 327 assertNotEquals(p, oldP); 328 } 329 } 330 } 331 332 @Test testHashCodeIsNotConstant()333 public void testHashCodeIsNotConstant() { 334 IpPrefix[] prefixes = { 335 new IpPrefix("2001:db8:f00::ace:d00d/127"), 336 new IpPrefix("192.0.2.0/23"), 337 new IpPrefix("::/0"), 338 new IpPrefix("0.0.0.0/0"), 339 }; 340 for (int i = 0; i < prefixes.length; i++) { 341 for (int j = i + 1; j < prefixes.length; j++) { 342 assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); 343 } 344 } 345 } 346 347 @Test testMappedAddressesAreBroken()348 public void testMappedAddressesAreBroken() { 349 // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress, 350 // we are unable to comprehend that. 351 byte[] ipv6bytes = { 352 (byte) 0, (byte) 0, (byte) 0, (byte) 0, 353 (byte) 0, (byte) 0, (byte) 0, (byte) 0, 354 (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff, 355 (byte) 192, (byte) 0, (byte) 2, (byte) 0}; 356 IpPrefix p = new IpPrefix(ipv6bytes, 120); 357 assertEquals(16, p.getRawAddress().length); // Fine. 358 assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine. 359 360 // Broken. 361 assertEquals("192.0.2.0/120", p.toString()); 362 assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress()); 363 } 364 365 @Test testParceling()366 public void testParceling() { 367 IpPrefix p; 368 369 p = new IpPrefix("2001:4860:db8::/64"); 370 assertParcelingIsLossless(p); 371 assertTrue(p.isIPv6()); 372 373 p = new IpPrefix("192.0.2.0/25"); 374 assertParcelingIsLossless(p); 375 assertTrue(p.isIPv4()); 376 } 377 } 378