blob: 241d61fa561bfed0b0f2cd98cb2dba2d162776db [file] [log] [blame]
Remi NGUYEN VAN678277c2021-05-11 13:37:06 +00001/*
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
17package android.net;
18
19import static com.android.testutils.MiscAsserts.assertEqualBothWays;
Remi NGUYEN VAN678277c2021-05-11 13:37:06 +000020import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
21import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
22
23import static org.junit.Assert.assertArrayEquals;
24import static org.junit.Assert.assertEquals;
25import static org.junit.Assert.assertFalse;
26import static org.junit.Assert.assertNotEquals;
27import static org.junit.Assert.assertTrue;
28import static org.junit.Assert.fail;
29
30import androidx.test.filters.SmallTest;
31import androidx.test.runner.AndroidJUnit4;
32
33import org.junit.Test;
34import org.junit.runner.RunWith;
35
36import java.net.InetAddress;
37import java.util.Random;
38
39@RunWith(AndroidJUnit4.class)
40@SmallTest
41public class IpPrefixTest {
42
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
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
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
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
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
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
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
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
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
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());
Remi NGUYEN VAN678277c2021-05-11 13:37:06 +0000370 }
371}