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