| /* | |
| * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package java.net; | |
| import java.net.spi.InetAddressResolver; | |
| import java.net.spi.InetAddressResolverProvider; | |
| import java.net.spi.InetAddressResolver.LookupPolicy; | |
| import java.util.List; | |
| import java.util.NavigableSet; | |
| import java.util.ArrayList; | |
| import java.util.Objects; | |
| import java.util.Scanner; | |
| import java.io.File; | |
| import java.io.ObjectStreamException; | |
| import java.io.ObjectStreamField; | |
| import java.io.IOException; | |
| import java.io.InvalidObjectException; | |
| import java.io.ObjectInputStream; | |
| import java.io.ObjectInputStream.GetField; | |
| import java.io.ObjectOutputStream; | |
| import java.io.ObjectOutputStream.PutField; | |
| import java.io.Serializable; | |
| import java.lang.annotation.Native; | |
| import java.util.ServiceLoader; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| import java.util.concurrent.ConcurrentMap; | |
| import java.util.concurrent.ConcurrentSkipListSet; | |
| import java.util.concurrent.atomic.AtomicLong; | |
| import java.util.Arrays; | |
| import java.util.concurrent.locks.Lock; | |
| import java.util.concurrent.locks.ReentrantLock; | |
| import java.util.stream.Stream; | |
| import jdk.internal.util.Exceptions; | |
| import jdk.internal.access.JavaNetInetAddressAccess; | |
| import jdk.internal.access.SharedSecrets; | |
| import jdk.internal.misc.Blocker; | |
| import jdk.internal.misc.VM; | |
| import jdk.internal.vm.annotation.Stable; | |
| import sun.net.ResolverProviderConfiguration; | |
| import sun.net.InetAddressCachePolicy; | |
| import sun.net.util.IPAddressUtil; | |
| import sun.nio.cs.UTF_8; | |
| import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4; | |
| import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4_FIRST; | |
| import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6; | |
| import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; | |
| import static jdk.internal.util.Exceptions.filterNonSocketInfo; | |
| import static jdk.internal.util.Exceptions.formatMsg; | |
| /** | |
| * This class represents an Internet Protocol (IP) address. | |
| * | |
| * <p> An IP address is either a 32-bit or 128-bit unsigned number | |
| * used by IP, a lower-level protocol on which protocols like UDP and | |
| * TCP are built. The IP address architecture is defined by <a | |
| * href="http://www.ietf.org/rfc/rfc790.txt"><i>RFC 790: | |
| * Assigned Numbers</i></a>, <a | |
| * href="http://www.ietf.org/rfc/rfc1918.txt"> <i>RFC 1918: | |
| * Address Allocation for Private Internets</i></a>, <a | |
| * href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC 2365: | |
| * Administratively Scoped IP Multicast</i></a>, and <a | |
| * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IP | |
| * Version 6 Addressing Architecture</i></a>. An instance of an | |
| * InetAddress consists of an IP address and possibly its | |
| * corresponding host name (depending on whether it is constructed | |
| * with a host name or whether it has already done reverse host name | |
| * resolution). | |
| * | |
| * <h2> Address types </h2> | |
| * | |
| * <table class="striped" style="margin-left:2em"> | |
| * <caption style="display:none">Description of unicast and multicast address types</caption> | |
| * <thead> | |
| * <tr><th scope="col">Address Type</th><th scope="col">Description</th></tr> | |
| * </thead> | |
| * <tbody> | |
| * <tr><th scope="row" style="vertical-align:top">unicast</th> | |
| * <td>An identifier for a single interface. A packet sent to | |
| * a unicast address is delivered to the interface identified by | |
| * that address. | |
| * | |
| * <p> The Unspecified Address -- Also called anylocal or wildcard | |
| * address. It must never be assigned to any node. It indicates the | |
| * absence of an address. One example of its use is as the target of | |
| * bind, which allows a server to accept a client connection on any | |
| * interface, in case the server host has multiple interfaces. | |
| * | |
| * <p> The <i>unspecified</i> address must not be used as | |
| * the destination address of an IP packet. | |
| * | |
| * <p> The <i>Loopback</i> Addresses -- This is the address | |
| * assigned to the loopback interface. Anything sent to this | |
| * IP address loops around and becomes IP input on the local | |
| * host. This address is often used when testing a | |
| * client.</td></tr> | |
| * <tr><th scope="row" style="vertical-align:top">multicast</th> | |
| * <td>An identifier for a set of interfaces (typically belonging | |
| * to different nodes). A packet sent to a multicast address is | |
| * delivered to all interfaces identified by that address.</td></tr> | |
| * </tbody> | |
| * </table> | |
| * | |
| * <h3> IP address scope </h3> | |
| * | |
| * <p> <i>Link-local</i> addresses are designed to be used for addressing | |
| * on a single link for purposes such as auto-address configuration, | |
| * neighbor discovery, or when no routers are present. | |
| * | |
| * <p> <i>Site-local</i> addresses are designed to be used for addressing | |
| * inside of a site without the need for a global prefix. | |
| * | |
| * <p> <i>Global</i> addresses are unique across the internet. | |
| * | |
| * <h3> <a id="format">Textual representation of IP addresses</a> </h3> | |
| * | |
| * The textual representation of an IP address is address family specific. | |
| * | |
| * <p> | |
| * | |
| * For IPv4 address format, please refer to the supported | |
| * {@linkplain Inet4Address##format IPv4 address textual representations}; | |
| * For IPv6 address format, please refer to the supported | |
| * {@linkplain Inet6Address##format IPv6 address textual representations}. | |
| * | |
| * <p> There are a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of | |
| * System Properties</a> affecting how IPv4 and IPv6 addresses are used. | |
| * | |
| * <h2 id="host-name-resolution"> Host Name Resolution </h2> | |
| * | |
| * <p> The InetAddress class provides methods to resolve host names to | |
| * their IP addresses and vice versa. The actual resolution is delegated to an | |
| * {@linkplain InetAddressResolver InetAddress resolver}. | |
| * | |
| * <p> <i>Host name-to-IP address resolution</i> maps a host name to an IP address. | |
| * For any host name, its corresponding IP address is returned. | |
| * | |
| * <p> <i>Reverse name resolution</i> means that for any IP address, | |
| * the host associated with the IP address is returned. | |
| * | |
| * <p id="built-in-resolver"> The built-in InetAddress resolver implementation does | |
| * host name-to-IP address resolution and vice versa through the use of | |
| * a combination of local machine configuration information and network | |
| * naming services such as the Domain Name System (DNS) and the Lightweight Directory | |
| * Access Protocol (LDAP). | |
| * The particular naming services that the built-in resolver uses by default | |
| * depends on the configuration of the local machine. | |
| * | |
| * <p> {@code InetAddress} has a service provider mechanism for InetAddress resolvers | |
| * that allows a custom InetAddress resolver to be used instead of the built-in implementation. | |
| * {@link InetAddressResolverProvider} is the service provider class. Its API docs provide all the | |
| * details on this mechanism. | |
| * | |
| * <h2> InetAddress Caching </h2> | |
| * | |
| * The InetAddress class has a cache to store successful as well as | |
| * unsuccessful host name resolutions. | |
| * | |
| * <p> The default behavior is to cache entries for a finite (implementation | |
| * dependent) period of time. The result of unsuccessful host | |
| * name resolution is cached for a very short period of time (10 | |
| * seconds) to improve performance. | |
| * | |
| * <p> If the default behavior is not desired, then a Java security property | |
| * can be set to a different Time-to-live (TTL) value for positive | |
| * caching. Likewise, a system admin can configure a different | |
| * negative caching TTL value when needed or extend the usage of the stale data. | |
| * | |
| * <p> Three Java {@linkplain java.security.Security security} properties control | |
| * the TTL values used for positive and negative host name resolution caching: | |
| * | |
| * <dl style="margin-left:2em"> | |
| * <dt><b>networkaddress.cache.ttl</b></dt> | |
| * <dd>Indicates the caching policy for successful name lookups from | |
| * the name service. The value is specified as an integer to indicate | |
| * the number of seconds to cache the successful lookup. The default | |
| * setting is to cache for an implementation specific period of time. | |
| * <p> | |
| * A value of -1 indicates "cache forever". | |
| * </dd> | |
| * <dt><b>networkaddress.cache.stale.ttl</b></dt> | |
| * <dd>Indicates the caching policy for stale names. The value is specified as | |
| * an integer to indicate the number of seconds that stale names will be kept in | |
| * the cache. A name is considered stale if the TTL has expired and an attempt | |
| * to lookup the host name again was not successful. This property is useful if | |
| * it is preferable to use a stale name rather than fail due to an unsuccessful | |
| * lookup. The default setting is to cache for an implementation specific period | |
| * of time. | |
| * <p> | |
| * If the value of this property is larger than "networkaddress.cache.ttl" then | |
| * "networkaddress.cache.ttl" will be used as a refresh interval of the name in | |
| * the cache. For example, if this property is set to 1 day and | |
| * "networkaddress.cache.ttl" is set to 30 seconds, then the positive response | |
| * will be cached for 1 day but an attempt to refresh it will be done every | |
| * 30 seconds. | |
| * <p> | |
| * A value of 0 (zero) or if the property is not set means do not use stale | |
| * names. Negative values are ignored. | |
| * </dd> | |
| * <dt><b>networkaddress.cache.negative.ttl</b> (default: 10)</dt> | |
| * <dd>Indicates the caching policy for un-successful name lookups | |
| * from the name service. The value is specified as an integer to | |
| * indicate the number of seconds to cache the failure for | |
| * un-successful lookups. | |
| * <p> | |
| * A value of 0 indicates "never cache". | |
| * A value of -1 indicates "cache forever". | |
| * </dd> | |
| * </dl> | |
| * | |
| * @spec https://www.rfc-editor.org/info/rfc1918 | |
| * RFC 1918: Address Allocation for Private Internets | |
| * @spec https://www.rfc-editor.org/info/rfc2365 | |
| * RFC 2365: Administratively Scoped IP Multicast | |
| * @spec https://www.rfc-editor.org/info/rfc2373 | |
| * RFC 2373: IP Version 6 Addressing Architecture | |
| * @spec https://www.rfc-editor.org/info/rfc790 | |
| * RFC 790: Assigned numbers | |
| * @author Chris Warth | |
| * @see java.net.InetAddress#getByAddress(byte[]) | |
| * @see java.net.InetAddress#getByAddress(java.lang.String, byte[]) | |
| * @see java.net.InetAddress#getAllByName(java.lang.String) | |
| * @see java.net.InetAddress#getByName(java.lang.String) | |
| * @see java.net.InetAddress#getLocalHost() | |
| * @since 1.0 | |
| * @sealedGraph | |
| */ | |
| public sealed class InetAddress implements Serializable permits Inet4Address, Inet6Address { | |
| /** | |
| * Specify the address family: Internet Protocol, Version 4 | |
| * @since 1.4 | |
| */ | |
| @Native static final int IPv4 = 1; | |
| /** | |
| * Specify the address family: Internet Protocol, Version 6 | |
| * @since 1.4 | |
| */ | |
| @Native static final int IPv6 = 2; | |
| static class InetAddressHolder { | |
| /** | |
| * Reserve the original application specified hostname. | |
| * | |
| * The original hostname is useful for domain-based endpoint | |
| * identification (see RFC 2818 and RFC 6125). If an address | |
| * was created with a raw IP address, a reverse name lookup | |
| * may introduce endpoint identification security issue via | |
| * DNS forging. | |
| * | |
| * Oracle JSSE provider is using this original hostname, via | |
| * jdk.internal.misc.JavaNetAccess, for SSL/TLS endpoint identification. | |
| * | |
| * Note: May define a new public method in the future if necessary. | |
| */ | |
| String originalHostName; | |
| InetAddressHolder() {} | |
| InetAddressHolder(String hostName, int address, int family) { | |
| this.originalHostName = hostName; | |
| this.hostName = hostName; | |
| this.address = address; | |
| this.family = family; | |
| } | |
| void init(String hostName, int family) { | |
| this.originalHostName = hostName; | |
| this.hostName = hostName; | |
| if (family != -1) { | |
| this.family = family; | |
| } | |
| } | |
| String hostName; | |
| String getHostName() { | |
| return hostName; | |
| } | |
| String getOriginalHostName() { | |
| return originalHostName; | |
| } | |
| /** | |
| * Holds a 32-bit IPv4 address. | |
| */ | |
| int address; | |
| int getAddress() { | |
| return address; | |
| } | |
| /** | |
| * Specifies the address family type, for instance, '1' for IPv4 | |
| * addresses, and '2' for IPv6 addresses. | |
| */ | |
| int family; | |
| int getFamily() { | |
| return family; | |
| } | |
| } | |
| /* Used to store the serializable fields of InetAddress */ | |
| final transient InetAddressHolder holder; | |
| InetAddressHolder holder() { | |
| return holder; | |
| } | |
| /* Used to store the system-wide resolver */ | |
| @Stable | |
| private static volatile InetAddressResolver resolver; | |
| private static final InetAddressResolver BUILTIN_RESOLVER; | |
| /** | |
| * Used to store the best available hostname. | |
| * Lazily initialized via a data race; safe because Strings are immutable. | |
| */ | |
| private transient String canonicalHostName = null; | |
| /** use serialVersionUID from JDK 1.0.2 for interoperability */ | |
| @java.io.Serial | |
| private static final long serialVersionUID = 3286316764910316507L; | |
| // "java.net.preferIPv4Stack" system property value | |
| private static final String PREFER_IPV4_STACK_VALUE; | |
| // "java.net.preferIPv6Addresses" system property value | |
| private static final String PREFER_IPV6_ADDRESSES_VALUE; | |
| // "jdk.net.hosts.file" system property value | |
| private static final String HOSTS_FILE_NAME; | |
| /* | |
| * Load net library into runtime, and perform initializations. | |
| */ | |
| static { | |
| PREFER_IPV4_STACK_VALUE = | |
| System.getProperty("java.net.preferIPv4Stack"); | |
| PREFER_IPV6_ADDRESSES_VALUE = | |
| System.getProperty("java.net.preferIPv6Addresses"); | |
| HOSTS_FILE_NAME = | |
| System.getProperty("jdk.net.hosts.file"); | |
| jdk.internal.loader.BootLoader.loadLibrary("net"); | |
| SharedSecrets.setJavaNetInetAddressAccess( | |
| new JavaNetInetAddressAccess() { | |
| public String getOriginalHostName(InetAddress ia) { | |
| return ia.holder.getOriginalHostName(); | |
| } | |
| public int addressValue(Inet4Address inet4Address) { | |
| return inet4Address.addressValue(); | |
| } | |
| public byte[] addressBytes(Inet6Address inet6Address) { | |
| return inet6Address.addressBytes(); | |
| } | |
| } | |
| ); | |
| Exceptions.setup(); // needed for native exceptions | |
| init(); | |
| } | |
| /** | |
| * Creates an address lookup policy from {@code "java.net.preferIPv4Stack"}, | |
| * {@code "java.net.preferIPv6Addresses"} system property values, and O/S configuration. | |
| */ | |
| private static final LookupPolicy initializePlatformLookupPolicy() { | |
| // Calculate AddressFamily value first | |
| boolean ipv4Available = isIPv4Available(); | |
| if ("true".equals(PREFER_IPV4_STACK_VALUE) && ipv4Available) { | |
| return LookupPolicy.of(IPV4); | |
| } | |
| // Check if IPv6 is not supported | |
| if (InetAddress.impl instanceof Inet4AddressImpl) { | |
| return LookupPolicy.of(IPV4); | |
| } | |
| // Check if system supports IPv4, if not use IPv6 | |
| if (!ipv4Available) { | |
| return LookupPolicy.of(IPV6); | |
| } | |
| // If both address families are needed - check preferIPv6Addresses value | |
| if (PREFER_IPV6_ADDRESSES_VALUE != null) { | |
| if (PREFER_IPV6_ADDRESSES_VALUE.equalsIgnoreCase("true")) { | |
| return LookupPolicy.of(IPV4 | IPV6 | IPV6_FIRST); | |
| } | |
| if (PREFER_IPV6_ADDRESSES_VALUE.equalsIgnoreCase("false")) { | |
| return LookupPolicy.of(IPV4 | IPV6 | IPV4_FIRST); | |
| } | |
| if (PREFER_IPV6_ADDRESSES_VALUE.equalsIgnoreCase("system")) { | |
| return LookupPolicy.of(IPV4 | IPV6); | |
| } | |
| } | |
| // Default value with both address families needed - IPv4 addresses come first | |
| return LookupPolicy.of(IPV4 | IPV6 | IPV4_FIRST); | |
| } | |
| static boolean systemAddressesOrder(int lookupCharacteristics) { | |
| return (lookupCharacteristics & (IPV4_FIRST | IPV6_FIRST)) == 0; | |
| } | |
| static boolean ipv4AddressesFirst(int lookupCharacteristics) { | |
| return (lookupCharacteristics & IPV4_FIRST) != 0; | |
| } | |
| static boolean ipv6AddressesFirst(int lookupCharacteristics) { | |
| return (lookupCharacteristics & IPV6_FIRST) != 0; | |
| } | |
| // Native method to check if IPv4 is available | |
| private static native boolean isIPv4Available(); | |
| // Native method to check if IPv6 is available | |
| private static native boolean isIPv6Supported(); | |
| private static final ReentrantLock RESOLVER_LOCK = new ReentrantLock(); | |
| private static volatile InetAddressResolver bootstrapResolver; | |
| private static InetAddressResolver resolver() { | |
| InetAddressResolver cns = resolver; | |
| if (cns != null) { | |
| return cns; | |
| } | |
| if (VM.isBooted()) { | |
| RESOLVER_LOCK.lock(); | |
| boolean bootstrapSet = false; | |
| try { | |
| cns = resolver; | |
| if (cns != null) { | |
| return cns; | |
| } | |
| // Protection against provider calling InetAddress APIs during initialization | |
| if (bootstrapResolver != null) { | |
| return bootstrapResolver; | |
| } | |
| bootstrapResolver = BUILTIN_RESOLVER; | |
| bootstrapSet = true; | |
| if (HOSTS_FILE_NAME != null) { | |
| // The default resolver service is already host file resolver | |
| cns = BUILTIN_RESOLVER; | |
| } else { | |
| cns = loadResolver(); | |
| } | |
| InetAddress.resolver = cns; | |
| return cns; | |
| } finally { | |
| // We want to clear bootstrap resolver reference only after an attempt to | |
| // instantiate a resolver has been completed. | |
| if (bootstrapSet) { | |
| bootstrapResolver = null; | |
| } | |
| RESOLVER_LOCK.unlock(); | |
| } | |
| } else { | |
| return BUILTIN_RESOLVER; | |
| } | |
| } | |
| private static InetAddressResolver loadResolver() { | |
| return ServiceLoader.load(InetAddressResolverProvider.class) | |
| .findFirst() | |
| .map(nsp -> nsp.get(builtinConfiguration())) | |
| .orElse(BUILTIN_RESOLVER); | |
| } | |
| private static InetAddressResolverProvider.Configuration builtinConfiguration() { | |
| return new ResolverProviderConfiguration(BUILTIN_RESOLVER, () -> { | |
| try { | |
| return impl.getLocalHostName(); | |
| } catch (UnknownHostException unknownHostException) { | |
| return "localhost"; | |
| } | |
| }); | |
| } | |
| /** | |
| * Constructor for the Socket.accept() method. | |
| * This creates an empty InetAddress, which is filled in by | |
| * the accept() method. This InetAddress, however, is not | |
| * put in the address cache, since it is not created by name. | |
| */ | |
| InetAddress() { | |
| holder = new InetAddressHolder(); | |
| } | |
| /** | |
| * Replaces the de-serialized object with an Inet4Address object. | |
| * | |
| * @return the alternate object to the de-serialized object. | |
| * | |
| * @throws ObjectStreamException if a new object replacing this | |
| * object could not be created | |
| */ | |
| @java.io.Serial | |
| private Object readResolve() throws ObjectStreamException { | |
| // will replace the deserialized 'this' object | |
| return new Inet4Address(holder().getHostName(), holder().getAddress()); | |
| } | |
| /** | |
| * Utility routine to check if the InetAddress is an | |
| * IP multicast address. | |
| * @return a {@code boolean} indicating if the InetAddress is | |
| * an IP multicast address | |
| * @since 1.1 | |
| */ | |
| public boolean isMulticastAddress() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the InetAddress is a wildcard address. | |
| * @return a {@code boolean} indicating if the InetAddress is | |
| * a wildcard address. | |
| * @since 1.4 | |
| */ | |
| public boolean isAnyLocalAddress() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the InetAddress is a loopback address. | |
| * | |
| * @return a {@code boolean} indicating if the InetAddress is | |
| * a loopback address; or false otherwise. | |
| * @since 1.4 | |
| */ | |
| public boolean isLoopbackAddress() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the InetAddress is a link local address. | |
| * | |
| * @return a {@code boolean} indicating if the InetAddress is | |
| * a link local address; or false if address is not a link local unicast address. | |
| * @since 1.4 | |
| */ | |
| public boolean isLinkLocalAddress() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the InetAddress is a site local address. | |
| * | |
| * @return a {@code boolean} indicating if the InetAddress is | |
| * a site local address; or false if address is not a site local unicast address. | |
| * @since 1.4 | |
| */ | |
| public boolean isSiteLocalAddress() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the multicast address has global scope. | |
| * | |
| * @return a {@code boolean} indicating if the address has | |
| * is a multicast address of global scope, false if it is not | |
| * of global scope or it is not a multicast address | |
| * @since 1.4 | |
| */ | |
| public boolean isMCGlobal() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the multicast address has node scope. | |
| * | |
| * @return a {@code boolean} indicating if the address has | |
| * is a multicast address of node-local scope, false if it is not | |
| * of node-local scope or it is not a multicast address | |
| * @since 1.4 | |
| */ | |
| public boolean isMCNodeLocal() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the multicast address has link scope. | |
| * | |
| * @return a {@code boolean} indicating if the address has | |
| * is a multicast address of link-local scope, false if it is not | |
| * of link-local scope or it is not a multicast address | |
| * @since 1.4 | |
| */ | |
| public boolean isMCLinkLocal() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the multicast address has site scope. | |
| * | |
| * @return a {@code boolean} indicating if the address has | |
| * is a multicast address of site-local scope, false if it is not | |
| * of site-local scope or it is not a multicast address | |
| * @since 1.4 | |
| */ | |
| public boolean isMCSiteLocal() { | |
| return false; | |
| } | |
| /** | |
| * Utility routine to check if the multicast address has organization scope. | |
| * | |
| * @return a {@code boolean} indicating if the address has | |
| * is a multicast address of organization-local scope, | |
| * false if it is not of organization-local scope | |
| * or it is not a multicast address | |
| * @since 1.4 | |
| */ | |
| public boolean isMCOrgLocal() { | |
| return false; | |
| } | |
| /** | |
| * Test whether that address is reachable. Best effort is made by the | |
| * implementation to try to reach the host, but firewalls and server | |
| * configuration may block requests resulting in an unreachable status | |
| * while some specific ports may be accessible. | |
| * A typical implementation will use ICMP ECHO REQUESTs if the | |
| * privilege can be obtained, otherwise it will try to establish | |
| * a TCP connection on port 7 (Echo) of the destination host. | |
| * <p> | |
| * The timeout value, in milliseconds, indicates the maximum amount of time | |
| * the try should take. If the operation times out before getting an | |
| * answer, the host is deemed unreachable. A negative value will result | |
| * in an IllegalArgumentException being thrown. | |
| * | |
| * @param timeout the time, in milliseconds, before the call aborts | |
| * @return a {@code boolean} indicating if the address is reachable. | |
| * @throws IOException if a network error occurs | |
| * @throws IllegalArgumentException if {@code timeout} is negative. | |
| * @since 1.5 | |
| */ | |
| public boolean isReachable(int timeout) throws IOException { | |
| return isReachable(null, 0 , timeout); | |
| } | |
| /** | |
| * Test whether that address is reachable. Best effort is made by the | |
| * implementation to try to reach the host, but firewalls and server | |
| * configuration may block requests resulting in a unreachable status | |
| * while some specific ports may be accessible. | |
| * A typical implementation will use ICMP ECHO REQUESTs if the | |
| * privilege can be obtained, otherwise it will try to establish | |
| * a TCP connection on port 7 (Echo) of the destination host. | |
| * <p> | |
| * The {@code network interface} and {@code ttl} parameters | |
| * let the caller specify which network interface the test will go through | |
| * and the maximum number of hops the packets should go through. | |
| * A negative value for the {@code ttl} will result in an | |
| * IllegalArgumentException being thrown. | |
| * <p> | |
| * The timeout value, in milliseconds, indicates the maximum amount of time | |
| * the try should take. If the operation times out before getting an | |
| * answer, the host is deemed unreachable. A negative value will result | |
| * in an IllegalArgumentException being thrown. | |
| * | |
| * @param netif the NetworkInterface through which the | |
| * test will be done, or null for any interface | |
| * @param ttl the maximum numbers of hops to try or 0 for the | |
| * default | |
| * @param timeout the time, in milliseconds, before the call aborts | |
| * @throws IllegalArgumentException if either {@code timeout} | |
| * or {@code ttl} are negative. | |
| * @return a {@code boolean} indicating if the address is reachable. | |
| * @throws IOException if a network error occurs | |
| * @since 1.5 | |
| */ | |
| public boolean isReachable(NetworkInterface netif, int ttl, | |
| int timeout) throws IOException { | |
| if (ttl < 0) | |
| throw new IllegalArgumentException("ttl can't be negative"); | |
| if (timeout < 0) | |
| throw new IllegalArgumentException("timeout can't be negative"); | |
| return impl.isReachable(this, timeout, netif, ttl); | |
| } | |
| /** | |
| * Gets the host name for this IP address. | |
| * | |
| * <p>If this InetAddress was created with a host name, | |
| * this host name will be remembered and returned; | |
| * otherwise, a reverse name lookup will be performed | |
| * and the result will be returned based on the system-wide | |
| * resolver. If a lookup of the name service | |
| * is required, call | |
| * {@link #getCanonicalHostName() getCanonicalHostName}. | |
| * | |
| * @return the host name for this IP address | |
| * | |
| * @see InetAddress#getCanonicalHostName | |
| */ | |
| public String getHostName() { | |
| if (holder().getHostName() == null) { | |
| holder().hostName = InetAddress.getHostFromNameService(this); | |
| } | |
| return holder().getHostName(); | |
| } | |
| /** | |
| * Gets the fully qualified domain name for this | |
| * {@linkplain InetAddress#getAddress() IP address} using the system-wide | |
| * {@linkplain InetAddressResolver resolver}. | |
| * | |
| * <p>The system-wide resolver will be used to do a reverse name lookup of the IP address. | |
| * The lookup can fail for many reasons that include the host not being registered with the name | |
| * service. If the resolver is unable to determine the fully qualified | |
| * domain name, this method returns the {@linkplain #getHostAddress() textual representation} | |
| * of the IP address. | |
| * | |
| * @return the fully qualified domain name for this IP address. | |
| * If the system-wide resolver wasn't able to determine the | |
| * fully qualified domain name for the IP address, the textual | |
| * representation of the IP address is returned instead. | |
| * | |
| * @since 1.4 | |
| */ | |
| public String getCanonicalHostName() { | |
| String value = canonicalHostName; | |
| if (value == null) | |
| canonicalHostName = value = | |
| InetAddress.getHostFromNameService(this); | |
| return value; | |
| } | |
| /** | |
| * Returns the fully qualified domain name for the given address. | |
| * | |
| * @return the fully qualified domain name for the given IP address. | |
| * If the system-wide resolver wasn't able to determine the | |
| * fully qualified domain name for the IP address, the textual | |
| * representation of the IP address is returned instead. | |
| */ | |
| private static String getHostFromNameService(InetAddress addr) { | |
| String host; | |
| var resolver = resolver(); | |
| try { | |
| // first lookup the hostname | |
| host = resolver.lookupByAddress(addr.getAddress()); | |
| /* now get all the IP addresses for this hostname, | |
| * and make sure one of them matches the original IP | |
| * address. We do this to try and prevent spoofing. | |
| */ | |
| InetAddress[] arr = InetAddress.getAllByName0(host); | |
| boolean ok = false; | |
| if (arr != null) { | |
| for (int i = 0; !ok && i < arr.length; i++) { | |
| ok = addr.equals(arr[i]); | |
| } | |
| } | |
| //XXX: if it looks like a spoof just return the address? | |
| if (!ok) { | |
| host = addr.getHostAddress(); | |
| return host; | |
| } | |
| } catch (RuntimeException | UnknownHostException e) { | |
| // 'resolver.lookupByAddress' and 'InetAddress.getAllByName0' delegate to | |
| // the system-wide resolver, which could be a custom one. At that point we | |
| // treat any unexpected RuntimeException thrown by the resolver as we would | |
| // treat an UnknownHostException or an unmatched host name. | |
| host = addr.getHostAddress(); | |
| } | |
| return host; | |
| } | |
| /** | |
| * Returns the raw IP address of this {@code InetAddress} | |
| * object. The result is in network byte order: the highest order | |
| * byte of the address is in {@code getAddress()[0]}. | |
| * | |
| * @return the raw IP address of this object. | |
| */ | |
| public byte[] getAddress() { | |
| return null; | |
| } | |
| /** | |
| * Returns the IP address string in textual presentation. | |
| * | |
| * @return the raw IP address in a string format. | |
| * @since 1.0.2 | |
| */ | |
| public String getHostAddress() { | |
| return null; | |
| } | |
| /** | |
| * Returns a hashcode for this IP address. | |
| * | |
| * @return a hash code value for this IP address. | |
| */ | |
| public int hashCode() { | |
| return -1; | |
| } | |
| /** | |
| * Compares this object against the specified object. | |
| * The result is {@code true} if and only if the argument is | |
| * not {@code null} and it represents the same IP address as | |
| * this object. | |
| * <p> | |
| * Two instances of {@code InetAddress} represent the same IP | |
| * address if the length of the byte arrays returned by | |
| * {@code getAddress} is the same for both, and each of the | |
| * array components is the same for the byte arrays. | |
| * | |
| * @param obj the object to compare against. | |
| * @return {@code true} if the objects are the same; | |
| * {@code false} otherwise. | |
| * @see java.net.InetAddress#getAddress() | |
| */ | |
| public boolean equals(Object obj) { | |
| return false; | |
| } | |
| /** | |
| * Converts this IP address to a {@code String}. The | |
| * string returned is of the form: hostname / literal IP | |
| * address. | |
| * | |
| * If the host name is unresolved, no reverse lookup | |
| * is performed. The hostname part will be represented | |
| * by an empty string. | |
| * | |
| * @return a string representation of this IP address. | |
| */ | |
| public String toString() { | |
| String hostName = holder().getHostName(); | |
| return Objects.toString(hostName, "") | |
| + "/" + getHostAddress(); | |
| } | |
| // mapping from host name to Addresses - either NameServiceAddresses (while | |
| // still being looked-up by NameService(s)) or CachedAddresses when cached | |
| private static final ConcurrentMap<String, Addresses> cache = | |
| new ConcurrentHashMap<>(); | |
| // CachedAddresses that have to expire are kept ordered in this NavigableSet | |
| // which is scanned on each access | |
| private static final NavigableSet<CachedLookup> expirySet = | |
| new ConcurrentSkipListSet<>(); | |
| // common interface | |
| private interface Addresses { | |
| InetAddress[] get() throws UnknownHostException; | |
| } | |
| /** | |
| * A cached result of a name service lookup. The result can be either valid | |
| * addresses or invalid (ie a failed lookup) containing no addresses. | |
| */ | |
| private static class CachedLookup implements Addresses, Comparable<CachedLookup> { | |
| private static final AtomicLong seq = new AtomicLong(); | |
| final String host; | |
| volatile InetAddress[] inetAddresses; | |
| /** | |
| * Time of expiry (in terms of System.nanoTime()). Can be modified only | |
| * when the record is not added to the "expirySet". | |
| */ | |
| volatile long expiryTime; | |
| final long id = seq.incrementAndGet(); // each instance is unique | |
| CachedLookup(String host, InetAddress[] inetAddresses, long expiryTime) { | |
| this.host = host; | |
| this.inetAddresses = inetAddresses; | |
| this.expiryTime = expiryTime; | |
| } | |
| @Override | |
| public InetAddress[] get() throws UnknownHostException { | |
| if (inetAddresses == null) { | |
| throw new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))); | |
| } | |
| return inetAddresses; | |
| } | |
| @Override | |
| public int compareTo(CachedLookup other) { | |
| // natural order is expiry time - | |
| // compare difference of expiry times rather than | |
| // expiry times directly, to avoid possible overflow. | |
| // (see System.nanoTime() recommendations...) | |
| long diff = this.expiryTime - other.expiryTime; | |
| if (diff < 0L) return -1; | |
| if (diff > 0L) return 1; | |
| // ties are broken using unique id | |
| return Long.compare(this.id, other.id); | |
| } | |
| /** | |
| * Checks if the current cache record is expired or not. Expired records | |
| * are removed from the expirySet and cache. | |
| * | |
| * @return {@code true} if the record was removed | |
| */ | |
| public boolean tryRemoveExpiredAddress(long now) { | |
| // compare difference of time instants rather than | |
| // time instants directly, to avoid possible overflow. | |
| // (see System.nanoTime() recommendations...) | |
| if ((expiryTime - now) < 0L) { | |
| // ConcurrentSkipListSet uses weakly consistent iterator, | |
| // so removing while iterating is OK... | |
| if (expirySet.remove(this)) { | |
| // ... remove from cache | |
| cache.remove(host, this); | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| /** | |
| * A cached valid lookup containing addresses whose validity may be | |
| * temporarily extended by an additional stale period pending the mapping | |
| * being refreshed or updated. | |
| */ | |
| private static final class ValidCachedLookup extends CachedLookup { | |
| /** | |
| * Time to refresh (in terms of System.nanoTime()). | |
| */ | |
| private volatile long refreshTime; | |
| /** | |
| * For how long the stale data should be used after TTL expiration. | |
| * Initially equal to the expiryTime, but increased over time after each | |
| * successful lookup. | |
| */ | |
| private volatile long staleTime; | |
| /** | |
| * only one thread is doing lookup to name service | |
| * for particular host at any time. | |
| */ | |
| private final Lock lookupLock = new ReentrantLock(); | |
| ValidCachedLookup(String host, InetAddress[] inetAddresses, | |
| long staleTime, long refreshTime) | |
| { | |
| super(host, inetAddresses, staleTime); | |
| this.refreshTime = refreshTime; | |
| this.staleTime = staleTime; | |
| } | |
| @Override | |
| public InetAddress[] get() { | |
| long now = System.nanoTime(); | |
| if ((refreshTime - now) < 0L && lookupLock.tryLock()) { | |
| try { | |
| // cachePolicy is in [s] - we need [ns] | |
| refreshTime = now + InetAddressCachePolicy.get() * 1000_000_000L; | |
| // getAddressesFromNameService returns non-empty/non-null value | |
| inetAddresses = getAddressesFromNameService(host); | |
| // don't update the "expirySet", will do that later | |
| staleTime = refreshTime + InetAddressCachePolicy.getStale() * 1000_000_000L; | |
| } catch (UnknownHostException ignore) { | |
| } finally { | |
| lookupLock.unlock(); | |
| } | |
| } | |
| return inetAddresses; | |
| } | |
| /** | |
| * Overrides the parent method to skip deleting the record from the | |
| * cache if the stale data can still be used. Note to update the | |
| * "expiryTime" field we have to remove the record from the expirySet | |
| * and add it back. It is not necessary to remove/add it here, we can do | |
| * that in the "get()" method above, but extracting it minimizes | |
| * contention on "expirySet". | |
| */ | |
| @Override | |
| public boolean tryRemoveExpiredAddress(long now) { | |
| // compare difference of time instants rather than | |
| // time instants directly, to avoid possible overflow. | |
| // (see System.nanoTime() recommendations...) | |
| if ((expiryTime - now) < 0L) { | |
| if ((staleTime - now) < 0L) { | |
| return super.tryRemoveExpiredAddress(now); | |
| } | |
| // ConcurrentSkipListSet uses weakly consistent iterator, | |
| // so removing while iterating is OK... | |
| if (expirySet.remove(this)) { | |
| expiryTime = staleTime; | |
| expirySet.add(this); | |
| } | |
| } | |
| return false; | |
| } | |
| } | |
| // a name service lookup based Addresses implementation which replaces itself | |
| // in cache when the result is obtained | |
| private static final class NameServiceAddresses implements Addresses { | |
| private final String host; | |
| private final ReentrantLock lookupLock = new ReentrantLock(); | |
| NameServiceAddresses(String host) { | |
| this.host = host; | |
| } | |
| @Override | |
| public InetAddress[] get() throws UnknownHostException { | |
| Addresses addresses; | |
| // only one thread is doing lookup to name service | |
| // for particular host at any time. | |
| lookupLock.lock(); | |
| try { | |
| // re-check that we are still us + re-install us if slot empty | |
| addresses = cache.putIfAbsent(host, this); | |
| if (addresses == null) { | |
| // this can happen when we were replaced by CachedAddresses in | |
| // some other thread, then CachedAddresses expired and were | |
| // removed from cache while we were waiting for lock... | |
| addresses = this; | |
| } | |
| // still us ? | |
| if (addresses == this) { | |
| // lookup name services | |
| InetAddress[] inetAddresses; | |
| UnknownHostException ex; | |
| int cachePolicy; | |
| try { | |
| inetAddresses = getAddressesFromNameService(host); | |
| ex = null; | |
| cachePolicy = InetAddressCachePolicy.get(); | |
| } catch (UnknownHostException uhe) { | |
| inetAddresses = null; | |
| ex = uhe; | |
| cachePolicy = InetAddressCachePolicy.getNegative(); | |
| } | |
| // remove or replace us with cached addresses according to cachePolicy | |
| if (cachePolicy == InetAddressCachePolicy.NEVER) { | |
| cache.remove(host, this); | |
| } else { | |
| long now = System.nanoTime(); | |
| long expiryTime = | |
| cachePolicy == InetAddressCachePolicy.FOREVER ? | |
| 0L | |
| // cachePolicy is in [s] - we need [ns] | |
| : now + 1000_000_000L * cachePolicy; | |
| CachedLookup cachedLookup; | |
| if (InetAddressCachePolicy.getStale() > 0 && | |
| ex == null && expiryTime > 0) | |
| { | |
| long refreshTime = expiryTime; | |
| // staleCachePolicy is in [s] - we need [ns] | |
| expiryTime = refreshTime + 1000_000_000L * | |
| InetAddressCachePolicy.getStale(); | |
| cachedLookup = new ValidCachedLookup(host, | |
| inetAddresses, | |
| expiryTime, | |
| refreshTime); | |
| } else { | |
| cachedLookup = new CachedLookup(host, | |
| inetAddresses, | |
| expiryTime); | |
| } | |
| if (cache.replace(host, this, cachedLookup) && | |
| cachePolicy != InetAddressCachePolicy.FOREVER) { | |
| // schedule expiry | |
| expirySet.add(cachedLookup); | |
| } | |
| } | |
| if (inetAddresses == null || inetAddresses.length == 0) { | |
| throw ex == null | |
| ? new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))) | |
| : ex; | |
| } | |
| return inetAddresses; | |
| } | |
| // else addresses != this | |
| } finally { | |
| lookupLock.unlock(); | |
| } | |
| // delegate to different addresses when we are already replaced | |
| // but outside of synchronized block to avoid any chance of dead-locking | |
| return addresses.get(); | |
| } | |
| } | |
| /** | |
| * The default InetAddressResolver implementation, which delegates to the underlying | |
| * OS network libraries to resolve host address mappings. | |
| * | |
| * @since 9 | |
| */ | |
| private static final class PlatformResolver implements InetAddressResolver { | |
| public Stream<InetAddress> lookupByName(String host, LookupPolicy policy) | |
| throws UnknownHostException { | |
| Objects.requireNonNull(host); | |
| Objects.requireNonNull(policy); | |
| validate(host); | |
| InetAddress[] addrs; | |
| boolean attempted = Blocker.begin(); | |
| try { | |
| addrs = impl.lookupAllHostAddr(host, policy); | |
| } finally { | |
| Blocker.end(attempted); | |
| } | |
| return Arrays.stream(addrs); | |
| } | |
| public String lookupByAddress(byte[] addr) throws UnknownHostException { | |
| Objects.requireNonNull(addr); | |
| if (addr.length != Inet4Address.INADDRSZ && addr.length != Inet6Address.INADDRSZ) { | |
| throw new IllegalArgumentException("Invalid address length"); | |
| } | |
| boolean attempted = Blocker.begin(); | |
| try { | |
| return impl.getHostByAddr(addr); | |
| } finally { | |
| Blocker.end(attempted); | |
| } | |
| } | |
| } | |
| /** | |
| * The HostsFileResolver provides host address mapping | |
| * by reading the entries in a hosts file, which is specified by | |
| * {@code jdk.net.hosts.file} system property | |
| * | |
| * <p>The file format is that which corresponds with the /etc/hosts file | |
| * IP Address host alias list. | |
| * | |
| * <p>When the file lookup is enabled it replaces the default InetAddressResolver | |
| * implementation | |
| * | |
| * @since 9 | |
| */ | |
| private static final class HostsFileResolver implements InetAddressResolver { | |
| private final String hostsFile; | |
| public HostsFileResolver(String hostsFileName) { | |
| this.hostsFile = hostsFileName; | |
| } | |
| /** | |
| * Lookup the host name corresponding to the IP address provided. | |
| * Search the configured host file a host name corresponding to | |
| * the specified IP address. | |
| * | |
| * @param addr byte array representing an IP address | |
| * @return {@code String} representing the host name mapping | |
| * @throws UnknownHostException if no host found for the specified IP address | |
| * @throws IllegalArgumentException if IP address is of illegal length | |
| * @throws NullPointerException if addr is {@code null} | |
| */ | |
| @Override | |
| public String lookupByAddress(byte[] addr) throws UnknownHostException { | |
| String hostEntry; | |
| String host = null; | |
| Objects.requireNonNull(addr); | |
| // Check the length of the address array | |
| if (addr.length != Inet4Address.INADDRSZ && addr.length != Inet6Address.INADDRSZ) { | |
| throw new IllegalArgumentException("Invalid address length"); | |
| } | |
| try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), | |
| UTF_8.INSTANCE)) { | |
| while (hostsFileScanner.hasNextLine()) { | |
| hostEntry = hostsFileScanner.nextLine(); | |
| if (!hostEntry.startsWith("#")) { | |
| hostEntry = removeComments(hostEntry); | |
| String[] mapping = hostEntry.split("\\s+"); | |
| if (mapping.length >= 2 && | |
| Arrays.equals(addr, createAddressByteArray(mapping[0]))) { | |
| host = mapping[1]; | |
| break; | |
| } | |
| } | |
| } | |
| } catch (IOException e) { | |
| throw new UnknownHostException( | |
| formatMsg("Unable to resolve address %s as hosts file %s not found", | |
| filterNonSocketInfo(Arrays.toString(addr)), | |
| filterNonSocketInfo(hostsFile) | |
| .replaceWith("from ${jdk.net.hosts.file} system property"))); | |
| } | |
| if ((host == null) || (host.isEmpty()) || (host.equals(" "))) { | |
| throw new UnknownHostException( | |
| formatMsg("Requested address %s resolves to an invalid entry in hosts file %s", | |
| filterNonSocketInfo(Arrays.toString(addr)), | |
| filterNonSocketInfo(hostsFile) | |
| .replaceWith("from ${jdk.net.hosts.file} system property"))); | |
| } | |
| return host; | |
| } | |
| /** | |
| * <p>Lookup a host mapping by name. Retrieve the IP addresses | |
| * associated with a host. | |
| * | |
| * <p>Search the configured hosts file for the addresses associated | |
| * with the specified host name. | |
| * | |
| * @param host the specified hostname | |
| * @param lookupPolicy IP addresses lookup policy which specifies addresses | |
| * family and their order | |
| * @return stream of IP addresses for the requested host | |
| * @throws NullPointerException if either parameter is {@code null} | |
| * @throws UnknownHostException | |
| * if no IP address for the {@code host} could be found | |
| */ | |
| public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) | |
| throws UnknownHostException { | |
| String hostEntry; | |
| String addrStr; | |
| byte addr[]; | |
| Objects.requireNonNull(host); | |
| Objects.requireNonNull(lookupPolicy); | |
| List<InetAddress> inetAddresses = new ArrayList<>(); | |
| List<InetAddress> inet4Addresses = new ArrayList<>(); | |
| List<InetAddress> inet6Addresses = new ArrayList<>(); | |
| int flags = lookupPolicy.characteristics(); | |
| boolean needIPv4 = (flags & IPv4) != 0; | |
| boolean needIPv6 = (flags & IPv6) != 0; | |
| // lookup the file and create a list InetAddress for the specified host | |
| try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), | |
| UTF_8.INSTANCE)) { | |
| while (hostsFileScanner.hasNextLine()) { | |
| hostEntry = hostsFileScanner.nextLine(); | |
| if (!hostEntry.startsWith("#")) { | |
| hostEntry = removeComments(hostEntry); | |
| if (hostEntry.contains(host)) { | |
| addrStr = extractHostAddr(hostEntry, host); | |
| if ((addrStr != null) && (!addrStr.isEmpty())) { | |
| addr = createAddressByteArray(addrStr); | |
| if (addr != null) { | |
| InetAddress address = InetAddress.getByAddress(host, addr); | |
| inetAddresses.add(address); | |
| if (address instanceof Inet4Address && needIPv4) { | |
| inet4Addresses.add(address); | |
| } | |
| if (address instanceof Inet6Address && needIPv6) { | |
| inet6Addresses.add(address); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } catch (IOException e) { | |
| throw new UnknownHostException( | |
| formatMsg("Unable to resolve host %s as hosts file %s not found", | |
| filterNonSocketInfo(host), filterNonSocketInfo(hostsFile) | |
| .replaceWith("from ${jdk.net.hosts.file} system property"))); | |
| } | |
| // Check if only IPv4 addresses are requested | |
| if (needIPv4 && !needIPv6) { | |
| checkResultsList(inet4Addresses, host); | |
| return inet4Addresses.stream(); | |
| } | |
| // Check if only IPv6 addresses are requested | |
| if (!needIPv4 && needIPv6) { | |
| checkResultsList(inet6Addresses, host); | |
| return inet6Addresses.stream(); | |
| } | |
| // If both type of addresses are requested: | |
| // First, check if there is any results. Then arrange | |
| // addresses according to LookupPolicy value. | |
| checkResultsList(inetAddresses, host); | |
| if (ipv6AddressesFirst(flags)) { | |
| return Stream.concat(inet6Addresses.stream(), inet4Addresses.stream()); | |
| } else if (ipv4AddressesFirst(flags)) { | |
| return Stream.concat(inet4Addresses.stream(), inet6Addresses.stream()); | |
| } | |
| // Only "system" addresses order is possible at this stage | |
| assert systemAddressesOrder(flags); | |
| return inetAddresses.stream(); | |
| } | |
| // Checks if result list with addresses is not empty. | |
| // If it is empty throw an UnknownHostException. | |
| private void checkResultsList(List<InetAddress> addressesList, String hostName) | |
| throws UnknownHostException { | |
| if (addressesList.isEmpty()) { | |
| throw new UnknownHostException( | |
| formatMsg("Unable to resolve host %s in hosts file %s", | |
| filterNonSocketInfo(hostName), filterNonSocketInfo(hostsFile) | |
| .replaceWith("from ${jdk.net.hosts.file} system property"))); | |
| } | |
| } | |
| private String removeComments(String hostsEntry) { | |
| String filteredEntry = hostsEntry; | |
| int hashIndex; | |
| if ((hashIndex = hostsEntry.indexOf("#")) != -1) { | |
| filteredEntry = hostsEntry.substring(0, hashIndex); | |
| } | |
| return filteredEntry; | |
| } | |
| private byte [] createAddressByteArray(String addrStr) { | |
| byte[] addrArray; | |
| // check if IPV4 address - most likely | |
| try { | |
| addrArray = IPAddressUtil.validateNumericFormatV4(addrStr, false); | |
| } catch (IllegalArgumentException iae) { | |
| return null; | |
| } | |
| if (addrArray == null) { | |
| addrArray = IPAddressUtil.textToNumericFormatV6(addrStr); | |
| } | |
| return addrArray; | |
| } | |
| /** host to ip address mapping */ | |
| private String extractHostAddr(String hostEntry, String host) { | |
| String[] mapping = hostEntry.split("\\s+"); | |
| String hostAddr = null; | |
| if (mapping.length >= 2) { | |
| // look at the host aliases | |
| for (int i = 1; i < mapping.length; i++) { | |
| if (mapping[i].equalsIgnoreCase(host)) { | |
| hostAddr = mapping[0]; | |
| } | |
| } | |
| } | |
| return hostAddr; | |
| } | |
| } | |
| static final InetAddressImpl impl; | |
| /** | |
| * Platform-wide {@code LookupPolicy} initialized from {@code "java.net.preferIPv4Stack"}, | |
| * {@code "java.net.preferIPv6Addresses"} system properties. | |
| */ | |
| static final LookupPolicy PLATFORM_LOOKUP_POLICY; | |
| static { | |
| // create the impl | |
| impl = isIPv6Supported() ? | |
| new Inet6AddressImpl() : new Inet4AddressImpl(); | |
| // impl must be initialized before calling this method | |
| PLATFORM_LOOKUP_POLICY = initializePlatformLookupPolicy(); | |
| // create built-in resolver | |
| BUILTIN_RESOLVER = createBuiltinInetAddressResolver(); | |
| } | |
| /** | |
| * Create an instance of the InetAddressResolver interface based on | |
| * the setting of the {@code jdk.net.hosts.file} system property. | |
| * | |
| * <p>The default InetAddressResolver is the PlatformResolver, which typically | |
| * delegates name and address resolution calls to the underlying | |
| * OS network libraries. | |
| * | |
| * <p> A HostsFileResolver is created if the {@code jdk.net.hosts.file} | |
| * system property is set. If the specified file doesn't exist, the name or | |
| * address lookup will result in an UnknownHostException. Thus, non existent | |
| * hosts file is handled as if the file is empty. | |
| * | |
| * @return an InetAddressResolver | |
| */ | |
| private static InetAddressResolver createBuiltinInetAddressResolver() { | |
| InetAddressResolver theResolver; | |
| if (HOSTS_FILE_NAME != null) { | |
| theResolver = new HostsFileResolver(HOSTS_FILE_NAME); | |
| } else { | |
| theResolver = new PlatformResolver(); | |
| } | |
| return theResolver; | |
| } | |
| /** | |
| * Creates an InetAddress based on the provided host name and IP address. | |
| * The system-wide {@linkplain InetAddressResolver resolver} is not used to check | |
| * the validity of the address. | |
| * | |
| * <p> The host name can either be a machine name, such as | |
| * "{@code www.example.com}", or a textual representation of its IP | |
| * address. | |
| * <p> No validity checking is done on the host name either. | |
| * | |
| * <p> If addr specifies an IPv4 address an instance of Inet4Address | |
| * will be returned; otherwise, an instance of Inet6Address | |
| * will be returned. | |
| * | |
| * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array | |
| * must be 16 bytes long | |
| * | |
| * @param host the specified host | |
| * @param addr the raw IP address in network byte order | |
| * @return an InetAddress object created from the raw IP address. | |
| * @throws UnknownHostException if IP address is of illegal length | |
| * @since 1.4 | |
| */ | |
| public static InetAddress getByAddress(String host, byte[] addr) | |
| throws UnknownHostException { | |
| if (host != null && !host.isEmpty() && host.charAt(0) == '[') { | |
| if (host.charAt(host.length()-1) == ']') { | |
| host = host.substring(1, host.length() -1); | |
| } | |
| } | |
| if (addr != null) { | |
| if (addr.length == Inet4Address.INADDRSZ) { | |
| return new Inet4Address(host, addr); | |
| } else if (addr.length == Inet6Address.INADDRSZ) { | |
| byte[] newAddr | |
| = IPAddressUtil.convertFromIPv4MappedAddress(addr); | |
| if (newAddr != null) { | |
| return new Inet4Address(host, newAddr); | |
| } else { | |
| return new Inet6Address(host, addr); | |
| } | |
| } | |
| } | |
| throw new UnknownHostException("addr is of illegal length"); | |
| } | |
| /** | |
| * Determines the IP address of a host, given the host's name. | |
| * | |
| * <p> The host name can either be a machine name, such as | |
| * "{@code www.example.com}", or a textual representation of its | |
| * IP address. If a literal IP address is supplied, only the | |
| * validity of the address format is checked. | |
| * | |
| * <p> For {@code host} specified in literal IPv6 address, | |
| * either the form defined in RFC 2732 or the literal IPv6 address | |
| * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also | |
| * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6 | |
| * scoped addresses. | |
| * | |
| * <p> If the host is {@code null} or {@code host.length()} is equal | |
| * to zero, then an {@code InetAddress} representing an address of the | |
| * loopback interface is returned. | |
| * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC 3330</a> | |
| * section 2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a> | |
| * section 2.5.3. | |
| * | |
| * @param host the specified host, or {@code null}. | |
| * @return an IP address for the given host name. | |
| * @throws UnknownHostException if no IP address for the | |
| * {@code host} could be found, or if a scope_id was specified | |
| * for a global IPv6 address. | |
| * | |
| * @spec https://www.rfc-editor.org/info/rfc2373 RFC 2373: IP Version 6 Addressing Architecture | |
| * @spec https://www.rfc-editor.org/info/rfc3330 RFC 3330: Special-Use IPv4 Addresses | |
| */ | |
| public static InetAddress getByName(String host) | |
| throws UnknownHostException { | |
| return InetAddress.getAllByName(host)[0]; | |
| } | |
| /** | |
| * Given the name of a host, returns an array of its IP addresses, | |
| * based on the system-wide {@linkplain InetAddressResolver resolver}. | |
| * | |
| * <p> The host name can either be a machine name, such as | |
| * "{@code www.example.com}", or a textual representation of its IP | |
| * address. If a literal IP address is supplied, only the | |
| * validity of the address format is checked. | |
| * | |
| * <p> For {@code host} specified in <i>literal IPv6 address</i>, | |
| * either the form defined in RFC 2732 or the literal IPv6 address | |
| * format defined in RFC 2373 is accepted. A literal IPv6 address may | |
| * also be qualified by appending a scoped zone identifier or scope_id. | |
| * The syntax and usage of scope_ids is described | |
| * <a href="Inet6Address.html#scoped">here</a>. | |
| * | |
| * <p> If the host is {@code null} or {@code host.length()} is equal | |
| * to zero, then an {@code InetAddress} representing an address of the | |
| * loopback interface is returned. | |
| * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC 3330</a> | |
| * section 2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a> | |
| * section 2.5.3. </p> | |
| * | |
| * @param host the name of the host, or {@code null}. | |
| * @return an array of all the IP addresses for a given host name. | |
| * | |
| * @throws UnknownHostException if no IP address for the | |
| * {@code host} could be found, or if a scope_id was specified | |
| * for a global IPv6 address. | |
| * | |
| * @spec https://www.rfc-editor.org/info/rfc2373 RFC 2373: IP Version 6 Addressing Architecture | |
| * @spec https://www.rfc-editor.org/info/rfc3330 RFC 3330: Special-Use IPv4 Addresses | |
| */ | |
| public static InetAddress[] getAllByName(String host) | |
| throws UnknownHostException { | |
| if (host == null || host.isEmpty()) { | |
| InetAddress[] ret = new InetAddress[1]; | |
| ret[0] = impl.loopbackAddress(); | |
| return ret; | |
| } | |
| validate(host); | |
| boolean ipv6Expected = false; | |
| if (host.charAt(0) == '[') { | |
| // This is supposed to be an IPv6 literal | |
| if (host.length() > 2 && host.charAt(host.length()-1) == ']') { | |
| host = host.substring(1, host.length() -1); | |
| ipv6Expected = true; | |
| } else { | |
| // This was supposed to be a IPv6 literal, but it's not | |
| throw invalidIPv6LiteralException(host, false); | |
| } | |
| } | |
| // Check and try to parse host string as an IP address literal | |
| if (IPAddressUtil.digit(host.charAt(0), 16) != -1 | |
| || (host.charAt(0) == ':')) { | |
| InetAddress inetAddress = null; | |
| if (!ipv6Expected) { | |
| // check if it is IPv4 address only if host is not wrapped in '[]' | |
| try { | |
| // Here we check the address string for ambiguity only | |
| inetAddress = Inet4Address.parseAddressString(host, false); | |
| } catch (IllegalArgumentException iae) { | |
| var uhe = new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))); | |
| uhe.initCause(iae); | |
| throw uhe; | |
| } | |
| } | |
| if (inetAddress == null) { | |
| // This is supposed to be an IPv6 literal | |
| // Check for presence of a numeric or string zone id | |
| // is done in Inet6Address.parseAddressString | |
| if ((inetAddress = Inet6Address.parseAddressString(host, false)) == null && | |
| (host.contains(":") || ipv6Expected)) { | |
| throw invalidIPv6LiteralException(host, ipv6Expected); | |
| } | |
| } | |
| if (inetAddress != null) { | |
| return new InetAddress[]{inetAddress}; | |
| } | |
| } else if (ipv6Expected) { | |
| // We were expecting an IPv6 Literal since host string starts | |
| // and ends with square brackets, but we got something else. | |
| throw invalidIPv6LiteralException(host, true); | |
| } | |
| return getAllByName0(host, true); | |
| } | |
| private static UnknownHostException invalidIPv6LiteralException(String host, boolean wrapInBrackets) { | |
| String hostString = wrapInBrackets ? "[" + host + "]" : host; | |
| return new UnknownHostException(formatMsg("%sinvalid IPv6 address literal", | |
| filterNonSocketInfo(hostString).suffixWith(": "))); | |
| } | |
| /** | |
| * Returns the loopback address. | |
| * <p> | |
| * The InetAddress returned will represent the IPv4 | |
| * loopback address, 127.0.0.1, or the IPv6 loopback | |
| * address, ::1. The IPv4 loopback address returned | |
| * is only one of many in the form 127.*.*.* | |
| * | |
| * @return the InetAddress loopback instance. | |
| * @since 1.7 | |
| */ | |
| public static InetAddress getLoopbackAddress() { | |
| return impl.loopbackAddress(); | |
| } | |
| /** | |
| * package private so SocketPermission can call it | |
| */ | |
| static InetAddress[] getAllByName0(String host) throws UnknownHostException { | |
| return getAllByName0(host, true); | |
| } | |
| /** | |
| * Creates an {@code InetAddress} based on the provided {@linkplain InetAddress##format | |
| * textual representation} of an IP address. | |
| * <p> The provided IP address literal is parsed as | |
| * {@linkplain Inet4Address#ofLiteral(String) an IPv4 address literal} first. | |
| * If it cannot be parsed as an IPv4 address literal, then the method attempts | |
| * to parse it as {@linkplain Inet6Address#ofLiteral(String) an IPv6 address literal}. | |
| * If neither attempts succeed an {@code IllegalArgumentException} is thrown. | |
| * <p> This method doesn't block, i.e. no reverse lookup is performed. | |
| * | |
| * @param ipAddressLiteral the textual representation of an IP address. | |
| * @return an {@link InetAddress} object with no hostname set, and constructed | |
| * from the provided IP address literal. | |
| * @throws IllegalArgumentException if the {@code ipAddressLiteral} cannot be parsed | |
| * as an IPv4 or IPv6 address literal. | |
| * @throws NullPointerException if the {@code ipAddressLiteral} is {@code null}. | |
| * @see Inet4Address#ofLiteral(String) | |
| * @see Inet6Address#ofLiteral(String) | |
| * @see Inet4Address#ofPosixLiteral(String) | |
| * @since 22 | |
| */ | |
| public static InetAddress ofLiteral(String ipAddressLiteral) { | |
| Objects.requireNonNull(ipAddressLiteral); | |
| if (ipAddressLiteral.isEmpty()) { | |
| throw IPAddressUtil.invalidIpAddressLiteral(ipAddressLiteral); | |
| } | |
| InetAddress inetAddress; | |
| try { | |
| // First try to parse the input as an IPv4 address literal | |
| inetAddress = Inet4Address.ofLiteral(ipAddressLiteral); | |
| } catch (IllegalArgumentException iae) { | |
| // If it fails try to parse the input as an IPv6 address literal | |
| inetAddress = Inet6Address.ofLiteral(ipAddressLiteral); | |
| } | |
| return inetAddress; | |
| } | |
| /** | |
| * Designated lookup method. | |
| * | |
| * @param host host name to look up | |
| * @param useCache use cached value if not expired else always | |
| * perform name service lookup (and cache the result) | |
| * @return array of InetAddress(es) | |
| * @throws UnknownHostException if host name is not found | |
| */ | |
| private static InetAddress[] getAllByName0(String host, | |
| boolean useCache) | |
| throws UnknownHostException { | |
| /* If it gets here it is presumed to be a hostname */ | |
| // remove expired addresses from cache - expirySet keeps them ordered | |
| // by expiry time so we only need to iterate the prefix of the NavigableSet... | |
| long now = System.nanoTime(); | |
| for (CachedLookup caddrs : expirySet) { | |
| if (!caddrs.tryRemoveExpiredAddress(now)) { | |
| // we encountered 1st element that expires in future | |
| break; | |
| } | |
| } | |
| // look-up or remove from cache | |
| Addresses addrs; | |
| if (useCache) { | |
| addrs = cache.get(host); | |
| } else { | |
| addrs = cache.remove(host); | |
| if (addrs != null) { | |
| if (addrs instanceof CachedLookup) { | |
| // try removing from expirySet too if CachedAddresses | |
| expirySet.remove(addrs); | |
| } | |
| addrs = null; | |
| } | |
| } | |
| if (addrs == null) { | |
| // create a NameServiceAddresses instance which will look up | |
| // the name service and install it within cache... | |
| Addresses oldAddrs = cache.putIfAbsent( | |
| host, | |
| addrs = new NameServiceAddresses(host) | |
| ); | |
| if (oldAddrs != null) { // lost putIfAbsent race | |
| addrs = oldAddrs; | |
| } | |
| } | |
| // ask Addresses to get an array of InetAddress(es) and clone it | |
| return addrs.get().clone(); | |
| } | |
| static InetAddress[] getAddressesFromNameService(String host) | |
| throws UnknownHostException { | |
| Stream<InetAddress> addresses = null; | |
| UnknownHostException ex = null; | |
| var resolver = resolver(); | |
| try { | |
| addresses = resolver.lookupByName(host, PLATFORM_LOOKUP_POLICY); | |
| } catch (RuntimeException | UnknownHostException x) { | |
| if (host.equalsIgnoreCase("localhost")) { | |
| addresses = Stream.of(impl.loopbackAddress()); | |
| } else if (x instanceof UnknownHostException uhe) { | |
| ex = uhe; | |
| } else { | |
| ex = new UnknownHostException(); | |
| ex.initCause(x); | |
| } | |
| } | |
| InetAddress[] result = addresses == null ? null | |
| : addresses.toArray(InetAddress[]::new); | |
| if (result == null || result.length == 0) { | |
| throw ex == null ? new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))) | |
| : ex; | |
| } | |
| return result; | |
| } | |
| /** | |
| * Returns an {@code InetAddress} object given the raw IP address . | |
| * The argument is in network byte order: the highest order | |
| * byte of the address is in {@code getAddress()[0]}. | |
| * | |
| * <p> This method doesn't block, i.e. no reverse lookup is performed. | |
| * | |
| * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array | |
| * must be 16 bytes long | |
| * | |
| * @param addr the raw IP address in network byte order | |
| * @return an InetAddress object created from the raw IP address. | |
| * @throws UnknownHostException if IP address is of illegal length | |
| * @since 1.4 | |
| */ | |
| public static InetAddress getByAddress(byte[] addr) | |
| throws UnknownHostException { | |
| return getByAddress(null, addr); | |
| } | |
| private static final class CachedLocalHost { | |
| final String host; | |
| final InetAddress addr; | |
| final long expiryTime = System.nanoTime() + 5000_000_000L; // now + 5s; | |
| CachedLocalHost(String host, InetAddress addr) { | |
| this.host = host; | |
| this.addr = addr; | |
| } | |
| } | |
| private static volatile CachedLocalHost cachedLocalHost; | |
| /** | |
| * Returns the address of the local host. This is achieved by retrieving | |
| * the name of the host from the system, then resolving that name into | |
| * an {@code InetAddress}. | |
| * | |
| * <P>Note: The resolved address may be cached for a short period of time. | |
| * </P> | |
| * | |
| * @return the address of the local host. | |
| * | |
| * @throws UnknownHostException if the local host name could not | |
| * be resolved into an address. | |
| * | |
| * @see java.net.InetAddress#getByName(java.lang.String) | |
| */ | |
| public static InetAddress getLocalHost() throws UnknownHostException { | |
| // is cached data still valid? | |
| CachedLocalHost clh = cachedLocalHost; | |
| if (clh != null && (clh.expiryTime - System.nanoTime()) >= 0L) { | |
| return clh.addr; | |
| } | |
| String local = impl.getLocalHostName(); | |
| InetAddress localAddr; | |
| if (local.equals("localhost")) { | |
| // shortcut for "localhost" host name | |
| localAddr = impl.loopbackAddress(); | |
| } else { | |
| // call getAllByName0 without using cached data | |
| try { | |
| localAddr = getAllByName0(local, false)[0]; | |
| } catch (UnknownHostException uhe) { | |
| // Rethrow with a more informative error message. | |
| UnknownHostException uhe2 = | |
| new UnknownHostException(formatMsg(filterNonSocketInfo(local) | |
| .suffixWith(": ") + uhe.getMessage())); | |
| uhe2.initCause(uhe); | |
| throw uhe2; | |
| } | |
| } | |
| cachedLocalHost = new CachedLocalHost(local, localAddr); | |
| return localAddr; | |
| } | |
| /** | |
| * Perform class load-time initializations. | |
| */ | |
| private static native void init(); | |
| /* | |
| * Returns the InetAddress representing anyLocalAddress | |
| * (typically 0.0.0.0 or ::0) | |
| */ | |
| static InetAddress anyLocalAddress() { | |
| return impl.anyLocalAddress(); | |
| } | |
| private static final jdk.internal.misc.Unsafe UNSAFE | |
| = jdk.internal.misc.Unsafe.getUnsafe(); | |
| private static final long FIELDS_OFFSET | |
| = UNSAFE.objectFieldOffset(InetAddress.class, "holder"); | |
| /** | |
| * Restores the state of this object from the stream. | |
| * | |
| * @param s the {@code ObjectInputStream} from which data is read | |
| * @throws IOException if an I/O error occurs | |
| * @throws ClassNotFoundException if a serialized class cannot be loaded | |
| */ | |
| @java.io.Serial | |
| private void readObject (ObjectInputStream s) throws | |
| IOException, ClassNotFoundException { | |
| GetField gf = s.readFields(); | |
| String host = (String)gf.get("hostName", null); | |
| int address = gf.get("address", 0); | |
| int family = gf.get("family", 0); | |
| if (family != IPv4 && family != IPv6) { | |
| throw new InvalidObjectException("invalid address family type: " + family); | |
| } | |
| InetAddressHolder h = new InetAddressHolder(host, address, family); | |
| UNSAFE.putReference(this, FIELDS_OFFSET, h); | |
| } | |
| /* needed because the serializable fields no longer exist */ | |
| /** | |
| * @serialField hostName String the hostname for this address | |
| * @serialField address int holds a 32-bit IPv4 address. | |
| * @serialField family int specifies the address family type, for instance, | |
| * {@code '1'} for IPv4 addresses, and {@code '2'} for IPv6 addresses. | |
| */ | |
| @java.io.Serial | |
| private static final ObjectStreamField[] serialPersistentFields = { | |
| new ObjectStreamField("hostName", String.class), | |
| new ObjectStreamField("address", int.class), | |
| new ObjectStreamField("family", int.class), | |
| }; | |
| /** | |
| * Writes the state of this object to the stream. | |
| * | |
| * @param s the {@code ObjectOutputStream} to which data is written | |
| * @throws IOException if an I/O error occurs | |
| */ | |
| @java.io.Serial | |
| private void writeObject (ObjectOutputStream s) throws IOException { | |
| PutField pf = s.putFields(); | |
| pf.put("hostName", holder().getHostName()); | |
| pf.put("address", holder().getAddress()); | |
| pf.put("family", holder().getFamily()); | |
| s.writeFields(); | |
| } | |
| private static void validate(String host) throws UnknownHostException { | |
| if (host.indexOf(0) != -1) { | |
| throw new UnknownHostException("NUL character not allowed in hostname"); | |
| } | |
| } | |
| } |