mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +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
|
@ -24,6 +24,9 @@
|
|||
*/
|
||||
package java.net;
|
||||
import java.io.IOException;
|
||||
import java.net.spi.InetAddressResolver.LookupPolicy;
|
||||
|
||||
import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4;
|
||||
|
||||
/*
|
||||
* Package private implementation of InetAddressImpl for IPv4.
|
||||
|
@ -32,8 +35,14 @@ import java.io.IOException;
|
|||
*/
|
||||
final class Inet4AddressImpl implements InetAddressImpl {
|
||||
public native String getLocalHostName() throws UnknownHostException;
|
||||
public native InetAddress[]
|
||||
lookupAllHostAddr(String hostname) throws UnknownHostException;
|
||||
public InetAddress[] lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy)
|
||||
throws UnknownHostException {
|
||||
if ((lookupPolicy.characteristics() & IPV4) == 0) {
|
||||
throw new UnknownHostException(hostname);
|
||||
}
|
||||
return lookupAllHostAddr(hostname);
|
||||
}
|
||||
private native InetAddress[] lookupAllHostAddr(String hostname) throws UnknownHostException;
|
||||
public native String getHostByAddr(byte[] addr) throws UnknownHostException;
|
||||
private native boolean isReachable0(byte[] addr, int timeout, byte[] ifaddr, int ttl) throws IOException;
|
||||
|
||||
|
|
|
@ -25,10 +25,9 @@
|
|||
package java.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.spi.InetAddressResolver.LookupPolicy;
|
||||
|
||||
import static java.net.InetAddress.IPv6;
|
||||
import static java.net.InetAddress.PREFER_IPV6_VALUE;
|
||||
import static java.net.InetAddress.PREFER_SYSTEM_VALUE;
|
||||
import static java.net.InetAddress.PLATFORM_LOOKUP_POLICY;
|
||||
|
||||
/*
|
||||
* Package private implementation of InetAddressImpl for dual
|
||||
|
@ -48,8 +47,13 @@ final class Inet6AddressImpl implements InetAddressImpl {
|
|||
|
||||
public native String getLocalHostName() throws UnknownHostException;
|
||||
|
||||
public native InetAddress[] lookupAllHostAddr(String hostname)
|
||||
throws UnknownHostException;
|
||||
public InetAddress[] lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy)
|
||||
throws UnknownHostException {
|
||||
return lookupAllHostAddr(hostname, lookupPolicy.characteristics());
|
||||
}
|
||||
|
||||
private native InetAddress[] lookupAllHostAddr(String hostname, int characteristics)
|
||||
throws UnknownHostException;
|
||||
|
||||
public native String getHostByAddr(byte[] addr) throws UnknownHostException;
|
||||
|
||||
|
@ -96,8 +100,9 @@ final class Inet6AddressImpl implements InetAddressImpl {
|
|||
|
||||
public synchronized InetAddress anyLocalAddress() {
|
||||
if (anyLocalAddress == null) {
|
||||
if (InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
|
||||
InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE) {
|
||||
int flags = PLATFORM_LOOKUP_POLICY.characteristics();
|
||||
if (InetAddress.ipv6AddressesFirst(flags) ||
|
||||
InetAddress.systemAddressesOrder(flags)) {
|
||||
anyLocalAddress = new Inet6Address();
|
||||
anyLocalAddress.holder().hostName = "::";
|
||||
} else {
|
||||
|
@ -109,9 +114,9 @@ final class Inet6AddressImpl implements InetAddressImpl {
|
|||
|
||||
public synchronized InetAddress loopbackAddress() {
|
||||
if (loopbackAddress == null) {
|
||||
boolean preferIPv6Address =
|
||||
InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
|
||||
InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE;
|
||||
int flags = PLATFORM_LOOKUP_POLICY.characteristics();
|
||||
boolean preferIPv6Address = InetAddress.ipv6AddressesFirst(flags) ||
|
||||
InetAddress.systemAddressesOrder(flags);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
InetAddress address;
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
*/
|
||||
|
||||
package java.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.spi.InetAddressResolver.LookupPolicy;
|
||||
|
||||
/*
|
||||
* Package private interface to "implementation" used by
|
||||
* {@link InetAddress}.
|
||||
|
@ -38,7 +41,7 @@ sealed interface InetAddressImpl permits Inet4AddressImpl, Inet6AddressImpl {
|
|||
|
||||
String getLocalHostName() throws UnknownHostException;
|
||||
InetAddress[]
|
||||
lookupAllHostAddr(String hostname) throws UnknownHostException;
|
||||
lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy) throws UnknownHostException;
|
||||
String getHostByAddr(byte[] addr) throws UnknownHostException;
|
||||
|
||||
InetAddress anyLocalAddress();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -61,7 +61,7 @@ If there is no special note, a property value is checked every time it is used.<
|
|||
(e.g. 192.168.1.1). This property can be set to <B>true</B> to
|
||||
change that preference and use IPv6 addresses over IPv4 ones where
|
||||
possible, or <B>system</B> to preserve the order of the addresses as
|
||||
returned by the operating system.</P>
|
||||
returned by the system-wide {@linkplain java.net.spi.InetAddressResolver resolver}.</P>
|
||||
</UL>
|
||||
<P>Both of these properties are checked only once, at startup.</P>
|
||||
<a id="Proxies"></a>
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.spi;
|
||||
|
||||
import java.lang.annotation.Native;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* This interface defines operations for looking up host names and IP addresses.
|
||||
* {@link InetAddress} delegates all lookup operations to the <i>system-wide
|
||||
* resolver</i>.
|
||||
*
|
||||
* <p> The <i>system-wide resolver</i> can be customized by
|
||||
* <a href="InetAddressResolverProvider.html#system-wide-resolver">
|
||||
* deploying an implementation</a> of {@link InetAddressResolverProvider}.
|
||||
*
|
||||
* @since 18
|
||||
*/
|
||||
public interface InetAddressResolver {
|
||||
|
||||
/**
|
||||
* Given the name of a host, returns a stream of IP addresses of the requested
|
||||
* address family associated with a provided hostname.
|
||||
*
|
||||
* <p> {@code host} should be a machine name, such as "{@code www.example.com}",
|
||||
* not a textual representation of its IP address. No validation is performed on
|
||||
* the given {@code host} name: if a textual representation is supplied, the name
|
||||
* resolution is likely to fail and {@link UnknownHostException} may be thrown.
|
||||
*
|
||||
* <p> The address family type and addresses order are specified by the
|
||||
* {@code LookupPolicy} instance. Lookup operation characteristics could be
|
||||
* acquired with {@link LookupPolicy#characteristics()}.
|
||||
* If {@link InetAddressResolver.LookupPolicy#IPV4} and
|
||||
* {@link InetAddressResolver.LookupPolicy#IPV6} characteristics provided then this
|
||||
* method returns addresses of both IPV4 and IPV6 families.
|
||||
*
|
||||
* @param host the specified hostname
|
||||
* @param lookupPolicy the address lookup policy
|
||||
* @return a 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
|
||||
* @see LookupPolicy
|
||||
*/
|
||||
Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException;
|
||||
|
||||
/**
|
||||
* Lookup the host name corresponding to the raw IP address provided.
|
||||
*
|
||||
* <p> {@code addr} argument is in network byte order: the highest order byte of the address
|
||||
* is in {@code addr[0]}.
|
||||
*
|
||||
* <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
|
||||
* must be 16 bytes long.
|
||||
*
|
||||
* @param addr byte array representing a raw IP address
|
||||
* @return {@code String} representing the host name mapping
|
||||
* @throws UnknownHostException if no host name is found for the specified IP address
|
||||
* @throws IllegalArgumentException if the length of the provided byte array doesn't correspond
|
||||
* to a valid IP address length
|
||||
* @throws NullPointerException if addr is {@code null}
|
||||
*/
|
||||
String lookupByAddress(byte[] addr) throws UnknownHostException;
|
||||
|
||||
/**
|
||||
* A {@code LookupPolicy} object describes characteristics that can be applied to a lookup operation.
|
||||
* In particular, it is used to specify the ordering and which filtering should be performed when
|
||||
* {@linkplain InetAddressResolver#lookupByName(String, LookupPolicy) looking up host addresses}.
|
||||
*
|
||||
* <p> The default platform-wide lookup policy is constructed by consulting
|
||||
* <a href="doc-files/net-properties.html#Ipv4IPv6">System Properties</a> which affect
|
||||
* how IPv4 and IPv6 addresses are returned.
|
||||
*
|
||||
* @since 18
|
||||
*/
|
||||
final class LookupPolicy {
|
||||
|
||||
/**
|
||||
* Characteristic value signifying if IPv4 addresses need to be queried during lookup.
|
||||
*/
|
||||
@Native
|
||||
public static final int IPV4 = 1 << 0;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying if IPv6 addresses need to be queried during lookup.
|
||||
*/
|
||||
@Native
|
||||
public static final int IPV6 = 1 << 1;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying if IPv4 addresses should be returned
|
||||
* first by {@code InetAddressResolver}.
|
||||
*/
|
||||
@Native
|
||||
public static final int IPV4_FIRST = 1 << 2;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying if IPv6 addresses should be returned
|
||||
* first by {@code InetAddressResolver}.
|
||||
*/
|
||||
@Native
|
||||
public static final int IPV6_FIRST = 1 << 3;
|
||||
|
||||
private final int characteristics;
|
||||
|
||||
private LookupPolicy(int characteristics) {
|
||||
this.characteristics = characteristics;
|
||||
}
|
||||
|
||||
/**
|
||||
* This factory method creates a {@link LookupPolicy LookupPolicy} instance with
|
||||
* the given {@code characteristics} value.
|
||||
*
|
||||
* <p> The {@code characteristics} value is an integer bit mask which defines
|
||||
* parameters of a forward lookup operation. These parameters define at least:
|
||||
* <ul>
|
||||
* <li>the family type of the returned addresses</li>
|
||||
* <li>the order in which a {@linkplain InetAddressResolver resolver}
|
||||
* implementation should return its results</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> To request addresses of specific family types the following bit masks can be combined:
|
||||
* <ul>
|
||||
* <li>{@link LookupPolicy#IPV4}: to request IPv4 addresses</li>
|
||||
* <li>{@link LookupPolicy#IPV6}: to request IPv6 addresses</li>
|
||||
* </ul>
|
||||
* <br>It is an error if neither {@link LookupPolicy#IPV4} or {@link LookupPolicy#IPV6} are set.
|
||||
*
|
||||
* <p> To request a specific ordering of the results:
|
||||
* <ul>
|
||||
* <li>{@link LookupPolicy#IPV4_FIRST}: return IPv4 addresses before any IPv6 address</li>
|
||||
* <li>{@link LookupPolicy#IPV6_FIRST}: return IPv6 addresses before any IPv4 address</li>
|
||||
* </ul>
|
||||
* <br>If neither {@link LookupPolicy#IPV4_FIRST} or {@link LookupPolicy#IPV6_FIRST} are set it
|
||||
* implies <a href="{@docRoot}/java.base/java/net/doc-files/net-properties.html#Ipv4IPv6">"system"</a>
|
||||
* order of addresses.
|
||||
* It is an error to request both {@link LookupPolicy#IPV4_FIRST} and {@link LookupPolicy#IPV6_FIRST}.
|
||||
*
|
||||
* @param characteristics a value which represents the set of lookup characteristics
|
||||
* @return an instance of {@code InetAddressResolver.LookupPolicy}
|
||||
* @throws IllegalArgumentException if an illegal characteristics bit mask is provided
|
||||
* @see InetAddressResolver#lookupByName(String, LookupPolicy)
|
||||
*/
|
||||
public static LookupPolicy of(int characteristics) {
|
||||
// At least one type of addresses should be requested
|
||||
if ((characteristics & IPV4) == 0 && (characteristics & IPV6) == 0) {
|
||||
throw new IllegalArgumentException("No address type specified");
|
||||
}
|
||||
|
||||
// Requested order of addresses couldn't be determined
|
||||
if ((characteristics & IPV4_FIRST) != 0 && (characteristics & IPV6_FIRST) != 0) {
|
||||
throw new IllegalArgumentException("Addresses order cannot be determined");
|
||||
}
|
||||
|
||||
// If IPv4 addresses requested to be returned first then they should be requested too
|
||||
if ((characteristics & IPV4_FIRST) != 0 && (characteristics & IPV4) == 0) {
|
||||
throw new IllegalArgumentException("Addresses order and type do not match");
|
||||
}
|
||||
|
||||
// If IPv6 addresses requested to be returned first then they should be requested too
|
||||
if ((characteristics & IPV6_FIRST) != 0 && (characteristics & IPV6) == 0) {
|
||||
throw new IllegalArgumentException("Addresses order and type do not match");
|
||||
}
|
||||
return new LookupPolicy(characteristics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of characteristics of this lookup policy.
|
||||
*
|
||||
* @return a characteristics value
|
||||
* @see InetAddressResolver#lookupByName(String, LookupPolicy)
|
||||
*/
|
||||
public int characteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.spi;
|
||||
|
||||
import sun.net.ResolverProviderConfiguration;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Service-provider class for {@linkplain InetAddressResolver InetAddress resolvers}.
|
||||
*
|
||||
* <p> A resolver provider is a factory for custom implementations of {@linkplain
|
||||
* InetAddressResolver InetAddress resolvers}. A resolver defines operations for
|
||||
* looking up (resolving) host names and IP addresses.
|
||||
* <p>A resolver provider is a concrete subclass of this class that has a
|
||||
* zero-argument constructor and implements the abstract methods specified below.
|
||||
*
|
||||
* <p> A given invocation of the Java virtual machine maintains a single
|
||||
* system-wide resolver instance, which is used by
|
||||
* <a href="{@docRoot}/java.base/java/net/InetAddress.html#host-name-resolution">
|
||||
* InetAddress</a>. It is set after the VM is fully initialized and when an
|
||||
* invocation of a method in {@link InetAddress} class triggers the first lookup
|
||||
* operation.
|
||||
*
|
||||
* <p id="system-wide-resolver"> A resolver provider is located and loaded by
|
||||
* {@link InetAddress} to create the system-wide resolver as follows:
|
||||
* <ol>
|
||||
* <li>The {@link ServiceLoader} mechanism is used to locate an
|
||||
* {@code InetAddressResolverProvider} using the
|
||||
* system class loader. The order in which providers are located is
|
||||
* {@linkplain ServiceLoader#load(java.lang.Class, java.lang.ClassLoader)
|
||||
* implementation specific}.
|
||||
* The first provider found will be used to instantiate the
|
||||
* {@link InetAddressResolver InetAddressResolver} by invoking the
|
||||
* {@link InetAddressResolverProvider#get(InetAddressResolverProvider.Configuration)}
|
||||
* method. The returned {@code InetAddressResolver} will be set as the
|
||||
* system-wide resolver.
|
||||
* <li>If the previous step fails to find any resolver provider the
|
||||
* <a href="{@docRoot}/java.base/java/net/InetAddress.html#built-in-resolver">
|
||||
* built-in resolver</a> will be set as the system-wide resolver.
|
||||
* </ol>
|
||||
*
|
||||
* <p> If instantiating a custom resolver from a provider discovered in
|
||||
* step 1 throws an error or exception, the system-wide resolver will not be
|
||||
* set and the error or exception will be propagated to the calling thread.
|
||||
* Otherwise, any lookup operation will be performed using the
|
||||
* <i>system-wide resolver</i>.
|
||||
*
|
||||
* @implNote {@link InetAddress} will use the <i>built-in resolver</i> for any lookup operation
|
||||
* that might occur before the VM is fully booted.
|
||||
*
|
||||
* @since 18
|
||||
*/
|
||||
public abstract class InetAddressResolverProvider {
|
||||
|
||||
/**
|
||||
* Initialize and return an {@link InetAddressResolver} provided by
|
||||
* this provider. This method is called by {@link InetAddress} when
|
||||
* <a href="#system-wide-resolver">installing</a>
|
||||
* the system-wide resolver implementation.
|
||||
*
|
||||
* <p> Any error or exception thrown by this method is considered as
|
||||
* a failure of {@code InetAddressResolver} instantiation and will be propagated to
|
||||
* the calling thread.
|
||||
* @param configuration a {@link Configuration} instance containing platform built-in address
|
||||
* resolution configuration.
|
||||
* @return the resolver provided by this provider
|
||||
*/
|
||||
public abstract InetAddressResolver get(Configuration configuration);
|
||||
|
||||
/**
|
||||
* {@return the name of this provider, or {@code null} if unnamed}
|
||||
*/
|
||||
public abstract String name();
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code InetAddressResolverProvider}.
|
||||
*
|
||||
* @throws SecurityException if a security manager is present and its
|
||||
* {@code checkPermission} method doesn't allow the
|
||||
* {@code RuntimePermission("inetAddressResolverProvider")}.
|
||||
* @implNote It is recommended that an {@code InetAddressResolverProvider} service
|
||||
* implementation initialization should be as simple as possible, in order to avoid
|
||||
* possible risks of deadlock or class loading cycles during the instantiation of the
|
||||
* service provider.
|
||||
*/
|
||||
protected InetAddressResolverProvider() {
|
||||
this(checkPermission());
|
||||
}
|
||||
|
||||
private InetAddressResolverProvider(Void unused) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static Void checkPermission() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(INET_ADDRESS_RESOLVER_PERMISSION);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Configuration} object is supplied to the
|
||||
* {@link InetAddressResolverProvider#get(Configuration)} method when
|
||||
* setting the system-wide resolver.
|
||||
* A resolver implementation can then delegate to the built-in resolver
|
||||
* provided by this interface if it needs to.
|
||||
*
|
||||
* @since 18
|
||||
*/
|
||||
public sealed interface Configuration permits ResolverProviderConfiguration {
|
||||
/**
|
||||
* Returns the built-in {@linkplain InetAddressResolver resolver}.
|
||||
*
|
||||
* @return the JDK built-in resolver.
|
||||
*/
|
||||
InetAddressResolver builtinResolver();
|
||||
|
||||
/**
|
||||
* Reads the localhost name from the system configuration.
|
||||
*
|
||||
* @return the localhost name.
|
||||
*/
|
||||
String lookupLocalHostName();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,8 +26,8 @@
|
|||
/**
|
||||
* Service-provider classes for the {@link java.net} package.
|
||||
*
|
||||
* <p> Only developers who are defining new URL stream handler providers
|
||||
* should need to make direct use of this package.
|
||||
* <p> Only developers who are defining new URL stream handler providers or implementing
|
||||
* a custom resolver provider should need to make direct use of this package.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue