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