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 javax.annotation.Nonnull;
15 * IPv6 address parsing for ietf-inet-types ipv6-address and ipv6-prefix. This is an internal implementation
16 * class, not meant to be exposed in any shape or form to the outside world, as the code relies on the fact that
17 * the strings presented to it have been previously validated to conform to the regular expressions defined in
21 * v6 routines added by Anton Ivanov on 14.6.2015
22 * revised by Robert Varga
25 * Read all of the following before you touch any v6 code or decide to
26 * optimize it by invoking a "simple" Guava call
28 * Java IPv6 is fundamentally broken and Google libraries do not fix it.
29 * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
30 * and there is absolutely no way to override this behaviour
31 * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
32 * exception. Even if they did, they re-use the same broken java code
35 * This is why we have to parse v6 by ourselves.
37 * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
39 * The original BSD code is licensed under standard BSD license. While we
40 * are not obliged to provide an attribution, credit where credit is due.
41 * As far as why it is similar to Sun's sun.net.util please ask Sun why
42 * their code has the same variable names, comments and code flow.
44 final class Ipv6Utils {
45 private static final int INADDR4SZ = 4;
46 private static final int INADDR6SZ = 16;
47 private static final int INT16SZ = Short.BYTES;
50 throw new UnsupportedOperationException();
54 * Convert Ipv6Address object to a valid Canonical v6 address in byte format
56 * @param addrStr IPv6 address string
57 * @return byte array of size 16 containing the binary IPv6 address
58 * @throws NullPointerException if ipv6address is null
60 public static @Nonnull byte[] bytesForString(final @Nonnull String addrStr) {
61 final int percentPos = addrStr.indexOf('%');
62 final int addrStrLen = percentPos == -1 ? addrStr.length() : percentPos;
64 /* Leading :: requires some special handling. */
66 if (addrStr.charAt(i) == ':') {
67 // Note ++i side-effect in check
68 Preconditions.checkArgument(addrStr.charAt(++i) == ':', "Invalid v6 address '%s'", addrStr);
71 final byte[] dst = new byte[INADDR6SZ];
73 boolean saw_xdigit = false;
78 while (i < addrStrLen) {
79 final char ch = addrStr.charAt(i++);
85 /* no need to check separator position validity - regexp does that */
90 /* removed overrun check - the regexp checks for valid data */
92 dst[j++] = (byte) ((val >>> 8) & 0xff);
93 dst[j++] = (byte) (val & 0xff);
99 /* frankenstein - v4 attached to v6, mixed notation */
100 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
103 * This has passed the regexp so it is fairly safe to parse it
104 * straight away. Use the Ipv4Utils for that.
106 Ipv4Utils.fillIpv4Bytes(dst, j, addrStr, curtok, addrStrLen);
112 /* Business as usual - ipv6 address digit.
113 * We can remove all checks from the original BSD code because
114 * the regexp has already verified that we are not being fed
115 * anything bigger than 0xffff between the separators.
117 final int chval = AbstractIetfYangUtil.hexValue(ch);
118 val = (val << 4) | chval;
123 Verify.verify(j + INT16SZ <= INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
124 dst[j++] = (byte) ((val >> 8) & 0xff);
125 dst[j++] = (byte) (val & 0xff);
129 Verify.verify(j != INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);
131 final int n = j - colonp;
132 for (i = 1; i <= n; i++) {
133 dst[INADDR6SZ - i] = dst[colonp + n - i];
134 dst[colonp + n - i] = 0;
137 Verify.verify(j == INADDR6SZ, "Overrun in parsing of '%s', should not occur", addrStr);