< prev index next > src/java.base/share/classes/java/net/InetAddress.java
Print this page
* questions.
*/
package java.net;
+ import java.net.spi.InetAddressResolver;
+ import java.net.spi.InetAddressResolverProvider;
+ import java.net.spi.InetAddressResolver.LookupPolicy;
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
import java.util.List;
import java.util.NavigableSet;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
import java.io.ObjectInputStream;
import java.io.ObjectInputStream.GetField;
import java.io.ObjectOutputStream;
import java.io.ObjectOutputStream.PutField;
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.ReentrantLock;
+ import java.util.stream.Stream;
+
+ import jdk.internal.misc.VM;
import jdk.internal.access.JavaNetInetAddressAccess;
import jdk.internal.access.SharedSecrets;
+ import jdk.internal.vm.annotation.Stable;
+ import sun.net.ResolverProviderConfiguration;
import sun.security.action.*;
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.
*
* <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
* For IPv4 address format, please refer to <A
* HREF="Inet4Address.html#format">Inet4Address#format</A>; For IPv6
* address format, please refer to <A
* HREF="Inet6Address.html#format">Inet6Address#format</A>.
*
! * <P>There is a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of
! * System Properties</a> affecting how IPv4 and IPv6 addresses are used.</P>
*
! * <h3> Host Name Resolution </h3>
*
! * Host name-to-IP address <i>resolution</i> is accomplished through
! * the use of a combination of local machine configuration information
- * and network naming services such as the Domain Name System (DNS)
- * and Network Information Service(NIS). The particular naming
- * services(s) being used is by default the local machine configured
- * one. 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> The InetAddress class provides methods to resolve host names to
! * their IP addresses and vice versa.
*
! * <h3> InetAddress Caching </h3>
*
* The InetAddress class has a cache to store successful as well as
* unsuccessful host name resolutions.
*
* <p> By default, when a security manager is installed, in order to
* For IPv4 address format, please refer to <A
* HREF="Inet4Address.html#format">Inet4Address#format</A>; For IPv6
* address format, please refer to <A
* HREF="Inet6Address.html#format">Inet6Address#format</A>.
*
! * <p> There is 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> By default, when a security manager is installed, in order to
* @see java.net.InetAddress#getLocalHost()
* @since 1.0
*/
public class InetAddress implements java.io.Serializable {
- @Native static final int PREFER_IPV4_VALUE = 0;
- @Native static final int PREFER_IPV6_VALUE = 1;
- @Native static final int PREFER_SYSTEM_VALUE = 2;
-
/**
* 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;
- /* Specify address family preference */
- static transient final int preferIPv6Address;
-
static class InetAddressHolder {
/**
* Reserve the original application specified hostname.
*
* The original hostname is useful for domain-based endpoint
InetAddressHolder holder() {
return holder;
}
! /* Used to store the name service provider */
! private static transient NameService nameService;
/**
* Used to store the best available hostname.
* Lazily initialized via a data race; safe because Strings are immutable.
*/
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.
*/
/** use serialVersionUID from JDK 1.0.2 for interoperability */
@java.io.Serial
private static final long serialVersionUID = 3286316764910316507L;
/*
* Load net library into runtime, and perform initializations.
*/
static {
! String str = GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses");
! if (str == null) {
! preferIPv6Address = PREFER_IPV4_VALUE;
! } else if (str.equalsIgnoreCase("true")) {
! preferIPv6Address = PREFER_IPV6_VALUE;
! } else if (str.equalsIgnoreCase("false")) {
- preferIPv6Address = PREFER_IPV4_VALUE;
- } else if (str.equalsIgnoreCase("system")) {
- preferIPv6Address = PREFER_SYSTEM_VALUE;
- } else {
- preferIPv6Address = PREFER_IPV4_VALUE;
- }
jdk.internal.loader.BootLoader.loadLibrary("net");
SharedSecrets.setJavaNetInetAddressAccess(
new JavaNetInetAddressAccess() {
public String getOriginalHostName(InetAddress ia) {
return ia.holder.getOriginalHostName();
}
- public InetAddress getByName(String hostName,
- InetAddress hostAddress)
- throws UnknownHostException
- {
- return InetAddress.getByName(hostName, hostAddress);
- }
-
public int addressValue(Inet4Address inet4Address) {
return inet4Address.addressValue();
}
public byte[] addressBytes(Inet6Address inet6Address) {
/** 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 =
! GetPropertyAction.privilegedGetProperty("java.net.preferIPv4Stack");
! PREFER_IPV6_ADDRESSES_VALUE =
! GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses");
! HOSTS_FILE_NAME =
! GetPropertyAction.privilegedGetProperty("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) {
}
);
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();
+
+ /**
+ * The {@code RuntimePermission("inetAddressResolverProvider")} is
+ * necessary to subclass and instantiate the {@code InetAddressResolverProvider}
+ * class, as well as to obtain resolver from an instance of that class,
+ * and it is also required to obtain the operating system name resolution configurations.
+ */
+ private static final RuntimePermission INET_ADDRESS_RESOLVER_PERMISSION =
+ new RuntimePermission("inetAddressResolverProvider");
+
+ private static final ReentrantLock RESOLVER_LOCK = new ReentrantLock();
+ private static volatile InetAddressResolver bootstrapResolver;
+
+ @SuppressWarnings("removal")
+ 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 if (System.getSecurityManager() != null) {
+ PrivilegedAction<InetAddressResolver> pa = InetAddress::loadResolver;
+ cns = AccessController.doPrivileged(
+ pa, null, INET_ADDRESS_RESOLVER_PERMISSION);
+ } 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.
*
* <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
! * configured name lookup service. If a lookup of the name service
* is required, call
* {@link #getCanonicalHostName() getCanonicalHostName}.
*
* <p>If there is a security manager, its
* {@code checkConnect} method is first called
*
* <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
! * configured resolver. If a lookup of the name service
* is required, call
* {@link #getCanonicalHostName() getCanonicalHostName}.
*
* <p>If there is a security manager, its
* {@code checkConnect} method is first called
* @param check make security check if true
*
* @see SecurityManager#checkConnect
*/
private static String getHostFromNameService(InetAddress addr, boolean check) {
! String host = null;
try {
// first lookup the hostname
! host = nameService.getHostByAddr(addr.getAddress());
/* check to see if calling code is allowed to know
* the hostname for this IP address, ie, connect to the host
*/
if (check) {
* @param check make security check if true
*
* @see SecurityManager#checkConnect
*/
private static String getHostFromNameService(InetAddress addr, boolean check) {
! String host;
+ var resolver = resolver();
try {
// first lookup the hostname
! host = resolver.lookupByAddress(addr.getAddress());
/* check to see if calling code is allowed to know
* the hostname for this IP address, ie, connect to the host
*/
if (check) {
//XXX: if it looks like a spoof just return the address?
if (!ok) {
host = addr.getHostAddress();
return host;
}
! } catch (SecurityException e) {
host = addr.getHostAddress();
- } catch (UnknownHostException e) {
- host = addr.getHostAddress();
- // let next provider resolve the hostname
}
return host;
}
/**
//XXX: if it looks like a spoof just return the address?
if (!ok) {
host = addr.getHostAddress();
return host;
}
! // '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.
+ } catch (RuntimeException | UnknownHostException e) {
host = addr.getHostAddress();
}
return host;
}
/**
/**
* 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 name service 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();
/**
* 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();
// 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 InetAddress reqAddr;
! NameServiceAddresses(String host, InetAddress reqAddr) {
this.host = host;
- this.reqAddr = reqAddr;
}
@Override
public InetAddress[] get() throws UnknownHostException {
Addresses addresses;
// 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;
! NameServiceAddresses(String host) {
this.host = host;
}
@Override
public InetAddress[] get() throws UnknownHostException {
Addresses addresses;
// lookup name services
InetAddress[] inetAddresses;
UnknownHostException ex;
int cachePolicy;
try {
! inetAddresses = getAddressesFromNameService(host, reqAddr);
ex = null;
cachePolicy = InetAddressCachePolicy.get();
} catch (UnknownHostException uhe) {
inetAddresses = null;
ex = uhe;
// 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.FOREVER) {
// schedule expiry
expirySet.add(cachedAddresses);
}
}
! if (inetAddresses == null) {
throw ex == null ? new UnknownHostException(host) : ex;
}
return inetAddresses;
}
// else addresses != this
cachePolicy != InetAddressCachePolicy.FOREVER) {
// schedule expiry
expirySet.add(cachedAddresses);
}
}
! if (inetAddresses == null || inetAddresses.length == 0) {
throw ex == null ? new UnknownHostException(host) : ex;
}
return inetAddresses;
}
// else addresses != this
return addresses.get();
}
}
/**
! * NameService provides host and address lookup service
- *
- * @since 9
- */
- private interface NameService {
-
- /**
- * Lookup a host mapping by name. Retrieve the IP addresses
- * associated with a host
- *
- * @param host the specified hostname
- * @return array of IP addresses for the requested host
- * @throws UnknownHostException
- * if no IP address for the {@code host} could be found
- */
- InetAddress[] lookupAllHostAddr(String host)
- throws UnknownHostException;
-
- /**
- * Lookup the host corresponding to the IP address provided
- *
- * @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
- */
- String getHostByAddr(byte[] addr) throws UnknownHostException;
-
- }
-
- /**
- * The default NameService implementation, which delegates to the underlying
* OS network libraries to resolve host address mappings.
*
* @since 9
*/
! private static final class PlatformNameService implements NameService {
! public InetAddress[] lookupAllHostAddr(String host)
! throws UnknownHostException
! {
! return impl.lookupAllHostAddr(host);
}
! public String getHostByAddr(byte[] addr)
! throws UnknownHostException
! {
return impl.getHostByAddr(addr);
}
}
/**
! * The HostsFileNameService 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 NameService
* implementation
*
* @since 9
*/
! private static final class HostsFileNameService implements NameService {
-
- private static final InetAddress[] EMPTY_ARRAY = new InetAddress[0];
-
- // Specify if only IPv4 addresses should be returned by HostsFileService implementation
- private static final boolean preferIPv4Stack = Boolean.parseBoolean(
- GetPropertyAction.privilegedGetProperty("java.net.preferIPv4Stack"));
private final String hostsFile;
! public HostsFileNameService(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
*/
@Override
! public String getHostByAddr(byte[] addr) throws UnknownHostException {
String hostEntry;
String host = null;
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+");
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);
+ return Arrays.stream(impl.lookupAllHostAddr(host, policy));
}
! 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");
+ }
return impl.getHostByAddr(addr);
}
}
/**
! * 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
*/
@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+");
*
* <p>Search the configured hosts file for the addresses associated
* with the specified host name.
*
* @param host the specified hostname
! * @return array of IP addresses for the requested host
* @throws UnknownHostException
* if no IP address for the {@code host} could be found
*/
! public InetAddress[] lookupAllHostAddr(String host)
throws UnknownHostException {
String hostEntry;
String addrStr;
byte addr[];
List<InetAddress> inetAddresses = new ArrayList<>();
List<InetAddress> inet4Addresses = new ArrayList<>();
List<InetAddress> inet6Addresses = new ArrayList<>();
// 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)) {
*
* <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 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)) {
if ((addrStr != null) && (!addrStr.isEmpty())) {
addr = createAddressByteArray(addrStr);
if (addr != null) {
InetAddress address = InetAddress.getByAddress(host, addr);
inetAddresses.add(address);
! if (address instanceof Inet4Address) {
inet4Addresses.add(address);
}
! if (address instanceof Inet6Address) {
inet6Addresses.add(address);
}
}
}
}
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("Unable to resolve host " + host
+ " as hosts file " + hostsFile + " not found ");
}
!
! List<InetAddress> res;
! // If "preferIPv4Stack" system property is set to "true" then return
! // only IPv4 addresses
- if (preferIPv4Stack) {
- res = inet4Addresses;
- } else {
- // Otherwise, analyse "preferIPv6Addresses" value
- res = switch (preferIPv6Address) {
- case PREFER_IPV4_VALUE -> concatAddresses(inet4Addresses, inet6Addresses);
- case PREFER_IPV6_VALUE -> concatAddresses(inet6Addresses, inet4Addresses);
- default -> inetAddresses;
- };
}
!
! if (res.isEmpty()) {
! throw new UnknownHostException("Unable to resolve host " + host
! + " in hosts file " + hostsFile);
}
! return res.toArray(EMPTY_ARRAY);
}
! private static List<InetAddress> concatAddresses(List<InetAddress> firstPart,
! List<InetAddress> secondPart) {
! List<InetAddress> result = new ArrayList<>(firstPart);
! result.addAll(secondPart);
! return result;
}
private String removeComments(String hostsEntry) {
String filteredEntry = hostsEntry;
int hashIndex;
}
} catch (IOException e) {
throw new UnknownHostException("Unable to resolve host " + host
+ " as hosts file " + hostsFile + " not found ");
}
! // 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("Unable to resolve host " + hostName
+ + " in hosts file " + hostsFile);
+ }
}
private String removeComments(String hostsEntry) {
String filteredEntry = hostsEntry;
int hashIndex;
}
}
static final InetAddressImpl impl;
static {
// create the impl
impl = InetAddressImplFactory.create();
! // create name service
! nameService = createNameService();
}
/**
! * Create an instance of the NameService interface based on
* the setting of the {@code jdk.net.hosts.file} system property.
*
! * <p>The default NameService is the PlatformNameService, which typically
* delegates name and address resolution calls to the underlying
* OS network libraries.
*
! * <p> A HostsFileNameService 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 a NameService
*/
! private static NameService createNameService() {
!
! String hostsFileName =
! GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file");
- NameService theNameService;
- if (hostsFileName != null) {
- theNameService = new HostsFileNameService(hostsFileName);
} else {
! theNameService = new PlatformNameService();
}
! return theNameService;
}
/**
* Creates an InetAddress based on the provided host name and IP address.
! * No name service is checked for 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.
}
}
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 = InetAddressImplFactory.create();
! // 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.
! * System {@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.
public static InetAddress getByName(String host)
throws UnknownHostException {
return InetAddress.getAllByName(host)[0];
}
- // called from deployment cache manager
- private static InetAddress getByName(String host, InetAddress reqAddr)
- throws UnknownHostException {
- return InetAddress.getAllByName(host, reqAddr)[0];
- }
-
/**
* Given the name of a host, returns an array of its IP addresses,
! * based on the configured name service on the system.
*
* <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.
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 configured system {@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.
*
* @see SecurityManager#checkConnect
*/
public static InetAddress[] getAllByName(String host)
throws UnknownHostException {
- return getAllByName(host, null);
- }
-
- private static InetAddress[] getAllByName(String host, InetAddress reqAddr)
- throws UnknownHostException {
if (host == null || host.isEmpty()) {
InetAddress[] ret = new InetAddress[1];
ret[0] = impl.loopbackAddress();
return ret;
}
} else if (ipv6Expected) {
// We were expecting an IPv6 Literal, but got something else
throw new UnknownHostException("["+host+"]");
}
! return getAllByName0(host, reqAddr, true, true);
}
/**
* Returns the loopback address.
* <p>
}
} else if (ipv6Expected) {
// We were expecting an IPv6 Literal, but got something else
throw new UnknownHostException("["+host+"]");
}
! return getAllByName0(host, true, true);
}
/**
* Returns the loopback address.
* <p>
zone = (zone * 10) + digit;
}
return zone;
}
- private static InetAddress[] getAllByName0 (String host)
- throws UnknownHostException
- {
- return getAllByName0(host, true);
- }
-
/**
* package private so SocketPermission can call it
*/
static InetAddress[] getAllByName0 (String host, boolean check)
throws UnknownHostException {
! return getAllByName0 (host, null, check, true);
}
/**
* Designated lookup method.
*
* @param host host name to look up
- * @param reqAddr requested address to be the 1st in returned array
* @param check perform security check
* @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,
- InetAddress reqAddr,
boolean check,
boolean useCache)
throws UnknownHostException {
/* If it gets here it is presumed to be a hostname */
zone = (zone * 10) + digit;
}
return zone;
}
/**
* package private so SocketPermission can call it
*/
static InetAddress[] getAllByName0 (String host, boolean check)
throws UnknownHostException {
! return getAllByName0(host, check, true);
}
/**
* Designated lookup method.
*
* @param host host name to look up
* @param check perform security check
* @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 check,
boolean useCache)
throws UnknownHostException {
/* If it gets here it is presumed to be a hostname */
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, reqAddr)
);
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, InetAddress reqAddr)
throws UnknownHostException {
! InetAddress[] addresses = null;
UnknownHostException ex = null;
try {
! addresses = nameService.lookupAllHostAddr(host);
! } catch (UnknownHostException uhe) {
if (host.equalsIgnoreCase("localhost")) {
! addresses = new InetAddress[]{impl.loopbackAddress()};
! } else {
ex = uhe;
}
}
!
! if (addresses == null) {
throw ex == null ? new UnknownHostException(host) : ex;
}
!
- // More to do?
- if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
- // Find it?
- int i = 1;
- for (; i < addresses.length; i++) {
- if (addresses[i].equals(reqAddr)) {
- break;
- }
- }
- // Rotate
- if (i < addresses.length) {
- InetAddress tmp, tmp2 = reqAddr;
- for (int j = 0; j < i; j++) {
- tmp = addresses[j];
- addresses[j] = tmp2;
- tmp2 = tmp;
- }
- addresses[i] = tmp2;
- }
- }
-
- return addresses;
}
/**
* 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 name service 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
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(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
localAddr = impl.loopbackAddress();
} else {
// call getAllByName0 without security checks and
// without using cached data
try {
! localAddr = getAllByName0(local, null, false, false)[0];
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
localAddr = impl.loopbackAddress();
} else {
// call getAllByName0 without security checks and
// without using cached data
try {
! localAddr = getAllByName0(local, false, false)[0];
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
< prev index next >