All Downloads are FREE. Search and download functionalities are using the official Maven repository.

inet.ipaddr.ipv6.IPv6Address Maven / Gradle / Ivy

There is a newer version: 5.5.1
Show newest version
/*
 * Copyright 2016-2018 Sean C Foley
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     or at
 *     https://github.com/seancfoley/IPAddress/blob/master/LICENSE
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package inet.ipaddr.ipv6;

import java.io.Serializable;
import java.math.BigInteger;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import inet.ipaddr.Address;
import inet.ipaddr.AddressConversionException;
import inet.ipaddr.AddressNetwork.PrefixConfiguration;
import inet.ipaddr.AddressPositionException;
import inet.ipaddr.AddressValueException;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressConverter;
import inet.ipaddr.IPAddressSection.IPStringBuilderOptions;
import inet.ipaddr.IPAddressSection.IPStringOptions;
import inet.ipaddr.IPAddressSegmentSeries;
import inet.ipaddr.IPAddressString;
import inet.ipaddr.IPAddressStringParameters;
import inet.ipaddr.IncompatibleAddressException;
import inet.ipaddr.PrefixLenException;
import inet.ipaddr.format.string.IPAddressStringDivisionSeries;
import inet.ipaddr.format.util.AddressComponentRangeSpliterator;
import inet.ipaddr.format.util.AddressComponentSpliterator;
import inet.ipaddr.format.util.IPAddressPartStringCollection;
import inet.ipaddr.format.validate.Validator;
import inet.ipaddr.ipv4.IPv4Address;
import inet.ipaddr.ipv4.IPv4Address.IPv4AddressConverter;
import inet.ipaddr.ipv4.IPv4AddressNetwork;
import inet.ipaddr.ipv4.IPv4AddressNetwork.IPv4AddressCreator;
import inet.ipaddr.ipv4.IPv4AddressSection;
import inet.ipaddr.ipv6.IPv6AddressNetwork.IPv6AddressCreator;
import inet.ipaddr.ipv6.IPv6AddressSection.IPv6AddressCache;
import inet.ipaddr.ipv6.IPv6AddressSection.IPv6StringBuilderOptions;
import inet.ipaddr.ipv6.IPv6AddressSection.IPv6StringCache;
import inet.ipaddr.ipv6.IPv6AddressSection.IPv6StringCollection;
import inet.ipaddr.ipv6.IPv6AddressSection.IPv6StringOptions;
import inet.ipaddr.ipv6.IPv6AddressTrie.IPv6TrieNode.IPv6TrieKeyData;
import inet.ipaddr.mac.MACAddress;
import inet.ipaddr.mac.MACAddressNetwork;
import inet.ipaddr.mac.MACAddressNetwork.MACAddressCreator;
import inet.ipaddr.mac.MACAddressSection;
import inet.ipaddr.mac.MACAddressSegment;

/**
 * An IPv6 address, or a subnet of multiple IPv6 addresses.  Each segment can represent a single value or a range of values.
 * 

* You can construct an IPv6 address from a byte array, from a BigInteger, from a {@link inet.ipaddr.Address.SegmentValueProvider}, * from Inet6Address, from MACAddress, from an {@link IPv6AddressSection} of 8 segments, or from an array of 8 {@link IPv6AddressSegment} objects. *

* To construct one from a {@link java.lang.String} use * {@link inet.ipaddr.IPAddressString#toAddress()} or {@link inet.ipaddr.IPAddressString#getAddress()}, {@link inet.ipaddr.IPAddressString#toHostAddress()} or {@link inet.ipaddr.IPAddressString#getHostAddress()} *

* An IPv6 address can have an associated zone, typically either a network interface name or a positive integer. * An IPv6 zone distinguishes two IPv6 addresses that are the same. *

    *
  • They are used with link-local addresses fe80::/10 to distinguish two interfaces to the link-local network, this is known as the zone id. *
  • They are used with site-local addresses to distinguish sites, using the site id, also known as the scope id. *
*

* A zone that consists of a scope id is called a scoped zone. * @custom.core * @author sfoley */ /* * rfc 6890 and the earlier 5156 has details on some of the special addresses * * For some of the various pre-specified IPv6 address formats (IPv4 mapped, IPv4 translated, IPv4 compatible, etc), * see gestioip.net/docu/ipv6_address_examples.html * * A nice summary of IPV6 formats at https://technet.microsoft.com/en-us/library/cc757359(v=ws.10).aspx * https://technet.microsoft.com/en-us/library/dd379548(v=ws.10).aspx */ public class IPv6Address extends IPAddress implements Iterable { private static final long serialVersionUID = 4L; public static final char SEGMENT_SEPARATOR = ':'; public static final char ZONE_SEPARATOR = '%'; public static final char ALTERNATIVE_ZONE_SEPARATOR = '\u00a7';//'§'; javadoc whines about this char public static final char UNC_SEGMENT_SEPARATOR = '-'; public static final char UNC_ZONE_SEPARATOR = 's'; public static final char UNC_RANGE_SEPARATOR = ALTERNATIVE_RANGE_SEPARATOR; public static final String UNC_RANGE_SEPARATOR_STR = String.valueOf(UNC_RANGE_SEPARATOR); public static final String UNC_SUFFIX = ".ipv6-literal.net"; public static final String REVERSE_DNS_SUFFIX = ".ip6.arpa"; public static final String REVERSE_DNS_SUFFIX_DEPRECATED = ".ip6.int"; public static final int BITS_PER_SEGMENT = 16; public static final int BYTES_PER_SEGMENT = 2; public static final int SEGMENT_COUNT = 8; public static final int MIXED_REPLACED_SEGMENT_COUNT = 2; //IPv4Address.BYTE_COUNT / BYTES_PER_SEGMENT; public static final int MIXED_ORIGINAL_SEGMENT_COUNT = 6; //SEGMENT_COUNT - MIXED_REPLACED_SEGMENT_COUNT public static final int BYTE_COUNT = 16; public static final int BIT_COUNT = 128; public static final int DEFAULT_TEXTUAL_RADIX = 16; public static final int BASE_85_RADIX = 85; public static final int MAX_VALUE_PER_SEGMENT = 0xffff; /* * An IPv6 zone distinguishes two IPv6 addresses that are the same. * They are used with link-local addresses fe80::/10 and distinguishes two interfaces to the link-local network, this is known as the zone id. * They are used with site-local addresses to distinguish sites, using the site id, also known as the scope id. * * A zone that consists of a scope id is called a scoped zone. */ private final IPv6Zone zone; /** * A reference to a scope id by number or a network interface by name. *

* An IPv6 zone distinguishes two IPv6 addresses that are the same. * They are used with link-local addresses fe80::/10 to distinguish two interfaces to the link-local network, this is known as the zone id. * They are used with site-local addresses to distinguish sites, using the site id, also known as the scope id. *

* A zone that consists of a scope id is called a scoped zone. *

* An IPv6 zone will reference an interface by a scoped identifier number or by interface name based on how it was constructed. * If constructed with a numeric identifier, whether integer or string, it will always reference by scoped identifier. * Otherwise, it will always reference by interface name. *

* Once constructed, it will always reference using the same method, either interface name or scope id. * To reference by the other method you must use a different IPv6Zone instance. *

* Even though it will always reference using the same method, * you can use the IPv6Zone instance to look up the scope id if the instance references by interface name, * or to look up the associated interface if the instance references by scope id. * * * @custom.core * @author scfoley * */ public static class IPv6Zone implements Serializable { private static final long serialVersionUID = 1L; String zoneStr; private int scopeId; private transient NetworkInterface networkInterface; private Boolean referencesInterface; /** * Constructs a zone that will use the given zone string, * either a non-negative integer indicating a scope identifier, * or the name of a network interface. *

* A scope identifier is indicated by a sequence of decimal digits. *

* To create an InetAddress by pairing this zone with an IPv6Address instance, * an interface name must reference an existing interface, otherwise the InetAddress cannot be created. *

* See {@link java.net.NetworkInterface} to get a list of existing interfaces or to look up interfaces by name. * * @param zoneStr */ public IPv6Zone(String zoneStr) { if(zoneStr == null) { throw new NullPointerException(); } this.zoneStr = zoneStr.trim(); scopeId = -1; } /** * Constructs a zone that will use a scope identifier with the address. * * @param scopeId */ public IPv6Zone(int scopeId) { if(scopeId < 0) { throw new IllegalArgumentException(); } this.scopeId = scopeId; referencesInterface = Boolean.FALSE; } /** * Constructs a zone that will use an interface name with the address. * * @param networkInterface */ public IPv6Zone(NetworkInterface networkInterface) { if(networkInterface == null) { throw new NullPointerException(); } this.networkInterface = networkInterface; referencesInterface = Boolean.TRUE; scopeId = -1; zoneStr = networkInterface.getName(); } /** * Whether this zone references a network interface. * * @return */ public boolean referencesIntf() { if(referencesInterface == null) { scopeId = checkIfScope(zoneStr); referencesInterface = scopeId < 0; } return referencesInterface; } /** * Whether this zone references a scope identifier. * * @return */ public boolean referencesScopeId() { return !referencesIntf(); } /** * If this zone references a network interface, returns that interface, * or null if no interface with the given name exists on the system. * * If this zone references a scope id, returns the associated interface. * * @return */ public NetworkInterface getAssociatedIntf() { try { if(referencesIntf()) { if(networkInterface == null) { networkInterface = NetworkInterface.getByName(zoneStr); } } else { if(networkInterface == null) { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); top: while(interfaces.hasMoreElements()) { NetworkInterface nif = interfaces.nextElement(); Enumeration addrs = nif.getInetAddresses(); while(addrs.hasMoreElements()) { InetAddress addr = addrs.nextElement(); if(addr instanceof Inet6Address) { Inet6Address inetAddr = (Inet6Address) addr; if(inetAddr.getScopeId() == scopeId) { networkInterface = nif; break top; } } } } } } } catch(SocketException e) {} return networkInterface; } /** * Returns the MAC address of the associated interface * * @return */ public MACAddress getAssociatedIntfMacAddr() { NetworkInterface intf = getAssociatedIntf(); try { if(intf != null) { byte bytes[] = intf.getHardwareAddress(); if(bytes != null) { return new MACAddress(bytes); } } } catch(SocketException e) {} return null; } /** * If this zone references a scoped identifier, returns that identifier. *

* If this zone references a network interface, returns the scope identifier for the addresses of that interface, * or -1 if the referenced interface cannot be found on the system, or no single scope identifier was assigned. * * @return */ public int getAssociatedScopeId() { if(referencesIntf()) { if(scopeId == -1) { NetworkInterface nif = getAssociatedIntf(); if(nif != null) { Enumeration addrs = nif.getInetAddresses(); int newScopeId = -1; while(addrs.hasMoreElements()) { InetAddress addr = addrs.nextElement(); if(addr instanceof Inet6Address) { Inet6Address inetAddr = (Inet6Address) addr; int sid = inetAddr.getScopeId(); if(sid != 0) { if(newScopeId != -1 && sid != newScopeId) { // multiple scope ids for the interface newScopeId = -1; break; } newScopeId = sid; } } } if(newScopeId != -1) { this.scopeId = newScopeId; } } } } return scopeId; } @Override public int hashCode() { return toString().hashCode(); } @Override public boolean equals(Object o) { return o instanceof IPv6Zone && toString().equals(o.toString()); } public String getName() { if(zoneStr == null) { if(referencesIntf()) { zoneStr = networkInterface.getName(); } else { zoneStr = IPv6AddressSegment.toUnsignedString(scopeId, 10, new StringBuilder(IPv6AddressSegment.toUnsignedStringLength(scopeId, 10))).toString(); } } return zoneStr; } @Override public String toString() { return getName(); } static int checkIfScope(String zoneStr) { long digits = 0; for(int i = 0, len = zoneStr.length(); i < len; i++) { char c = zoneStr.charAt(i); int digit = Character.digit(c, 10); if(digit < 0) { return -1; } digits = (digits * 10) + digit; if(digits > Integer.MAX_VALUE) { return -1; } } return (int) digits; } } private transient IPv6StringCache stringCache; private transient IPv6TrieKeyData cachedTrieKeyData; transient IPv6AddressCache addressCache; IPv6Address(IPv6AddressSection section, CharSequence zone, boolean checkZone) throws AddressValueException { this(section, checkZone ? checkZone(zone) : (zone != null && zone.length() > 0 ? new IPv6Zone(zone.toString()) : null)); } /** * Constructs an IPv6 address or subnet. * @throws AddressValueException if segment count is not 8 or zone is invalid * @param section * @param zone */ public IPv6Address(IPv6AddressSection section, IPv6Zone zone) throws AddressValueException { super(section); if(section.getSegmentCount() != SEGMENT_COUNT) { throw new AddressValueException("ipaddress.error.ipv6.invalid.segment.count", section.getSegmentCount()); } if(section.addressSegmentIndex != 0) { throw new AddressPositionException(section.addressSegmentIndex); } this.zone = zone; } /** * @deprecated use {@link #IPv6Address(IPv6AddressSection, IPv6Zone)} * @throws AddressValueException if segment count is not 8 or zone is invalid * @param section * @param zone */ @Deprecated public IPv6Address(IPv6AddressSection section, CharSequence zone) throws AddressValueException { this(section, zone, true); } public IPv6Address(IPv6AddressSection section) throws AddressValueException { this(section, (CharSequence) null); } /** * Constructs an IPv6 address or subnet. * @throws AddressValueException if segment count is not 8 * @param segments the address segments */ public IPv6Address(IPv6AddressSegment[] segments) throws AddressValueException { this(segments, null, null); } /** * Constructs an IPv6 address or a set of addresses. * * @throws AddressValueException if segment count is not 8 * @param segments the address segments * @param networkPrefixLength * @throws AddressValueException if network prefix length invalid */ public IPv6Address(IPv6AddressSegment[] segments, Integer networkPrefixLength) throws AddressValueException { this(segments, networkPrefixLength, null); } /** * Constructs an IPv6 address or a set of addresses. * * @deprecated use {@link #IPv6Address(IPv6AddressSegment[], IPv6Zone)} * @param segments the address segments * @param zone the zone or scope id * * @throws AddressValueException if segment count is not 8 or the zone invalid */ @Deprecated public IPv6Address(IPv6AddressSegment[] segments, CharSequence zone) throws AddressValueException { this(segments, checkZone(zone)); } /** * Constructs an IPv6 address or a set of addresses. * * @param segments the address segments * @param zone the zone or scope id * * @throws AddressValueException if segment count is not 8 or the zone invalid */ public IPv6Address(IPv6AddressSegment[] segments, IPv6Zone zone) throws AddressValueException { this(segments, null, zone); } private IPv6Address(IPv6AddressSegment[] segments, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createSection(segments, networkPrefixLength)); if(segments.length != SEGMENT_COUNT) { throw new AddressValueException("ipaddress.error.ipv6.invalid.segment.count", segments.length); } this.zone = zone; } /** * Constructs an IPv6 address. * * @param inet6Address the java.net address object */ public IPv6Address(Inet6Address inet6Address) { this(inet6Address, inet6Address.getAddress(), null, getZone(inet6Address)); } /** * Constructs an IPv6 address. * * @param inet6Address the java.net address object */ public IPv6Address(Inet6Address inet6Address, Integer networkPrefixLength) { this(inet6Address, inet6Address.getAddress(), networkPrefixLength, getZone(inet6Address)); } private IPv6Address(Inet6Address inet6Address, byte[] bytes, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createSection(bytes, 0, bytes.length, IPv6Address.SEGMENT_COUNT, networkPrefixLength)); this.zone = zone; getSection().setInetAddress(inet6Address); } /** * Constructs an IPv6 address. *

* The byte array can be a 16 byte IPv6 address, but may have additional zero-valued bytes, or it may be fewer than 16 bytes. * * @deprecated use {@link #IPv6Address(byte[], IPv6Zone)} * @throws AddressValueException if bytes not equivalent to a 16 byte address * @param bytes the 16 byte IPv6 address in network byte order - if longer than 16 bytes the additional bytes must be zero (and are ignored), if shorter than 16 bytes then the bytes are sign-extended to 16 bytes. * @throws AddressValueException if byte range invalid or zone invalid */ @Deprecated public IPv6Address(byte[] bytes, CharSequence zone) throws AddressValueException { this(bytes, checkZone(zone)); } /** * Constructs an IPv6 address. *

* The byte array can be a 16 byte IPv6 address, but may have additional zero-valued bytes, or it may be fewer than 16 bytes. * * @throws AddressValueException if bytes not equivalent to a 16 byte address * @param bytes the 16 byte IPv6 address in network byte order - if longer than 16 bytes the additional bytes must be zero (and are ignored), if shorter than 16 bytes then the bytes are sign-extended to 16 bytes. * @throws AddressValueException if byte range invalid or zone invalid */ public IPv6Address(byte[] bytes, IPv6Zone zone) throws AddressValueException { this(bytes, null, zone); } /** * Constructs an IPv6 address. *

* The byte array can be a 16 byte IPv6 address, but may have additional zero-valued bytes, or it may be fewer than 16 bytes. * * @throws AddressValueException if bytes not equivalent to a 16 byte address * @param bytes the 16 byte IPv6 address in network byte order - if longer than 16 bytes the additional bytes must be zero (and are ignored), if shorter than 16 bytes then the bytes are sign-extended to 16 bytes. */ public IPv6Address(byte[] bytes) throws AddressValueException { this(bytes, null, null); } /** * Constructs an IPv6 address or subnet. *

* Similar to {@link #IPv6Address(byte[])} except that you can specify the start and end of the address in the given byte array. * @throws AddressValueException if byte range invalid */ public IPv6Address(byte[] bytes, int byteStartIndex, int byteEndIndex) throws AddressValueException { this(bytes, byteStartIndex, byteEndIndex, null, null); } /** * Constructs an IPv6 address or subnet. *

* The byte array can be a 16 byte IPv6 address, but may have additional zero-valued bytes, or it may be fewer than 16 bytes. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* @param bytes the 16 byte IPv6 address in network byte order - if longer than 16 bytes the additional bytes must be zero (and are ignored), if shorter than 16 bytes then the bytes are sign-extended to 16 bytes. * @param networkPrefixLength the CIDR prefix, which can be null for no prefix length * @throws AddressValueException if bytes not equivalent to a 16 byte address */ public IPv6Address(byte[] bytes, Integer networkPrefixLength) throws AddressValueException { this(bytes, networkPrefixLength, null); } /** * Constructs an IPv6 address or subnet. *

* Similar to {@link #IPv6Address(byte[], Integer)} except that you can specify the start and end of the address in the given byte array. */ public IPv6Address(byte[] bytes, int byteStartIndex, int byteEndIndex, Integer networkPrefixLength) throws AddressValueException { this(bytes, byteStartIndex, byteEndIndex, networkPrefixLength, null); } /** * Constructs an IPv6 address. *

* The byte representation from {@link BigInteger#toByteArray()} is used, and the byte array follows the rules according to {@link #IPv6Address(byte[])}. * Either it must be exactly 16 bytes, or if larger then any extra bytes must be significant leading zeros, * or if smaller it is sign-extended to the required 16 byte length. *

* This means that you can end up with the same address from two different values of BigInteger, one positive and one negative. * For instance, -1 and ffffffffffffffffffffffffffffffff are represented by the two's complement byte arrays [ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff] * and [0,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff] respectively. * Both create the address ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff *

* In fact, the two's complement byte array [ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff] can be shortened to [ff], the former being the sign-extension of the latter. * So the byte array [ff] also creates the address ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff. *

* When using positive integers you end up with the results you expect, the magnitude of the big integer becomes the address. *

* When ranging over all 16-byte arrays and constructing BigInteger from those arrays, you range over all possible addresses. *

* @throws AddressValueException if value is outside the range of potential values * @param val must be an IPv6 address value. * @throws AddressValueException if val is invalid */ public IPv6Address(BigInteger val) throws AddressValueException { this(val, null, (IPv6Zone) null); } /** * Constructs an IPv6 address. *

* The byte representation from {@link BigInteger#toByteArray()} is used, and the byte array follows the rules according to {@link #IPv6Address(byte[])}. * Either it must be exactly 16 bytes, or if larger then any extra bytes must be significant leading zeros, * or if smaller it is sign-extended to the required 16 byte length. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. * * @param val * @param networkPrefixLength * @throws AddressValueException if val is invalid */ public IPv6Address(BigInteger val, Integer networkPrefixLength) throws AddressValueException { this(val, networkPrefixLength, (IPv6Zone) null); } /** * Constructs an IPv6 address. *

* The byte representation from {@link BigInteger#toByteArray()} is used, and the byte array follows the rules according to {@link #IPv6Address(byte[])}. * Either it must be exactly 16 bytes, or if larger then any extra bytes must be significant leading zeros, * or if smaller it is sign-extended to the required 16 byte length. *

* @deprecated use {@link #IPv6Address(BigInteger, IPv6Zone)} * @param val * @param zone * @throws AddressValueException if val is invalid or if zone is invalid */ @Deprecated public IPv6Address(BigInteger val, CharSequence zone) throws AddressValueException { this(val, checkZone(zone)); } /** * Constructs an IPv6 address. *

* The byte representation from {@link BigInteger#toByteArray()} is used, and the byte array follows the rules according to {@link #IPv6Address(byte[])}. * Either it must be exactly 16 bytes, or if larger then any extra bytes must be significant leading zeros, * or if smaller it is sign-extended to the required 16 byte length. *

* @param val * @param zone * @throws AddressValueException if val is invalid or if zone is invalid */ public IPv6Address(BigInteger val, IPv6Zone zone) throws AddressValueException { this(val, null, zone); } /** * Constructs an IPv6 address or subnet. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* * @deprecated use {@link #IPv6Address(BigInteger, Integer, IPv6Zone)} * @param val must be an IPv6 address value * @param networkPrefixLength the CIDR prefix length, which can be null for no prefix length * @param zone the zone or scope id * @throws AddressValueException if value is outside the range of potential values, or if zone is invalid */ @Deprecated public IPv6Address(BigInteger val, Integer networkPrefixLength, CharSequence zone) throws AddressValueException { this(val, networkPrefixLength, checkZone(zone)); } /** * Constructs an IPv6 address or subnet. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* * @param val must be an IPv6 address value * @param networkPrefixLength the CIDR prefix length, which can be null for no prefix length * @param zone the zone or scope id * @throws AddressValueException if value is outside the range of potential values, or if zone is invalid */ public IPv6Address(BigInteger val, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createSectionInternal(val.toByteArray(), IPv6Address.SEGMENT_COUNT, networkPrefixLength, false)); this.zone = zone; } private IPv6Address(byte[] bytes, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { this(bytes, 0, bytes.length, networkPrefixLength, zone); } private IPv6Address(byte[] bytes, int byteStartIndex, int byteEndIndex, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createSection(bytes, byteStartIndex, byteEndIndex, IPv6Address.SEGMENT_COUNT, networkPrefixLength)); this.zone = zone; } /** * Constructs an IPv6 address. *

* The highBytes form the more significant 4 bytes of the address. * * @param highBytes the 4 more significant bytes in network byte order * @param lowBytes the 4 least significant bytes in network byte order * @throws AddressValueException if zone invalid */ public IPv6Address(long highBytes, long lowBytes, IPv6Zone zone) throws AddressValueException { this(highBytes, lowBytes, null, zone); } /** * Constructs an IPv6 address. *

* The highBytes form the more significant 4 bytes of the address. * * @param highBytes the 4 more significant bytes in network byte order * @param lowBytes the 4 least significant bytes in network byte order */ public IPv6Address(long highBytes, long lowBytes) throws AddressValueException { this(highBytes, lowBytes, null, null); } /** * Constructs an IPv6 address or subnet. *

* The highBytes form the more significant 4 bytes of the address. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* @param highBytes the 4 more significant bytes in network byte order * @param lowBytes the 4 least significant bytes in network byte order * @param networkPrefixLength the CIDR prefix, which can be null for no prefix length */ public IPv6Address(long highBytes, long lowBytes, Integer networkPrefixLength) throws AddressValueException { this(highBytes, lowBytes, networkPrefixLength, null); } private IPv6Address(long highBytes, long lowBytes, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createSection(highBytes, lowBytes, IPv6Address.SEGMENT_COUNT, networkPrefixLength)); this.zone = zone; } /** * Constructs an IPv6 address or subnet. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* * @param lowerValueProvider supplies the 2 byte lower values for each segment * @param upperValueProvider supplies the 2 byte upper values for each segment * @param networkPrefixLength the CIDR network prefix length, which can be null for no prefix */ public IPv6Address(SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider, Integer networkPrefixLength) throws AddressValueException { this(lowerValueProvider, upperValueProvider, networkPrefixLength, null); } /** * Constructs an IPv6 address or subnet. * * @param lowerValueProvider supplies the 2 byte lower values for each segment * @param upperValueProvider supplies the 2 byte upper values for each segment */ public IPv6Address(SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider) { this(lowerValueProvider, upperValueProvider, null, null); } /** * Constructs an IPv6 address. *

* When networkPrefixLength is non-null, depending on the prefix configuration (see {@link inet.ipaddr.AddressNetwork#getPrefixConfiguration()}, * this object may represent either a single address with that network prefix length, or the prefix subnet block containing all addresses with the same network prefix. *

* * @param valueProvider supplies the 2 byte value for each segment * @param networkPrefixLength the CIDR network prefix length, which can be null for no prefix */ public IPv6Address(SegmentValueProvider valueProvider, Integer networkPrefixLength) throws AddressValueException { this(valueProvider, valueProvider, networkPrefixLength); } /** * Constructs an IPv6 address. * * @param valueProvider supplies the 2 byte value for each segment */ public IPv6Address(SegmentValueProvider valueProvider) { this(valueProvider, (Integer) null); } /** * Constructs an IPv6 address. * * @deprecated use {@link #IPv6Address(Address.SegmentValueProvider, Address.SegmentValueProvider, IPv6Zone)} * @param lowerValueProvider supplies the 2 byte lower values for each segment * @param upperValueProvider supplies the 2 byte upper values for each segment * @throws AddressValueException if zone is invalid */ @Deprecated public IPv6Address(SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider, CharSequence zone) throws AddressValueException { this(lowerValueProvider, upperValueProvider, checkZone(zone)); } /** * Constructs an IPv6 address. * * @param lowerValueProvider supplies the 2 byte lower values for each segment * @param upperValueProvider supplies the 2 byte upper values for each segment * @throws AddressValueException if zone is invalid */ public IPv6Address(SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider, IPv6Zone zone) throws AddressValueException { this(lowerValueProvider, upperValueProvider, null, zone); } private IPv6Address(SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider, Integer networkPrefixLength, IPv6Zone zone) throws AddressValueException { super(thisAddress -> ((IPv6Address) thisAddress).getDefaultCreator().createFullSectionInternal(lowerValueProvider, upperValueProvider, networkPrefixLength)); this.zone = zone; } /** * Constructs an IPv6 address from a modified EUI-64 (Extended Unique Identifier) address section and an IPv6 address section network prefix. *

* If the supplied MAC section is an 8 byte EUI-64, then it must match the required EUI-64 format of xx-xx-ff-fe-xx-xx * with the ff-fe section in the middle. * * If the supplied section is a 6 byte MAC-48 or EUI-48, then the ff-fe pattern will be inserted. *

* If the supplied section neither 6 nor 8 bytes, or if the 8-byte section does not have required EUI-64 format of xx-xx-ff-fe-xx-xx, * {@link IncompatibleAddressException} will be thrown. *

* The constructor will toggle the MAC U/L (universal/local) bit as required with EUI-64. *

* Only the first 8 bytes (4 segments) of the IPv6Address are used to construct the address. *

* Any prefix length in the MAC address is ignored, while a prefix length in the IPv6 address is preserved but only up to the first 4 segments. * * @throws IncompatibleAddressException if the MACAddress is an 8 byte MAC address incompatible with EUI-64 IPv6 format * @param prefix an address from which the first four segments will be used as the same initial segments in the returned address * @param eui */ public IPv6Address(IPv6Address prefix, MACAddress eui) throws IncompatibleAddressException { this(prefix.getSection(), eui.getSection()); } /** * Constructs an IPv6 address from a modified EUI-64 (Extended Unique Identifier) address section and an IPv6 address section network prefix. *

* If the supplied MAC section is an 8 byte EUI-64, then it must match the required EUI-64 format of xx-xx-ff-fe-xx-xx * with the ff-fe section in the middle. * * If the supplied section is a 6 byte MAC-48 or EUI-48, then the ff-fe pattern will be inserted. *

* If the supplied section neither 6 nor 8 bytes, or if the 8-byte section does not have required EUI-64 format of xx-xx-ff-fe-xx-xx, * {@link IncompatibleAddressException} will be thrown. *

* The constructor will toggle the MAC U/L (universal/local) bit as required with EUI-64. *

* The IPv6 address section must be 8 bytes. *

* Any prefix length in the MAC address is ignored, while a prefix length in the IPv6 address is preserved but only up to the first 4 segments. * @throws IncompatibleAddressException if the MACAddress is an 8 byte MAC address incompatible with EUI-64 IPv6 format * @throws AddressValueException if the IPv6 section is the wrong size or structure * @param section * @param eui */ public IPv6Address(IPv6AddressSection section, MACAddress eui) throws IncompatibleAddressException, AddressValueException { this(section, eui.getSection()); } /** * Constructs an IPv6 address from a modified EUI-64 (Extended Unique Identifier) address and an IPv6 address section network prefix. *

* If the supplied address is an 8 byte EUI-64, then it must match the required EUI-64 format of xx-xx-ff-fe-xx-xx * with the ff-fe section in the middle. * * If the supplied address is a 6 byte MAC-48 or EUI-48, then the ff-fe pattern will be inserted. *

* The constructor will toggle the MAC U/L (universal/local) bit as required with EUI-64. *

* The IPv6 address section must be 8 bytes. *

* Any prefix length in the MAC address is ignored, while a prefix length in the IPv6 address is preserved but only up to the first 4 segments. * @throws IncompatibleAddressException if the MACAddress is an 8 byte MAC address incompatible with EUI-64 IPv6 format * @throws AddressValueException if the MACAddress or IPv6 sections are the wrong size or structure * @param section * @param eui */ public IPv6Address(IPv6AddressSection section, MACAddressSection eui) throws IncompatibleAddressException, AddressValueException { this(section, eui, (IPv6Zone) null); } /** * Constructs an IPv6 address from a modified EUI-64 (Extended Unique Identifier) address and an IPv6 address section network prefix. * * @deprecated use {@link #IPv6Address(IPv6AddressSection, MACAddressSection, IPv6Zone)} * @param section * @param eui * @param zone * @throws IncompatibleAddressException if the MACAddress is an 8 byte MAC address incompatible with EUI-64 IPv6 format * @throws AddressValueException if the MACAddress or IPv6 sections are the wrong size or structure, or if zone is invalid */ @Deprecated public IPv6Address(IPv6AddressSection section, MACAddressSection eui, CharSequence zone) throws IncompatibleAddressException, AddressValueException { this(section, eui, checkZone(zone)); } /** * Constructs an IPv6 address from a modified EUI-64 (Extended Unique Identifier) address and an IPv6 address section network prefix. * * @param section * @param eui * @param zone * @throws IncompatibleAddressException if the MACAddress is an 8 byte MAC address incompatible with EUI-64 IPv6 format * @throws AddressValueException if the MACAddress or IPv6 sections are the wrong size or structure, or if zone is invalid */ public IPv6Address(IPv6AddressSection section, MACAddressSection eui, IPv6Zone zone) throws IncompatibleAddressException, AddressValueException { super(thisAddress -> toFullEUI64Section(section, eui, ((IPv6Address) thisAddress).getDefaultCreator(), ((IPv6Address) thisAddress).getMACNetwork().getAddressCreator())); this.zone = zone; } static IPv6Zone checkZone(CharSequence zone) throws AddressValueException { if(zone == null) { return null; } String zoneStr = zone.toString().trim(); if(zone.length() == 0) { return null; } int invalidIndex = Validator.validateZone(zoneStr); if(invalidIndex >= 0) { throw new AddressValueException("ipaddress.error.invalid.zone", invalidIndex); } return new IPv6Zone(zoneStr); } IPv6AddressCreator getDefaultCreator() { return getNetwork().getAddressCreator(); } IPv6AddressCreator getCreator() { IPv6AddressCreator defaultCreator = getDefaultCreator(); if(!hasZone()) { return defaultCreator; } IPv6AddressCreator creator = new IPv6AddressCreator(getNetwork(), defaultCreator.cache) {// using a lambda for this one results in a big performance hit, so we use anonymous class private static final long serialVersionUID = 4L; @Override protected IPv6Address createAddressInternal(IPv6AddressSegment segments[]) { IPv6AddressCreator creator = getDefaultCreator(); return creator.createAddress(segments, zone); /* address creation */ } @Override public IPv6Address createAddress(IPv6AddressSection section) { IPv6AddressCreator creator = getDefaultCreator(); return creator.createAddress(section, zone); /* address creation */ } }; creator.useSegmentCache = defaultCreator.useSegmentCache; return creator; } private static IPv6Zone getZone(Inet6Address inet6Address) { NetworkInterface networkInterface = inet6Address.getScopedInterface(); if(networkInterface != null) { return new IPv6Zone(networkInterface); } int scopeId = inet6Address.getScopeId(); if(scopeId != 0) { return new IPv6Zone(scopeId); } return null; } private static IPv6AddressSection toFullEUI64Section(IPv6AddressSection section, MACAddressSection eui, IPv6AddressCreator creator, MACAddressCreator macCreator) throws AddressValueException, IncompatibleAddressException { boolean euiIsExtended = eui.isExtended(); if(eui.addressSegmentIndex != 0) { throw new AddressPositionException(eui, eui.addressSegmentIndex); } if(section.addressSegmentIndex != 0) { throw new AddressPositionException(section, section.addressSegmentIndex); } if(section.getSegmentCount() < 4) { throw new AddressValueException(section, "ipaddress.mac.error.not.eui.convertible"); } if(eui.getSegmentCount() != (euiIsExtended ? MACAddress.EXTENDED_UNIQUE_IDENTIFIER_64_SEGMENT_COUNT : MACAddress.EXTENDED_UNIQUE_IDENTIFIER_48_SEGMENT_COUNT)) { throw new AddressValueException(eui, "ipaddress.mac.error.not.eui.convertible"); } IPv6AddressSegment segments[] = creator.createSegmentArray(8); section.getSegments(0, 4, segments, 0); Integer prefLength = section.getNetworkPrefixLength(); Integer prefixLength = prefLength != null && (prefLength <= 64) ? prefLength : null; toEUI64Segments(segments, 4, eui, 0, eui.isExtended(), creator, macCreator, prefixLength); return creator.createSectionInternal(segments); } static IPv6AddressSegment[] toEUI64Segments( IPv6AddressSegment segments[], int ipv6StartIndex, MACAddressSection eui, int euiStartIndex, boolean isExtended, IPv6AddressCreator creator, MACAddressCreator macCreator, Integer prefixLength) throws IncompatibleAddressException { int euiSegmentIndex = 0; int euiSegmentCount = eui.getSegmentCount(); MACAddressSegment seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7; seg0 = (euiStartIndex == 0 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg1 = (euiStartIndex <= 1 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg2 = (euiStartIndex <= 2 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg3 = (euiStartIndex <= 3 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg4 = (euiStartIndex <= 4 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg5 = (euiStartIndex <= 5 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg6 = (euiStartIndex <= 6 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex++) : null; seg7 = (euiStartIndex <= 7 && euiSegmentIndex < euiSegmentCount) ? eui.getSegment(euiSegmentIndex) : null; boolean isNotNull; MACAddressSegment zeroSegment = macCreator.createSegment(0); MACAddressSegment ffSegment = macCreator.createSegment(0xff); MACAddressSegment feSegment = macCreator.createSegment(0xfe); Integer currentPrefix = null; if(prefixLength != null) { //since the prefix comes from the ipv6 section and not the MAC section, any segment prefix for the MAC section is 0 or null //prefixes across segments have the pattern: null, null, ..., null, 0-16, 0, 0, ..., 0 //So if the overall prefix is 0, then the prefix of every segment is 0 currentPrefix = 0; } if((isNotNull = (seg0 != null)) || seg1 != null) { if(isNotNull) { if(seg1 == null) { seg1 = zeroSegment; } } else { seg0 = zeroSegment; } segments[ipv6StartIndex++] = join(creator, seg0, seg1, true /* only this first one gets the flipped bit */, currentPrefix); } //join 2 and 3 if(isExtended) { if((isNotNull = (seg2 != null)) || seg3 != null) { if(!isNotNull) { seg2 = zeroSegment; if(!seg3.matches(0xff)) { throw new IncompatibleAddressException(eui, "ipaddress.mac.error.not.eui.convertible"); } } segments[ipv6StartIndex++] = join(creator, seg2, ffSegment, currentPrefix); } if((isNotNull = (seg4 != null)) || seg5 != null) { if(isNotNull) { if(!seg4.matches(0xfe)) { throw new IncompatibleAddressException(eui, "ipaddress.mac.error.not.eui.convertible"); } if(seg5 == null) { seg5 = zeroSegment; } } segments[ipv6StartIndex++] = join(creator, feSegment, seg5, currentPrefix); } } else { if(seg2 != null) { segments[ipv6StartIndex++] = join(creator, seg2, ffSegment, currentPrefix); } if(seg3 != null) { segments[ipv6StartIndex++] = join(creator, feSegment, seg3, currentPrefix); } if((isNotNull = (seg4 != null)) || seg5 != null) { if(isNotNull) { if(seg5 == null) { seg5 = zeroSegment; } } else { seg4 = zeroSegment; } segments[ipv6StartIndex++] = join(creator, seg4, seg5, currentPrefix); } } if((isNotNull = (seg6 != null)) || seg7 != null) { if(isNotNull) { if(seg7 == null) { seg7 = zeroSegment; } } else { seg6 = zeroSegment; } segments[ipv6StartIndex] = join(creator, seg6, seg7, currentPrefix); } return segments; } private static IPv6AddressSegment join(IPv6AddressCreator creator, MACAddressSegment macSegment0, MACAddressSegment macSegment1, Integer prefixLength) { return join(creator, macSegment0, macSegment1, false, prefixLength); } private static IPv6AddressSegment join(IPv6AddressCreator creator, MACAddressSegment macSegment0, MACAddressSegment macSegment1, boolean flip, Integer prefixLength) { if(macSegment0.isMultiple()) { // if the high segment has a range, the low segment must match the full range, // otherwise it is not possible to create an equivalent range when joining if(!macSegment1.isFullRange()) { throw new IncompatibleAddressException(macSegment0, macSegment1, "ipaddress.error.invalidMACIPv6Range"); } } int lower0 = macSegment0.getSegmentValue(); int upper0 = macSegment0.getUpperSegmentValue(); if(flip) { int mask2ndBit = 0x2; if(!macSegment0.matchesWithMask(mask2ndBit & lower0, mask2ndBit)) { throw new IncompatibleAddressException(macSegment0, "ipaddress.mac.error.not.eui.convertible"); } lower0 ^= mask2ndBit;//flip the universal/local bit upper0 ^= mask2ndBit; } return creator.createSegment( (lower0 << 8) | macSegment1.getSegmentValue(), (upper0 << 8) | macSegment1.getUpperSegmentValue(), prefixLength); } @Override public IPv6AddressNetwork getNetwork() { return defaultIpv6Network(); } public MACAddressNetwork getMACNetwork() { return defaultMACNetwork(); } public IPv4AddressNetwork getIPv4Network() { return defaultIpv4Network(); } @Override public IPv6AddressSection getSection() { return (IPv6AddressSection) super.getSection(); } @Override public IPv6AddressSection getSection(int index) { return getSection().getSection(index); } @Override public IPv6AddressSection getSection(int index, int endIndex) { return getSection().getSection(index, endIndex); } @Override public IPv6AddressSegment getDivision(int index) { return getSegment(index); } @Override public IPv6AddressSegment getSegment(int index) { return getSection().getSegment(index); } @Override public IPv6AddressSegment[] getSegments() { return getSection().getSegments(); } public boolean isEUI64() { return getSection().isEUI64(); } public MACAddress toEUI(boolean extended) { MACAddressSection section = getSection().toEUI(extended); if(section == null) { return null; } MACAddressCreator creator = getMACNetwork().getAddressCreator(); return creator.createAddress(section); } @Override public IPAddressStringDivisionSeries[] getParts(IPStringBuilderOptions options) { return getParts(IPv6StringBuilderOptions.from(options)); } public IPAddressStringDivisionSeries[] getParts(IPv6StringBuilderOptions options) { IPAddressStringDivisionSeries parts[] = getSection().getParts(options); IPv4Address ipv4Addr = getConverted(options); if(ipv4Addr != null) { IPAddressStringDivisionSeries ipv4Parts[] = ipv4Addr.getParts(options.ipv4ConverterOptions); IPAddressStringDivisionSeries tmp[] = parts; parts = new IPAddressStringDivisionSeries[tmp.length + ipv4Parts.length]; System.arraycopy(tmp, 0, parts, 0, tmp.length); System.arraycopy(ipv4Parts, 0, parts, tmp.length, ipv4Parts.length); } return parts; } @Override public int getSegmentCount() { return SEGMENT_COUNT; } @Override public int getByteCount() { return BYTE_COUNT; } @Override public int getBitCount() { return BIT_COUNT; } void cache(IPv6Address lower, IPv6Address upper) { if((lower != null || upper != null) && getSection().getSingleLowestOrHighestSection() == null) { getSection().cache(lower != null ? lower.getSection() : null, upper != null ? upper.getSection() : null); IPv6AddressCache cache = addressCache; if(cache == null || (lower != null && cache.lower == null) || (upper != null && cache.upper == null)) { synchronized(this) { cache = addressCache; boolean create = (cache == null); if(create) { addressCache = cache = new IPv6AddressCache(); cache.lower = lower; cache.upper = upper; } else { if(cache.lower == null) { cache.lower = lower; } if(cache.upper == null) { cache.upper = upper; } } } } } } private IPv6Address getLowestOrHighest(boolean lowest, boolean excludeZeroHost) { IPv6AddressSection currentSection = getSection(); IPv6AddressSection sectionResult = currentSection.getLowestOrHighestSection(lowest, excludeZeroHost); if(sectionResult == currentSection) { return this; } else if(sectionResult == null) { return null; } IPv6Address result = null; IPv6AddressCache cache = addressCache; if(cache == null || (result = lowest ? (excludeZeroHost ? cache.lowerNonZeroHost : cache.lower) : cache.upper) == null) { synchronized(this) { cache = addressCache; boolean create = (cache == null); if(create) { addressCache = cache = new IPv6AddressCache(); } else { if(lowest) { if(excludeZeroHost) { create = (result = cache.lowerNonZeroHost) == null; } else { create = (result = cache.lower) == null; } } else { create = (result = cache.upper) == null; } } if(create) { result = getCreator().createAddress(sectionResult); if(lowest) { if(excludeZeroHost) { cache.lowerNonZeroHost = result; } else { cache.lower = result; } } else { cache.upper = result; } } } } return result; } @Override public IPv6Address getLowerNonZeroHost() { return getLowestOrHighest(true, true); } @Override public IPv6Address getLower() { return getLowestOrHighest(true, false); } @Override public IPv6Address getUpper() { return getLowestOrHighest(false, false); } /** * Returns a pair of longs with the lower address value in the range of this individual address or subnet. * The high bits are in the first element, the low bits in the second. * * @return */ public long[] longValues() { return getSection().longValues(); } /** * Returns a pair of longs with the upper address value in the range of this individual address or subnet. * The high bits are in the first element, the low bits in the second. * * @return */ public long[] upperLongValues() { return getSection().upperLongValues(); } IPv6TrieKeyData getTrieKeyCache() { IPv6TrieKeyData keyData = cachedTrieKeyData; if(keyData == null) { keyData = new IPv6TrieKeyData(); Integer prefLen = getPrefixLength(); keyData.prefixLength = prefLen; long vals[] = longValues(); keyData.uint64HighVal = vals[0]; keyData.uint64LowVal = vals[1]; if(prefLen != null) { int bits = prefLen; IPv6Address mask = getNetwork().getNetworkMask(bits, false); vals = mask.longValues(); keyData.mask64HighVal = vals[0]; keyData.mask64LowVal = vals[1]; if(bits > 63) { keyData.nextBitMask64Val = 0x8000000000000000L >>> (bits - 64); } else { keyData.nextBitMask64Val = 0x8000000000000000L >>> bits; } } cachedTrieKeyData = keyData; } return keyData; } /** * Replaces segments starting from startIndex and ending before endIndex with the same number of segments starting at replacementStartIndex from the replacement section * * @param startIndex * @param endIndex * @param replacement * @param replacementIndex * @throws IndexOutOfBoundsException * @return */ public IPv6Address replace(int startIndex, int endIndex, IPv6Address replacement, int replacementIndex) { return checkIdentity(getSection().replace(startIndex, endIndex, replacement.getSection(), replacementIndex, replacementIndex + (endIndex - startIndex))); } /** * Replaces segments starting from startIndex with as many segments as possible from the replacement section * * @param startIndex * @param replacement * @throws IndexOutOfBoundsException * @return */ public IPv6Address replace(int startIndex, IPv6AddressSection replacement) { int replacementCount = Math.min(IPv6Address.SEGMENT_COUNT - startIndex, replacement.getSegmentCount()); return checkIdentity(getSection().replace(startIndex, startIndex + replacementCount, replacement, 0, replacementCount)); } @Override public IPv6Address reverseBits(boolean perByte) { return getCreator().createAddress(getSection().reverseBits(perByte)); } @Override public IPv6Address reverseBytes() { return checkIdentity(getSection().reverseBytes()); } @Override public IPv6Address reverseBytesPerSegment() { return checkIdentity(getSection().reverseBytesPerSegment()); } @Override public IPv6Address reverseSegments() { return checkIdentity(getSection().reverseSegments()); } @Override public Iterator segmentsNonZeroHostIterator() { return getSection().segmentsNonZeroHostIterator(); } @Override public Iterator segmentsIterator() { return getSection().segmentsIterator(); } @Override public AddressComponentRangeSpliterator segmentsSpliterator() { return getSection().segmentsSpliterator(this, getCreator()); } @Override public Stream segmentsStream() { return StreamSupport.stream(segmentsSpliterator(), false); } @Override public Iterator prefixBlockIterator() { return getSection().prefixIterator(this, getCreator(), true); } @Override public AddressComponentSpliterator prefixBlockSpliterator() { return getSection().prefixSpliterator(this, getCreator(), true); } @Override public Stream prefixBlockStream() { return StreamSupport.stream(prefixBlockSpliterator(), false); } @Override public Iterator prefixBlockIterator(int prefixLength) { return getSection().prefixIterator(this, getCreator(), true, prefixLength); } @Override public AddressComponentSpliterator prefixBlockSpliterator(int prefixLength) { return getSection().prefixSpliterator(this, getCreator(), true, prefixLength); } @Override public Stream prefixBlockStream(int prefixLength) { return StreamSupport.stream(prefixBlockSpliterator(prefixLength), false); } @Override public Iterator prefixIterator() { return getSection().prefixIterator(this, getCreator(), false); } @Override public AddressComponentSpliterator prefixSpliterator() { return getSection().prefixSpliterator(this, getCreator(), false); } @Override public Stream prefixStream() { return StreamSupport.stream(prefixSpliterator(), false); } @Override public Iterator prefixIterator(int prefixLength) { return getSection().prefixIterator(this, getCreator(), false, prefixLength); } @Override public AddressComponentSpliterator prefixSpliterator(int prefixLength) { return getSection().prefixSpliterator(this, getCreator(), false, prefixLength); } @Override public Stream prefixStream(int prefixLength) { return StreamSupport.stream(prefixSpliterator(prefixLength), false); } @Override public Iterator blockIterator(int segmentCount) { return getSection().blockIterator(this, getCreator(), segmentCount); } @Override public AddressComponentSpliterator blockSpliterator(int segmentCount) { return getSection().blockSpliterator(this, getCreator(), segmentCount); } @Override public Stream blockStream(int segmentCount) { return StreamSupport.stream(blockSpliterator(segmentCount), false); } @SuppressWarnings("unchecked") @Override public Iterator sequentialBlockIterator() { return (Iterator) super.sequentialBlockIterator(); } @SuppressWarnings("unchecked") @Override public AddressComponentSpliterator sequentialBlockSpliterator() { return (AddressComponentSpliterator) super.sequentialBlockSpliterator(); } @SuppressWarnings("unchecked") @Override public Stream sequentialBlockStream() { return (Stream) super.sequentialBlockStream(); } @Override public Iterator iterator() { return getSection().iterator(this, getCreator(), null); } @Override public AddressComponentSpliterator spliterator() { return getSection().spliterator(this, getCreator(), false); } @Override public Stream stream() { return StreamSupport.stream(spliterator(), false); } @Override public Iterator nonZeroHostIterator() { Predicate excludeFunc = null; if(includesZeroHost()) { int prefLength = getNetworkPrefixLength(); excludeFunc = segments -> getSection().isZeroHost(segments, prefLength); } return getSection().iterator(this, getCreator(), excludeFunc); } @Override public Iterable getIterable() { return this; } public IPv6Address increment(BigInteger increment) { return checkIdentity(getSection().increment(increment)); } @Override public IPv6Address increment(long increment) { return checkIdentity(getSection().increment(increment)); } @Override public IPv6Address incrementBoundary(long increment) { return checkIdentity(getSection().incrementBoundary(increment)); } /** * If this address is IPv4 convertible, returns that address. * Otherwise, returns null. *

* You can also use {@link #isIPv4Convertible()} to determine convertibility. Both use an instance of {@link IPAddressConverter.DefaultAddressConverter} which uses IPv4-mapped address mappings from rfc 4038. *

* Override this method and {@link IPv6Address#isIPv4Convertible()} if you wish to map IPv6 to IPv4 according to the mappings defined by * in {@link IPv6Address#isIPv4Compatible()}, {@link IPv6Address#isIPv4Mapped()}, {@link IPv6Address#is6To4()} or by some other mapping. *

* For the reverse mapping, see {@link IPv4Address#toIPv6()} */ @Override public IPv4Address toIPv4() { IPAddressConverter conv = DEFAULT_ADDRESS_CONVERTER; return conv.toIPv4(this); } @Override public IPv6Address toIPv6() { return this; } @Override public boolean isIPv6() { return true; } /** * Determines whether this address can be converted to IPv4. * Override this method to convert in your own way. * The default behaviour is to use isIPv4Mapped() * * You should also override {@link #toIPv4()} to match the conversion. * * @return */ @Override public boolean isIPv4Convertible() { IPAddressConverter conv = DEFAULT_ADDRESS_CONVERTER; return conv.isIPv4Convertible(this); } @Override public boolean isIPv6Convertible() { return true; } /** * ::ffff:x:x/96 indicates IPv6 address mapped to IPv4 */ public IPv4AddressSection toMappedIPv4Segments() { if(isIPv4Mapped()) { return getSection().getEmbeddedIPv4AddressSection(); } return null; } /** * Returns the second and third segments as an {@link IPv4Address}. * * This can be used for IPv4 or for IPv6 6to4 addresses convertible to IPv4. * * @return the address */ public IPv4Address get6To4IPv4Address() { return getEmbeddedIPv4Address(2); } /** * Returns the embedded {@link IPv4Address} in the lowest (least-significant) two segments. * This is used by IPv4-mapped, IPv4-compatible, ISATAP addresses and 6over4 addresses * * @return the embedded {@link IPv4Address} */ public IPv4Address getEmbeddedIPv4Address() { IPv4AddressCreator creator = getIPv4Network().getAddressCreator(); return creator.createAddress(getSection().getEmbeddedIPv4AddressSection()); /* address creation */ } /** * Produces an IPv4 address from any sequence of 4 bytes in this IPv6 address. * * @param byteIndex the byte index to start * @throws IndexOutOfBoundsException if the index is less than zero or bigger than 7 * @return */ public IPv4Address getEmbeddedIPv4Address(int byteIndex) { if(byteIndex == IPv6Address.MIXED_ORIGINAL_SEGMENT_COUNT * IPv6Address.BYTES_PER_SEGMENT) { return getEmbeddedIPv4Address(); } IPv4AddressCreator creator = getIPv4Network().getAddressCreator(); return creator.createAddress(getSection().getEmbeddedIPv4AddressSection(byteIndex, byteIndex + IPv4Address.BYTE_COUNT)); /* address creation */ } @Override public boolean isLocal() { if(isMulticast()) { /* [RFC4291][RFC7346] 11111111|flgs|scop scope 4 bits 1 Interface-Local scope 2 Link-Local scope 3 Realm-Local scope 4 Admin-Local scope 5 Site-Local scope 8 Organization-Local scope E Global scope */ IPv6AddressSegment firstSeg = getSegment(0); if(firstSeg.matchesWithMask(8, 0xf)) { return true; } if(firstSeg.getValueCount() <= 5 && (firstSeg.getSegmentValue() & 0xf) >= 1 && (firstSeg.getUpperSegmentValue() & 0xf) <= 5) { //all values fall within the range from interface local to site local return true; } //source specific multicast //rfc4607 and https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml //FF3X::8000:0 - FF3X::FFFF:FFFF Reserved for local host allocation [RFC4607] if(firstSeg.matchesWithPrefixMask(0xff30, 12) && getSegment(6).matchesWithPrefixMask(0x8000, 1)) { return true; } } return isLinkLocal() || isSiteLocal() || isUniqueLocal() || isAnyLocal(); } /** * @see java.net.InetAddress#isLinkLocalAddress() */ @Override public boolean isLinkLocal() { IPv6AddressSegment firstSeg = getSegment(0); return (isMulticast() && firstSeg.matchesWithMask(2, 0xf)) || // ffx2::/16 //1111 1110 10 .... fe8x currently only in use firstSeg.matchesWithPrefixMask(0xfe80, 10); } /** * @see java.net.InetAddress#isSiteLocalAddress() */ public boolean isSiteLocal() { IPv6AddressSegment firstSeg = getSegment(0); return (isMulticast() && firstSeg.matchesWithMask(5, 0xf)) || // ffx5::/16 //1111 1110 11 ... firstSeg.matchesWithPrefixMask(0xfec0, 10); // deprecated RFC 3879 } public boolean isUniqueLocal() { //RFC 4193 return getSegment(0).matchesWithPrefixMask(0xfc00, 7); } /** * Whether the address is IPv4-mapped * * ::ffff:x:x/96 indicates IPv6 address mapped to IPv4 */ public boolean isIPv4Mapped() { //::ffff:x:x/96 indicates IPv6 address mapped to IPv4 if(getSegment(5).matches(IPv6Address.MAX_VALUE_PER_SEGMENT)) { for(int i = 0; i < 5; i++) { if(!getSegment(i).isZero()) { return false; } } return true; } return false; } /** * Whether the address is IPv4-compatible * * @see java.net.Inet6Address#isIPv4CompatibleAddress() */ public boolean isIPv4Compatible() { return getSegment(0).isZero() && getSegment(1).isZero() && getSegment(2).isZero() && getSegment(3).isZero() && getSegment(4).isZero() && getSegment(5).isZero(); } /** * Whether the address is IPv6 to IPv4 relay * @see #get6To4IPv4Address() */ public boolean is6To4() { //2002::/16 return getSegment(0).matches(0x2002); } /** * Whether the address is 6over4 */ public boolean is6Over4() { return getSegment(0).matches(0xfe80) && getSegment(1).isZero() && getSegment(2).isZero() && getSegment(3).isZero() && getSegment(4).isZero() && getSegment(5).isZero(); } /** * Whether the address is Teredo */ public boolean isTeredo() { //2001::/32 return getSegment(0).matches(0x2001) && getSegment(1).isZero(); } /** * Whether the address is ISATAP */ public boolean isIsatap() { // 0,1,2,3 is fe80:: // 4 can be 0200 return getSegment(0).matches(0xfe80) && getSegment(1).isZero() && getSegment(2).isZero() && getSegment(3).isZero() && (getSegment(4).isZero() || getSegment(4).matches(0x200)) && getSegment(5).matches(0x5efe); } /** * * @return Whether the address is IPv4 translatable as in rfc 2765 */ public boolean isIPv4Translatable() { //rfc 2765 //::ffff:0:x:x/96 indicates IPv6 addresses translated from IPv4 return getSegment(4).matches(0xffff) && getSegment(5).isZero() && getSegment(0).isZero() && getSegment(1).isZero() && getSegment(2).isZero() && getSegment(3).isZero(); } /** * Whether the address has the well-known prefix for IPv4 translatable addresses as in rfc 6052 and 6144 * @return */ public boolean isWellKnownIPv4Translatable() { //rfc 6052 rfc 6144 //64:ff9b::/96 prefix for auto ipv4/ipv6 translation if(getSegment(0).matches(0x64) && getSegment(1).matches(0xff9b)) { for(int i=2; i<=5; i++) { if(!getSegment(i).isZero()) { return false; } } return true; } return false; } @Override public boolean isMulticast() { // 11111111... return getSegment(0).matchesWithPrefixMask(0xff00, 8); } /** * @see java.net.InetAddress#isLoopbackAddress() */ @Override public boolean isLoopback() { //::1 int i=0; for(; i < getSegmentCount() - 1; i++) { if(!getSegment(i).isZero()) { return false; } } return getSegment(i).matches(1); } @Override public IPv6Address intersect(IPAddress other) throws AddressConversionException { IPv6AddressSection thisSection = getSection(); IPv6Address otherAddr = convertArg(other); IPv6AddressSection section = thisSection.intersect(otherAddr.getSection()); if(section == null) { return null; } //if they have the same zone, then use it in the intersection, otherwise ignore the zones IPv6AddressCreator creator = isSameZone(otherAddr) ? getCreator() : getDefaultCreator(); IPv6Address result = creator.createAddress(section); return result; } @Override public IPv6Address[] subtract(IPAddress other) throws AddressConversionException { IPv6AddressSection thisSection = getSection(); IPv6AddressSection sections[] = thisSection.subtract(convertArg(other).getSection()); if(sections == null) { return null; } IPv6Address result[] = new IPv6Address[sections.length]; for(int i = 0; i < result.length; i++) { result[i] = getCreator().createAddress(sections[i]); /* address creation */ } return result; } private IPv6Address checkIdentity(IPv6AddressSection newSection) { if(newSection == getSection()) { return this; } return getCreator().createAddress(newSection); } @Override public IPv6Address adjustPrefixBySegment(boolean nextSegment) { return checkIdentity(getSection().adjustPrefixBySegment(nextSegment)); } @Override public IPv6Address adjustPrefixBySegment(boolean nextSegment, boolean zeroed) { return checkIdentity(getSection().adjustPrefixBySegment(nextSegment, zeroed)); } @Override public IPv6Address adjustPrefixLength(int adjustment) { return checkIdentity(getSection().adjustPrefixLength(adjustment)); } @Override public IPv6Address adjustPrefixLength(int adjustment, boolean zeroed) { return checkIdentity(getSection().adjustPrefixLength(adjustment, zeroed)); } @Override public IPv6Address setPrefixLength(int prefixLength) throws PrefixLenException { return setPrefixLength(prefixLength, true); } @Override public IPv6Address setPrefixLength(int prefixLength, boolean zeroed) throws PrefixLenException { return checkIdentity(getSection().setPrefixLength(prefixLength, zeroed)); } @Override public IPv6Address setPrefixLength(int prefixLength, boolean zeroed, boolean zeroHostIsBlock) throws PrefixLenException { return checkIdentity(getSection().setPrefixLength(prefixLength, zeroed, zeroHostIsBlock)); } @Deprecated @Override public IPv6Address applyPrefixLength(int networkPrefixLength) throws PrefixLenException { return checkIdentity(getSection().applyPrefixLength(networkPrefixLength)); } @Override @Deprecated public IPv6Address removePrefixLength() { return removePrefixLength(true); } @Override public IPv6Address withoutPrefixLength() { return removePrefixLength(false); } @Override @Deprecated public IPv6Address removePrefixLength(boolean zeroed) { return checkIdentity(getSection().removePrefixLength(zeroed)); } @Override protected IPv6Address convertArg(IPAddress arg) throws AddressConversionException { IPv6Address converted = arg.toIPv6(); if(converted == null) { throw new AddressConversionException(this, arg); } return converted; } @Override public IPv6Address toZeroHost() { return toZeroHost(false); } @Override protected IPv6Address toZeroHost(boolean boundariesOnly) { if(!isPrefixed()) { IPv6AddressNetwork network = getNetwork(); PrefixConfiguration config = network.getPrefixConfiguration(); IPv6Address addr = network.getNetworkMask(0, !config.allPrefixedAddressesAreSubnets()); if(config.zeroHostsAreSubnets()) { addr = addr.getLower(); } return addr; } if(includesZeroHost() && isSingleNetwork()) { return getLower();//cached } return checkIdentity(getSection().createZeroHost(boundariesOnly)); } @Override public IPv6Address toZeroHost(int prefixLength) { if(isPrefixed() && prefixLength == getNetworkPrefixLength()) { return toZeroHost(); } return checkIdentity(getSection().toZeroHost(prefixLength)); } @Override public IPv6Address toZeroNetwork() { if(!isPrefixed()) { return getNetwork().getHostMask(getBitCount()); } return checkIdentity(getSection().createZeroNetwork()); } @Override public IPv6Address toMaxHost() { if(!isPrefixed()) { IPv6Address resultNoPrefix = getNetwork().getHostMask(0); if(getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets()) { return resultNoPrefix; } return resultNoPrefix.setPrefixLength(0); } if(includesMaxHost() && isSingleNetwork()) { return getUpper(); } return checkIdentity(getSection().createMaxHost()); } @Override public IPv6Address toMaxHost(int prefixLength) { if(isPrefixed() && prefixLength == getNetworkPrefixLength()) { return toMaxHost(); } return checkIdentity(getSection().toMaxHost(prefixLength)); } @Override public IPv6Address mask(IPAddress mask, boolean retainPrefix) throws IncompatibleAddressException, AddressConversionException { return checkIdentity(getSection().mask(convertArg(mask).getSection(), retainPrefix)); } @Override public IPv6Address mask(IPAddress mask) throws IncompatibleAddressException, AddressConversionException { return mask(mask, false); } @Override public IPv6Address maskNetwork(IPAddress mask, int networkPrefixLength) throws IncompatibleAddressException, PrefixLenException, AddressConversionException { return checkIdentity(getSection().maskNetwork(convertArg(mask).getSection(), networkPrefixLength)); } @Override public IPv6Address bitwiseOr(IPAddress mask, boolean retainPrefix) throws IncompatibleAddressException, AddressConversionException { return checkIdentity(getSection().bitwiseOr(convertArg(mask).getSection(), retainPrefix)); } @Override public IPv6Address bitwiseOr(IPAddress mask) throws IncompatibleAddressException, AddressConversionException { return bitwiseOr(mask, false); } @Override public IPv6Address bitwiseOrNetwork(IPAddress mask, int networkPrefixLength) throws IncompatibleAddressException, PrefixLenException, AddressConversionException { return checkIdentity(getSection().bitwiseOrNetwork(convertArg(mask).getSection(), networkPrefixLength)); } @Override public IPv6Address getHostMask() { return (IPv6Address) super.getHostMask(); } @Override public IPv6Address getNetworkMask() { return (IPv6Address) super.getNetworkMask(); } @Override public IPv6AddressSection getNetworkSection() { return getSection().getNetworkSection(); } @Override public IPv6AddressSection getNetworkSection(int networkPrefixLength) throws PrefixLenException { return getSection().getNetworkSection(networkPrefixLength); } @Override public IPv6AddressSection getNetworkSection(int networkPrefixLength, boolean withPrefixLength) throws PrefixLenException { return getSection().getNetworkSection(networkPrefixLength, withPrefixLength); } @Override public IPv6AddressSection getHostSection(int networkPrefixLength) throws PrefixLenException { return getSection().getHostSection(networkPrefixLength); } @Override public IPv6AddressSection getHostSection() { return getSection().getHostSection(); } @Override public IPv6Address toPrefixBlock() { Integer prefixLength = getNetworkPrefixLength(); if(prefixLength == null || getNetwork().getPrefixConfiguration().allPrefixedAddressesAreSubnets()) { return this; } return toPrefixBlock(prefixLength); } @Override public IPv6Address toPrefixBlock(int networkPrefixLength) throws PrefixLenException { return checkIdentity(getSection().toPrefixBlock(networkPrefixLength)); } @Override public IPv6Address assignPrefixForSingleBlock() { return (IPv6Address) super.assignPrefixForSingleBlock(); } @Override public IPv6Address assignMinPrefixForBlock() { return (IPv6Address) super.assignMinPrefixForBlock(); } @Override public IPv6Address coverWithPrefixBlock() { return (IPv6Address) IPv6AddressSection.coverWithPrefixBlock(this, getLower(), getUpper()); } @Override public IPv6Address coverWithPrefixBlock(IPAddress other) throws AddressConversionException { return IPv6AddressSection.coverWithPrefixBlock( this.removeZone(), convertArg(other).removeZone(), IPv6Address::getLower, IPv6Address::getUpper, Address.ADDRESS_LOW_VALUE_COMPARATOR::compare); } /** * Produces an array of prefix blocks that cover the same set of addresses as this. *

* Unlike {@link #spanWithPrefixBlocks(IPAddress)} this method only includes addresses that are a part of this subnet. */ @Override public IPv6Address[] spanWithPrefixBlocks() { if(isSequential()) { if(isSinglePrefixBlock()) { return new IPv6Address[] {removeZone()}; } return spanWithPrefixBlocks(this); } @SuppressWarnings("unchecked") ArrayList list = (ArrayList) removeZone().spanWithBlocks(true); return list.toArray(new IPv6Address[list.size()]); } @Override public IPv6Address[] spanWithPrefixBlocks(IPAddress other) throws AddressConversionException { return IPAddress.getSpanningPrefixBlocks( removeZone(), convertArg(other).removeZone(), IPv6Address::getLower, IPv6Address::getUpper, Address.ADDRESS_LOW_VALUE_COMPARATOR::compare, IPv6Address::assignPrefixForSingleBlock, IPv6Address::withoutPrefixLength, getCreator()::createAddressArray); } /** * Produces an array of blocks that are sequential that cover the same set of addresses as this. *

* This array can be shorter than that produced by {@link #spanWithPrefixBlocks()} and is never longer. *

* Unlike {@link #spanWithSequentialBlocks(IPAddress)} this method only includes addresses that are a part of this subnet. */ @Override public IPv6Address[] spanWithSequentialBlocks() throws AddressConversionException { if(isSequential()) { return new IPv6Address[] { withoutPrefixLength().removeZone() }; } @SuppressWarnings("unchecked") ArrayList list = (ArrayList) removeZone().spanWithBlocks(false); return list.toArray(new IPv6Address[list.size()]); } @Override public IPv6Address[] spanWithSequentialBlocks(IPAddress other) throws AddressConversionException { return IPAddress.getSpanningSequentialBlocks( this.removeZone(), convertArg(other).removeZone(), IPv6Address::getLower, IPv6Address::getUpper, Address.ADDRESS_LOW_VALUE_COMPARATOR::compare, IPv6Address::withoutPrefixLength, getDefaultCreator()); } @Override public IPv6AddressSeqRange spanWithRange(IPAddress other) throws AddressConversionException { return toSequentialRange(other); } @Override public IPv6Address[] mergeToPrefixBlocks(IPAddress ...addresses) throws AddressConversionException { if(addresses.length == 0) { if(isSinglePrefixBlock()) { return new IPv6Address[] {removeZone()}; } } IPAddress[] converted = getConverted(addresses); List blocks = getMergedPrefixBlocks(converted); return blocks.toArray(new IPv6Address[blocks.size()]); } private IPAddress[] getConverted(IPAddress... addresses) { IPAddress converted[] = new IPAddress[addresses.length + 1]; for(int i = 0, j = 1; i < addresses.length; i = j++) { converted[j] = convertArg(addresses[i]).removeZone(); } converted[0] = removeZone(); return converted; } @Override public IPv6Address[] mergeToSequentialBlocks(IPAddress ...addresses) throws AddressConversionException { if(addresses.length == 0) { if(isSequential()) { return new IPv6Address[] {removeZone()}; } } addresses = addresses.clone(); for(int i = 0; i < addresses.length; i++) { addresses[i] = convertArg(addresses[i]).removeZone(); } IPAddress[] converted = getConverted(addresses); List blocks = getMergedSequentialBlocks(converted, getDefaultCreator()); return blocks.toArray(new IPv6Address[blocks.size()]); } /** * Returns whether {@link #getZone()} returns a non-null value * * @return */ public boolean hasZone() { return zone != null; } /** * The zone or scope id string, which as a string is typically appended to an address with a '%', eg fe80::71a3:2b00:ddd3:753f%16 * * If there is no zone or scope id, returns null. *

* See {@link #getIPv6Zone()} * * @return */ public String getZone() { return getZoneString(); } /** * Returns a new address with the same address values but with the supplied zone. * If the supplied zone is null, equivalent to calling {@link #removeZone()} * * @param newZone * @return */ public IPv6Address setZone(IPv6Zone newZone) { if(newZone == null) { return removeZone(); } return getDefaultCreator().createAddress(getSection(), newZone); /* address creation */ } /** * Returns the zone or scope id, consisting of a network interface name or a positive integer scope identifier. * * If there is no zone or scope id, returns null *

* An IPv6 zone distinguishes two IPv6 addresses that are the same. * They are used with link-local addresses fe80::/10 and distinguishes two interfaces to the link-local network, this is known as the zone id. * They are used with site-local addresses to distinguish sites, using the site id, also known as the scope id. * * A zone that consists of a scope id is called a scoped zone. * * See {@link #getZone()} * * @return */ public IPv6Zone getIPv6Zone() { return zone; } /** * Returns the equivalent address but with no zone. * * @return */ public IPv6Address removeZone() { if(hasZone()) { return getDefaultCreator().createAddress(getSection()); /* address creation */ } return this; } protected boolean hasNoValueCache() { if(addressCache == null) { synchronized(this) { if(addressCache == null) { addressCache = new IPv6AddressCache(); return true; } } } return false; } /** * Converts the lowest value of this address and the associated zone to an Inet6Address. *

* Address with a zone should check for null. *

* This will return null if this IPv6 Address has a zone (available from {@link #getIPv6Zone()}), * that zone references a network interface ({@link IPv6Zone#referencesInterface} is true) * and that network interface (from {@link IPv6Zone#getAssociatedIntf()}) is an IPv4-only interface, * or that interface is not entirely link-local and this address is link-local, * or that interface is not entirely site-local and this address is site-local. *

* This will return null if this IPv6 Address has a zone (available from {@link #getIPv6Zone()}) and: *

    *
  • the zone is a scoped id and the address is a global IPv6 address.
  • *
  • the zone specifies an interface that does not exist on this host.
  • *
  • the zone specifies an interface that is IPv4 only.
  • *
  • the zone specifies an interface that is not entirely link-local and this address is link-local.
  • *
  • the zone specifies an interface that is not entirely site-local and this address is site-local.
  • *
* In those cases, the corresponding Java SDK methods such as {@link Inet6Address#getByAddress(String, byte[], NetworkInterface)} * will throw UnknownHostException when constructed with the same network interface. *

* If this address is IPv4-mapped, then any associated zone will be discarded, * because it is not possible to create an IPv4-mapped Inet6Address with a zone. */ @Override public Inet6Address toInetAddress() { if(hasZone()) { //we cache the address in here and not in the address section if there is a zone Inet6Address result; if(hasNoValueCache() || (result = addressCache.inetAddress) == null) { addressCache.inetAddress = result = (Inet6Address) toInetAddressImpl(); } return result; } return (Inet6Address) super.toInetAddress(); } @Override public Inet6Address toUpperInetAddress() { return (Inet6Address) super.toUpperInetAddress(); } @Override protected Inet6Address toInetAddressImpl() { Inet6Address result; byte bytes[] = getSection().getBytesInternal(); try { if(hasZone()) { if(zone.referencesScopeId()) { result = Inet6Address.getByAddress(null, bytes, zone.getAssociatedScopeId()); } else if(zone.referencesIntf() && zone.getAssociatedIntf() != null) { result = Inet6Address.getByAddress(null, bytes, zone.getAssociatedIntf()); } else { // When the original zone was provided as a string, we use that here. // There is no related function that takes a string as third arg, so we reconstruct the address string. // // When interface name is not known as an interface on the current host, this throws UnknownHostException // // We need to drop the prefix, and we also need to use the lower address so no wildcards // // Note that this call to getLower() assumes we want the lower address. // Since toUpperInetAddress calls getUpper().toInetAddress, this works. IPv6Address adjusted = getLower().withoutPrefixLength(); InetAddress resultIP = InetAddress.getByName(adjusted.toNormalizedString()); if(resultIP instanceof Inet6Address) { result = (Inet6Address) resultIP; } else { // the InetAddress code is throwing away the interface name because the address is IPv4-mapped // so the only way to get an IPv6 address, any address at all in fact, requires that we throw it away result = Inet6Address.getByAddress(null, bytes, null); } } } else { result = Inet6Address.getByAddress(null, bytes, null); } } catch(UnknownHostException e) { result = null; } return result; } @Override @Deprecated public IPv6AddressSeqRange toSequentialRange(IPAddress other) { return new IPv6AddressSeqRange(this, convertArg(other)); } @Override public IPv6AddressSeqRange toSequentialRange() { IPv6Address thiz = removeZone().withoutPrefixLength(); return new IPv6AddressSeqRange(thiz.getLower(), thiz.getUpper(), true); } @Override public int hashCode() { int result = super.hashCode(); if(hasZone()) { result *= zone.getName().hashCode(); } return result; } @Override public boolean isSameAddress(Address other) { return other instanceof IPv6Address && super.isSameAddress(other) && isSameZone((IPv6Address) other); } private boolean isSameZone(IPv6Address otherIPv6Address) { return Objects.equals(zone, otherIPv6Address.zone); } /** * * @param other * @return whether this subnet overlaps with the given address */ @Override public boolean overlaps(Address other) { if(super.overlaps(other)) { //must check the zone too if(other != this) { IPv6Address otherAddr = (IPv6Address) other; if(hasZone() || otherAddr.hasZone()) { //if it has a zone, then it does not overlap addresses from other zones return isSameZone(otherAddr); } } return true; } return false; } /** * * @param other * @return whether this subnet contains the given address */ @Override public boolean contains(Address other) { if(super.contains(other)) { //must check the zone too if(other != this) { IPv6Address otherAddr = (IPv6Address) other; if(hasZone() || otherAddr.hasZone()) { //if it has a zone, then it does not contain addresses from other zones return isSameZone(otherAddr); } } return true; } return false; } @Override public BigInteger enumerate(Address other) { if(other instanceof IPv6Address) { return IPv6AddressSection.enumerate(getSection(), other.getSection()); } return null; } @Override public BigInteger enumerate(IPAddress other) { if(other.isIPv6()) { return IPv6AddressSection.enumerate(getSection(), other.getSection()); } return null; } //////////////// string creation below /////////////////////////////////////////////////////////////////////////////////////////// @Override protected IPAddressStringParameters createFromStringParams() { return new IPAddressStringParameters.Builder(). getIPv4AddressParametersBuilder().setNetwork(getIPv4Network()).getParentBuilder(). getIPv6AddressParametersBuilder().setNetwork(getNetwork()).getParentBuilder().toParams(); } private boolean hasNoStringCache() { if(stringCache == null) { synchronized(this) { if(stringCache == null) { if(hasZone()) { stringCache = new IPv6StringCache(); return true; } else { //when there is no zone, the section and address strings are the same, so we use the same cache IPv6AddressSection section = getSection(); boolean result = section.hasNoStringCache(); stringCache = section.getStringCache(); return result; } } } } return false; } /** * Produces a string in which the lower 4 bytes are expressed as an IPv4 address and the remaining upper bytes are expressed in IPv6 format. * * This the mixed IPv6/IPv4 format described in RFC 1884 https://tools.ietf.org/html/rfc1884 * * @return */ public String toMixedString() { String result; if(hasNoStringCache() || (result = stringCache.mixedString) == null) { if(hasZone()) { stringCache.mixedString = result = toNormalizedString(IPv6StringCache.mixedParams); } else { result = getSection().toMixedString();//the cache is shared so no need to update it here } } return result; } /** * This produces a canonical string. * * RFC 5952 describes canonical representations. * http://en.wikipedia.org/wiki/IPv6_address#Recommended_representation_as_text * http://tools.ietf.org/html/rfc5952 * * If this has a prefix length, that will be included in the string. */ @Override public String toCanonicalString() { String result; if(hasNoStringCache() || (result = stringCache.canonicalString) == null) { if(hasZone()) { stringCache.canonicalString = result = toNormalizedString(IPv6StringCache.canonicalParams); } else { result = getSection().toCanonicalString();//the cache is shared so no need to update it here } } return result; } @Override public String toFullString() { String result; if(hasNoStringCache() || (result = stringCache.fullString) == null) { if(hasZone()) { stringCache.fullString = result = toNormalizedString(IPv6StringCache.fullParams); } else { result = getSection().toFullString();//the cache is shared so no need to update it here } } return result; } /** * Creates the normalized string for an address without having to create the address objects first. * * @param lowerValueProvider * @param upperValueProvider * @param prefixLength * @param zone * @param network use {@link #defaultIpv6Network()} if there is no custom network in use * @return */ public static String toNormalizedString(IPv6AddressNetwork network, SegmentValueProvider lowerValueProvider, SegmentValueProvider upperValueProvider, Integer prefixLength, CharSequence zone) { return toNormalizedString(network.getPrefixConfiguration(), lowerValueProvider, upperValueProvider, prefixLength, SEGMENT_COUNT, BYTES_PER_SEGMENT, BITS_PER_SEGMENT, MAX_VALUE_PER_SEGMENT, SEGMENT_SEPARATOR, DEFAULT_TEXTUAL_RADIX, zone); } /** * The normalized string returned by this method is consistent with java.net.Inet6address. * * IPs are not compressed nor mixed in this representation. If this has a prefix length, that will be included in the string. */ @Override public String toNormalizedString() { String result; if(hasNoStringCache() || (result = stringCache.normalizedString) == null) { if(hasZone()) { stringCache.normalizedString = result = toNormalizedString(IPv6StringCache.normalizedParams); } else { result = getSection().toNormalizedString();//the cache is shared so no need to update it here } } return result; } /** * This compresses the maximum number of zeros and/or host segments with the IPv6 compression notation '::' */ @Override public String toCompressedString() { String result; if(hasNoStringCache() || (result = stringCache.compressedString) == null) { if(hasZone()) { stringCache.compressedString = result = toNormalizedString(IPv6StringCache.compressedParams); } else { result = getSection().toCompressedString();//the cache is shared so no need to update it here } } return result; } @Override public String toSubnetString() { return toPrefixLengthString(); } //note this string is used by hashCode @Override public String toNormalizedWildcardString() { String result; if(hasNoStringCache() || (result = stringCache.normalizedWildcardString) == null) { if(hasZone()) { stringCache.normalizedWildcardString = result = toNormalizedString(IPv6StringCache.wildcardNormalizedParams); } else { result = getSection().toNormalizedWildcardString();//the cache is shared so no need to update it here } } return result; } /** * The base 85 string is described by RFC 1924 * @return */ public String toBase85String() throws IncompatibleAddressException { //first we see if we obtained this address from a base 85 string //in the case of a prefix, applying the prefix changes the value IPAddressString originator = getAddressfromString(); if(originator != null && (!isPrefixed() || getNetworkPrefixLength() == IPv6Address.BIT_COUNT) && originator.isBase85IPv6()) { return originator.toString(); } String result; if(hasNoStringCache() || (result = stringCache.base85String) == null) { if(hasZone()) { stringCache.base85String = result = getSection().toBase85String(getZone()); } else { result = getSection().toBase85String();//the cache is shared so no need to update it here } } return result; } @Override public String toCanonicalWildcardString() { String result; if(hasNoStringCache() || (result = stringCache.canonicalWildcardString) == null) { if(hasZone()) { stringCache.canonicalWildcardString = result = toNormalizedString(IPv6StringCache.wildcardCanonicalParams); } else { result = getSection().toCanonicalWildcardString();//the cache is shared so no need to update it here } } return result; } @Override public String toCompressedWildcardString() { String result; if(hasNoStringCache() || (result = stringCache.compressedWildcardString) == null) { if(hasZone()) { stringCache.compressedWildcardString = result = toNormalizedString(IPv6StringCache.wildcardCompressedParams); } else { result = getSection().toCompressedWildcardString();//the cache is shared with the section, so no need to update it here } } return result; } @Override public String toSQLWildcardString() { String result; if(hasNoStringCache() || (result = stringCache.sqlWildcardString) == null) { if(hasZone()) { stringCache.sqlWildcardString = result = toNormalizedString(IPv6StringCache.sqlWildcardParams); } else { result = getSection().toSQLWildcardString();//the cache is shared so no need to update it here } } return result; } @Override public String toHexString(boolean with0xPrefix) throws IncompatibleAddressException { String result; if(hasNoStringCache() || (result = (with0xPrefix ? stringCache.hexStringPrefixed : stringCache.hexString)) == null) { if(hasZone()) { result = getSection().toHexString(with0xPrefix, zone.getName()); if(with0xPrefix) { stringCache.hexStringPrefixed = result; } else { stringCache.hexString = result; } } else { result = getSection().toHexString(with0xPrefix);//the cache is shared so no need to update it here } } return result; } private String getZoneString() { return hasZone() ? zone.getName() : null; } @Override public String toBinaryString() throws IncompatibleAddressException { String result; if(hasNoStringCache() || (result = stringCache.binaryString) == null) { if(hasZone()) { result = getSection().toBinaryString(zone.getName()); stringCache.binaryString = result; } else { result = getSection().toBinaryString();//the cache is shared so no need to update it here } } return result; } @Override public String toSegmentedBinaryString() { String result; if(hasNoStringCache() || (result = stringCache.segmentedBinaryString) == null) { if(hasZone()) { result = getSection().toSegmentedBinaryString(zone.getName()); stringCache.segmentedBinaryString = result; } else { result = getSection().toSegmentedBinaryString();//the cache is shared so no need to update it here } } return result; } @Override public String toOctalString(boolean with0Prefix) throws IncompatibleAddressException { String result; if(hasNoStringCache() || (result = (with0Prefix ? stringCache.octalStringPrefixed : stringCache.octalString)) == null) { if(hasZone()) { result = getSection().toOctalString(with0Prefix, zone.getName()); if(with0Prefix) { stringCache.octalStringPrefixed = result; } else { stringCache.octalString = result; } } else { result = getSection().toOctalString(with0Prefix);//the cache is shared so no need to update it here } } return result; } @Override public String toPrefixLengthString() { String result; if(hasNoStringCache() || (result = stringCache.networkPrefixLengthString) == null) { if(hasZone()) { stringCache.networkPrefixLengthString = result = toNormalizedString(IPv6StringCache.networkPrefixLengthParams); } else { result = getSection().toPrefixLengthString();//the cache is shared so no need to update it here } } return result; } @Override public String toConvertedString() { if(isIPv4Convertible()) { return toMixedString(); } return toNormalizedString(); } @Override public String toNormalizedString(IPStringOptions params) { return getSection().toNormalizedString(params, getZoneString()); } public String toNormalizedString(IPv6StringOptions params) { return getSection().toNormalizedString(params, getZoneString()); } /** * Constructs a string representing this address according to the given parameters * * @param keepMixed if this address was constructed from a string with mixed representation (a:b:c:d:e:f:1.2.3.4), whether to keep it that way (ignored if makeMixed is true in the params argument) * @param params the parameters for the address string */ public String toNormalizedString(boolean keepMixed, IPv6StringOptions params) { if(keepMixed && fromString != null && getAddressfromString().isMixedIPv6() && !params.makeMixed()) { params = new IPv6StringOptions( params.base, params.expandSegments, params.wildcardOption, params.wildcards, params.segmentStrPrefix, true, params.ipv4Opts, params.compressOptions, params.separator, params.zoneSeparator, params.addrLabel, params.addrSuffix, params.reverse, params.splitDigits, params.uppercase); } return toNormalizedString(params); } @Override public String toUNCHostName() { String result; if(hasNoStringCache() || (result = stringCache.uncString) == null) { //it seems for unc hosts we not only replace the zone character % with s and the segment separator : with -, //we do the same for any such characters appearing in the zone itself as well //see https://blogs.msdn.microsoft.com/oldnewthing/20100915-00/?p=12863/ String newZone; if(hasZone()) { newZone = zone.getName().replace(IPv6Address.ZONE_SEPARATOR, IPv6Address.UNC_ZONE_SEPARATOR).replace(IPv6Address.SEGMENT_SEPARATOR, IPv6Address.UNC_SEGMENT_SEPARATOR); } else { newZone = null; } stringCache.uncString = result = getSection().toNormalizedString(IPv6StringCache.uncParams, newZone); } return result; } @Override public IPAddressPartStringCollection toStandardStringCollection() { return toStringCollection(IPv6StringBuilderOptions.STANDARD_OPTS); } @Override public IPAddressPartStringCollection toAllStringCollection() { return toStringCollection(IPv6StringBuilderOptions.ALL_OPTS); } @Override public IPAddressPartStringCollection toStringCollection(IPStringBuilderOptions opts) { return toStringCollection(IPv6StringBuilderOptions.from(opts)); } private IPv4Address getConverted(IPv6StringBuilderOptions opts) { if(!hasZone() && opts.includes(IPv6StringBuilderOptions.IPV4_CONVERSIONS)) {//we cannot convert to ipv4 if there is a zone IPv4AddressConverter converter = opts.converter; return converter.toIPv4(this); } return null; } public IPAddressPartStringCollection toStringCollection(IPv6StringBuilderOptions opts) { IPv6StringCollection coll = getSection().toStringCollection(opts, getZoneString()); IPv4Address ipv4Addr = getConverted(opts); if(ipv4Addr != null) { IPAddressPartStringCollection ipv4StringCollection = ipv4Addr.toStringCollection(opts.ipv4ConverterOptions); coll.addAll(ipv4StringCollection); } return coll; } /** * @custom.core * @author sfoley * */ public interface IPv6AddressConverter { /** * If the given address is IPv6, or can be converted to IPv6, returns that {@link IPv6Address}. Otherwise, returns null. */ IPv6Address toIPv6(IPAddress address); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy