/* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.util.Enumeration; /** * This class represents an Internet Protocol version 6 (IPv6) address. * Defined by * RFC 2373: IP Version 6 Addressing Architecture. * *
The preferred form is x:x:x:x:x:x:x:x, * where the 'x's are * the hexadecimal values of the eight 16-bit pieces of the * address. This is the full form. For example, * *
* **
* 1080:0:0:0:8:800:200C:417A
Note that it is not necessary to write the leading zeros in * an individual field. However, there must be at least one numeral * in every field, except as described below.
Due to some methods of allocating certain styles of IPv6 * addresses, it will be common for addresses to contain long * strings of zero bits. In order to make writing addresses * containing zero bits easier, a special syntax is available to * compress the zeros. The use of "::" indicates multiple groups * of 16-bits of zeros. The "::" can only appear once in an address. * The "::" can also be used to compress the leading and/or trailing * zeros in an address. For example, * *
* **
* 1080::8:800:200C:417A
An alternative form that is sometimes more convenient * when dealing with a mixed environment of IPv4 and IPv6 nodes is * x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values * of the six high-order 16-bit pieces of the address, and the 'd's * are the decimal values of the four low-order 8-bit pieces of the * standard IPv4 representation address, for example, * *
* **
* ::FFFF:129.144.52.38 * ::129.144.52.38
where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the * general forms of an IPv4-mapped IPv6 address and an * IPv4-compatible IPv6 address. Note that the IPv4 portion must be * in the "d.d.d.d" form. The following forms are invalid: * *
* **
* ::FFFF:d.d.d * ::FFFF:d.d * ::d.d.d * ::d.d
The following form: * *
* **
* ::FFFF:d
is valid, however it is an unconventional representation of * the IPv4-compatible IPv6 address, * *
* **
* ::255.255.0.d
while "::d" corresponds to the general IPv6 address * "0:0:0:0:0:0:0:d".
For methods that return a textual representation as output * value, the full form is used. Inet6Address will return the full * form because it is unambiguous when used in combination with other * textual data. * *
***
* IPv4-mapped address *Of the form::ffff:w.x.y.z, this IPv6 address is used to * represent an IPv4 address. It allows the native program to * use the same address data structure and also the same * socket when communicating with both IPv4 and IPv6 nodes. * * In InetAddress and Inet6Address, it is used for internal * representation; it has no functional role. Java will never * return an IPv4-mapped address. These classes can take an * IPv4-mapped address as input, both in byte array and text * representation. However, it will be converted into an IPv4 * address.
*
The textual representation of IPv6 addresses as described above can be * extended to specify IPv6 scoped addresses. This extension to the basic * addressing architecture is described in [draft-ietf-ipngwg-scoping-arch-04.txt]. * *
Because link-local and site-local addresses are non-global, it is possible * that different hosts may have the same destination address and may be * reachable through different interfaces on the same originating system. In * this case, the originating system is said to be connected to multiple zones * of the same scope. In order to disambiguate which is the intended destination * zone, it is possible to append a zone identifier (or scope_id) to an * IPv6 address. * *
The general format for specifying the scope_id is the following: * *
IPv6-address%scope_id*
The IPv6-address is a literal IPv6 address as described above. * The scope_id refers to an interface on the local system, and it can be * specified in two ways. *
Note also, that the numeric scope_id can be retrieved from
* Inet6Address instances returned from the NetworkInterface class. This can be
* used to find out the current scope ids configured on the system.
* @since 1.4
*/
public final
class Inet6Address extends InetAddress {
final static int INADDRSZ = 16;
/*
* cached scope_id - for link-local address use only.
*/
private transient int cached_scope_id; // 0
/**
* Holds a 128-bit (16 bytes) IPv6 address.
*
* @serial
*/
byte[] ipaddress;
/**
* scope_id. The scope specified when the object is created. If the object
* is created with an interface name, then the scope_id is not determined
* until the time it is needed.
*/
private int scope_id; // 0
/**
* This will be set to true when the scope_id field contains a valid
* integer scope_id.
*/
private boolean scope_id_set; // false
/**
* scoped interface. scope_id is derived from this as the scope_id of the first
* address whose scope is the same as this address for the named interface.
*/
private transient NetworkInterface scope_ifname; // null
/**
* set if the object is constructed with a scoped
* interface instead of a numeric scope id.
*/
private boolean scope_ifname_set; // false;
private static final long serialVersionUID = 6880410070516793377L;
// Perform native initialization
static { init(); }
Inet6Address() {
super();
holder().hostName = null;
ipaddress = new byte[INADDRSZ];
holder().family = IPv6;
}
/* checking of value for scope_id should be done by caller
* scope_id must be >= 0, or -1 to indicate not being set
*/
Inet6Address(String hostName, byte addr[], int scope_id) {
holder().hostName = hostName;
if (addr.length == INADDRSZ) { // normal IPv6 address
holder().family = IPv6;
ipaddress = addr.clone();
}
if (scope_id >= 0) {
this.scope_id = scope_id;
scope_id_set = true;
}
}
Inet6Address(String hostName, byte addr[]) {
try {
initif (hostName, addr, null);
} catch (UnknownHostException e) {} /* cant happen if ifname is null */
}
Inet6Address (String hostName, byte addr[], NetworkInterface nif)
throws UnknownHostException
{
initif (hostName, addr, nif);
}
Inet6Address (String hostName, byte addr[], String ifname)
throws UnknownHostException
{
initstr (hostName, addr, ifname);
}
/**
* Create an Inet6Address in the exact manner of {@link
* InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
* set to the value corresponding to the given interface for the address
* type specified in addr
. The call will fail with an
* UnknownHostException if the given interface does not have a numeric
* scope_id assigned for the given address type (eg. link-local or site-local).
* See here for a description of IPv6
* scoped addresses.
*
* @param host the specified host
* @param addr the raw IP address in network byte order
* @param nif an interface this address must be associated with.
* @return an Inet6Address object created from the raw IP address.
* @throws UnknownHostException
* if IP address is of illegal length, or if the interface does not
* have a numeric scope_id assigned for the given address type.
*
* @since 1.5
*/
public static Inet6Address getByAddress(String host, byte[] addr,
NetworkInterface nif)
throws UnknownHostException
{
if (host != null && host.length() > 0 && host.charAt(0) == '[') {
if (host.charAt(host.length()-1) == ']') {
host = host.substring(1, host.length() -1);
}
}
if (addr != null) {
if (addr.length == Inet6Address.INADDRSZ) {
return new Inet6Address(host, addr, nif);
}
}
throw new UnknownHostException("addr is of illegal length");
}
/**
* Create an Inet6Address in the exact manner of {@link
* InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
* set to the given numeric value. The scope_id is not checked to determine
* if it corresponds to any interface on the system.
* See here for a description of IPv6
* scoped addresses.
*
* @param host the specified host
* @param addr the raw IP address in network byte order
* @param scope_id the numeric scope_id for the address.
* @return an Inet6Address object created from the raw IP address.
* @throws UnknownHostException if IP address is of illegal length.
*
* @since 1.5
*/
public static Inet6Address getByAddress(String host, byte[] addr,
int scope_id)
throws UnknownHostException
{
if (host != null && host.length() > 0 && host.charAt(0) == '[') {
if (host.charAt(host.length()-1) == ']') {
host = host.substring(1, host.length() -1);
}
}
if (addr != null) {
if (addr.length == Inet6Address.INADDRSZ) {
return new Inet6Address(host, addr, scope_id);
}
}
throw new UnknownHostException("addr is of illegal length");
}
private void initstr(String hostName, byte addr[], String ifname)
throws UnknownHostException
{
try {
NetworkInterface nif = NetworkInterface.getByName (ifname);
if (nif == null) {
throw new UnknownHostException ("no such interface " + ifname);
}
initif (hostName, addr, nif);
} catch (SocketException e) {
throw new UnknownHostException ("SocketException thrown" + ifname);
}
}
private void initif(String hostName, byte addr[], NetworkInterface nif)
throws UnknownHostException
{
holder().hostName = hostName;
if (addr.length == INADDRSZ) { // normal IPv6 address
holder().family = IPv6;
ipaddress = addr.clone();
}
if (nif != null) {
scope_ifname = nif;
scope_id = deriveNumericScope(nif);
scope_id_set = true;
scope_ifname_set = true; // for consistency
}
}
/* check the two Ipv6 addresses and return false if they are both
* non global address types, but not the same.
* (ie. one is sitelocal and the other linklocal)
* return true otherwise.
*/
private boolean differentLocalAddressTypes(Inet6Address other) {
if (isLinkLocalAddress() && !other.isLinkLocalAddress())
return false;
if (isSiteLocalAddress() && !other.isSiteLocalAddress())
return false;
return true;
}
private int deriveNumericScope(NetworkInterface ifc)
throws UnknownHostException
{
Enumeration