/* * Copyright (c) 1995, 2024, 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.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; /** * This class represents an Internet Protocol (IP) address. * *
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 RFC 790: * Assigned Numbers, RFC 1918: * Address Allocation for Private Internets, RFC 2365: * Administratively Scoped IP Multicast, and RFC 2373: IP * Version 6 Addressing Architecture. 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). * *
| Address Type | Description |
|---|---|
| unicast | *An identifier for a single interface. A packet sent to
* a unicast address is delivered to the interface identified by
* that address.
*
* 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. * * The unspecified address must not be used as * the destination address of an IP packet. * * The Loopback 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. |
| multicast | *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. |
Link-local 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. * *
Site-local addresses are designed to be used for addressing * inside of a site without the need for a global prefix. * *
Global addresses are unique across the internet. * *
* * 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}. * *
There are a couple of * System Properties affecting how IPv4 and IPv6 addresses are used. * *
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}. * *
Host name-to-IP address resolution maps a host name to an IP address. * For any host name, its corresponding IP address is returned. * *
Reverse name resolution means that for any IP address, * the host associated with the IP address is returned. * *
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. * *
{@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. * *
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. * *
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. * *
Three Java {@linkplain java.security.Security security} properties control * the TTL values used for positive and negative host name resolution caching: * *
* A value of -1 indicates "cache forever". *
* 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. *
* A value of 0 (zero) or if the property is not set means do not use stale * names. Negative values are ignored. *
* A value of 0 indicates "never cache". * A value of -1 indicates "cache forever". *
* 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. *
* 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. *
* 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. * *
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}. * *
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. *
* 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 The file format is that which corresponds with the /etc/hosts file
* IP Address host alias list.
*
* 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("Unable to resolve address "
+ Arrays.toString(addr) + " as hosts file " + hostsFile
+ " not found ");
}
if ((host == null) || (host.isEmpty()) || (host.equals(" "))) {
throw new UnknownHostException("Requested address "
+ Arrays.toString(addr)
+ " resolves to an invalid entry in hosts file "
+ hostsFile);
}
return host;
}
/**
* Lookup a host mapping by name. Retrieve the IP addresses
* associated with a host.
*
* 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 The default InetAddressResolver is the PlatformResolver, which typically
* delegates name and address resolution calls to the underlying
* OS network libraries.
*
* 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.
*
* The host name can either be a machine name, such as
* "{@code www.example.com}", or a textual representation of its IP
* address.
* No validity checking is done on the host name either.
*
* If addr specifies an IPv4 address an instance of Inet4Address
* will be returned; otherwise, an instance of Inet6Address
* will be returned.
*
* 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.
*
* 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.
*
* 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 here for a description of IPv6
* scoped addresses.
*
* 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 RFC 3330
* section 2 and RFC 2373
* 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}.
*
* 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.
*
* 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. 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
* here.
*
* 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 RFC 3330
* section 2 and RFC 2373
* section 2.5.3.
* 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.
* 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.
* 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 This method doesn't block, i.e. no reverse lookup is performed.
*
* 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}.
*
* Note: The resolved address may be cached for a short period of time.
*