blob: 4f4701ae7286fe2259db12b977569fcfa59645de [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Jonathan Hartdec62d42014-09-22 15:59:04 -070016package org.onlab.packet;
17
Pier Ventre48ca5192016-11-28 16:52:24 -080018import com.google.common.net.InetAddresses;
19import com.google.common.primitives.UnsignedBytes;
20
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070021import java.net.Inet4Address;
22import java.net.Inet6Address;
Pier Ventre48ca5192016-11-28 16:52:24 -080023import java.net.InetAddress;
24import java.net.UnknownHostException;
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070025import java.nio.ByteBuffer;
Jonathan Hartdec62d42014-09-22 15:59:04 -070026import java.util.Arrays;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070027import java.util.Objects;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070028
Jonathan Hartdec62d42014-09-22 15:59:04 -070029
30/**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070031 * A class representing an IP address.
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080032 * This class is immutable.
Jonathan Hartdec62d42014-09-22 15:59:04 -070033 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080034public class IpAddress implements Comparable<IpAddress> {
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -070035 private static final int BIT_MASK = 0x000000ff;
36
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070037 // IP Versions
Jon Hall8c7b06a2017-02-22 13:37:33 -080038 public enum Version { INET, INET6 }
Jonathan Hartdec62d42014-09-22 15:59:04 -070039
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070040 // lengths of address, in bytes
41 public static final int INET_BYTE_LENGTH = 4;
42 public static final int INET_BIT_LENGTH = INET_BYTE_LENGTH * Byte.SIZE;
43 public static final int INET6_BYTE_LENGTH = 16;
44 public static final int INET6_BIT_LENGTH = INET6_BYTE_LENGTH * Byte.SIZE;
Jonathan Hartdec62d42014-09-22 15:59:04 -070045
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070046 private final Version version;
47 private final byte[] octets;
Jonathan Hartdec62d42014-09-22 15:59:04 -070048
49 /**
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070050 * Constructor for given IP address version and address octets.
51 *
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070052 * @param version the IP address version
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070053 * @param value the IP address value stored in network byte order
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070054 * (i.e., the most significant byte first)
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070055 * @throws IllegalArgumentException if the arguments are invalid
Jonathan Hartdec62d42014-09-22 15:59:04 -070056 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080057 protected IpAddress(Version version, byte[] value) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070058 checkArguments(version, value, 0);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070059 this.version = version;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070060 switch (version) {
61 case INET:
62 this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
63 break;
64 case INET6:
65 this.octets = Arrays.copyOf(value, INET6_BYTE_LENGTH);
66 break;
67 default:
68 // Should not be reached
69 this.octets = null;
70 break;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070071 }
Jonathan Hartdec62d42014-09-22 15:59:04 -070072 }
73
74 /**
Pier Ventre48ca5192016-11-28 16:52:24 -080075 * Default constructor for Kryo serialization.
76 */
77 protected IpAddress() {
78 this.version = null;
79 this.octets = null;
80 }
81
82 /**
Jonathan Hartdec62d42014-09-22 15:59:04 -070083 * Returns the IP version of this address.
84 *
85 * @return the version
86 */
87 public Version version() {
88 return this.version;
89 }
90
91 /**
Pavlin Radoslavov34ffe722015-03-10 12:48:55 -070092 * Tests whether the IP version of this address is IPv4.
93 *
94 * @return true if the IP version of this address is IPv4, otherwise false.
95 */
96 public boolean isIp4() {
97 return (version() == Ip4Address.VERSION);
98 }
99
100 /**
101 * Tests whether the IP version of this address is IPv6.
102 *
103 * @return true if the IP version of this address is IPv6, otherwise false.
104 */
105 public boolean isIp6() {
106 return (version() == Ip6Address.VERSION);
107 }
108
109 /**
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800110 * Gets the {@link Ip4Address} view of the IP address.
111 *
112 * @return the {@link Ip4Address} view of the IP address if it is IPv4,
113 * otherwise null
114 */
115 public Ip4Address getIp4Address() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700116 if (!isIp4()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800117 return null;
118 }
119
120 // Return this object itself if it is already instance of Ip4Address
121 if (this instanceof Ip4Address) {
122 return (Ip4Address) this;
123 }
124 return Ip4Address.valueOf(octets);
125 }
126
127 /**
128 * Gets the {@link Ip6Address} view of the IP address.
129 *
130 * @return the {@link Ip6Address} view of the IP address if it is IPv6,
131 * otherwise null
132 */
133 public Ip6Address getIp6Address() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700134 if (!isIp6()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800135 return null;
136 }
137
138 // Return this object itself if it is already instance of Ip6Address
139 if (this instanceof Ip6Address) {
140 return (Ip6Address) this;
141 }
142 return Ip6Address.valueOf(octets);
143 }
144
145 /**
Jonathan Hartdec62d42014-09-22 15:59:04 -0700146 * Returns the IP address as a byte array.
147 *
148 * @return a byte array
149 */
150 public byte[] toOctets() {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700151 return Arrays.copyOf(octets, octets.length);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700152 }
153
154 /**
Yuta HIGUCHIc012dda2016-08-17 00:43:46 -0700155 * Returns the IP address as InetAddress.
156 *
157 * @return InetAddress
158 */
159 public InetAddress toInetAddress() {
160 try {
161 return InetAddress.getByAddress(octets);
162 } catch (UnknownHostException e) {
163 // Should never reach here
164 return null;
165 }
166 }
167
168 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700169 * Computes the IP address byte length for a given IP version.
170 *
171 * @param version the IP version
172 * @return the IP address byte length for the IP version
173 * @throws IllegalArgumentException if the IP version is invalid
174 */
175 public static int byteLength(Version version) {
176 switch (version) {
177 case INET:
178 return INET_BYTE_LENGTH;
179 case INET6:
180 return INET6_BYTE_LENGTH;
181 default:
182 String msg = "Invalid IP version " + version;
183 throw new IllegalArgumentException(msg);
184 }
185 }
186
187 /**
188 * Converts an integer into an IPv4 address.
189 *
190 * @param value an integer representing an IPv4 address value
191 * @return an IP address
192 */
193 public static IpAddress valueOf(int value) {
194 byte[] bytes =
195 ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
196 return new IpAddress(Version.INET, bytes);
197 }
198
199 /**
200 * Converts a byte array into an IP address.
201 *
202 * @param version the IP address version
203 * @param value the IP address value stored in network byte order
204 * (i.e., the most significant byte first)
205 * @return an IP address
206 * @throws IllegalArgumentException if the arguments are invalid
207 */
208 public static IpAddress valueOf(Version version, byte[] value) {
209 return new IpAddress(version, value);
210 }
211
212 /**
213 * Converts a byte array and a given offset from the beginning of the
214 * array into an IP address.
215 * <p>
216 * The IP address is stored in network byte order (i.e., the most
217 * significant byte first).
218 * </p>
219 * @param version the IP address version
220 * @param value the value to use
221 * @param offset the offset in bytes from the beginning of the byte array
222 * @return an IP address
223 * @throws IllegalArgumentException if the arguments are invalid
224 */
225 public static IpAddress valueOf(Version version, byte[] value,
226 int offset) {
227 checkArguments(version, value, offset);
228 byte[] bc = Arrays.copyOfRange(value, offset, value.length);
229 return IpAddress.valueOf(version, bc);
230 }
231
232 /**
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700233 * Converts an InetAddress into an IP address.
234 *
235 * @param inetAddress the InetAddress value to use
236 * @return an IP address
237 * @throws IllegalArgumentException if the argument is invalid
238 */
239 public static IpAddress valueOf(InetAddress inetAddress) {
240 byte[] bytes = inetAddress.getAddress();
241 if (inetAddress instanceof Inet4Address) {
242 return new IpAddress(Version.INET, bytes);
243 }
244 if (inetAddress instanceof Inet6Address) {
245 return new IpAddress(Version.INET6, bytes);
246 }
247 // Use the number of bytes as a hint
248 if (bytes.length == INET_BYTE_LENGTH) {
249 return new IpAddress(Version.INET, bytes);
250 }
251 if (bytes.length == INET6_BYTE_LENGTH) {
252 return new IpAddress(Version.INET6, bytes);
253 }
254 final String msg = "Unrecognized IP version address string: " +
255 inetAddress.toString();
256 throw new IllegalArgumentException(msg);
257 }
258
259 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700260 * Converts an IPv4 or IPv6 string literal (e.g., "10.2.3.4" or
261 * "1111:2222::8888") into an IP address.
262 *
263 * @param value an IP address value in string form
264 * @return an IP address
265 * @throws IllegalArgumentException if the argument is invalid
266 */
267 public static IpAddress valueOf(String value) {
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700268 InetAddress inetAddress = null;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700269 try {
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700270 inetAddress = InetAddresses.forString(value);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700271 } catch (IllegalArgumentException e) {
272 final String msg = "Invalid IP address string: " + value;
273 throw new IllegalArgumentException(msg);
274 }
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700275 return valueOf(inetAddress);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700276 }
277
278 /**
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700279 * Creates an IP network mask prefix.
280 *
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700281 * @param version the IP address version
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700282 * @param prefixLength the length of the mask prefix. Must be in the
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700283 * interval [0, 32] for IPv4, or [0, 128] for IPv6
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700284 * @return a new IP address that contains a mask prefix of the
285 * specified length
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700286 * @throws IllegalArgumentException if the arguments are invalid
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700287 */
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700288 public static IpAddress makeMaskPrefix(Version version, int prefixLength) {
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800289 byte[] mask = makeMaskPrefixArray(version, prefixLength);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700290 return new IpAddress(version, mask);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700291 }
292
293 /**
294 * Creates an IP address by masking it with a network mask of given
295 * mask length.
296 *
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800297 * @param address the address to mask
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700298 * @param prefixLength the length of the mask prefix. Must be in the
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700299 * interval [0, 32] for IPv4, or [0, 128] for IPv6
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700300 * @return a new IP address that is masked with a mask prefix of the
301 * specified length
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700302 * @throws IllegalArgumentException if the prefix length is invalid
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700303 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800304 public static IpAddress makeMaskedAddress(final IpAddress address,
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700305 int prefixLength) {
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800306 if (address instanceof Ip4Address) {
307 Ip4Address ip4a = (Ip4Address) address;
308 return Ip4Address.makeMaskedAddress(ip4a, prefixLength);
309 } else if (address instanceof Ip6Address) {
310 Ip6Address ip6a = (Ip6Address) address;
311 return Ip6Address.makeMaskedAddress(ip6a, prefixLength);
312 } else {
313 byte[] net = makeMaskedAddressArray(address, prefixLength);
314 return IpAddress.valueOf(address.version(), net);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700315 }
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700316 }
317
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800318 /**
319 * Check if this IP address is zero.
320 *
Thomas Vachuskae7966102015-09-09 17:33:33 -0700321 * @return true if this address is zero
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800322 */
323 public boolean isZero() {
324 for (byte b : octets) {
325 if (b != 0) {
326 return false;
327 }
328 }
329 return true;
330 }
331
Thomas Vachuskae7966102015-09-09 17:33:33 -0700332 /**
333 * Check if this IP address is self-assigned.
334 *
335 * @return true if this address is self-assigned
336 */
337 public boolean isSelfAssigned() {
Eduardo Ferreiracf8ee3c2018-01-24 18:59:43 -0200338 return isIp4() && octets[0] == (byte) 169 && octets[1] == (byte) 254;
Thomas Vachuskae7966102015-09-09 17:33:33 -0700339 }
340
Charles Chan4ca8e602016-02-25 18:05:59 -0800341 /**
342 * Check if this IP address is a multicast address.
343 *
Yi Tseng13a41a12017-07-26 13:45:01 -0700344 * @return true if this address is a multicast address
Charles Chan4ca8e602016-02-25 18:05:59 -0800345 */
346 public boolean isMulticast() {
347 return isIp4() ?
Charles Chanaedabfd2016-02-26 09:31:48 -0800348 Ip4Prefix.IPV4_MULTICAST_PREFIX.contains(this.getIp4Address()) :
349 Ip6Prefix.IPV6_MULTICAST_PREFIX.contains(this.getIp6Address());
Charles Chan4ca8e602016-02-25 18:05:59 -0800350 }
351
Yi Tseng13a41a12017-07-26 13:45:01 -0700352 /**
353 * Check if this IP address is a link-local address.
354 *
355 * @return true if this address is a link-local address
356 */
357 public boolean isLinkLocal() {
358 return isIp4() ?
359 Ip4Prefix.IPV4_LINK_LOCAL_PREFIX.contains(this.getIp4Address()) :
360 Ip6Prefix.IPV6_LINK_LOCAL_PREFIX.contains(this.getIp6Address());
361 }
362
Jonathan Hartdec62d42014-09-22 15:59:04 -0700363 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700364 public int compareTo(IpAddress o) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700365 // Compare first the version
366 if (this.version != o.version) {
367 return this.version.compareTo(o.version);
368 }
369
370 // Compare the bytes, one-by-one
371 for (int i = 0; i < this.octets.length; i++) {
372 if (this.octets[i] != o.octets[i]) {
373 return UnsignedBytes.compare(this.octets[i], o.octets[i]);
374 }
375 }
376 return 0; // Equal
Jonathan Hartab63aac2014-10-16 08:52:55 -0700377 }
378
379 @Override
Jonathan Hartdec62d42014-09-22 15:59:04 -0700380 public int hashCode() {
Thomas Vachuskad16ce182014-10-29 17:25:29 -0700381 return Objects.hash(version, Arrays.hashCode(octets));
Jonathan Hartdec62d42014-09-22 15:59:04 -0700382 }
383
384 @Override
385 public boolean equals(Object obj) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700386 if (this == obj) {
Jonathan Hartdec62d42014-09-22 15:59:04 -0700387 return true;
388 }
Pavlin Radoslavov50b70672014-11-05 11:22:25 -0800389 if ((obj == null) || (!(obj instanceof IpAddress))) {
Jonathan Hartdec62d42014-09-22 15:59:04 -0700390 return false;
391 }
392 IpAddress other = (IpAddress) obj;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700393 return (version == other.version) &&
394 Arrays.equals(octets, other.octets);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700395 }
396
397 @Override
398 /*
399 * (non-Javadoc)
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700400 * The string representation of the IP address: "x.x.x.x" for IPv4
401 * addresses, or ':' separated string for IPv6 addresses.
Jonathan Hartdec62d42014-09-22 15:59:04 -0700402 *
403 * @see java.lang.Object#toString()
404 */
405 public String toString() {
Brian O'Connor041515f2015-02-19 15:36:17 -0800406 // FIXME InetAddress is super slow
407 switch (version) {
408 case INET:
409 return String.format("%d.%d.%d.%d", octets[0] & 0xff,
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700410 octets[1] & 0xff,
411 octets[2] & 0xff,
412 octets[3] & 0xff);
Brian O'Connor041515f2015-02-19 15:36:17 -0800413 case INET6:
414 default:
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700415 return ipv6ToStringHelper();
Jonathan Hartdec62d42014-09-22 15:59:04 -0700416 }
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700417 }
418
419 /**
Pingping Line28ae4c2015-03-13 11:37:03 -0700420 * Generates an IP prefix.
421 *
422 * @return the IP prefix of the IP address
423 */
424 public IpPrefix toIpPrefix() {
425
426 if (isIp4()) {
427 return IpPrefix.valueOf(new IpAddress(Version.INET, octets),
428 Ip4Address.BIT_LENGTH);
429 } else {
430 return IpPrefix.valueOf(new IpAddress(Version.INET6, octets),
431 Ip6Address.BIT_LENGTH);
432 }
433 }
434
435 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700436 * Gets the IP address name for the IP address version.
437 *
438 * @param version the IP address version
439 * @return the IP address name for the IP address version
440 */
441 private static String addressName(Version version) {
442 switch (version) {
443 case INET:
444 return "IPv4";
445 case INET6:
446 return "IPv6";
447 default:
448 break;
449 }
450 return "UnknownIP(" + version + ")";
451 }
452
453 /**
454 * Checks whether the arguments are valid.
455 *
456 * @param version the IP address version
457 * @param value the IP address value stored in a byte array
458 * @param offset the offset in bytes from the beginning of the byte
459 * array with the address
460 * @throws IllegalArgumentException if any of the arguments is invalid
461 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800462 static void checkArguments(Version version, byte[] value, int offset) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700463 // Check the offset and byte array length
464 int addrByteLength = byteLength(version);
465 if ((offset < 0) || (offset + addrByteLength > value.length)) {
466 String msg;
467 if (value.length < addrByteLength) {
468 msg = "Invalid " + addressName(version) +
469 " address array: array length: " + value.length +
470 ". Must be at least " + addrByteLength;
471 } else {
472 msg = "Invalid " + addressName(version) +
473 " address array: array offset: " + offset +
474 ". Must be in the interval [0, " +
475 (value.length - addrByteLength) + "]";
476 }
477 throw new IllegalArgumentException(msg);
478 }
Jonathan Hartdec62d42014-09-22 15:59:04 -0700479 }
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800480
481 /**
482 * Creates a byte array for IP network mask prefix.
483 *
484 * @param version the IP address version
485 * @param prefixLength the length of the mask prefix. Must be in the
486 * interval [0, 32] for IPv4, or [0, 128] for IPv6
487 * @return a byte array that contains a mask prefix of the
488 * specified length
489 * @throws IllegalArgumentException if the arguments are invalid
490 */
491 static byte[] makeMaskPrefixArray(Version version, int prefixLength) {
492 int addrByteLength = byteLength(version);
493 int addrBitLength = addrByteLength * Byte.SIZE;
494
495 // Verify the prefix length
496 if ((prefixLength < 0) || (prefixLength > addrBitLength)) {
497 final String msg = "Invalid IP prefix length: " + prefixLength +
498 ". Must be in the interval [0, " + addrBitLength + "].";
499 throw new IllegalArgumentException(msg);
500 }
501
502 // Number of bytes and extra bits that should be all 1s
503 int maskBytes = prefixLength / Byte.SIZE;
504 int maskBits = prefixLength % Byte.SIZE;
505 byte[] mask = new byte[addrByteLength];
506
507 // Set the bytes and extra bits to 1s
508 for (int i = 0; i < maskBytes; i++) {
509 mask[i] = (byte) 0xff; // Set mask bytes to 1s
510 }
511 for (int i = maskBytes; i < addrByteLength; i++) {
512 mask[i] = 0; // Set remaining bytes to 0s
513 }
514 if (maskBits > 0) {
515 mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits));
516 }
517 return mask;
518 }
519
520 /**
521 * Creates a byte array that represents an IP address masked with
522 * a network mask of given mask length.
523 *
524 * @param addr the address to mask
525 * @param prefixLength the length of the mask prefix. Must be in the
526 * interval [0, 32] for IPv4, or [0, 128] for IPv6
527 * @return a byte array that represents the IP address masked with
528 * a mask prefix of the specified length
529 * @throws IllegalArgumentException if the prefix length is invalid
530 */
531 static byte[] makeMaskedAddressArray(final IpAddress addr,
532 int prefixLength) {
533 byte[] mask = IpAddress.makeMaskPrefixArray(addr.version(),
534 prefixLength);
535 byte[] net = new byte[mask.length];
536
537 // Mask each byte
538 for (int i = 0; i < net.length; i++) {
539 net[i] = (byte) (addr.octets[i] & mask[i]);
540 }
541 return net;
542 }
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700543
544 /**
545 * Creates a string based on the IPv6 recommendations for canonical representations found here:
546 * https://tools.ietf.org/html/rfc5952#section-1.
547 * @return A properly formatted IPv6 canonical representation.
548 */
549 private String ipv6ToStringHelper() {
550 //Populate a buffer with the string of the full address with leading zeros stripped
Yuta HIGUCHI2dce08a2017-04-20 21:57:48 -0700551 StringBuilder buff = new StringBuilder();
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700552 buff.append(String.format("%x:%x:%x:%x:%x:%x:%x:%x",
553 (((octets[0] & BIT_MASK) << 8) | (octets[1] & BIT_MASK)),
554 (((octets[2] & BIT_MASK) << 8) | (octets[3] & BIT_MASK)),
555 (((octets[4] & BIT_MASK) << 8) | (octets[5] & BIT_MASK)),
556 (((octets[6] & BIT_MASK) << 8) | (octets[7] & BIT_MASK)),
557 (((octets[8] & BIT_MASK) << 8) | (octets[9] & BIT_MASK)),
558 (((octets[10] & BIT_MASK) << 8) | (octets[11] & BIT_MASK)),
559 (((octets[12] & BIT_MASK) << 8) | (octets[13] & BIT_MASK)),
560 (((octets[14] & BIT_MASK) << 8) | (octets[15] & BIT_MASK))));
561 //Initialize variables for tracking longest zero subsequence, tiebreaking by first occurence
562 int longestSeqStart, longestSeqLen, currSeqStart, currSeqLen;
563 longestSeqStart = 0;
564 longestSeqLen = 0;
565 currSeqStart = 0;
566 currSeqLen = 0;
567
568 for (int index = 0; index < buff.length(); index++) {
569 if (buff.charAt(index) == ':') {
570 if (currSeqLen != 0 && buff.charAt(index + 1) == '0') {
571 currSeqLen += 1;
572 }
573 } else if (buff.charAt(index) == '0' && ((index == 0) || (buff.charAt(index - 1) == ':'))) {
574 if (currSeqLen == 0) {
575 currSeqStart = index;
576 }
577 currSeqLen += 1;
578 } else {
579 if (currSeqLen > longestSeqLen) {
580 longestSeqStart = currSeqStart;
581 longestSeqLen = currSeqLen;
582 }
583 currSeqLen = 0;
584 }
585 }
586
587 if (currSeqLen > longestSeqLen) {
588 longestSeqLen = currSeqLen;
589 longestSeqStart = currSeqStart;
590 }
591 if (longestSeqLen > 1) {
592 if (buff.length() == (longestSeqStart + longestSeqLen)) {
593 buff.append(':');
594 }
595
596 buff.delete(longestSeqStart, longestSeqStart + longestSeqLen);
597
598 if (longestSeqStart == 0) {
599 buff.insert(0, ':');
600 }
601 }
602
603 return buff.toString();
604 }
Jonathan Hartdec62d42014-09-22 15:59:04 -0700605}