8244202: Implementation of JEP 418: Internet-Address Resolution SPI

Co-authored-by: Chris Hegarty <chegar@openjdk.org>
Co-authored-by: Daniel Fuchs <dfuchs@openjdk.org>
Co-authored-by: Alan Bateman <alanb@openjdk.org>
Reviewed-by: dfuchs, alanb, michaelm, chegar
This commit is contained in:
Aleksei Efimov 2021-11-11 14:33:58 +00:00
parent c29cab8ab4
commit 2ca4ff87b7
56 changed files with 2986 additions and 293 deletions

View file

@ -25,6 +25,11 @@
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;
@ -40,19 +45,31 @@ 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.
*
@ -128,25 +145,35 @@ import sun.nio.cs.UTF_8;
* 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>
* <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.
*
* <h3> Host Name Resolution </h3>
* <h2 id="host-name-resolution"> Host Name Resolution </h2>
*
* 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> 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> The InetAddress class provides methods to resolve host names to
* their IP addresses and vice versa.
* <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.
*
* <h3> InetAddress Caching </h3>
* <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.
@ -198,10 +225,6 @@ import sun.nio.cs.UTF_8;
*/
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
@ -214,9 +237,6 @@ public class InetAddress implements java.io.Serializable {
*/
@Native static final int IPv6 = 2;
/* Specify address family preference */
static final transient int preferIPv6Address;
static class InetAddressHolder {
/**
* Reserve the original application specified hostname.
@ -288,8 +308,11 @@ public class InetAddress implements java.io.Serializable {
return holder;
}
/* Used to store the name service provider */
private static transient NameService nameService;
/* 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.
@ -301,22 +324,25 @@ public class InetAddress implements java.io.Serializable {
@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 {
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;
}
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() {
@ -324,13 +350,6 @@ public class InetAddress implements java.io.Serializable {
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();
}
@ -343,6 +362,131 @@ public class InetAddress implements java.io.Serializable {
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
@ -555,7 +699,7 @@ public class InetAddress implements java.io.Serializable {
* 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
* configured resolver. If a lookup of the name service
* is required, call
* {@link #getCanonicalHostName() getCanonicalHostName}.
*
@ -656,10 +800,11 @@ public class InetAddress implements java.io.Serializable {
* @see SecurityManager#checkConnect
*/
private static String getHostFromNameService(InetAddress addr, boolean check) {
String host = null;
String host;
var resolver = resolver();
try {
// first lookup the hostname
host = nameService.getHostByAddr(addr.getAddress());
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
@ -691,11 +836,12 @@ public class InetAddress implements java.io.Serializable {
host = addr.getHostAddress();
return host;
}
} catch (SecurityException e) {
} 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();
} catch (UnknownHostException e) {
host = addr.getHostAddress();
// let next provider resolve the hostname
}
return host;
}
@ -755,8 +901,9 @@ public class InetAddress implements java.io.Serializable {
* 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.
* 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.
*/
@ -821,11 +968,9 @@ public class InetAddress implements java.io.Serializable {
// 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) {
NameServiceAddresses(String host) {
this.host = host;
this.reqAddr = reqAddr;
}
@Override
@ -849,7 +994,7 @@ public class InetAddress implements java.io.Serializable {
UnknownHostException ex;
int cachePolicy;
try {
inetAddresses = getAddressesFromNameService(host, reqAddr);
inetAddresses = getAddressesFromNameService(host);
ex = null;
cachePolicy = InetAddressCachePolicy.get();
} catch (UnknownHostException uhe) {
@ -875,7 +1020,7 @@ public class InetAddress implements java.io.Serializable {
expirySet.add(cachedAddresses);
}
}
if (inetAddresses == null) {
if (inetAddresses == null || inetAddresses.length == 0) {
throw ex == null ? new UnknownHostException(host) : ex;
}
return inetAddresses;
@ -889,81 +1034,48 @@ public class InetAddress implements java.io.Serializable {
}
/**
* 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
* The default InetAddressResolver implementation, which delegates to the underlying
* OS network libraries to resolve host address mappings.
*
* @since 9
*/
private static final class PlatformNameService implements NameService {
private static final class PlatformResolver implements InetAddressResolver {
public InetAddress[] lookupAllHostAddr(String host)
throws UnknownHostException
{
return impl.lookupAllHostAddr(host);
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 getHostByAddr(byte[] addr)
throws UnknownHostException
{
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 HostsFileNameService provides host address mapping
* 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 NameService
* <p>When the file lookup is enabled it replaces the default InetAddressResolver
* 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 static final class HostsFileResolver implements InetAddressResolver {
private final String hostsFile;
public HostsFileNameService(String hostsFileName) {
public HostsFileResolver(String hostsFileName) {
this.hostsFile = hostsFileName;
}
@ -974,17 +1086,22 @@ public class InetAddress implements java.io.Serializable {
*
* @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 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 getHostByAddr(byte[] addr) throws UnknownHostException {
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))
{
UTF_8.INSTANCE)) {
while (hostsFileScanner.hasNextLine()) {
hostEntry = hostsFileScanner.nextLine();
if (!hostEntry.startsWith("#")) {
@ -1020,22 +1137,31 @@ public class InetAddress implements java.io.Serializable {
* with the specified host name.
*
* @param host the specified hostname
* @return array of IP addresses for the requested host
* @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 InetAddress[] lookupAllHostAddr(String host)
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)) {
UTF_8.INSTANCE)) {
while (hostsFileScanner.hasNextLine()) {
hostEntry = hostsFileScanner.nextLine();
if (!hostEntry.startsWith("#")) {
@ -1047,10 +1173,10 @@ public class InetAddress implements java.io.Serializable {
if (addr != null) {
InetAddress address = InetAddress.getByAddress(host, addr);
inetAddresses.add(address);
if (address instanceof Inet4Address) {
if (address instanceof Inet4Address && needIPv4) {
inet4Addresses.add(address);
}
if (address instanceof Inet6Address) {
if (address instanceof Inet6Address && needIPv6) {
inet6Addresses.add(address);
}
}
@ -1062,33 +1188,38 @@ public class InetAddress implements java.io.Serializable {
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;
};
// Check if only IPv4 addresses are requested
if (needIPv4 && !needIPv6) {
checkResultsList(inet4Addresses, host);
return inet4Addresses.stream();
}
if (res.isEmpty()) {
throw new UnknownHostException("Unable to resolve host " + host
+ " in hosts file " + hostsFile);
// Check if only IPv6 addresses are requested
if (!needIPv4 && needIPv6) {
checkResultsList(inet6Addresses, host);
return inet6Addresses.stream();
}
return res.toArray(EMPTY_ARRAY);
// 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();
}
private static List<InetAddress> concatAddresses(List<InetAddress> firstPart,
List<InetAddress> secondPart) {
List<InetAddress> result = new ArrayList<>(firstPart);
result.addAll(secondPart);
return result;
// 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) {
@ -1130,45 +1261,52 @@ public class InetAddress implements java.io.Serializable {
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();
// create name service
nameService = createNameService();
// impl must be initialized before calling this method
PLATFORM_LOOKUP_POLICY = initializePlatformLookupPolicy();
// create built-in resolver
BUILTIN_RESOLVER = createBuiltinInetAddressResolver();
}
/**
* Create an instance of the NameService interface based on
* Create an instance of the InetAddressResolver interface based on
* the setting of the {@code jdk.net.hosts.file} system property.
*
* <p>The default NameService is the PlatformNameService, which typically
* <p>The default InetAddressResolver is the PlatformResolver, 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}
* <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 a NameService
* @return an InetAddressResolver
*/
private static NameService createNameService() {
String hostsFileName =
GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file");
NameService theNameService;
if (hostsFileName != null) {
theNameService = new HostsFileNameService(hostsFileName);
private static InetAddressResolver createBuiltinInetAddressResolver() {
InetAddressResolver theResolver;
if (HOSTS_FILE_NAME != null) {
theResolver = new HostsFileResolver(HOSTS_FILE_NAME);
} else {
theNameService = new PlatformNameService();
theResolver = new PlatformResolver();
}
return theNameService;
return theResolver;
}
/**
* Creates an InetAddress based on the provided host name and IP address.
* No name service is checked for the validity of the 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
@ -1251,15 +1389,9 @@ public class InetAddress implements java.io.Serializable {
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.
* 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
@ -1298,11 +1430,6 @@ public class InetAddress implements java.io.Serializable {
*/
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];
@ -1364,7 +1491,7 @@ public class InetAddress implements java.io.Serializable {
// We were expecting an IPv6 Literal, but got something else
throw new UnknownHostException("["+host+"]");
}
return getAllByName0(host, reqAddr, true, true);
return getAllByName0(host, true, true);
}
/**
@ -1414,25 +1541,18 @@ public class InetAddress implements java.io.Serializable {
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);
return getAllByName0(host, 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)
@ -1440,7 +1560,6 @@ public class InetAddress implements java.io.Serializable {
* @throws UnknownHostException if host name is not found
*/
private static InetAddress[] getAllByName0(String host,
InetAddress reqAddr,
boolean check,
boolean useCache)
throws UnknownHostException {
@ -1498,7 +1617,7 @@ public class InetAddress implements java.io.Serializable {
// the name service and install it within cache...
Addresses oldAddrs = cache.putIfAbsent(
host,
addrs = new NameServiceAddresses(host, reqAddr)
addrs = new NameServiceAddresses(host)
);
if (oldAddrs != null) { // lost putIfAbsent race
addrs = oldAddrs;
@ -1509,47 +1628,30 @@ public class InetAddress implements java.io.Serializable {
return addrs.get().clone();
}
static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
static InetAddress[] getAddressesFromNameService(String host)
throws UnknownHostException {
InetAddress[] addresses = null;
Stream<InetAddress> addresses = null;
UnknownHostException ex = null;
var resolver = resolver();
try {
addresses = nameService.lookupAllHostAddr(host);
} catch (UnknownHostException uhe) {
addresses = resolver.lookupByName(host, PLATFORM_LOOKUP_POLICY);
} catch (RuntimeException | UnknownHostException x) {
if (host.equalsIgnoreCase("localhost")) {
addresses = new InetAddress[]{impl.loopbackAddress()};
} else {
addresses = Stream.of(impl.loopbackAddress());
} else if (x instanceof UnknownHostException uhe) {
ex = uhe;
} else {
ex = new UnknownHostException();
ex.initCause(x);
}
}
if (addresses == null) {
InetAddress[] result = addresses == null ? null
: addresses.toArray(InetAddress[]::new);
if (result == null || result.length == 0) {
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;
return result;
}
/**
@ -1557,8 +1659,7 @@ public class InetAddress implements java.io.Serializable {
* 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> 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
@ -1637,7 +1738,7 @@ public class InetAddress implements java.io.Serializable {
// call getAllByName0 without security checks and
// without using cached data
try {
localAddr = getAllByName0(local, null, false, false)[0];
localAddr = getAllByName0(local, false, false)[0];
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =