378 lines
14 KiB
Java
378 lines
14 KiB
Java
/*
|
|
* 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());
|
|
}
|
|
}
|