2 * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Verify.verify;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.annotations.Beta;
15 import com.google.common.net.InetAddresses;
16 import java.net.Inet4Address;
17 import java.net.Inet6Address;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.AbstractMap.SimpleImmutableEntry;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map.Entry;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.opendaylight.mdsal.binding.spec.reflect.StringValueObjectFactory;
28 import org.opendaylight.mdsal.model.ietf.util.Ipv4Utils;
29 import org.opendaylight.mdsal.model.ietf.util.Ipv6Utils;
32 * A set of utility methods to efficiently instantiate various {@code ietf-inet-types} DTOs.
34 public final class IetfInetUtil {
35 private static final StringValueObjectFactory<Ipv4AddressNoZone> V4NZ_FACTORY =
36 StringValueObjectFactory.create(Ipv4AddressNoZone.class, "0.0.0.0");
37 private static final StringValueObjectFactory<Ipv4Prefix> P4_FACTORY =
38 StringValueObjectFactory.create(Ipv4Prefix.class, "0.0.0.0/0");
39 private static final StringValueObjectFactory<Ipv6AddressNoZone> V6NZ_FACTORY =
40 StringValueObjectFactory.create(Ipv6AddressNoZone.class, "::0");
41 private static final StringValueObjectFactory<Ipv6Prefix> P6_FACTORY =
42 StringValueObjectFactory.create(Ipv6Prefix.class, "::0/0");
43 private static final Pattern HOST_IPV4_PATTERN = Pattern.compile(
44 "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
45 + "(%[\\p{N}\\p{L}]+)?");
46 private static final Pattern HOST_IPV6_PATTERN1 = Pattern.compile("((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}"
47 +"((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}"
48 + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(%[\\p{N}\\p{L}]+)?");
49 private static final Pattern HOST_IPV6_PATTERN2 = Pattern.compile(
50 "(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)(%.+)?");
51 private static final Pattern HOST_DOMAIN_PATTERN = Pattern.compile(
52 "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?"
53 +"[a-zA-Z0-9]\\.?)|\\.");
55 private static final Pattern IPADDRESS_IPV4_PATTERN;
57 verify(Ipv4Address.PATTERN_CONSTANTS.size() == 1);
58 IPADDRESS_IPV4_PATTERN = Pattern.compile(Ipv4Address.PATTERN_CONSTANTS.get(0));
61 private static final Pattern IPADDRESS_NO_ZONE_IPV4_PATTERN = Pattern.compile("[0-9\\.]*");
62 private static final Pattern IPADDRESS_NO_ZONE_IPV6_PATTERN = Pattern.compile("[0-9a-fA-F:\\.]*");
64 private static final Pattern IPPREFIX_IPV4_PATTERN;
66 verify(Ipv4Prefix.PATTERN_CONSTANTS.size() == 1);
67 IPPREFIX_IPV4_PATTERN = Pattern.compile(Ipv4Prefix.PATTERN_CONSTANTS.get(0));
71 public static Host hostFor(final String str) {
72 final Matcher ipv4Matcher = HOST_IPV4_PATTERN.matcher(str);
73 final Matcher ipv6Matcher1 = HOST_IPV6_PATTERN1.matcher(str);
74 final Matcher ipv6Matcher2 = HOST_IPV6_PATTERN2.matcher(str);
75 final Matcher domainMatcher = HOST_DOMAIN_PATTERN.matcher(str);
76 List<String> matchers = new ArrayList<>(3);
77 if (ipv6Matcher1.matches() || ipv6Matcher2.matches()) {
78 matchers.add(Ipv6Address.class.getSimpleName());
80 // Ipv4 and Domain Name patterns are not exclusive
81 // Address 127.0.0.1 matches both patterns
82 // This way Ipv4 address is preferred to domain name
83 if (ipv4Matcher.matches()) {
84 matchers.add(Ipv4Address.class.getSimpleName());
85 } else if (domainMatcher.matches()) {
86 matchers.add(DomainName.class.getSimpleName());
88 if (matchers.size() > 1) {
89 throw new IllegalArgumentException("Cannot create Host from " + str + ". Value is ambigious for "
92 if (ipv4Matcher.matches()) {
93 Ipv4Address ipv4 = new Ipv4Address(str);
94 IpAddress ipAddress = new IpAddress(ipv4);
95 return new Host(ipAddress);
97 if (ipv6Matcher1.matches() || ipv6Matcher2.matches()) {
98 Ipv6Address ipv6 = new Ipv6Address(str);
99 IpAddress ipAddress = new IpAddress(ipv6);
100 return new Host(ipAddress);
102 if (domainMatcher.matches()) {
103 DomainName domainName = new DomainName(str);
104 return new Host(domainName);
106 throw new IllegalArgumentException("Cannot create Host from " + str);
110 public static IpAddress ipAddressFor(final String str) {
111 return IPADDRESS_IPV4_PATTERN.matcher(str).matches() ? new IpAddress(new Ipv4Address(str))
112 : new IpAddress(new Ipv6Address(str));
116 public static IpAddressNoZone ipAddressNoZoneFor(final String str) {
117 if (IPADDRESS_NO_ZONE_IPV4_PATTERN.matcher(str).matches()) {
118 return new IpAddressNoZone(new Ipv4AddressNoZone(str));
119 } else if (IPADDRESS_NO_ZONE_IPV6_PATTERN.matcher(str).matches()) {
120 return new IpAddressNoZone(new Ipv6AddressNoZone(str));
122 throw new IllegalArgumentException("Cannot create IpAddress from " + str);
127 public static IpPrefix ipPrefixFor(final String defaultValue) {
128 return IPPREFIX_IPV4_PATTERN.matcher(defaultValue).matches() ? new IpPrefix(new Ipv4Prefix(defaultValue))
129 : new IpPrefix(new Ipv6Prefix(defaultValue));
133 * Create an IpAddress by interpreting input bytes as an IPv4 or IPv6 address, based on array length.
135 * @param bytes 4-byte (IPv4) or 6-byte (IPv6) array
136 * @return An IpAddress object
137 * @throws IllegalArgumentException if bytes has length different from 4 or 6
138 * @throws NullPointerException if bytes is null
140 public static @NonNull IpAddress ipAddressFor(final byte @NonNull[] bytes) {
141 return switch (bytes.length) {
142 case Ipv4Utils.INET4_LENGTH -> new IpAddress(ipv4AddressFor(bytes));
143 case Ipv6Utils.INET6_LENGTH -> new IpAddress(ipv6AddressFor(bytes));
144 default -> throwInvalidArray(bytes);
148 public static @NonNull IpAddress ipAddressFor(final @NonNull InetAddress addr) {
149 requireAddress(addr);
150 if (addr instanceof Inet4Address) {
151 return new IpAddress(ipv4AddressFor(addr));
152 } else if (addr instanceof Inet6Address) {
153 return new IpAddress(ipv6AddressFor(addr));
155 throw unhandledAddress(addr);
159 private static <T> @NonNull T requireAddress(final T addr) {
160 return requireNonNull(addr, "Address must not be null");
164 * Create an IpAddress by interpreting input bytes as an IPv4 or IPv6 address, based on array length.
166 * @param bytes 4-byte (IPv4) or 6-byte (IPv6) array
167 * @return A no-zone IpAddress object
168 * @throws IllegalArgumentException if bytes has length different from 4 or 6
169 * @throws NullPointerException if bytes is null
171 public static @NonNull IpAddressNoZone ipAddressNoZoneFor(final byte @NonNull[] bytes) {
172 return switch (bytes.length) {
173 case Ipv4Utils.INET4_LENGTH -> new IpAddressNoZone(ipv4AddressFor(bytes));
174 case Ipv6Utils.INET6_LENGTH -> new IpAddressNoZone(ipv6AddressFor(bytes));
175 default -> throwInvalidArray(bytes);
179 public static @NonNull IpAddressNoZone ipAddressNoZoneFor(final @NonNull InetAddress addr) {
180 requireAddress(addr);
181 if (addr instanceof Inet4Address) {
182 return new IpAddressNoZone(ipv4AddressFor(addr));
183 } else if (addr instanceof Inet6Address) {
184 return new IpAddressNoZone(ipv6AddressFor(addr));
186 throw unhandledAddress(addr);
190 private static <T> T throwInvalidArray(final byte[] bytes) {
191 throw new IllegalArgumentException("Invalid array length " + bytes.length);
194 private static IllegalArgumentException unhandledAddress(final InetAddress addr) {
195 return new IllegalArgumentException("Unhandled address " + addr);
199 * Create an IpPrefix by combining the address with a mask. The address
200 * bytes are interpreted as an address and the specified mask is concatenated to
201 * it. The address bytes are not masked.
203 * @param bytes Input address as a 4-byte (IPv4) or 16-byte (IPv6) array
204 * @param mask Prefix mask
205 * @return An IpPrefix object
206 * @throws IllegalArgumentException if bytes has length different from 4 or 16 or if mask is not
207 * in range 0-32 or 0-128 respectively
208 * @throws NullPointerException if bytes is null
210 public static @NonNull IpPrefix ipPrefixFor(final byte @NonNull[] bytes, final int mask) {
211 return switch (bytes.length) {
212 case Ipv4Utils.INET4_LENGTH -> new IpPrefix(ipv4PrefixFor(bytes, mask));
213 case Ipv6Utils.INET6_LENGTH -> new IpPrefix(ipv6PrefixFor(bytes, mask));
214 default -> throwInvalidArray(bytes);
218 public static @NonNull IpPrefix ipPrefixFor(final @NonNull InetAddress addr, final int mask) {
219 requireAddress(addr);
220 if (addr instanceof Inet4Address) {
221 return new IpPrefix(ipv4PrefixFor(addr, mask));
222 } else if (addr instanceof Inet6Address) {
223 return new IpPrefix(ipv6PrefixFor(addr, mask));
225 throw unhandledAddress(addr);
229 public static @NonNull IpPrefix ipPrefixFor(final @NonNull IpAddress addr) {
230 final var v4 = addr.getIpv4Address();
231 return v4 != null ? new IpPrefix(ipv4PrefixFor(v4)) : new IpPrefix(ipv6PrefixFor(coerceIpv6Address(addr)));
234 public static @NonNull IpPrefix ipPrefixForNoZone(final @NonNull IpAddressNoZone addr) {
235 final var v4 = addr.getIpv4AddressNoZone();
236 return v4 != null ? new IpPrefix(ipv4PrefixFor(inet4AddressForNoZone(v4)))
237 : new IpPrefix(ipv6PrefixFor(coerceIpv6AddressNoZone(addr)));
240 public static @NonNull InetAddress inetAddressFor(final @NonNull IpAddress addr) {
241 final var v4 = addr.getIpv4Address();
242 return v4 != null ? inet4AddressFor(v4) : inet6AddressFor(coerceIpv6Address(addr));
245 public static @NonNull InetAddress inetAddressForNoZone(final @NonNull IpAddressNoZone addr) {
246 final var v4 = addr.getIpv4AddressNoZone();
247 return v4 != null ? inet4AddressForNoZone(v4) : inet6AddressForNoZone(coerceIpv6AddressNoZone(addr));
250 public static @NonNull Inet4Address inet4AddressFor(final @NonNull Ipv4Address addr) {
252 return (Inet4Address) InetAddress.getByAddress(ipv4AddressBytes(addr));
253 } catch (UnknownHostException e) {
254 throw new IllegalArgumentException("Invalid address " + addr, e);
258 public static @NonNull Inet4Address inet4AddressForNoZone(final @NonNull Ipv4AddressNoZone addr) {
260 return (Inet4Address) InetAddress.getByAddress(ipv4AddressNoZoneBytes(addr));
261 } catch (UnknownHostException e) {
262 throw new IllegalArgumentException("Invalid address " + addr, e);
266 public static @NonNull Inet6Address inet6AddressFor(final @NonNull Ipv6Address addr) {
268 return (Inet6Address) InetAddress.getByAddress(ipv6AddressBytes(addr));
269 } catch (UnknownHostException e) {
270 throw new IllegalArgumentException("Invalid address " + addr, e);
274 public static @NonNull Inet6Address inet6AddressForNoZone(final @NonNull Ipv6AddressNoZone addr) {
276 return (Inet6Address) InetAddress.getByAddress(ipv6AddressNoZoneBytes(addr));
277 } catch (UnknownHostException e) {
278 throw new IllegalArgumentException("Invalid address " + addr, e);
283 * Create an Ipv4AddressNoZone by interpreting input bytes as an IPv4 address.
285 * @param bytes 4-byte array
286 * @return An Ipv4AddressNoZone object
287 * @throws IllegalArgumentException if bytes has length different from 4
288 * @throws NullPointerException if bytes is null
290 public static @NonNull Ipv4AddressNoZone ipv4AddressFor(final byte @NonNull[] bytes) {
291 return V4NZ_FACTORY.newInstance(Ipv4Utils.addressString(bytes));
295 * Create an Ipv4AddressNoZone by interpreting an {@link Inet4Address}.
297 * @param addr An {@link Inet4Address}
298 * @return An Ipv4AddressNoZone object
299 * @throws IllegalArgumentException if addr is not an {@link Inet4Address}
300 * @throws NullPointerException if addr is null
302 public static @NonNull Ipv4AddressNoZone ipv4AddressFor(final @NonNull InetAddress addr) {
303 return V4NZ_FACTORY.newInstance(addressStringV4(addr));
307 * Create an Ipv4AddressNoZone by interpreting input 32 bits as an IPv4 address in big-endian format.
309 * @param bits 32 bits, big endian
310 * @return An Ipv4AddressNoZone object
312 public static @NonNull Ipv4AddressNoZone ipv4AddressFor(final int bits) {
313 return V4NZ_FACTORY.newInstance(Ipv4Utils.addressString(bits));
317 * Create an Ipv4AddressNoZone by interpreting an Ipv4Address.
319 * @param addr An Ipv4Address
320 * @return An Ipv4AddressNoZone object
321 * @throws NullPointerException if {@code addr} is {@code null}
323 public static @NonNull Ipv4AddressNoZone ipv4AddressNoZoneFor(final @NonNull Ipv4Address addr) {
324 requireAddress(addr);
325 return addr instanceof Ipv4AddressNoZone noZone ? noZone
326 : V4NZ_FACTORY.newInstance(stripZone(addr.getValue()));
329 public static @NonNull Ipv4AddressNoZone ipv4AddressFrom(final @NonNull Ipv4Prefix prefix) {
330 return prefixToAddress(V4NZ_FACTORY, prefix.getValue());
333 public static byte @NonNull[] ipv4AddressBytes(final @NonNull Ipv4Address addr) {
335 * This implementation relies heavily on the input string having been validated to comply with
336 * the Ipv4Address pattern, which may include a zone index.
338 final var str = addr.getValue();
339 final int percent = str.indexOf('%');
340 return Ipv4Utils.addressBytes(str, percent == -1 ? str.length() : percent);
343 public static int ipv4AddressBits(final @NonNull Ipv4Address addr) {
344 final var str = addr.getValue();
345 final int percent = str.indexOf('%');
346 return Ipv4Utils.addressBits(str, percent == -1 ? str.length() : percent);
349 public static byte @NonNull[] ipv4AddressNoZoneBytes(final @NonNull Ipv4AddressNoZone addr) {
351 * This implementation relies heavily on the input string having been validated to comply with
352 * the Ipv4AddressNoZone pattern, which must not include a zone index.
354 final String str = addr.getValue();
355 return Ipv4Utils.addressBytes(str, str.length());
358 public static int ipv4AddressNoZoneBits(final @NonNull Ipv4AddressNoZone addr) {
359 final var str = addr.getValue();
360 return Ipv4Utils.addressBits(str, str.length());
364 * Create a /32 Ipv4Prefix by interpreting input bytes as an IPv4 address.
366 * @param bytes four-byte array
367 * @return An Ipv4Prefix object
368 * @throws IllegalArgumentException if bytes has length different from 4
369 * @throws NullPointerException if bytes is null
371 public static @NonNull Ipv4Prefix ipv4PrefixFor(final byte @NonNull[] bytes) {
372 return P4_FACTORY.newInstance(prefixStringV4(bytes));
376 * Create a Ipv4Prefix by combining the address with a mask. The address
377 * bytes are interpreted as an address and the specified mask is concatenated to
378 * it. The address bytes are not masked, hence input <code>address = { 1, 2, 3, 4 }</code>
379 * and <code>mask=24</code> will result in <code>1.2.3.4/24</code>.
381 * @param address Input address as a 4-byte array
382 * @param mask Prefix mask
383 * @return An Ipv4Prefix object
384 * @throws IllegalArgumentException if bytes has length different from 4 or if mask is not in range 0-32
385 * @throws NullPointerException if bytes is null
387 public static @NonNull Ipv4Prefix ipv4PrefixFor(final byte @NonNull[] address, final int mask) {
388 return P4_FACTORY.newInstance(prefixStringV4(address, mask));
392 * Create a /32 Ipv4Prefix for an {@link Inet4Address}.
394 * @param addr An {@link Inet4Address}
395 * @return An Ipv4Prefix object
396 * @throws IllegalArgumentException if addr is not an Inet4Address
397 * @throws NullPointerException if addr is null
399 public static @NonNull Ipv4Prefix ipv4PrefixFor(final @NonNull InetAddress addr) {
400 return P4_FACTORY.newInstance(addressStringV4(addr) + "/32");
404 * Create a Ipv4Prefix by combining the address with a mask. The address bytes are not masked.
406 * @param addr An {@link Inet4Address}
407 * @param mask Prefix mask
408 * @return An Ipv4Prefix object
409 * @throws IllegalArgumentException if addr is not an Inet4Address or if mask is not in range 0-32
410 * @throws NullPointerException if addr is null
412 public static @NonNull Ipv4Prefix ipv4PrefixFor(final @NonNull InetAddress addr, final int mask) {
413 return newIpv4Prefix(addressStringV4(addr), mask);
416 public static @NonNull Ipv4Prefix ipv4PrefixFor(final @NonNull Ipv4Address addr) {
417 return P4_FACTORY.newInstance(stripZone(addr.getValue()) + "/32");
420 public static @NonNull Ipv4Prefix ipv4PrefixFor(final @NonNull Ipv4Address addr, final int mask) {
421 return newIpv4Prefix(stripZone(addr.getValue()), mask);
424 public static @NonNull Ipv4Prefix ipv4PrefixForNoZone(final @NonNull Ipv4AddressNoZone addr) {
425 return P4_FACTORY.newInstance(addr.getValue() + "/32");
428 public static @NonNull Ipv4Prefix ipv4PrefixForNoZone(final @NonNull Ipv4AddressNoZone addr, final int mask) {
429 return newIpv4Prefix(addr.getValue(), mask);
432 public static @NonNull Ipv4Prefix ipv4PrefixForShort(final byte @NonNull[] address, final int mask) {
434 // Easy case, reuse the template
435 return P4_FACTORY.getTemplate();
438 return v4PrefixForShort(address, 0, mask / Byte.SIZE + (mask % Byte.SIZE == 0 ? 0 : 1), mask);
441 public static @NonNull Ipv4Prefix ipv4PrefixForShort(final byte @NonNull[] array, final int startOffset,
444 // Easy case, reuse the template
445 return P4_FACTORY.getTemplate();
448 return v4PrefixForShort(array, startOffset, mask / Byte.SIZE + (mask % Byte.SIZE == 0 ? 0 : 1), mask);
451 private static String stripZone(final String str) {
452 final int percent = str.indexOf('%');
453 return percent == -1 ? str : str.substring(0, percent);
456 private static @NonNull Ipv4Prefix newIpv4Prefix(final String addr, final int mask) {
457 checkArgument(mask >= 0 && mask <= 32, "Invalid mask %s", mask);
458 return P4_FACTORY.newInstance(addr + '/' + mask);
461 public static @NonNull Entry<Ipv4AddressNoZone, Integer> splitIpv4Prefix(final @NonNull Ipv4Prefix prefix) {
462 return splitPrefix(V4NZ_FACTORY, prefix.getValue());
465 public static byte @NonNull[] ipv4PrefixToBytes(final @NonNull Ipv4Prefix prefix) {
466 final var str = prefix.getValue();
467 final int slash = str.lastIndexOf('/');
469 final byte[] bytes = new byte[Ipv4Utils.INET4_LENGTH + 1];
470 Ipv4Utils.fillIpv4Bytes(bytes, 0, str, 0, slash);
471 bytes[Ipv4Utils.INET4_LENGTH] = (byte)Integer.parseInt(str.substring(slash + 1), 10);
476 * Create an Ipv6Address by interpreting input bytes as an IPv6 address.
478 * @param bytes 16-byte array
479 * @return An Ipv6Address object
480 * @throws IllegalArgumentException if bytes has length different from 16
481 * @throws NullPointerException if {@code bytes} is {@code null}
483 public static @NonNull Ipv6AddressNoZone ipv6AddressFor(final byte @NonNull[] bytes) {
484 return V6NZ_FACTORY.newInstance(addressStringV6(bytes));
488 * Create an Ipv6Address by interpreting an {@link Inet6Address}.
490 * @param addr An {@link Inet6Address}
491 * @return An Ipv6Address object
492 * @throws IllegalArgumentException if @{code addr} is not an {@link Inet6Address}
493 * @throws NullPointerException if {@code addr} is {@code null}
495 public static @NonNull Ipv6AddressNoZone ipv6AddressFor(final @NonNull InetAddress addr) {
496 return V6NZ_FACTORY.newInstance(addressStringV6(addr));
500 * Create an Ipv6AddressNoZone by interpreting an Ipv6Address.
502 * @param addr An Ipv6Address
503 * @return An Ipv6AddressNoZone object
504 * @throws NullPointerException if addr is null
506 public static @NonNull Ipv6AddressNoZone ipv6AddressNoZoneFor(final @NonNull Ipv6Address addr) {
507 requireAddress(addr);
508 return addr instanceof Ipv6AddressNoZone noZone ? noZone
509 : V6NZ_FACTORY.newInstance(stripZone(addr.getValue()));
512 public static @NonNull Ipv6AddressNoZone ipv6AddressFrom(final @NonNull Ipv6Prefix prefix) {
513 return prefixToAddress(V6NZ_FACTORY, prefix.getValue());
516 public static byte @NonNull[] ipv6AddressBytes(final @NonNull Ipv6Address addr) {
517 final var str = addr.getValue();
518 final int percent = str.indexOf('%');
519 return ipv6StringBytes(str, percent == -1 ? str.length() : percent);
522 public static byte @NonNull[] ipv6AddressNoZoneBytes(final @NonNull Ipv6Address addr) {
523 final var str = addr.getValue();
524 return ipv6StringBytes(str, str.length());
527 private static byte @NonNull[] ipv6StringBytes(final @NonNull String str, final int limit) {
528 final byte[] bytes = new byte[Ipv6Utils.INET6_LENGTH];
529 Ipv6Utils.fillIpv6Bytes(bytes, str, limit);
534 * Create a /128 Ipv6Prefix by interpreting input bytes as an IPv6 address.
536 * @param bytes four-byte array
537 * @return An Ipv6Prefix object
538 * @throws IllegalArgumentException if bytes has length different from 16
539 * @throws NullPointerException if bytes is null
541 public static @NonNull Ipv6Prefix ipv6PrefixFor(final byte @NonNull[] bytes) {
542 return P6_FACTORY.newInstance(addressStringV6(bytes) + "/128");
546 * Create a Ipv6Prefix by combining the address with a mask. The address
547 * bytes are interpreted as an address and the specified mask is concatenated to
548 * it. The address bytes are not masked.
550 * @param address Input address as a 16-byte array
551 * @param mask Prefix mask
552 * @return An Ipv6Prefix object
553 * @throws IllegalArgumentException if bytes has length different from 16 or if mask is not in range 0-128
554 * @throws NullPointerException if bytes is null
556 public static @NonNull Ipv6Prefix ipv6PrefixFor(final byte @NonNull[] address, final int mask) {
557 checkArgument(mask >= 0 && mask <= 128, "Invalid mask %s", mask);
558 return P6_FACTORY.newInstance(addressStringV6(address) + '/' + mask);
562 * Create a /128 Ipv6Prefix by interpreting input bytes as an IPv6 address.
564 * @param addr an {@link Inet6Address}
565 * @return An Ipv6Prefix object
566 * @throws IllegalArgumentException if addr is not an Inet6Address
567 * @throws NullPointerException if addr is null
569 public static @NonNull Ipv6Prefix ipv6PrefixFor(final @NonNull InetAddress addr) {
570 return P6_FACTORY.newInstance(addressStringV6(addr) + "/128");
574 * Create a Ipv6Prefix by combining the address with a mask. The address
575 * bytes are interpreted as an address and the specified mask is concatenated to
576 * it. The address bytes are not masked.
578 * @param addr Input address
579 * @param mask Prefix mask
580 * @return An Ipv6Prefix object
581 * @throws IllegalArgumentException if addr is not an Inet6Address or if mask is not in range 0-128
582 * @throws NullPointerException if addr is null
584 public static @NonNull Ipv6Prefix ipv6PrefixFor(final @NonNull InetAddress addr, final int mask) {
585 checkArgument(mask >= 0 && mask <= 128, "Invalid mask %s", mask);
586 return P6_FACTORY.newInstance(addressStringV6(addr) + '/' + mask);
589 public static @NonNull Ipv6Prefix ipv6PrefixFor(final @NonNull Ipv6Address addr) {
590 return P6_FACTORY.newInstance(stripZone(addr.getValue()) + "/128");
593 public static @NonNull Ipv6Prefix ipv6PrefixFor(final @NonNull Ipv6Address addr, final int mask) {
594 return newIpv6Prefix(stripZone(addr.getValue()), mask);
597 public static @NonNull Ipv6Prefix ipv6PrefixForNoZone(final @NonNull Ipv6AddressNoZone addr) {
598 return P6_FACTORY.newInstance(addr.getValue() + "/128");
601 public static @NonNull Ipv6Prefix ipv6PrefixForNoZone(final @NonNull Ipv6AddressNoZone addr, final int mask) {
602 return newIpv6Prefix(addr.getValue(), mask);
605 public static @NonNull Ipv6Prefix ipv6PrefixForShort(final byte @NonNull[] address, final int mask) {
606 return ipv6PrefixForShort(address, 0, mask);
609 public static @NonNull Ipv6Prefix ipv6PrefixForShort(final byte @NonNull[] array, final int startOffset,
612 // Easy case, reuse the template
613 return P6_FACTORY.getTemplate();
616 checkArgument(mask > 0 && mask <= 128, "Invalid mask %s", mask);
617 final int size = mask / Byte.SIZE + (mask % Byte.SIZE == 0 ? 0 : 1);
619 // Until we can instantiate an IPv6 address for a partial array, use a temporary buffer
620 byte[] tmp = new byte[Ipv6Utils.INET6_LENGTH];
621 System.arraycopy(array, startOffset, tmp, 0, size);
622 return ipv6PrefixFor(tmp, mask);
625 private static Ipv6Prefix newIpv6Prefix(final String addr, final int mask) {
626 checkArgument(mask >= 0 && mask <= 128, "Invalid mask %s", mask);
627 return P6_FACTORY.newInstance(addr + '/' + mask);
630 public static @NonNull Entry<Ipv6AddressNoZone, Integer> splitIpv6Prefix(final @NonNull Ipv6Prefix prefix) {
631 return splitPrefix(V6NZ_FACTORY, prefix.getValue());
634 private static <T> @NonNull T prefixToAddress(final StringValueObjectFactory<T> factory, final String str) {
635 return factory.newInstance(str.substring(0, str.lastIndexOf('/')));
638 private static <T> @NonNull Entry<T, Integer> splitPrefix(final StringValueObjectFactory<T> factory,
640 final int slash = str.lastIndexOf('/');
641 return new SimpleImmutableEntry<>(factory.newInstance(str.substring(0, slash)),
642 Integer.valueOf(str.substring(slash + 1)));
645 public static byte @NonNull[] ipv6PrefixToBytes(final @NonNull Ipv6Prefix prefix) {
646 final var str = prefix.getValue();
647 final byte[] bytes = new byte[Ipv6Utils.INET6_LENGTH + 1];
648 final int slash = str.lastIndexOf('/');
649 Ipv6Utils.fillIpv6Bytes(bytes, str, slash);
650 bytes[Ipv6Utils.INET6_LENGTH] = (byte)Integer.parseInt(str.substring(slash + 1), 10);
654 private static @NonNull String addressStringV4(final InetAddress addr) {
655 requireAddress(addr);
656 checkArgument(addr instanceof Inet4Address, "Address has to be an Inet4Address");
657 return addr.getHostAddress();
660 private static String addressStringV6(final byte @NonNull[] bytes) {
661 checkArgument(bytes.length == Ipv6Utils.INET6_LENGTH, "IPv6 address length is 16 bytes");
664 return addressStringV6(Inet6Address.getByAddress(null, bytes, null));
665 } catch (UnknownHostException e) {
666 throw new IllegalArgumentException(String.format("Invalid input %s", bytes), e);
670 private static String addressStringV6(final InetAddress addr) {
671 requireAddress(addr);
672 checkArgument(addr instanceof Inet6Address, "Address has to be an Inet6Address");
673 return addressStringV6((Inet6Address) addr);
676 private static String addressStringV6(final Inet6Address addr) {
677 return InetAddresses.toAddrString(addr);
680 private static String prefixStringV4(final byte @NonNull[] bytes) {
681 final StringBuilder sb = new StringBuilder(18);
682 Ipv4Utils.appendIpv4String(sb, bytes);
683 return sb.append("/32").toString();
686 private static String prefixStringV4(final byte @NonNull[] bytes, final int mask) {
687 checkArgument(mask >= 0 && mask <= 32, "Invalid mask %s", mask);
689 final StringBuilder sb = new StringBuilder(18);
690 Ipv4Utils.appendIpv4String(sb, bytes);
691 return sb.append('/').append(mask).toString();
694 private static @NonNull Ipv4Prefix v4PrefixForShort(final byte @NonNull[] array, final int startOffset,
695 final int size, final int mask) {
696 if (startOffset == 0 && size == Ipv4Utils.INET4_LENGTH && array.length == Ipv4Utils.INET4_LENGTH) {
697 // Easy case, fall back to non-short
698 return ipv4PrefixFor(array, mask);
701 final StringBuilder sb = new StringBuilder(18);
704 sb.append(Byte.toUnsignedInt(array[startOffset]));
705 for (int i = 1; i < size; i++) {
706 sb.append('.').append(Byte.toUnsignedInt(array[startOffset + i]));
710 for (int i = size; i < Ipv4Utils.INET4_LENGTH; i++) {
715 checkArgument(mask > 0 && mask <= 32, "Invalid mask %s", mask);
716 sb.append('/').append(mask);
718 return P4_FACTORY.newInstance(sb.toString());
721 private static @NonNull Ipv6Address coerceIpv6Address(final @NonNull IpAddress addr) {
722 final var ret = addr.getIpv6Address();
723 checkArgument(ret != null, "Address %s is neither IPv4 nor IPv6", addr);
727 private static @NonNull Ipv6AddressNoZone coerceIpv6AddressNoZone(final @NonNull IpAddressNoZone addr) {
728 final var ret = addr.getIpv6AddressNoZone();
729 checkArgument(ret != null, "Address %s is neither IPv4 nor IPv6", addr);