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.mdsal.model.ietf.util;
10 import com.google.common.base.Preconditions;
11 import com.google.common.base.Verify;
12 import com.google.common.net.InetAddresses;
13 import java.net.Inet4Address;
14 import java.net.InetAddress;
15 import javax.annotation.Nonnull;
18 * IPv6 address parsing for ietf-inet-types ipv6-address and ipv6-prefix. This is an internal implementation
19 * class, not meant to be exposed in any shape or form to the outside world, as the code relies on the fact that
20 * the strings presented to it have been previously validated to conform to the regular expressions defined in
24 * v6 routines added by Anton Ivanov on 14.6.2015
25 * revised by Robert Varga
28 * Read all of the following before you touch any v6 code or decide to
29 * optimize it by invoking a "simple" Guava call
31 * Java IPv6 is fundamentally broken and Google libraries do not fix it.
32 * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
33 * and there is absolutely no way to override this behaviour
34 * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
35 * exception. Even if they did, they re-use the same broken java code
38 * This is why we have to parse v6 by ourselves.
40 * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
42 * The original BSD code is licensed under standard BSD license. While we
43 * are not obliged to provide an attribution, credit where credit is due.
44 * As far as why it is similar to Sun's sun.net.util please ask Sun why
45 * their code has the same variable names, comments and code flow.
47 final class Ipv6Utils {
48 private static final int INADDR4SZ = 4;
49 private static final int INADDR6SZ = 16;
50 private static final int INT16SZ = Short.BYTES;
53 throw new UnsupportedOperationException();
57 * Convert Ipv6Address object to a valid Canonical v6 address in byte format
59 * @param addrStr IPv6 address string
60 * @return byte array of size 16 containing the binary IPv6 address
61 * @throws NullPointerException if ipv6address is null
63 public static @Nonnull byte[] bytesForString(final @Nonnull String addrStr) {
64 final int percentPos = addrStr.indexOf('%');
65 final int addrStrLen = percentPos == -1 ? addrStr.length() : percentPos;
67 /* Leading :: requires some special handling. */
69 if (addrStr.charAt(i) == ':') {
70 // Note ++i side-effect in check
71 Preconditions.checkArgument(addrStr.charAt(++i) == ':', "Invalid v6 address '%s'", addrStr);
74 final byte[] dst = new byte[INADDR6SZ];
76 boolean saw_xdigit = false;
81 while (i < addrStrLen) {
82 final char ch = addrStr.charAt(i++);
88 /* no need to check separator position validity - regexp does that */
93 /* removed overrun check - the regexp checks for valid data */
95 dst[j++] = (byte) ((val >>> 8) & 0xff);
96 dst[j++] = (byte) (val & 0xff);
102 /* frankenstein - v4 attached to v6, mixed notation */
103 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
105 /* this has passed the regexp so it is fairly safe to parse it
106 * straight away. As v4 addresses do not suffer from the same
107 * deficiencies as the java v6 implementation we can invoke it
108 * straight away and be done with it
110 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping in %s", addrStr);
111 InetAddress _inet_form = InetAddresses.forString(addrStr.substring(curtok, addrStrLen));
113 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
114 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
121 /* Business as usual - ipv6 address digit.
122 * We can remove all checks from the original BSD code because
123 * the regexp has already verified that we are not being fed
124 * anything bigger than 0xffff between the separators.
126 final int chval = AbstractIetfYangUtil.hexValue(ch);
127 val = (val << 4) | chval;
132 Verify.verify(j + INT16SZ <= INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
133 dst[j++] = (byte) ((val >> 8) & 0xff);
134 dst[j++] = (byte) (val & 0xff);
138 Verify.verify(j != INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
140 final int n = j - colonp;
141 for (i = 1; i <= n; i++) {
142 dst[INADDR6SZ - i] = dst[colonp + n - i];
143 dst[colonp + n - i] = 0;
146 Verify.verify(j == INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);