11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2008 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.net; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.VisibleForTesting; 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Preconditions; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.io.ByteStreams; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.primitives.Ints; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.net.Inet4Address; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.net.Inet6Address; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.net.InetAddress; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.net.UnknownHostException; 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.nio.ByteBuffer; 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Arrays; 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.Nullable; 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Static utility methods pertaining to {@link InetAddress} instances. 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p><b>Important note:</b> Unlike {@code InetAddress.getByName()}, the 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * methods of this class never cause DNS services to be accessed. For 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * this reason, you should prefer these methods as much as possible over 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * their JDK equivalents whenever you are expecting to handle only 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IP address string literals -- there is no blocking DNS penalty for a 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * malformed string. 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This class hooks into the {@code sun.net.util.IPAddressUtil} class 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * to make use of the {@code textToNumericFormatV4} and 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code textToNumericFormatV6} methods directly as a means to avoid 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * accidentally traversing all nameservices (it can be vitally important 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * to avoid, say, blocking on DNS at times). 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>When dealing with {@link Inet4Address} and {@link Inet6Address} 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * objects as byte arrays (vis. {@code InetAddress.getAddress()}) they 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * are 4 and 16 bytes in length, respectively, and represent the address 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in network byte order. 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Examples of IP addresses and their byte representations: 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <ul> 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>The IPv4 loopback address, {@code "127.0.0.1"}.<br/> 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code 7f 00 00 01} 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>The IPv6 loopback address, {@code "::1"}.<br/> 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01} 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>From the IPv6 reserved documentation prefix ({@code 2001:db8::/32}), 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code "2001:db8::1"}.<br/> 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01} 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>An IPv6 "IPv4 compatible" (or "compat") address, 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code "::192.168.0.1"}.<br/> 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 00 01} 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>An IPv6 "IPv4 mapped" address, {@code "::ffff:192.168.0.1"}.<br/> 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code 00 00 00 00 00 00 00 00 00 00 ff ff c0 a8 00 01} 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * </ul> 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>A few notes about IPv6 "IPv4 mapped" addresses and their observed 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * use in Java. 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <br><br> 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * "IPv4 mapped" addresses were originally a representation of IPv4 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * addresses for use on an IPv6 socket that could receive both IPv4 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * and IPv6 connections (by disabling the {@code IPV6_V6ONLY} socket 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * option on an IPv6 socket). Yes, it's confusing. Nevertheless, 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * these "mapped" addresses were never supposed to be seen on the 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * wire. That assumption was dropped, some say mistakenly, in later 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * RFCs with the apparent aim of making IPv4-to-IPv6 transition simpler. 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Technically one <i>can</i> create a 128bit IPv6 address with the wire 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * format of a "mapped" address, as shown above, and transmit it in an 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6 packet header. However, Java's InetAddress creation methods 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * appear to adhere doggedly to the original intent of the "mapped" 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * address: all "mapped" addresses return {@link Inet4Address} objects. 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For added safety, it is common for IPv6 network operators to filter 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * all packets where either the source or destination address appears to 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * be a "compat" or "mapped" address. Filtering suggestions usually 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * recommend discarding any packets with source or destination addresses 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in the invalid range {@code ::/3}, which includes both of these bizarre 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * address formats. For more information on "bogons", including lists 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of IPv6 bogon space, see: 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <ul> 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li><a target="_parent" 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://en.wikipedia.org/wiki/Bogon_filtering" 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://en.wikipedia.org/wiki/Bogon_filtering</a> 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li><a target="_parent" 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://www.cymru.com/Bogons/ipv6.txt" 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://www.cymru.com/Bogons/ipv6.txt</a> 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li><a target="_parent" 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://www.cymru.com/Bogons/v6bogon.html" 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://www.cymru.com/Bogons/v6bogon.html</a> 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li><a target="_parent" 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://www.space.net/~gert/RIPE/ipv6-filters.html" 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://www.space.net/~gert/RIPE/ipv6-filters.html</a> 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * </ul> 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Erik Kline 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 5.0 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic final class InetAddresses { 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final int IPV4_PART_COUNT = 4; 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final int IPV6_PART_COUNT = 8; 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Inet4Address LOOPBACK4 = 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert (Inet4Address) forString("127.0.0.1"); 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final Inet4Address ANY4 = 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert (Inet4Address) forString("0.0.0.0"); 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private InetAddresses() {} 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an {@link Inet4Address}, given a byte array representation 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of the IPv4 address. 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param bytes byte array representing an IPv4 address (should be 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of length 4). 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} corresponding to the supplied byte 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * array. 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if a valid {@link Inet4Address} 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * can not be created. 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static Inet4Address getInet4Address(byte[] bytes) { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(bytes.length == 4, 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Byte array has invalid length for an IPv4 address: %s != 4.", 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bytes.length); 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert InetAddress ipv4 = InetAddress.getByAddress(bytes); 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (!(ipv4 instanceof Inet4Address)) { 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new UnknownHostException( 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String.format("'%s' is not an IPv4 address.", 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ipv4.getHostAddress())); 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (Inet4Address) ipv4; 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (UnknownHostException e) { 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This really shouldn't happen in practice since all our byte 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * sequences should be valid IP addresses. 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * However {@link InetAddress#getByAddress} is documented as 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * potentially throwing this "if IP address is of illegal length". 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This is mapped to IllegalArgumentException since, presumably, 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the argument triggered some bizarre processing bug. 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException( 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String.format("Host address '%s' is not a valid IPv4 address.", 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Arrays.toString(bytes)), 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert e); 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the {@link InetAddress} having the given string 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * representation. 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This deliberately avoids all nameservice lookups (e.g. no DNS). 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ipString {@code String} containing an IPv4 or IPv6 string literal, 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * e.g. {@code "192.168.0.1"} or {@code "2001:db8::1"} 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link InetAddress} representing the argument 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument is not a valid 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IP string literal 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static InetAddress forString(String ipString) { 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] addr = ipStringToBytes(ipString); 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // The argument was malformed, i.e. not an IP string literal. 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (addr == null) { 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException( 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String.format("'%s' is not an IP string literal.", ipString)); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return InetAddress.getByAddress(addr); 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (UnknownHostException e) { 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This really shouldn't happen in practice since all our byte 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * sequences should be valid IP addresses. 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * However {@link InetAddress#getByAddress} is documented as 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * potentially throwing this "if IP address is of illegal length". 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This is mapped to IllegalArgumentException since, presumably, 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the argument triggered some processing bug in either 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link IPAddressUtil#textToNumericFormatV4} or 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link IPAddressUtil#textToNumericFormatV6}. 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException( 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String.format("'%s' is extremely broken.", ipString), e); 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns {@code true} if the supplied string is a valid IP string 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * literal, {@code false} otherwise. 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ipString {@code String} to evaluated as an IP string literal 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a valid IP string literal 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isInetAddress(String ipString) { 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return ipStringToBytes(ipString) != null; 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static byte[] ipStringToBytes(String ipString) { 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Make a first pass to categorize the characters in this string. 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean hasColon = false; 2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean hasDot = false; 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < ipString.length(); i++) { 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert char c = ipString.charAt(i); 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (c == '.') { 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasDot = true; 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else if (c == ':') { 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (hasDot) { 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; // Colons must not appear after dots. 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hasColon = true; 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else if (Character.digit(c, 16) == -1) { 2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; // Everything else must be a decimal or hex digit. 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Now decide which address family to parse. 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (hasColon) { 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (hasDot) { 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ipString = convertDottedQuadToHex(ipString); 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (ipString == null) { 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return textToNumericFormatV6(ipString); 2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else if (hasDot) { 2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return textToNumericFormatV4(ipString); 2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static byte[] textToNumericFormatV4(String ipString) { 2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String[] address = ipString.split("\\.", IPV4_PART_COUNT + 1); 2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (address.length != IPV4_PART_COUNT) { 2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = new byte[IPV4_PART_COUNT]; 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < bytes.length; i++) { 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bytes[i] = parseOctet(address[i]); 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (NumberFormatException ex) { 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return bytes; 2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static byte[] textToNumericFormatV6(String ipString) { 2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // An address can have [2..8] colons, and N colons make N+1 parts. 2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String[] parts = ipString.split(":", IPV6_PART_COUNT + 2); 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (parts.length < 3 || parts.length > IPV6_PART_COUNT + 1) { 2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Disregarding the endpoints, find "::" with nothing in between. 2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // This indicates that a run of zeroes has been skipped. 2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int skipIndex = -1; 2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 1; i < parts.length - 1; i++) { 2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (parts[i].length() == 0) { 2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (skipIndex >= 0) { 2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; // Can't have more than one :: 2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert skipIndex = i; 2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int partsHi; // Number of parts to copy from above/before the "::" 2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int partsLo; // Number of parts to copy from below/after the "::" 2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (skipIndex >= 0) { 2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If we found a "::", then check if it also covers the endpoints. 3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert partsHi = skipIndex; 3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert partsLo = parts.length - skipIndex - 1; 3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (parts[0].length() == 0 && --partsHi != 0) { 3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; // ^: requires ^:: 3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (parts[parts.length - 1].length() == 0 && --partsLo != 0) { 3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; // :$ requires ::$ 3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Otherwise, allocate the entire address to partsHi. The endpoints 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // could still be empty, but parseHextet() will check for that. 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert partsHi = parts.length; 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert partsLo = 0; 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If we found a ::, then we must have skipped at least one part. 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Otherwise, we must have exactly the right number of parts. 3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int partsSkipped = IPV6_PART_COUNT - (partsHi + partsLo); 3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (!(skipIndex >= 0 ? partsSkipped >= 1 : partsSkipped == 0)) { 3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Now parse the hextets into a byte array. 3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ByteBuffer rawBytes = ByteBuffer.allocate(2 * IPV6_PART_COUNT); 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < partsHi; i++) { 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert rawBytes.putShort(parseHextet(parts[i])); 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < partsSkipped; i++) { 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert rawBytes.putShort((short) 0); 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = partsLo; i > 0; i--) { 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert rawBytes.putShort(parseHextet(parts[parts.length - i])); 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (NumberFormatException ex) { 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return rawBytes.array(); 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static String convertDottedQuadToHex(String ipString) { 3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int lastColon = ipString.lastIndexOf(':'); 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String initialPart = ipString.substring(0, lastColon + 1); 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String dottedQuad = ipString.substring(lastColon + 1); 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] quad = textToNumericFormatV4(dottedQuad); 3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (quad == null) { 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return null; 3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String penultimate = Integer.toHexString(((quad[0] & 0xff) << 8) | (quad[1] & 0xff)); 3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String ultimate = Integer.toHexString(((quad[2] & 0xff) << 8) | (quad[3] & 0xff)); 3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return initialPart + penultimate + ":" + ultimate; 3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static byte parseOctet(String ipPart) { 3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Note: we already verified that this string contains only hex digits. 3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int octet = Integer.parseInt(ipPart); 3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Disallow leading zeroes, because no clear standard exists on 3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // whether these should be interpreted as decimal or octal. 3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (octet > 255 || (ipPart.startsWith("0") && ipPart.length() > 1)) { 3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new NumberFormatException(); 3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (byte) octet; 3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static short parseHextet(String ipPart) { 3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Note: we already verified that this string contains only hex digits. 3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int hextet = Integer.parseInt(ipPart, 16); 3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (hextet > 0xffff) { 3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new NumberFormatException(); 3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (short) hextet; 3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the string representation of an {@link InetAddress}. 3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For IPv4 addresses, this is identical to 3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddress#getHostAddress()}, but for IPv6 addresses, the output 3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * follows <a href="http://tools.ietf.org/html/rfc5952">RFC 5952</a> 3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * section 4. The main difference is that this method uses "::" for zero 3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * compression, while Java's version uses the uncompressed form. 3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This method uses hexadecimal for all IPv6 addresses, including 3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv4-mapped IPv6 addresses such as "::c000:201". The output does not 3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * include a Scope ID. 3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link InetAddress} to be converted to an address string 3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code String} containing the text-formatted IP address 3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 10.0 3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static String toAddrString(InetAddress ip) { 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkNotNull(ip); 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (ip instanceof Inet4Address) { 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // For IPv4, Java's formatting is good enough. 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return ip.getHostAddress(); 3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(ip instanceof Inet6Address); 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int[] hextets = new int[IPV6_PART_COUNT]; 3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < hextets.length; i++) { 4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert hextets[i] = Ints.fromBytes( 4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert (byte) 0, (byte) 0, bytes[2 * i], bytes[2 * i + 1]); 4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert compressLongestRunOfZeroes(hextets); 4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return hextetsToIPv6String(hextets); 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Identify and mark the longest run of zeroes in an IPv6 address. 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Only runs of two or more hextets are considered. In case of a tie, the 4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * leftmost run wins. If a qualifying run is found, its hextets are replaced 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * by the sentinel value -1. 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param hextets {@code int[]} mutable array of eight 16-bit hextets. 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static void compressLongestRunOfZeroes(int[] hextets) { 4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int bestRunStart = -1; 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int bestRunLength = -1; 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int runStart = -1; 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < hextets.length + 1; i++) { 4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (i < hextets.length && hextets[i] == 0) { 4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (runStart < 0) { 4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runStart = i; 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else if (runStart >= 0) { 4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int runLength = i - runStart; 4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (runLength > bestRunLength) { 4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bestRunStart = runStart; 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert bestRunLength = runLength; 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runStart = -1; 4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (bestRunLength >= 2) { 4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Arrays.fill(hextets, bestRunStart, bestRunStart + bestRunLength, -1); 4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Convert a list of hextets into a human-readable IPv6 address. 4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>In order for "::" compression to work, the input should contain negative 4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * sentinel values in place of the elided zeroes. 4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param hextets {@code int[]} array of eight 16-bit hextets, or -1s. 4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static String hextetsToIPv6String(int[] hextets) { 4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * While scanning the array, handle these state transitions: 4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * start->num => "num" start->gap => "::" 4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * num->num => ":num" num->gap => "::" 4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * gap->num => "num" gap->gap => "" 4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert StringBuilder buf = new StringBuilder(39); 4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean lastWasNumber = false; 4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < hextets.length; i++) { 4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean thisIsNumber = hextets[i] >= 0; 4581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (thisIsNumber) { 4591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (lastWasNumber) { 4601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buf.append(':'); 4611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buf.append(Integer.toHexString(hextets[i])); 4631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 4641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (i == 0 || lastWasNumber) { 4651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert buf.append("::"); 4661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert lastWasNumber = thisIsNumber; 4691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return buf.toString(); 4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the string representation of an {@link InetAddress} suitable 4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for inclusion in a URI. 4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For IPv4 addresses, this is identical to 4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddress#getHostAddress()}, but for IPv6 addresses it 4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * compresses zeroes and surrounds the text with square brackets; for example 4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code "[2001:db8::1]"}. 4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Per section 3.2.2 of 4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" 4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://tools.ietf.org/html/rfc3986#section-3.2.2" 4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc3986</a>, 4861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * a URI containing an IPv6 string literal is of the form 4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code "http://[2001:db8::1]:8888/index.html"}. 4881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Use of either {@link InetAddresses#toAddrString}, 4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddress#getHostAddress()}, or this method is recommended over 4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddress#toString()} when an IP address string literal is 4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * desired. This is because {@link InetAddress#toString()} prints the 4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * hostname and the IP address string joined by a "/". 4941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link InetAddress} to be converted to URI string literal 4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code String} containing URI-safe string literal 4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static String toUriString(InetAddress ip) { 4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (ip instanceof Inet6Address) { 5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return "[" + toAddrString(ip) + "]"; 5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return toAddrString(ip); 5031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 5061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an InetAddress representing the literal IPv4 or IPv6 host 5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2. 5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This function is similar to {@link InetAddresses#forString(String)}, 5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * however, it requires that IPv6 addresses are surrounded by square brackets. 5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This function is the inverse of 5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddresses#toUriString(java.net.InetAddress)}. 5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param hostAddr A RFC 3986 section 3.2.2 encoded IPv4 or IPv6 address 5161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return an InetAddress representing the address in {@code hostAddr} 5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if {@code hostAddr} is not a valid 5181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv4 address, or IPv6 address surrounded by square brackets 5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static InetAddress forUriString(String hostAddr) { 5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkNotNull(hostAddr); 5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(hostAddr.length() > 0, "host string is empty"); 5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert InetAddress retval = null; 5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // IPv4 address? 5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert retval = forString(hostAddr); 5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (retval instanceof Inet4Address) { 5291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return retval; 5301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IllegalArgumentException e) { 5321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Not a valid IP address, fall through. 5331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // IPv6 address 5361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (!(hostAddr.startsWith("[") && hostAddr.endsWith("]"))) { 5371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"'); 5381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert retval = forString(hostAddr.substring(1, hostAddr.length() - 1)); 5411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (retval instanceof Inet6Address) { 5421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return retval; 5431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"'); 5461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 5491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns {@code true} if the supplied string is a valid URI IP string 5501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * literal, {@code false} otherwise. 5511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ipString {@code String} to evaluated as an IP URI host string literal 5531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a valid IP URI host 5541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isUriInetAddress(String ipString) { 5561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 5571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert forUriString(ipString); 5581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return true; 5591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (IllegalArgumentException e) { 5601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 5611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 5651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Evaluates whether the argument is an IPv6 "compat" address. 5661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>An "IPv4 compatible", or "compat", address is one with 96 leading 5681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * bits of zero, with the remaining 32 bits interpreted as an 5691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv4 address. These are conventionally represented in string 5701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * literals as {@code "::192.168.0.1"}, though {@code "::c0a8:1"} is 5711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * also considered an IPv4 compatible address (and equivalent to 5721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code "::192.168.0.1"}). 5731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For more on IPv4 compatible addresses see section 2.5.5.1 of 5751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" 5761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://tools.ietf.org/html/rfc4291#section-2.5.5.1" 5771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc4291</a> 5781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>NOTE: This method is different from 5801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Inet6Address#isIPv4CompatibleAddress} in that it more 5811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * correctly classifies {@code "::"} and {@code "::1"} as 5821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * proper IPv6 addresses (which they are), NOT IPv4 compatible 5831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * addresses (which they are generally NOT considered to be). 5841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 5851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded IPv4 5861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * compatible address format 5871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a valid "compat" address 5881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 5891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isCompatIPv4Address(Inet6Address ip) { 5901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (!ip.isIPv4CompatibleAddress()) { 5911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 5921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 5941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 5951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if ((bytes[12] == 0) && (bytes[13] == 0) && (bytes[14] == 0) 5961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert && ((bytes[15] == 0) || (bytes[15] == 1))) { 5971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 5981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 5991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return true; 6011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 6041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the IPv4 address embedded in an IPv4 compatible address. 6051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for an embedded 6071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv4 address 6081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} of the embedded IPv4 address 6091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument is not a valid 6101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv4 compatible address 6111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 6121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address getCompatIPv4Address(Inet6Address ip) { 6131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(isCompatIPv4Address(ip), 6141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Address '%s' is not IPv4-compatible.", toAddrString(ip)); 6151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getInet4Address(copyOfRange(ip.getAddress(), 12, 16)); 6171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 6201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Evaluates whether the argument is a 6to4 address. 6211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>6to4 addresses begin with the {@code "2002::/16"} prefix. 6231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The next 32 bits are the IPv4 address of the host to which 6241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6-in-IPv4 tunneled packets should be routed. 6251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For more on 6to4 addresses see section 2 of 6271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" href="http://tools.ietf.org/html/rfc3056#section-2" 6281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc3056</a> 6291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for 6to4 address 6311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * format 6321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a 6to4 address 6331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 6341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean is6to4Address(Inet6Address ip) { 6351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 6361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (bytes[0] == (byte) 0x20) && (bytes[1] == (byte) 0x02); 6371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 6401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the IPv4 address embedded in a 6to4 address. 6411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded IPv4 6431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in 6to4 address. 6441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} of embedded IPv4 in 6to4 address. 6451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument is not a valid 6461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6 6to4 address. 6471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 6481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address get6to4IPv4Address(Inet6Address ip) { 6491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(is6to4Address(ip), 6501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Address '%s' is not a 6to4 address.", toAddrString(ip)); 6511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getInet4Address(copyOfRange(ip.getAddress(), 2, 6)); 6531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 6541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 6561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A simple data class to encapsulate the information to be found in a 6571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Teredo address. 6581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>All of the fields in this class are encoded in various portions 6601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of the IPv6 address as part of the protocol. More protocols details 6611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * can be found at: 6621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" href="http://en.wikipedia.org/wiki/Teredo_tunneling" 6631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://en.wikipedia.org/wiki/Teredo_tunneling</a>. 6641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>The RFC can be found here: 6661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" href="http://tools.ietf.org/html/rfc4380" 6671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc4380</a>. 6681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 5.0 6701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 6711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Beta 6721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static final class TeredoInfo { 6731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Inet4Address server; 6741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final Inet4Address client; 6751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final int port; 6761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final int flags; 6771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 6791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Constructs a TeredoInfo instance. 6801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Both server and client can be {@code null}, in which case the 6821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * value {@code "0.0.0.0"} will be assumed. 6831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 6841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if either of the {@code port} 6851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * or the {@code flags} arguments are out of range of an 6861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * unsigned short 6871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 6881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // TODO: why is this public? 6891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public TeredoInfo(@Nullable Inet4Address server, 6901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Nullable Inet4Address client, 6911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int port, int flags) { 6921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument((port >= 0) && (port <= 0xffff), 6931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "port '%s' is out of range (0 <= port <= 0xffff)", port); 6941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument((flags >= 0) && (flags <= 0xffff), 6951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "flags '%s' is out of range (0 <= flags <= 0xffff)", flags); 6961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 6971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (server != null) { 6981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.server = server; 6991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 7001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.server = ANY4; 7011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (client != null) { 7041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.client = client; 7051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 7061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.client = ANY4; 7071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.port = port; 7101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.flags = flags; 7111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Inet4Address getServer() { 7141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return server; 7151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Inet4Address getClient() { 7181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return client; 7191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public int getPort() { 7221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return port; 7231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public int getFlags() { 7261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return flags; 7271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 7311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Evaluates whether the argument is a Teredo address. 7321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Teredo addresses begin with the {@code "2001::/32"} prefix. 7341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for Teredo address 7361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * format. 7371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a Teredo address 7381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 7391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isTeredoAddress(Inet6Address ip) { 7401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 7411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (bytes[0] == (byte) 0x20) && (bytes[1] == (byte) 0x01) 7421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert && (bytes[2] == 0) && (bytes[3] == 0); 7431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 7461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the Teredo information embedded in a Teredo address. 7471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded Teredo 7491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * information 7501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return extracted {@code TeredoInfo} 7511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument is not a valid 7521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6 Teredo address 7531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 7541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static TeredoInfo getTeredoInfo(Inet6Address ip) { 7551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(isTeredoAddress(ip), 7561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Address '%s' is not a Teredo address.", toAddrString(ip)); 7571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 7591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Inet4Address server = getInet4Address(copyOfRange(bytes, 4, 8)); 7601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int flags = ByteStreams.newDataInput(bytes, 8).readShort() & 0xffff; 7621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Teredo obfuscates the mapped client port, per section 4 of the RFC. 7641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int port = ~ByteStreams.newDataInput(bytes, 10).readShort() & 0xffff; 7651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] clientBytes = copyOfRange(bytes, 12, 16); 7671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < clientBytes.length; i++) { 7681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Teredo obfuscates the mapped client IP, per section 4 of the RFC. 7691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert clientBytes[i] = (byte) ~clientBytes[i]; 7701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Inet4Address client = getInet4Address(clientBytes); 7721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new TeredoInfo(server, client, port, flags); 7741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 7771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Evaluates whether the argument is an ISATAP address. 7781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>From RFC 5214: "ISATAP interface identifiers are constructed in 7801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Modified EUI-64 format [...] by concatenating the 24-bit IANA OUI 7811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (00-00-5E), the 8-bit hexadecimal value 0xFE, and a 32-bit IPv4 7821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * address in network byte order [...]" 7831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For more on ISATAP addresses see section 6.1 of 7851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" href="http://tools.ietf.org/html/rfc5214#section-6.1" 7861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc5214</a> 7871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 7881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for ISATAP address 7891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * format. 7901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is an ISATAP address 7911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 7921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isIsatapAddress(Inet6Address ip) { 7931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 7941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // If it's a Teredo address with the right port (41217, or 0xa101) 7951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // which would be encoded as 0x5efe then it can't be an ISATAP address. 7961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (isTeredoAddress(ip)) { 7971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 7981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 7991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 8011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if ((bytes[8] | (byte) 0x03) != (byte) 0x03) { 8031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Verify that high byte of the 64 bit identifier is zero, modulo 8051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // the U/L and G bits, with which we are not concerned. 8061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 8071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (bytes[9] == (byte) 0x00) && (bytes[10] == (byte) 0x5e) 8101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert && (bytes[11] == (byte) 0xfe); 8111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 8141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the IPv4 address embedded in an ISATAP address. 8151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded IPv4 8171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in ISATAP address 8181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} of embedded IPv4 in an ISATAP address 8191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument is not a valid 8201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6 ISATAP address 8211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 8221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address getIsatapIPv4Address(Inet6Address ip) { 8231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(isIsatapAddress(ip), 8241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Address '%s' is not an ISATAP address.", toAddrString(ip)); 8251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getInet4Address(copyOfRange(ip.getAddress(), 12, 16)); 8271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 8301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Examines the Inet6Address to determine if it is an IPv6 address of one 8311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of the specified address types that contain an embedded IPv4 address. 8321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>NOTE: ISATAP addresses are explicitly excluded from this method 8341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * due to their trivial spoofability. With other transition addresses 8351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * spoofing involves (at least) infection of one's BGP routing table. 8361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded IPv4 8381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * client address. 8391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if there is an embedded IPv4 client address. 8401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 7.0 8411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 8421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean hasEmbeddedIPv4ClientAddress(Inet6Address ip) { 8431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return isCompatIPv4Address(ip) || is6to4Address(ip) || 8441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert isTeredoAddress(ip); 8451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 8481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Examines the Inet6Address to extract the embedded IPv4 client address 8491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * if the InetAddress is an IPv6 address of one of the specified address 8501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * types that contain an embedded IPv4 address. 8511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>NOTE: ISATAP addresses are explicitly excluded from this method 8531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * due to their trivial spoofability. With other transition addresses 8541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * spoofing involves (at least) infection of one's BGP routing table. 8551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link Inet6Address} to be examined for embedded IPv4 8571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * client address. 8581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} of embedded IPv4 client address. 8591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if the argument does not have a valid 8601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * embedded IPv4 address. 8611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 8621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address getEmbeddedIPv4ClientAddress(Inet6Address ip) { 8631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (isCompatIPv4Address(ip)) { 8641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getCompatIPv4Address(ip); 8651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (is6to4Address(ip)) { 8681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return get6to4IPv4Address(ip); 8691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (isTeredoAddress(ip)) { 8721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getTeredoInfo(ip).getClient(); 8731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException( 8761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String.format("'%s' has no embedded IPv4 address.", 8771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert toAddrString(ip))); 8781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 8791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 8801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 8811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Evaluates whether the argument is an "IPv4 mapped" IPv6 address. 8821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>An "IPv4 mapped" address is anything in the range ::ffff:0:0/96 8841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (sometimes written as ::ffff:0.0.0.0/96), with the last 32 bits 8851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * interpreted as an IPv4 address. 8861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>For more on IPv4 mapped addresses see section 2.5.5.2 of 8881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <a target="_parent" 8891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * href="http://tools.ietf.org/html/rfc4291#section-2.5.5.2" 8901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * >http://tools.ietf.org/html/rfc4291</a> 8911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Note: This method takes a {@code String} argument because 8931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link InetAddress} automatically collapses mapped addresses to IPv4. 8941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (It is actually possible to avoid this using one of the obscure 8951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Inet6Address} methods, but it would be unwise to depend on such 8961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * a poorly-documented feature.) 8971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 8981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ipString {@code String} to be examined for embedded IPv4-mapped 8991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * IPv6 address format 9001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code true} if the argument is a valid "mapped" address 9011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 10.0 9021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 9031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isMappedIPv4Address(String ipString) { 9041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ipStringToBytes(ipString); 9051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (bytes != null && bytes.length == 16) { 9061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 9071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (bytes[i] != 0) { 9081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 9091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 10; i < 12; i++) { 9121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (bytes[i] != (byte) 0xff) { 9131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 9141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return true; 9171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 9191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 9221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Coerces an IPv6 address into an IPv4 address. 9231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>HACK: As long as applications continue to use IPv4 addresses for 9251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * indexing into tables, accounting, et cetera, it may be necessary to 9261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <b>coerce</b> IPv6 addresses into IPv4 addresses. This function does 9271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * so by hashing the upper 64 bits into {@code 224.0.0.0/3} 9281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (64 bits into 29 bits). 9291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>A "coerced" IPv4 address is equivalent to itself. 9311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>NOTE: This function is failsafe for security purposes: ALL IPv6 9331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * addresses (except localhost (::1)) are hashed to avoid the security 9341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * risk associated with extracting an embedded IPv4 address that might 9351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * permit elevated privileges. 9361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link InetAddress} to "coerce" 9381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} represented "coerced" address 9391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 7.0 9401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 9411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address getCoercedIPv4Address(InetAddress ip) { 9421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (ip instanceof Inet4Address) { 9431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (Inet4Address) ip; 9441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Special cases: 9471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] bytes = ip.getAddress(); 9481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean leadingBytesOfZero = true; 9491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 15; ++i) { 9501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (bytes[i] != 0) { 9511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert leadingBytesOfZero = false; 9521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert break; 9531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (leadingBytesOfZero && (bytes[15] == 1)) { 9561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return LOOPBACK4; // ::1 9571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else if (leadingBytesOfZero && (bytes[15] == 0)) { 9581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return ANY4; // ::0 9591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Inet6Address ip6 = (Inet6Address) ip; 9621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long addressAsLong = 0; 9631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (hasEmbeddedIPv4ClientAddress(ip6)) { 9641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert addressAsLong = getEmbeddedIPv4ClientAddress(ip6).hashCode(); 9651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 9661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Just extract the high 64 bits (assuming the rest is user-modifiable). 9681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert addressAsLong = ByteBuffer.wrap(ip6.getAddress(), 0, 8).getLong(); 9691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Many strategies for hashing are possible. This might suffice for now. 9721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int coercedHash = hash64To32(addressAsLong); 9731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Squash into 224/4 Multicast and 240/4 Reserved space (i.e. 224/3). 9751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert coercedHash |= 0xe0000000; 9761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Fixup to avoid some "illegal" values. Currently the only potential 9781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // illegal value is 255.255.255.255. 9791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (coercedHash == 0xffffffff) { 9801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert coercedHash = 0xfffffffe; 9811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getInet4Address(Ints.toByteArray(coercedHash)); 9841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 9851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 9861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 9871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an {@code int} hash of a 64-bit long. 9881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This comes from http://www.concentric.net/~ttwang/tech/inthash.htm 9901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This hash gives no guarantees on the cryptographic suitability nor the 9921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * quality of randomness produced, and the mapping may change in the future. 9931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 9941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param key A 64-bit number to hash 9951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code int} the input hashed into 32 bits 9961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 9971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @VisibleForTesting static int hash64To32(long key) { 9981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = (~key) + (key << 18); 9991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = key ^ (key >>> 31); 10001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = key * 21; 10011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = key ^ (key >>> 11); 10021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = key + (key << 6); 10031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert key = key ^ (key >>> 22); 10041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (int) key; 10051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 10081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an integer representing an IPv4 address regardless of 10091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * whether the supplied argument is an IPv4 address or not. 10101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>IPv6 addresses are <b>coerced</b> to IPv4 addresses before being 10121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * converted to integers. 10131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>As long as there are applications that assume that all IP addresses 10151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * are IPv4 addresses and can therefore be converted safely to integers 10161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (for whatever purpose) this function can be used to handle IPv6 10171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * addresses as well until the application is suitably fixed. 10181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>NOTE: an IPv6 address coerced to an IPv4 address can only be used 10201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for such purposes as rudimentary identification or indexing into a 10211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * collection of real {@link InetAddress}es. They cannot be used as 10221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * real addresses for the purposes of network communication. 10231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param ip {@link InetAddress} to convert 10251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@code int}, "coerced" if ip is not an IPv4 address 10261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 7.0 10271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 10281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static int coerceToInteger(InetAddress ip) { 10291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return ByteStreams.newDataInput(getCoercedIPv4Address(ip).getAddress()).readInt(); 10301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 10331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an Inet4Address having the integer value specified by 10341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the argument. 10351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param address {@code int}, the 32bit integer address to be converted 10371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return {@link Inet4Address} equivalent of the argument 10381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 10391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static Inet4Address fromInteger(int address) { 10401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getInet4Address(Ints.toByteArray(address)); 10411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 10441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns an address from a <b>little-endian ordered</b> byte array 10451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * (the opposite of what {@link InetAddress#getByAddress} expects). 10461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>IPv4 address byte array must be 4 bytes long and IPv6 byte array 10481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * must be 16 bytes long. 10491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param addr the raw IP address in little-endian byte order 10511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return an InetAddress object created from the raw IP address 10521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws UnknownHostException if IP address is of illegal length 10531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 10541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static InetAddress fromLittleEndianByteArray(byte[] addr) 10551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throws UnknownHostException { 10561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] reversed = new byte[addr.length]; 10571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < addr.length; i++) { 10581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert reversed[i] = addr[addr.length - i - 1]; 10591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return InetAddress.getByAddress(reversed); 10611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 10641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a new InetAddress that is one more than the passed in address. 10651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This method works for both IPv4 and IPv6 addresses. 10661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param address the InetAddress to increment 10681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return a new InetAddress that is one more than the passed in address. 10691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if InetAddress is at the end of its 10701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * range. 10711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 10.0 10721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 10731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static InetAddress increment(InetAddress address) { 10741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] addr = address.getAddress(); 10751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int i = addr.length - 1; 10761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert while (i >= 0 && addr[i] == (byte) 0xff) { 10771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert addr[i] = 0; 10781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert i--; 10791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkArgument(i >= 0, "Incrementing %s would wrap.", address); 10821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert addr[i]++; 10841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 10851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return InetAddress.getByAddress(addr); 10861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (UnknownHostException e) { 10871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new AssertionError(e); 10881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 10901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 10911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 10921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns true if the InetAddress is either 255.255.255.255 for IPv4 or 10931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for IPv6. 10941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 10951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @return true if the InetAddress is either 255.255.255.255 for IPv4 or 10961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for IPv6. 10971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 10.0 10981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 10991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static boolean isMaximum(InetAddress address) { 11001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] addr = address.getAddress(); 11011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < addr.length; i++) { 11021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (addr[i] != (byte) 0xff) { 11031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 11041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 11051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 11061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return true; 11071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 11081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 11091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 11101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This method emulates the Java 6 method 11111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code Arrays.copyOfRange(byte, int, int)}, which is not available in 11121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Java 5, and thus cannot be used in Guava code. 11131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 11141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static byte[] copyOfRange(byte[] original, int from, int to) { 11151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Preconditions.checkNotNull(original); 11161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 11171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int end = Math.min(to, original.length); 11181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] result = new byte[to - from]; 11191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 11201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert System.arraycopy(original, from, result, 0, end - from); 11211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return result; 11221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 11231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 1124