mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
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:
parent
c29cab8ab4
commit
2ca4ff87b7
56 changed files with 2986 additions and 293 deletions
|
@ -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 =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue