| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net; |
| |
| import static com.android.testutils.MiscAsserts.assertEqualBothWays; |
| import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay; |
| import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.testutils.ConnectivityModuleTest; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.net.InetAddress; |
| import java.util.Random; |
| |
| @RunWith(AndroidJUnit4.class) |
| @SmallTest |
| @ConnectivityModuleTest |
| public class IpPrefixTest { |
| |
| private static InetAddress address(String addr) { |
| return InetAddress.parseNumericAddress(addr); |
| } |
| |
| // Explicitly cast everything to byte because "error: possible loss of precision". |
| private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4}; |
| private static final byte[] IPV6_BYTES = { |
| (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, |
| (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, |
| (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, |
| (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0 |
| }; |
| |
| @Test |
| public void testConstructor() { |
| IpPrefix p; |
| try { |
| p = new IpPrefix((byte[]) null, 9); |
| fail("Expected NullPointerException: null byte array"); |
| } catch (RuntimeException expected) { } |
| |
| try { |
| p = new IpPrefix((InetAddress) null, 10); |
| fail("Expected NullPointerException: null InetAddress"); |
| } catch (RuntimeException expected) { } |
| |
| try { |
| p = new IpPrefix((String) null); |
| fail("Expected NullPointerException: null String"); |
| } catch (RuntimeException expected) { } |
| |
| |
| try { |
| byte[] b2 = {1, 2, 3, 4, 5}; |
| p = new IpPrefix(b2, 29); |
| fail("Expected IllegalArgumentException: invalid array length"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("1.2.3.4"); |
| fail("Expected IllegalArgumentException: no prefix length"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("1.2.3.4/"); |
| fail("Expected IllegalArgumentException: empty prefix length"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("foo/32"); |
| fail("Expected IllegalArgumentException: invalid address"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("1/32"); |
| fail("Expected IllegalArgumentException: deprecated IPv4 format"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("1.2.3.256/32"); |
| fail("Expected IllegalArgumentException: invalid IPv4 address"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("foo/32"); |
| fail("Expected IllegalArgumentException: non-address"); |
| } catch (IllegalArgumentException expected) { } |
| |
| try { |
| p = new IpPrefix("f00:::/32"); |
| fail("Expected IllegalArgumentException: invalid IPv6 address"); |
| } catch (IllegalArgumentException expected) { } |
| |
| p = new IpPrefix("/64"); |
| assertEquals("::/64", p.toString()); |
| |
| p = new IpPrefix("/128"); |
| assertEquals("::1/128", p.toString()); |
| |
| p = new IpPrefix("[2001:db8::123]/64"); |
| assertEquals("2001:db8::/64", p.toString()); |
| |
| p = new IpPrefix(InetAddresses.parseNumericAddress("::128"), 64); |
| assertEquals("::/64", p.toString()); |
| } |
| |
| @Test |
| public void testTruncation() { |
| IpPrefix p; |
| |
| p = new IpPrefix(IPV4_BYTES, 32); |
| assertEquals("192.0.2.4/32", p.toString()); |
| |
| p = new IpPrefix(IPV4_BYTES, 29); |
| assertEquals("192.0.2.0/29", p.toString()); |
| |
| p = new IpPrefix(IPV4_BYTES, 8); |
| assertEquals("192.0.0.0/8", p.toString()); |
| |
| p = new IpPrefix(IPV4_BYTES, 0); |
| assertEquals("0.0.0.0/0", p.toString()); |
| |
| try { |
| p = new IpPrefix(IPV4_BYTES, 33); |
| fail("Expected IllegalArgumentException: invalid prefix length"); |
| } catch (RuntimeException expected) { } |
| |
| try { |
| p = new IpPrefix(IPV4_BYTES, 128); |
| fail("Expected IllegalArgumentException: invalid prefix length"); |
| } catch (RuntimeException expected) { } |
| |
| try { |
| p = new IpPrefix(IPV4_BYTES, -1); |
| fail("Expected IllegalArgumentException: negative prefix length"); |
| } catch (RuntimeException expected) { } |
| |
| p = new IpPrefix(IPV6_BYTES, 128); |
| assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString()); |
| |
| p = new IpPrefix(IPV6_BYTES, 122); |
| assertEquals("2001:db8:dead:beef:f00::80/122", p.toString()); |
| |
| p = new IpPrefix(IPV6_BYTES, 64); |
| assertEquals("2001:db8:dead:beef::/64", p.toString()); |
| |
| p = new IpPrefix(IPV6_BYTES, 3); |
| assertEquals("2000::/3", p.toString()); |
| |
| p = new IpPrefix(IPV6_BYTES, 0); |
| assertEquals("::/0", p.toString()); |
| |
| try { |
| p = new IpPrefix(IPV6_BYTES, -1); |
| fail("Expected IllegalArgumentException: negative prefix length"); |
| } catch (RuntimeException expected) { } |
| |
| try { |
| p = new IpPrefix(IPV6_BYTES, 129); |
| fail("Expected IllegalArgumentException: negative prefix length"); |
| } catch (RuntimeException expected) { } |
| |
| } |
| |
| @Test |
| public void testEquals() { |
| IpPrefix p1, p2; |
| |
| p1 = new IpPrefix("192.0.2.251/23"); |
| p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23); |
| assertEqualBothWays(p1, p2); |
| |
| p1 = new IpPrefix("192.0.2.5/23"); |
| assertEqualBothWays(p1, p2); |
| |
| p1 = new IpPrefix("192.0.2.5/24"); |
| assertNotEqualEitherWay(p1, p2); |
| |
| p1 = new IpPrefix("192.0.4.5/23"); |
| assertNotEqualEitherWay(p1, p2); |
| |
| |
| p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122"); |
| p2 = new IpPrefix(IPV6_BYTES, 122); |
| assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString()); |
| assertEqualBothWays(p1, p2); |
| |
| p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122"); |
| assertEqualBothWays(p1, p2); |
| |
| p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123"); |
| assertNotEqualEitherWay(p1, p2); |
| |
| p1 = new IpPrefix("2001:db8:dead:beef::/122"); |
| assertNotEqualEitherWay(p1, p2); |
| |
| // 192.0.2.4/32 != c000:0204::/32. |
| byte[] ipv6bytes = new byte[16]; |
| System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length); |
| p1 = new IpPrefix(ipv6bytes, 32); |
| assertEqualBothWays(p1, new IpPrefix("c000:0204::/32")); |
| |
| p2 = new IpPrefix(IPV4_BYTES, 32); |
| assertNotEqualEitherWay(p1, p2); |
| } |
| |
| @Test |
| public void testContainsInetAddress() { |
| IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); |
| assertTrue(p.contains(address("2001:db8:f00::ace:d00c"))); |
| assertTrue(p.contains(address("2001:db8:f00::ace:d00d"))); |
| assertFalse(p.contains(address("2001:db8:f00::ace:d00e"))); |
| assertFalse(p.contains(address("2001:db8:f00::bad:d00d"))); |
| assertFalse(p.contains(address("2001:4868:4860::8888"))); |
| assertFalse(p.contains(address("8.8.8.8"))); |
| |
| p = new IpPrefix("192.0.2.0/23"); |
| assertTrue(p.contains(address("192.0.2.43"))); |
| assertTrue(p.contains(address("192.0.3.21"))); |
| assertFalse(p.contains(address("192.0.0.21"))); |
| assertFalse(p.contains(address("8.8.8.8"))); |
| assertFalse(p.contains(address("2001:4868:4860::8888"))); |
| |
| IpPrefix ipv6Default = new IpPrefix("::/0"); |
| assertTrue(ipv6Default.contains(address("2001:db8::f00"))); |
| assertFalse(ipv6Default.contains(address("192.0.2.1"))); |
| |
| IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0"); |
| assertTrue(ipv4Default.contains(address("255.255.255.255"))); |
| assertTrue(ipv4Default.contains(address("192.0.2.1"))); |
| assertFalse(ipv4Default.contains(address("2001:db8::f00"))); |
| } |
| |
| @Test |
| public void testContainsIpPrefix() { |
| assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0"))); |
| assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0"))); |
| assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8"))); |
| assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24"))); |
| assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23"))); |
| |
| assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8"))); |
| assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8"))); |
| assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21"))); |
| assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32"))); |
| |
| assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24"))); |
| |
| assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32"))); |
| assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8"))); |
| assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15"))); |
| assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8"))); |
| |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113"))); |
| assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128"))); |
| |
| assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:d00d/64"))); |
| assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:d00d/120"))); |
| assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:d00d/32"))); |
| assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix( |
| new IpPrefix("2006:db8:f00::ace:d00d/96"))); |
| |
| assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:d00d/128"))); |
| assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:ccaf/110"))); |
| |
| assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix( |
| new IpPrefix("2001:db8:f00::ace:d00e/128"))); |
| assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29"))); |
| } |
| |
| @Test |
| public void testHashCode() { |
| IpPrefix p = new IpPrefix(new byte[4], 0); |
| Random random = new Random(); |
| for (int i = 0; i < 100; i++) { |
| final IpPrefix oldP = p; |
| if (random.nextBoolean()) { |
| // IPv4. |
| byte[] b = new byte[4]; |
| random.nextBytes(b); |
| p = new IpPrefix(b, random.nextInt(33)); |
| } else { |
| // IPv6. |
| byte[] b = new byte[16]; |
| random.nextBytes(b); |
| p = new IpPrefix(b, random.nextInt(129)); |
| } |
| if (p.equals(oldP)) { |
| assertEquals(p.hashCode(), oldP.hashCode()); |
| } |
| if (p.hashCode() != oldP.hashCode()) { |
| assertNotEquals(p, oldP); |
| } |
| } |
| } |
| |
| @Test |
| public void testHashCodeIsNotConstant() { |
| IpPrefix[] prefixes = { |
| new IpPrefix("2001:db8:f00::ace:d00d/127"), |
| new IpPrefix("192.0.2.0/23"), |
| new IpPrefix("::/0"), |
| new IpPrefix("0.0.0.0/0"), |
| }; |
| for (int i = 0; i < prefixes.length; i++) { |
| for (int j = i + 1; j < prefixes.length; j++) { |
| assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); |
| } |
| } |
| } |
| |
| @Test |
| public void testMappedAddressesAreBroken() { |
| // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress, |
| // we are unable to comprehend that. |
| byte[] ipv6bytes = { |
| (byte) 0, (byte) 0, (byte) 0, (byte) 0, |
| (byte) 0, (byte) 0, (byte) 0, (byte) 0, |
| (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff, |
| (byte) 192, (byte) 0, (byte) 2, (byte) 0}; |
| IpPrefix p = new IpPrefix(ipv6bytes, 120); |
| assertEquals(16, p.getRawAddress().length); // Fine. |
| assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine. |
| |
| // Broken. |
| assertEquals("192.0.2.0/120", p.toString()); |
| assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress()); |
| } |
| |
| @Test |
| public void testParceling() { |
| IpPrefix p; |
| |
| p = new IpPrefix("2001:4860:db8::/64"); |
| assertParcelingIsLossless(p); |
| assertTrue(p.isIPv6()); |
| |
| p = new IpPrefix("192.0.2.0/25"); |
| assertParcelingIsLossless(p); |
| assertTrue(p.isIPv4()); |
| } |
| } |