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 17package android.net; 18 19import android.net.IpPrefix; 20import android.os.Parcel; 21import static android.test.MoreAsserts.assertNotEqual; 22import android.test.suitebuilder.annotation.SmallTest; 23 24import static org.junit.Assert.assertArrayEquals; 25import java.net.InetAddress; 26import java.util.Random; 27import junit.framework.TestCase; 28 29 30public class IpPrefixTest extends TestCase { 31 32 private static InetAddress Address(String addr) { 33 return InetAddress.parseNumericAddress(addr); 34 } 35 36 // Explicitly cast everything to byte because "error: possible loss of precision". 37 private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4}; 38 private static final byte[] IPV6_BYTES = { 39 (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, 40 (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef, 41 (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00, 42 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0 43 }; 44 45 @SmallTest 46 public void testConstructor() { 47 IpPrefix p; 48 try { 49 p = new IpPrefix((byte[]) null, 9); 50 fail("Expected NullPointerException: null byte array"); 51 } catch(RuntimeException expected) {} 52 53 try { 54 p = new IpPrefix((InetAddress) null, 10); 55 fail("Expected NullPointerException: null InetAddress"); 56 } catch(RuntimeException expected) {} 57 58 try { 59 p = new IpPrefix((String) null); 60 fail("Expected NullPointerException: null String"); 61 } catch(RuntimeException expected) {} 62 63 64 try { 65 byte[] b2 = {1, 2, 3, 4, 5}; 66 p = new IpPrefix(b2, 29); 67 fail("Expected IllegalArgumentException: invalid array length"); 68 } catch(IllegalArgumentException expected) {} 69 70 try { 71 p = new IpPrefix("1.2.3.4"); 72 fail("Expected IllegalArgumentException: no prefix length"); 73 } catch(IllegalArgumentException expected) {} 74 75 try { 76 p = new IpPrefix("1.2.3.4/"); 77 fail("Expected IllegalArgumentException: empty prefix length"); 78 } catch(IllegalArgumentException expected) {} 79 80 try { 81 p = new IpPrefix("foo/32"); 82 fail("Expected IllegalArgumentException: invalid address"); 83 } catch(IllegalArgumentException expected) {} 84 85 try { 86 p = new IpPrefix("1/32"); 87 fail("Expected IllegalArgumentException: deprecated IPv4 format"); 88 } catch(IllegalArgumentException expected) {} 89 90 try { 91 p = new IpPrefix("1.2.3.256/32"); 92 fail("Expected IllegalArgumentException: invalid IPv4 address"); 93 } catch(IllegalArgumentException expected) {} 94 95 try { 96 p = new IpPrefix("foo/32"); 97 fail("Expected IllegalArgumentException: non-address"); 98 } catch(IllegalArgumentException expected) {} 99 100 try { 101 p = new IpPrefix("f00:::/32"); 102 fail("Expected IllegalArgumentException: invalid IPv6 address"); 103 } catch(IllegalArgumentException expected) {} 104 } 105 106 public void testTruncation() { 107 IpPrefix p; 108 109 p = new IpPrefix(IPV4_BYTES, 32); 110 assertEquals("192.0.2.4/32", p.toString()); 111 112 p = new IpPrefix(IPV4_BYTES, 29); 113 assertEquals("192.0.2.0/29", p.toString()); 114 115 p = new IpPrefix(IPV4_BYTES, 8); 116 assertEquals("192.0.0.0/8", p.toString()); 117 118 p = new IpPrefix(IPV4_BYTES, 0); 119 assertEquals("0.0.0.0/0", p.toString()); 120 121 try { 122 p = new IpPrefix(IPV4_BYTES, 33); 123 fail("Expected IllegalArgumentException: invalid prefix length"); 124 } catch(RuntimeException expected) {} 125 126 try { 127 p = new IpPrefix(IPV4_BYTES, 128); 128 fail("Expected IllegalArgumentException: invalid prefix length"); 129 } catch(RuntimeException expected) {} 130 131 try { 132 p = new IpPrefix(IPV4_BYTES, -1); 133 fail("Expected IllegalArgumentException: negative prefix length"); 134 } catch(RuntimeException expected) {} 135 136 p = new IpPrefix(IPV6_BYTES, 128); 137 assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString()); 138 139 p = new IpPrefix(IPV6_BYTES, 122); 140 assertEquals("2001:db8:dead:beef:f00::80/122", p.toString()); 141 142 p = new IpPrefix(IPV6_BYTES, 64); 143 assertEquals("2001:db8:dead:beef::/64", p.toString()); 144 145 p = new IpPrefix(IPV6_BYTES, 3); 146 assertEquals("2000::/3", p.toString()); 147 148 p = new IpPrefix(IPV6_BYTES, 0); 149 assertEquals("::/0", p.toString()); 150 151 try { 152 p = new IpPrefix(IPV6_BYTES, -1); 153 fail("Expected IllegalArgumentException: negative prefix length"); 154 } catch(RuntimeException expected) {} 155 156 try { 157 p = new IpPrefix(IPV6_BYTES, 129); 158 fail("Expected IllegalArgumentException: negative prefix length"); 159 } catch(RuntimeException expected) {} 160 161 } 162 163 private void assertAreEqual(Object o1, Object o2) { 164 assertTrue(o1.equals(o2)); 165 assertTrue(o2.equals(o1)); 166 } 167 168 private void assertAreNotEqual(Object o1, Object o2) { 169 assertFalse(o1.equals(o2)); 170 assertFalse(o2.equals(o1)); 171 } 172 173 @SmallTest 174 public void testEquals() { 175 IpPrefix p1, p2; 176 177 p1 = new IpPrefix("192.0.2.251/23"); 178 p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23); 179 assertAreEqual(p1, p2); 180 181 p1 = new IpPrefix("192.0.2.5/23"); 182 assertAreEqual(p1, p2); 183 184 p1 = new IpPrefix("192.0.2.5/24"); 185 assertAreNotEqual(p1, p2); 186 187 p1 = new IpPrefix("192.0.4.5/23"); 188 assertAreNotEqual(p1, p2); 189 190 191 p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122"); 192 p2 = new IpPrefix(IPV6_BYTES, 122); 193 assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString()); 194 assertAreEqual(p1, p2); 195 196 p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122"); 197 assertAreEqual(p1, p2); 198 199 p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123"); 200 assertAreNotEqual(p1, p2); 201 202 p1 = new IpPrefix("2001:db8:dead:beef::/122"); 203 assertAreNotEqual(p1, p2); 204 205 // 192.0.2.4/32 != c000:0204::/32. 206 byte[] ipv6bytes = new byte[16]; 207 System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length); 208 p1 = new IpPrefix(ipv6bytes, 32); 209 assertAreEqual(p1, new IpPrefix("c000:0204::/32")); 210 211 p2 = new IpPrefix(IPV4_BYTES, 32); 212 assertAreNotEqual(p1, p2); 213 } 214 215 @SmallTest 216 public void testContains() { 217 IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); 218 assertTrue(p.contains(Address("2001:db8:f00::ace:d00c"))); 219 assertTrue(p.contains(Address("2001:db8:f00::ace:d00d"))); 220 assertFalse(p.contains(Address("2001:db8:f00::ace:d00e"))); 221 assertFalse(p.contains(Address("2001:db8:f00::bad:d00d"))); 222 assertFalse(p.contains(Address("2001:4868:4860::8888"))); 223 assertFalse(p.contains(null)); 224 assertFalse(p.contains(Address("8.8.8.8"))); 225 226 p = new IpPrefix("192.0.2.0/23"); 227 assertTrue(p.contains(Address("192.0.2.43"))); 228 assertTrue(p.contains(Address("192.0.3.21"))); 229 assertFalse(p.contains(Address("192.0.0.21"))); 230 assertFalse(p.contains(Address("8.8.8.8"))); 231 assertFalse(p.contains(Address("2001:4868:4860::8888"))); 232 233 IpPrefix ipv6Default = new IpPrefix("::/0"); 234 assertTrue(ipv6Default.contains(Address("2001:db8::f00"))); 235 assertFalse(ipv6Default.contains(Address("192.0.2.1"))); 236 237 IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0"); 238 assertTrue(ipv4Default.contains(Address("255.255.255.255"))); 239 assertTrue(ipv4Default.contains(Address("192.0.2.1"))); 240 assertFalse(ipv4Default.contains(Address("2001:db8::f00"))); 241 } 242 243 @SmallTest 244 public void testHashCode() { 245 IpPrefix p; 246 int oldCode = -1; 247 Random random = new Random(); 248 for (int i = 0; i < 100; i++) { 249 if (random.nextBoolean()) { 250 // IPv4. 251 byte[] b = new byte[4]; 252 random.nextBytes(b); 253 p = new IpPrefix(b, random.nextInt(33)); 254 assertNotEqual(oldCode, p.hashCode()); 255 oldCode = p.hashCode(); 256 } else { 257 // IPv6. 258 byte[] b = new byte[16]; 259 random.nextBytes(b); 260 p = new IpPrefix(b, random.nextInt(129)); 261 assertNotEqual(oldCode, p.hashCode()); 262 oldCode = p.hashCode(); 263 } 264 } 265 } 266 267 @SmallTest 268 public void testMappedAddressesAreBroken() { 269 // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress, 270 // we are unable to comprehend that. 271 byte[] ipv6bytes = { 272 (byte) 0, (byte) 0, (byte) 0, (byte) 0, 273 (byte) 0, (byte) 0, (byte) 0, (byte) 0, 274 (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff, 275 (byte) 192, (byte) 0, (byte) 2, (byte) 0}; 276 IpPrefix p = new IpPrefix(ipv6bytes, 120); 277 assertEquals(16, p.getRawAddress().length); // Fine. 278 assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine. 279 280 // Broken. 281 assertEquals("192.0.2.0/120", p.toString()); 282 assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress()); 283 } 284 285 public IpPrefix passThroughParcel(IpPrefix p) { 286 Parcel parcel = Parcel.obtain(); 287 IpPrefix p2 = null; 288 try { 289 p.writeToParcel(parcel, 0); 290 parcel.setDataPosition(0); 291 p2 = IpPrefix.CREATOR.createFromParcel(parcel); 292 } finally { 293 parcel.recycle(); 294 } 295 assertNotNull(p2); 296 return p2; 297 } 298 299 public void assertParcelingIsLossless(IpPrefix p) { 300 IpPrefix p2 = passThroughParcel(p); 301 assertEquals(p, p2); 302 } 303 304 public void testParceling() { 305 IpPrefix p; 306 307 p = new IpPrefix("2001:4860:db8::/64"); 308 assertParcelingIsLossless(p); 309 310 p = new IpPrefix("192.0.2.0/25"); 311 assertParcelingIsLossless(p); 312 } 313} 314