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

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -378,6 +378,16 @@ import java.lang.module.ModuleFinder;
* {@linkplain ModuleFinder#ofSystem system modules} in the runtime image.</td> * {@linkplain ModuleFinder#ofSystem system modules} in the runtime image.</td>
* </tr> * </tr>
* *
* <tr>
* <th scope="row">inetAddressResolverProvider</th>
* <td>This {@code RuntimePermission} is required to be granted to
* classes which subclass and implement {@code java.net.spi.InetAddressResolverProvider}.
* The permission is checked during invocation of the abstract base class constructor.
* This permission ensures trust in classes which provide resolvers used by
* {@link java.net.InetAddress} hostname and address resolution methods.</td>
* <td>See {@link java.net.spi.InetAddressResolverProvider} for more information.</td>
* </tr>
*
* </tbody> * </tbody>
* </table> * </table>
* *

View file

@ -24,6 +24,9 @@
*/ */
package java.net; package java.net;
import java.io.IOException; 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. * Package private implementation of InetAddressImpl for IPv4.
@ -32,8 +35,14 @@ import java.io.IOException;
*/ */
final class Inet4AddressImpl implements InetAddressImpl { final class Inet4AddressImpl implements InetAddressImpl {
public native String getLocalHostName() throws UnknownHostException; public native String getLocalHostName() throws UnknownHostException;
public native InetAddress[] public InetAddress[] lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy)
lookupAllHostAddr(String hostname) throws UnknownHostException; 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; public native String getHostByAddr(byte[] addr) throws UnknownHostException;
private native boolean isReachable0(byte[] addr, int timeout, byte[] ifaddr, int ttl) throws IOException; private native boolean isReachable0(byte[] addr, int timeout, byte[] ifaddr, int ttl) throws IOException;

View file

@ -25,10 +25,9 @@
package java.net; package java.net;
import java.io.IOException; import java.io.IOException;
import java.net.spi.InetAddressResolver.LookupPolicy;
import static java.net.InetAddress.IPv6; import static java.net.InetAddress.PLATFORM_LOOKUP_POLICY;
import static java.net.InetAddress.PREFER_IPV6_VALUE;
import static java.net.InetAddress.PREFER_SYSTEM_VALUE;
/* /*
* Package private implementation of InetAddressImpl for dual * Package private implementation of InetAddressImpl for dual
@ -48,8 +47,13 @@ final class Inet6AddressImpl implements InetAddressImpl {
public native String getLocalHostName() throws UnknownHostException; public native String getLocalHostName() throws UnknownHostException;
public native InetAddress[] lookupAllHostAddr(String hostname) public InetAddress[] lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy)
throws UnknownHostException; 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; public native String getHostByAddr(byte[] addr) throws UnknownHostException;
@ -96,8 +100,9 @@ final class Inet6AddressImpl implements InetAddressImpl {
public synchronized InetAddress anyLocalAddress() { public synchronized InetAddress anyLocalAddress() {
if (anyLocalAddress == null) { if (anyLocalAddress == null) {
if (InetAddress.preferIPv6Address == PREFER_IPV6_VALUE || int flags = PLATFORM_LOOKUP_POLICY.characteristics();
InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE) { if (InetAddress.ipv6AddressesFirst(flags) ||
InetAddress.systemAddressesOrder(flags)) {
anyLocalAddress = new Inet6Address(); anyLocalAddress = new Inet6Address();
anyLocalAddress.holder().hostName = "::"; anyLocalAddress.holder().hostName = "::";
} else { } else {
@ -109,9 +114,9 @@ final class Inet6AddressImpl implements InetAddressImpl {
public synchronized InetAddress loopbackAddress() { public synchronized InetAddress loopbackAddress() {
if (loopbackAddress == null) { if (loopbackAddress == null) {
boolean preferIPv6Address = int flags = PLATFORM_LOOKUP_POLICY.characteristics();
InetAddress.preferIPv6Address == PREFER_IPV6_VALUE || boolean preferIPv6Address = InetAddress.ipv6AddressesFirst(flags) ||
InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE; InetAddress.systemAddressesOrder(flags);
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
InetAddress address; InetAddress address;

View file

@ -25,6 +25,11 @@
package java.net; 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.List;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,19 +45,31 @@ import java.io.ObjectInputStream.GetField;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectOutputStream.PutField; import java.io.ObjectOutputStream.PutField;
import java.lang.annotation.Native; import java.lang.annotation.Native;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.Arrays; 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.JavaNetInetAddressAccess;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.vm.annotation.Stable;
import sun.net.ResolverProviderConfiguration;
import sun.security.action.*; import sun.security.action.*;
import sun.net.InetAddressCachePolicy; import sun.net.InetAddressCachePolicy;
import sun.net.util.IPAddressUtil; import sun.net.util.IPAddressUtil;
import sun.nio.cs.UTF_8; 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. * This class represents an Internet Protocol (IP) address.
* *
@ -128,25 +145,35 @@ import sun.nio.cs.UTF_8;
* address format, please refer to <A * address format, please refer to <A
* HREF="Inet6Address.html#format">Inet6Address#format</A>. * HREF="Inet6Address.html#format">Inet6Address#format</A>.
* *
* <P>There is a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of * <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> * 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 * <p> The InetAddress class provides methods to resolve host names to
* the use of a combination of local machine configuration information * their IP addresses and vice versa. The actual resolution is delegated to an
* and network naming services such as the Domain Name System (DNS) * {@linkplain InetAddressResolver InetAddress resolver}.
* and Network Information Service(NIS). The particular naming *
* services(s) being used is by default the local machine configured * <p> <i>Host name-to-IP address resolution</i> maps a host name to an IP address.
* one. For any host name, its corresponding IP address is returned. * For any host name, its corresponding IP address is returned.
* *
* <p> <i>Reverse name resolution</i> means that for any IP address, * <p> <i>Reverse name resolution</i> means that for any IP address,
* the host associated with the IP address is returned. * the host associated with the IP address is returned.
* *
* <p> The InetAddress class provides methods to resolve host names to * <p id="built-in-resolver"> The built-in InetAddress resolver implementation does
* their IP addresses and vice versa. * 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 * The InetAddress class has a cache to store successful as well as
* unsuccessful host name resolutions. * unsuccessful host name resolutions.
@ -198,10 +225,6 @@ import sun.nio.cs.UTF_8;
*/ */
public class InetAddress implements java.io.Serializable { 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 * Specify the address family: Internet Protocol, Version 4
* @since 1.4 * @since 1.4
@ -214,9 +237,6 @@ public class InetAddress implements java.io.Serializable {
*/ */
@Native static final int IPv6 = 2; @Native static final int IPv6 = 2;
/* Specify address family preference */
static final transient int preferIPv6Address;
static class InetAddressHolder { static class InetAddressHolder {
/** /**
* Reserve the original application specified hostname. * Reserve the original application specified hostname.
@ -288,8 +308,11 @@ public class InetAddress implements java.io.Serializable {
return holder; return holder;
} }
/* Used to store the name service provider */ /* Used to store the system-wide resolver */
private static transient NameService nameService; @Stable
private static volatile InetAddressResolver resolver;
private static final InetAddressResolver BUILTIN_RESOLVER;
/** /**
* Used to store the best available hostname. * Used to store the best available hostname.
@ -301,22 +324,25 @@ public class InetAddress implements java.io.Serializable {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 3286316764910316507L; 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. * Load net library into runtime, and perform initializations.
*/ */
static { static {
String str = GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses"); PREFER_IPV4_STACK_VALUE =
if (str == null) { GetPropertyAction.privilegedGetProperty("java.net.preferIPv4Stack");
preferIPv6Address = PREFER_IPV4_VALUE; PREFER_IPV6_ADDRESSES_VALUE =
} else if (str.equalsIgnoreCase("true")) { GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses");
preferIPv6Address = PREFER_IPV6_VALUE; HOSTS_FILE_NAME =
} else if (str.equalsIgnoreCase("false")) { GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file");
preferIPv6Address = PREFER_IPV4_VALUE;
} else if (str.equalsIgnoreCase("system")) {
preferIPv6Address = PREFER_SYSTEM_VALUE;
} else {
preferIPv6Address = PREFER_IPV4_VALUE;
}
jdk.internal.loader.BootLoader.loadLibrary("net"); jdk.internal.loader.BootLoader.loadLibrary("net");
SharedSecrets.setJavaNetInetAddressAccess( SharedSecrets.setJavaNetInetAddressAccess(
new JavaNetInetAddressAccess() { new JavaNetInetAddressAccess() {
@ -324,13 +350,6 @@ public class InetAddress implements java.io.Serializable {
return ia.holder.getOriginalHostName(); return ia.holder.getOriginalHostName();
} }
public InetAddress getByName(String hostName,
InetAddress hostAddress)
throws UnknownHostException
{
return InetAddress.getByName(hostName, hostAddress);
}
public int addressValue(Inet4Address inet4Address) { public int addressValue(Inet4Address inet4Address) {
return inet4Address.addressValue(); return inet4Address.addressValue();
} }
@ -343,6 +362,131 @@ public class InetAddress implements java.io.Serializable {
init(); 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. * Constructor for the Socket.accept() method.
* This creates an empty InetAddress, which is filled in by * 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; * this host name will be remembered and returned;
* otherwise, a reverse name lookup will be performed * otherwise, a reverse name lookup will be performed
* and the result will be returned based on the system * 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 * is required, call
* {@link #getCanonicalHostName() getCanonicalHostName}. * {@link #getCanonicalHostName() getCanonicalHostName}.
* *
@ -656,10 +800,11 @@ public class InetAddress implements java.io.Serializable {
* @see SecurityManager#checkConnect * @see SecurityManager#checkConnect
*/ */
private static String getHostFromNameService(InetAddress addr, boolean check) { private static String getHostFromNameService(InetAddress addr, boolean check) {
String host = null; String host;
var resolver = resolver();
try { try {
// first lookup the hostname // first lookup the hostname
host = nameService.getHostByAddr(addr.getAddress()); host = resolver.lookupByAddress(addr.getAddress());
/* check to see if calling code is allowed to know /* check to see if calling code is allowed to know
* the hostname for this IP address, ie, connect to the host * 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(); host = addr.getHostAddress();
return host; 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(); host = addr.getHostAddress();
} catch (UnknownHostException e) {
host = addr.getHostAddress();
// let next provider resolve the hostname
} }
return host; return host;
} }
@ -755,8 +901,9 @@ public class InetAddress implements java.io.Serializable {
* string returned is of the form: hostname / literal IP * string returned is of the form: hostname / literal IP
* address. * address.
* *
* If the host name is unresolved, no reverse name service lookup * If the host name is unresolved, no reverse lookup
* is performed. The hostname part will be represented by an empty string. * is performed. The hostname part will be represented
* by an empty string.
* *
* @return a string representation of this IP address. * @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 // in cache when the result is obtained
private static final class NameServiceAddresses implements Addresses { private static final class NameServiceAddresses implements Addresses {
private final String host; private final String host;
private final InetAddress reqAddr;
NameServiceAddresses(String host, InetAddress reqAddr) { NameServiceAddresses(String host) {
this.host = host; this.host = host;
this.reqAddr = reqAddr;
} }
@Override @Override
@ -849,7 +994,7 @@ public class InetAddress implements java.io.Serializable {
UnknownHostException ex; UnknownHostException ex;
int cachePolicy; int cachePolicy;
try { try {
inetAddresses = getAddressesFromNameService(host, reqAddr); inetAddresses = getAddressesFromNameService(host);
ex = null; ex = null;
cachePolicy = InetAddressCachePolicy.get(); cachePolicy = InetAddressCachePolicy.get();
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
@ -875,7 +1020,7 @@ public class InetAddress implements java.io.Serializable {
expirySet.add(cachedAddresses); expirySet.add(cachedAddresses);
} }
} }
if (inetAddresses == null) { if (inetAddresses == null || inetAddresses.length == 0) {
throw ex == null ? new UnknownHostException(host) : ex; throw ex == null ? new UnknownHostException(host) : ex;
} }
return inetAddresses; return inetAddresses;
@ -889,81 +1034,48 @@ public class InetAddress implements java.io.Serializable {
} }
/** /**
* NameService provides host and address lookup service * The default InetAddressResolver implementation, which delegates to the underlying
*
* @since 9
*/
private interface NameService {
/**
* Lookup a host mapping by name. Retrieve the IP addresses
* associated with a host
*
* @param host the specified hostname
* @return array of IP addresses for the requested host
* @throws UnknownHostException
* if no IP address for the {@code host} could be found
*/
InetAddress[] lookupAllHostAddr(String host)
throws UnknownHostException;
/**
* Lookup the host corresponding to the IP address provided
*
* @param addr byte array representing an IP address
* @return {@code String} representing the host name mapping
* @throws UnknownHostException
* if no host found for the specified IP address
*/
String getHostByAddr(byte[] addr) throws UnknownHostException;
}
/**
* The default NameService implementation, which delegates to the underlying
* OS network libraries to resolve host address mappings. * OS network libraries to resolve host address mappings.
* *
* @since 9 * @since 9
*/ */
private static final class PlatformNameService implements NameService { private static final class PlatformResolver implements InetAddressResolver {
public InetAddress[] lookupAllHostAddr(String host) public Stream<InetAddress> lookupByName(String host, LookupPolicy policy)
throws UnknownHostException throws UnknownHostException {
{ Objects.requireNonNull(host);
return impl.lookupAllHostAddr(host); Objects.requireNonNull(policy);
return Arrays.stream(impl.lookupAllHostAddr(host, policy));
} }
public String getHostByAddr(byte[] addr) public String lookupByAddress(byte[] addr)
throws UnknownHostException throws UnknownHostException {
{ Objects.requireNonNull(addr);
if (addr.length != Inet4Address.INADDRSZ && addr.length != Inet6Address.INADDRSZ) {
throw new IllegalArgumentException("Invalid address length");
}
return impl.getHostByAddr(addr); 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 * by reading the entries in a hosts file, which is specified by
* {@code jdk.net.hosts.file} system property * {@code jdk.net.hosts.file} system property
* *
* <p>The file format is that which corresponds with the /etc/hosts file * <p>The file format is that which corresponds with the /etc/hosts file
* IP Address host alias list. * 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 * implementation
* *
* @since 9 * @since 9
*/ */
private static final class HostsFileNameService implements NameService { private static final class HostsFileResolver implements InetAddressResolver {
private static final InetAddress[] EMPTY_ARRAY = new InetAddress[0];
// Specify if only IPv4 addresses should be returned by HostsFileService implementation
private static final boolean preferIPv4Stack = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("java.net.preferIPv4Stack"));
private final String hostsFile; private final String hostsFile;
public HostsFileNameService(String hostsFileName) { public HostsFileResolver(String hostsFileName) {
this.hostsFile = hostsFileName; this.hostsFile = hostsFileName;
} }
@ -974,17 +1086,22 @@ public class InetAddress implements java.io.Serializable {
* *
* @param addr byte array representing an IP address * @param addr byte array representing an IP address
* @return {@code String} representing the host name mapping * @return {@code String} representing the host name mapping
* @throws UnknownHostException * @throws UnknownHostException if no host found for the specified IP address
* 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 @Override
public String getHostByAddr(byte[] addr) throws UnknownHostException { public String lookupByAddress(byte[] addr) throws UnknownHostException {
String hostEntry; String hostEntry;
String host = null; 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), try (Scanner hostsFileScanner = new Scanner(new File(hostsFile),
UTF_8.INSTANCE)) UTF_8.INSTANCE)) {
{
while (hostsFileScanner.hasNextLine()) { while (hostsFileScanner.hasNextLine()) {
hostEntry = hostsFileScanner.nextLine(); hostEntry = hostsFileScanner.nextLine();
if (!hostEntry.startsWith("#")) { if (!hostEntry.startsWith("#")) {
@ -1020,22 +1137,31 @@ public class InetAddress implements java.io.Serializable {
* with the specified host name. * with the specified host name.
* *
* @param host the specified hostname * @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 * @throws UnknownHostException
* if no IP address for the {@code host} could be found * 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 { throws UnknownHostException {
String hostEntry; String hostEntry;
String addrStr; String addrStr;
byte addr[]; byte addr[];
Objects.requireNonNull(host);
Objects.requireNonNull(lookupPolicy);
List<InetAddress> inetAddresses = new ArrayList<>(); List<InetAddress> inetAddresses = new ArrayList<>();
List<InetAddress> inet4Addresses = new ArrayList<>(); List<InetAddress> inet4Addresses = new ArrayList<>();
List<InetAddress> inet6Addresses = 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 // lookup the file and create a list InetAddress for the specified host
try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), try (Scanner hostsFileScanner = new Scanner(new File(hostsFile),
UTF_8.INSTANCE)) { UTF_8.INSTANCE)) {
while (hostsFileScanner.hasNextLine()) { while (hostsFileScanner.hasNextLine()) {
hostEntry = hostsFileScanner.nextLine(); hostEntry = hostsFileScanner.nextLine();
if (!hostEntry.startsWith("#")) { if (!hostEntry.startsWith("#")) {
@ -1047,10 +1173,10 @@ public class InetAddress implements java.io.Serializable {
if (addr != null) { if (addr != null) {
InetAddress address = InetAddress.getByAddress(host, addr); InetAddress address = InetAddress.getByAddress(host, addr);
inetAddresses.add(address); inetAddresses.add(address);
if (address instanceof Inet4Address) { if (address instanceof Inet4Address && needIPv4) {
inet4Addresses.add(address); inet4Addresses.add(address);
} }
if (address instanceof Inet6Address) { if (address instanceof Inet6Address && needIPv6) {
inet6Addresses.add(address); inet6Addresses.add(address);
} }
} }
@ -1062,33 +1188,38 @@ public class InetAddress implements java.io.Serializable {
throw new UnknownHostException("Unable to resolve host " + host throw new UnknownHostException("Unable to resolve host " + host
+ " as hosts file " + hostsFile + " not found "); + " as hosts file " + hostsFile + " not found ");
} }
// Check if only IPv4 addresses are requested
List<InetAddress> res; if (needIPv4 && !needIPv6) {
// If "preferIPv4Stack" system property is set to "true" then return checkResultsList(inet4Addresses, host);
// only IPv4 addresses return inet4Addresses.stream();
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 IPv6 addresses are requested
if (res.isEmpty()) { if (!needIPv4 && needIPv6) {
throw new UnknownHostException("Unable to resolve host " + host checkResultsList(inet6Addresses, host);
+ " in hosts file " + hostsFile); 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, // Checks if result list with addresses is not empty.
List<InetAddress> secondPart) { // If it is empty throw an UnknownHostException.
List<InetAddress> result = new ArrayList<>(firstPart); private void checkResultsList(List<InetAddress> addressesList, String hostName)
result.addAll(secondPart); throws UnknownHostException {
return result; if (addressesList.isEmpty()) {
throw new UnknownHostException("Unable to resolve host " + hostName
+ " in hosts file " + hostsFile);
}
} }
private String removeComments(String hostsEntry) { private String removeComments(String hostsEntry) {
@ -1130,45 +1261,52 @@ public class InetAddress implements java.io.Serializable {
static final InetAddressImpl impl; 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 { static {
// create the impl // create the impl
impl = InetAddressImplFactory.create(); impl = InetAddressImplFactory.create();
// create name service // impl must be initialized before calling this method
nameService = createNameService(); 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. * 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 * delegates name and address resolution calls to the underlying
* OS network libraries. * 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 * system property is set. If the specified file doesn't exist, the name or
* address lookup will result in an UnknownHostException. Thus, non existent * address lookup will result in an UnknownHostException. Thus, non existent
* hosts file is handled as if the file is empty. * hosts file is handled as if the file is empty.
* *
* @return a NameService * @return an InetAddressResolver
*/ */
private static NameService createNameService() { private static InetAddressResolver createBuiltinInetAddressResolver() {
InetAddressResolver theResolver;
String hostsFileName = if (HOSTS_FILE_NAME != null) {
GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file"); theResolver = new HostsFileResolver(HOSTS_FILE_NAME);
NameService theNameService;
if (hostsFileName != null) {
theNameService = new HostsFileNameService(hostsFileName);
} else { } else {
theNameService = new PlatformNameService(); theResolver = new PlatformResolver();
} }
return theNameService; return theResolver;
} }
/** /**
* Creates an InetAddress based on the provided host name and IP address. * 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 * <p> The host name can either be a machine name, such as
* "{@code www.example.com}", or a textual representation of its IP * "{@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]; 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, * 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 * <p> The host name can either be a machine name, such as
* "{@code www.example.com}", or a textual representation of its IP * "{@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) public static InetAddress[] getAllByName(String host)
throws UnknownHostException { throws UnknownHostException {
return getAllByName(host, null);
}
private static InetAddress[] getAllByName(String host, InetAddress reqAddr)
throws UnknownHostException {
if (host == null || host.isEmpty()) { if (host == null || host.isEmpty()) {
InetAddress[] ret = new InetAddress[1]; 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 // We were expecting an IPv6 Literal, but got something else
throw new UnknownHostException("["+host+"]"); 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; return zone;
} }
private static InetAddress[] getAllByName0 (String host)
throws UnknownHostException
{
return getAllByName0(host, true);
}
/** /**
* package private so SocketPermission can call it * package private so SocketPermission can call it
*/ */
static InetAddress[] getAllByName0 (String host, boolean check) static InetAddress[] getAllByName0 (String host, boolean check)
throws UnknownHostException { throws UnknownHostException {
return getAllByName0 (host, null, check, true); return getAllByName0(host, check, true);
} }
/** /**
* Designated lookup method. * Designated lookup method.
* *
* @param host host name to look up * @param host host name to look up
* @param reqAddr requested address to be the 1st in returned array
* @param check perform security check * @param check perform security check
* @param useCache use cached value if not expired else always * @param useCache use cached value if not expired else always
* perform name service lookup (and cache the result) * 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 * @throws UnknownHostException if host name is not found
*/ */
private static InetAddress[] getAllByName0(String host, private static InetAddress[] getAllByName0(String host,
InetAddress reqAddr,
boolean check, boolean check,
boolean useCache) boolean useCache)
throws UnknownHostException { throws UnknownHostException {
@ -1498,7 +1617,7 @@ public class InetAddress implements java.io.Serializable {
// the name service and install it within cache... // the name service and install it within cache...
Addresses oldAddrs = cache.putIfAbsent( Addresses oldAddrs = cache.putIfAbsent(
host, host,
addrs = new NameServiceAddresses(host, reqAddr) addrs = new NameServiceAddresses(host)
); );
if (oldAddrs != null) { // lost putIfAbsent race if (oldAddrs != null) { // lost putIfAbsent race
addrs = oldAddrs; addrs = oldAddrs;
@ -1509,47 +1628,30 @@ public class InetAddress implements java.io.Serializable {
return addrs.get().clone(); return addrs.get().clone();
} }
static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr) static InetAddress[] getAddressesFromNameService(String host)
throws UnknownHostException { throws UnknownHostException {
InetAddress[] addresses = null; Stream<InetAddress> addresses = null;
UnknownHostException ex = null; UnknownHostException ex = null;
var resolver = resolver();
try { try {
addresses = nameService.lookupAllHostAddr(host); addresses = resolver.lookupByName(host, PLATFORM_LOOKUP_POLICY);
} catch (UnknownHostException uhe) { } catch (RuntimeException | UnknownHostException x) {
if (host.equalsIgnoreCase("localhost")) { if (host.equalsIgnoreCase("localhost")) {
addresses = new InetAddress[]{impl.loopbackAddress()}; addresses = Stream.of(impl.loopbackAddress());
} else { } else if (x instanceof UnknownHostException uhe) {
ex = uhe; ex = uhe;
} else {
ex = new UnknownHostException();
ex.initCause(x);
} }
} }
InetAddress[] result = addresses == null ? null
if (addresses == null) { : addresses.toArray(InetAddress[]::new);
if (result == null || result.length == 0) {
throw ex == null ? new UnknownHostException(host) : ex; throw ex == null ? new UnknownHostException(host) : ex;
} }
return result;
// 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;
} }
/** /**
@ -1557,8 +1659,7 @@ public class InetAddress implements java.io.Serializable {
* The argument is in network byte order: the highest order * The argument is in network byte order: the highest order
* byte of the address is in {@code getAddress()[0]}. * byte of the address is in {@code getAddress()[0]}.
* *
* <p> This method doesn't block, i.e. no reverse name service lookup * <p> This method doesn't block, i.e. no reverse lookup is performed.
* is performed.
* *
* <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
* must be 16 bytes long * must be 16 bytes long
@ -1637,7 +1738,7 @@ public class InetAddress implements java.io.Serializable {
// call getAllByName0 without security checks and // call getAllByName0 without security checks and
// without using cached data // without using cached data
try { try {
localAddr = getAllByName0(local, null, false, false)[0]; localAddr = getAllByName0(local, false, false)[0];
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
// Rethrow with a more informative error message. // Rethrow with a more informative error message.
UnknownHostException uhe2 = UnknownHostException uhe2 =

View file

@ -24,7 +24,10 @@
*/ */
package java.net; package java.net;
import java.io.IOException; import java.io.IOException;
import java.net.spi.InetAddressResolver.LookupPolicy;
/* /*
* Package private interface to "implementation" used by * Package private interface to "implementation" used by
* {@link InetAddress}. * {@link InetAddress}.
@ -38,7 +41,7 @@ sealed interface InetAddressImpl permits Inet4AddressImpl, Inet6AddressImpl {
String getLocalHostName() throws UnknownHostException; String getLocalHostName() throws UnknownHostException;
InetAddress[] InetAddress[]
lookupAllHostAddr(String hostname) throws UnknownHostException; lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy) throws UnknownHostException;
String getHostByAddr(byte[] addr) throws UnknownHostException; String getHostByAddr(byte[] addr) throws UnknownHostException;
InetAddress anyLocalAddress(); InetAddress anyLocalAddress();

View file

@ -1,6 +1,6 @@
<!DOCTYPE HTML> <!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. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it 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 (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 change that preference and use IPv6 addresses over IPv4 ones where
possible, or <B>system</B> to preserve the order of the addresses as 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> </UL>
<P>Both of these properties are checked only once, at startup.</P> <P>Both of these properties are checked only once, at startup.</P>
<a id="Proxies"></a> <a id="Proxies"></a>

View file

@ -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;
}
}
}

View file

@ -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();
}
}

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. * Service-provider classes for the {@link java.net} package.
* *
* <p> Only developers who are defining new URL stream handler providers * <p> Only developers who are defining new URL stream handler providers or implementing
* should need to make direct use of this package. * a custom resolver provider should need to make direct use of this package.
* *
* @since 9 * @since 9
*/ */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2019, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,6 @@ package jdk.internal.access;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException;
public interface JavaNetInetAddressAccess { public interface JavaNetInetAddressAccess {
/** /**
@ -37,15 +36,6 @@ public interface JavaNetInetAddressAccess {
*/ */
String getOriginalHostName(InetAddress ia); String getOriginalHostName(InetAddress ia);
/**
* Get the InetAddress of the provided host. If an InetAddress is provided
* then it will be the default address returned for all calls to either
* form of getByName. This is required to maintain consistency when
* caching addresses and hostnames.
*/
InetAddress getByName(String hostName, InetAddress hostAddress)
throws UnknownHostException;
/** /**
* Returns the 32-bit IPv4 address. * Returns the 32-bit IPv4 address.
*/ */

View file

@ -369,6 +369,7 @@ module java.base {
uses java.lang.System.LoggerFinder; uses java.lang.System.LoggerFinder;
uses java.net.ContentHandlerFactory; uses java.net.ContentHandlerFactory;
uses java.net.spi.InetAddressResolverProvider;
uses java.net.spi.URLStreamHandlerProvider; uses java.net.spi.URLStreamHandlerProvider;
uses java.nio.channels.spi.AsynchronousChannelProvider; uses java.nio.channels.spi.AsynchronousChannelProvider;
uses java.nio.channels.spi.SelectorProvider; uses java.nio.channels.spi.SelectorProvider;

View file

@ -0,0 +1,53 @@
/*
* 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 sun.net;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.function.Supplier;
public final class ResolverProviderConfiguration implements
InetAddressResolverProvider.Configuration {
private final InetAddressResolver builtinResolver;
private final Supplier<String> localHostNameSupplier;
public ResolverProviderConfiguration(InetAddressResolver builtinResolver,
Supplier<String> localHostNameSupplier) {
this.builtinResolver = builtinResolver;
this.localHostNameSupplier = localHostNameSupplier;
}
@Override
public InetAddressResolver builtinResolver() {
return builtinResolver;
}
@Override
public String lookupLocalHostName() {
return localHostNameSupplier.get();
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,6 @@ jfieldID iac_addressID;
jfieldID iac_familyID; jfieldID iac_familyID;
jfieldID iac_hostNameID; jfieldID iac_hostNameID;
jfieldID iac_origHostNameID; jfieldID iac_origHostNameID;
jfieldID ia_preferIPv6AddressID;
static int ia_initialized = 0; static int ia_initialized = 0;
@ -61,8 +60,6 @@ Java_java_net_InetAddress_init(JNIEnv *env, jclass cls) {
CHECK_NULL(iac_class); CHECK_NULL(iac_class);
ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;"); ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;");
CHECK_NULL(ia_holderID); CHECK_NULL(ia_holderID);
ia_preferIPv6AddressID = (*env)->GetStaticFieldID(env, ia_class, "preferIPv6Address", "I");
CHECK_NULL(ia_preferIPv6AddressID);
iac_addressID = (*env)->GetFieldID(env, iac_class, "address", "I"); iac_addressID = (*env)->GetFieldID(env, iac_class, "address", "I");
CHECK_NULL(iac_addressID); CHECK_NULL(iac_addressID);
@ -75,3 +72,12 @@ Java_java_net_InetAddress_init(JNIEnv *env, jclass cls) {
ia_initialized = 1; ia_initialized = 1;
} }
} }
/*
* Class: java_net_InetAddress
* Method: isIPv4Available
*/
JNIEXPORT jboolean JNICALL
Java_java_net_InetAddress_isIPv4Available(JNIEnv *env, jclass clazz) {
return ipv4_available();
}

View file

@ -26,6 +26,7 @@
#include "net_util.h" #include "net_util.h"
#include "java_net_InetAddress.h" #include "java_net_InetAddress.h"
#include "java_net_spi_InetAddressResolver_LookupPolicy.h"
int IPv4_supported(); int IPv4_supported();
int IPv6_supported(); int IPv6_supported();
@ -332,3 +333,23 @@ in_cksum(unsigned short *addr, int len) {
answer = ~sum; answer = ~sum;
return (answer); return (answer);
} }
int lookupCharacteristicsToAddressFamily(int characteristics) {
int ipv4 = characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4;
int ipv6 = characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6;
if (ipv4 != 0 && ipv6 == 0) {
return AF_INET;
}
if (ipv4 == 0 && ipv6 != 0) {
return AF_INET6;
}
return AF_UNSPEC;
}
int addressesInSystemOrder(int characteristics) {
return (characteristics &
(java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST |
java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST)) == 0;
}

View file

@ -51,7 +51,6 @@ extern jfieldID iac_addressID;
extern jfieldID iac_familyID; extern jfieldID iac_familyID;
extern jfieldID iac_hostNameID; extern jfieldID iac_hostNameID;
extern jfieldID iac_origHostNameID; extern jfieldID iac_origHostNameID;
extern jfieldID ia_preferIPv6AddressID;
JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env); JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env);
@ -192,4 +191,8 @@ unsigned short in_cksum(unsigned short *addr, int len);
jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
int lookupCharacteristicsToAddressFamily(int characteristics);
int addressesInSystemOrder(int characteristics);
#endif /* NET_UTILS_H */ #endif /* NET_UTILS_H */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -36,9 +36,11 @@
#include "net_util.h" #include "net_util.h"
#include "java_net_Inet4AddressImpl.h" #include "java_net_Inet4AddressImpl.h"
#include "java_net_spi_InetAddressResolver_LookupPolicy.h"
#if defined(MACOSX) #if defined(MACOSX)
extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6); extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6,
int addressesOrder);
#endif #endif
#define SET_NONBLOCKING(fd) { \ #define SET_NONBLOCKING(fd) { \
@ -111,7 +113,9 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
if (error) { if (error) {
#if defined(MACOSX) #if defined(MACOSX)
// If getaddrinfo fails try getifaddrs, see bug 8170910. // If getaddrinfo fails try getifaddrs, see bug 8170910.
ret = lookupIfLocalhost(env, hostname, JNI_FALSE); // java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST and no ordering is ok
// here since only AF_INET addresses will be returned.
ret = lookupIfLocalhost(env, hostname, JNI_FALSE, java_net_spi_InetAddressResolver_LookupPolicy_IPV4);
if (ret != NULL || (*env)->ExceptionCheck(env)) { if (ret != NULL || (*env)->ExceptionCheck(env)) {
goto cleanupAndReturn; goto cleanupAndReturn;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -41,6 +41,8 @@
#include "java_net_InetAddress.h" #include "java_net_InetAddress.h"
#include "java_net_Inet4AddressImpl.h" #include "java_net_Inet4AddressImpl.h"
#include "java_net_Inet6AddressImpl.h" #include "java_net_Inet6AddressImpl.h"
#include "java_net_spi_InetAddressResolver_LookupPolicy.h"
#define SET_NONBLOCKING(fd) { \ #define SET_NONBLOCKING(fd) { \
int flags = fcntl(fd, F_GETFL); \ int flags = fcntl(fd, F_GETFL); \
@ -74,7 +76,7 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
#if defined(MACOSX) #if defined(MACOSX)
/* also called from Inet4AddressImpl.c */ /* also called from Inet4AddressImpl.c */
__private_extern__ jobjectArray __private_extern__ jobjectArray
lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6) lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6, int characteristics)
{ {
jobjectArray result = NULL; jobjectArray result = NULL;
char myhostname[NI_MAXHOST + 1]; char myhostname[NI_MAXHOST + 1];
@ -151,7 +153,7 @@ lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL); result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
if (!result) goto done; if (!result) goto done;
if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) { if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks); i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
j = 0; j = 0;
} else { } else {
@ -204,7 +206,7 @@ lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
*/ */
JNIEXPORT jobjectArray JNICALL JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
jstring host) { jstring host, jint characteristics) {
jobjectArray ret = NULL; jobjectArray ret = NULL;
const char *hostname; const char *hostname;
int error = 0; int error = 0;
@ -224,14 +226,14 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
// try once, with our static buffer // try once, with our static buffer
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME; hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC; hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics);
error = getaddrinfo(hostname, NULL, &hints, &res); error = getaddrinfo(hostname, NULL, &hints, &res);
if (error) { if (error) {
#if defined(MACOSX) #if defined(MACOSX)
// if getaddrinfo fails try getifaddrs // if getaddrinfo fails try getifaddrs
ret = lookupIfLocalhost(env, hostname, JNI_TRUE); ret = lookupIfLocalhost(env, hostname, JNI_TRUE, characteristics);
if (ret != NULL || (*env)->ExceptionCheck(env)) { if (ret != NULL || (*env)->ExceptionCheck(env)) {
goto cleanupAndReturn; goto cleanupAndReturn;
} }
@ -242,8 +244,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
} else { } else {
int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
inet6Index = 0, originalIndex = 0; inet6Index = 0, originalIndex = 0;
int addressPreference =
(*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);;
iterator = res; iterator = res;
while (iterator != NULL) { while (iterator != NULL) {
// skip duplicates // skip duplicates
@ -322,13 +322,13 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
goto cleanupAndReturn; goto cleanupAndReturn;
} }
if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) { if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
inetIndex = inet6Count; inetIndex = inet6Count;
inet6Index = 0; inet6Index = 0;
} else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) { } else if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST) != 0) {
inetIndex = 0; inetIndex = 0;
inet6Index = inetCount; inet6Index = inetCount;
} else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { } else {
inetIndex = inet6Index = originalIndex = 0; inetIndex = inet6Index = originalIndex = 0;
} }
@ -371,7 +371,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
(*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj); (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
inet6Index++; inet6Index++;
} }
if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { // Check if addresses are requested to be returned in SYSTEM order
if (addressesInSystemOrder(characteristics)) {
originalIndex++; originalIndex++;
inetIndex = inet6Index = 0; inetIndex = inet6Index = 0;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@
#include "java_net_InetAddress.h" #include "java_net_InetAddress.h"
#include "java_net_Inet4AddressImpl.h" #include "java_net_Inet4AddressImpl.h"
#include "java_net_Inet6AddressImpl.h" #include "java_net_Inet6AddressImpl.h"
#include "java_net_spi_InetAddressResolver_LookupPolicy.h"
/* /*
* Inet6AddressImpl * Inet6AddressImpl
@ -56,7 +57,7 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
*/ */
JNIEXPORT jobjectArray JNICALL JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
jstring host) { jstring host, jint characteristics) {
jobjectArray ret = NULL; jobjectArray ret = NULL;
const char *hostname; const char *hostname;
int error = 0; int error = 0;
@ -76,7 +77,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
// try once, with our static buffer // try once, with our static buffer
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME; hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC; hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics);
error = getaddrinfo(hostname, NULL, &hints, &res); error = getaddrinfo(hostname, NULL, &hints, &res);
@ -88,8 +89,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
} else { } else {
int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
inet6Index = 0, originalIndex = 0; inet6Index = 0, originalIndex = 0;
int addressPreference =
(*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);
iterator = res; iterator = res;
while (iterator != NULL) { while (iterator != NULL) {
// skip duplicates // skip duplicates
@ -168,13 +167,13 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
goto cleanupAndReturn; goto cleanupAndReturn;
} }
if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) { if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
inetIndex = inet6Count; inetIndex = inet6Count;
inet6Index = 0; inet6Index = 0;
} else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) { } else if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST) != 0) {
inetIndex = 0; inetIndex = 0;
inet6Index = inetCount; inet6Index = inetCount;
} else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { } else {
inetIndex = inet6Index = originalIndex = 0; inetIndex = inet6Index = originalIndex = 0;
} }
@ -217,7 +216,8 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
(*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj); (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
inet6Index++; inet6Index++;
} }
if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { // Check if addresses are requested to be returned in SYSTEM order
if (addressesInSystemOrder(characteristics)) {
originalIndex++; originalIndex++;
inetIndex = inet6Index = 0; inetIndex = inet6Index = 0;
} }

View file

@ -0,0 +1,104 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.testng.Assert;
import org.testng.annotations.Test;
import impl.SimpleResolverProviderImpl;
/*
* @test
* @summary Test that InetAddress caching security properties work as expected
* when a custom resolver is installed.
* @library lib providers/simple
* @build test.library/testlib.ResolutionRegistry
* simple.provider/impl.SimpleResolverProviderImpl AddressesCachingTest
* @run testng/othervm -Djava.security.properties=${test.src}/NeverCache.props
* -Dtest.cachingDisabled=true AddressesCachingTest
* @run testng/othervm -Djava.security.properties=${test.src}/ForeverCache.props
* -Dtest.cachingDisabled=false AddressesCachingTest
*/
public class AddressesCachingTest {
@Test
public void testPositiveCaching() {
boolean observedTwoLookups = performLookups(false);
if (CACHING_DISABLED) {
Assert.assertTrue(observedTwoLookups,
"Two positive lookups are expected with caching disabled");
} else {
Assert.assertFalse(observedTwoLookups,
"Only one positive lookup is expected with caching enabled");
}
}
@Test
public void testNegativeCaching() {
boolean observedTwoLookups = performLookups(true);
if (CACHING_DISABLED) {
Assert.assertTrue(observedTwoLookups,
"Two negative lookups are expected with caching disabled");
} else {
Assert.assertFalse(observedTwoLookups,
"Only one negative lookup is expected with caching enabled");
}
}
/*
* Performs two subsequent positive or negative lookups.
* Returns true if the timestamp of this lookups differs,
* false otherwise.
*/
private static boolean performLookups(boolean performNegativeLookup) {
doLookup(performNegativeLookup);
long firstTimestamp = SimpleResolverProviderImpl.getLastLookupTimestamp();
doLookup(performNegativeLookup);
long secondTimestamp = SimpleResolverProviderImpl.getLastLookupTimestamp();
return firstTimestamp != secondTimestamp;
}
// Performs negative or positive lookup.
// It is a test error if UnknownHostException is thrown during positive lookup.
// It is a test error if UnknownHostException is NOT thrown during negative lookup.
private static void doLookup(boolean performNegativeLookup) {
String hostName = performNegativeLookup ? "notKnowHost.org" : "javaTest.org";
try {
InetAddress.getByName(hostName);
if (performNegativeLookup) {
Assert.fail("Host name is expected to get unresolved");
}
} catch (UnknownHostException uhe) {
if (!performNegativeLookup) {
Assert.fail("Host name is expected to get resolved");
}
}
}
// Helper system property that signals to the test if both negative and positive
// caches are disabled.
private static final boolean CACHING_DISABLED = Boolean.getBoolean("test.cachingDisabled");
}

View file

@ -0,0 +1,49 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import org.testng.Assert;
import org.testng.annotations.Test;
import static impl.WithBootstrapResolverUsageProvider.numberOfGetCalls;
/**
* @test
* @summary Test that InetAddress class properly avoids stack-overflow by
* correctly tracking the bootstrap resolver instance when
* InetAddressResolverProvider.get method uses InetAddress lookup API.
* @library providers/bootstrapUsage
* @build bootstrap.usage.provider/impl.WithBootstrapResolverUsageProvider
* @run testng/othervm BootstrapResolverUsageTest
*/
public class BootstrapResolverUsageTest {
@Test
public void testSuccessfulProviderInstantiationTest() throws Exception {
System.err.println(InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()));
Assert.assertEquals(numberOfGetCalls, 1,
"InetAddressResolverProvider.get was called more than once");
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.
*
* 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.
*/
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import static org.testng.Assert.*;
/*
* @test
* @summary white-box test to check that the built-in resolver
* is used by default.
* @modules java.base/java.net:open
* @run testng/othervm BuiltInResolverTest
*/
public class BuiltInResolverTest {
private Field builtInResolverField, resolverField;
@BeforeTest
public void beforeTest() throws NoSuchFieldException {
Class<InetAddress> inetAddressClass = InetAddress.class;
// Needs to happen for InetAddress.resolver to be initialized
try {
InetAddress.getByName("test");
} catch (UnknownHostException e) {
// Do nothing, only want to assign resolver
}
builtInResolverField = inetAddressClass.getDeclaredField("BUILTIN_RESOLVER");
builtInResolverField.setAccessible(true);
resolverField = inetAddressClass.getDeclaredField("resolver");
resolverField.setAccessible(true);
}
@Test
public void testDefaultNSContext() throws IllegalAccessException {
// Test that the resolver used by default is the BUILTIN_RESOLVER
Object defaultResolverObject = builtInResolverField.get(InetAddressResolver.class);
Object usedResolverObject = resolverField.get(InetAddressResolver.class);
assertTrue(defaultResolverObject == usedResolverObject);
String defaultClassName = defaultResolverObject.getClass().getCanonicalName();
String currentClassName = usedResolverObject.getClass().getCanonicalName();
assertNotNull(defaultClassName, "defaultClassName not set");
assertNotNull(currentClassName, "currentClassName name not set");
assertEquals(currentClassName, defaultClassName,
"BUILTIN_RESOLVER resolver was not used.");
System.err.println("Resolver used by default is the built-in resolver");
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.
*
* 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.
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
/*
* @test
* @summary checks that InetAddress forward lookup API throw UnknownHostException
* when resolver returns empty address stream.
* @library providers/empty
* @build empty.results.provider/impl.EmptyResultsProviderImpl
* @run testng/othervm EmptyResultsStreamTest
*/
public class EmptyResultsStreamTest {
@Test(expectedExceptions = UnknownHostException.class)
public void getAllByNameTest() throws UnknownHostException {
System.err.println("getAllByName unexpectedly completed: " +
Arrays.deepToString(InetAddress.getAllByName("test1.org")));
}
@Test(expectedExceptions = UnknownHostException.class)
public void getByNameTest() throws UnknownHostException {
System.err.println("getByName unexpectedly completed: " +
InetAddress.getByName("test2.org"));
}
}

View file

@ -0,0 +1,2 @@
networkaddress.cache.ttl=-1
networkaddress.cache.negative.ttl=-1

View file

@ -0,0 +1,44 @@
/*
* 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.
*
* 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.
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import java.net.InetAddress;
/**
* @test
* @summary Test that provider which uses InetAddress APIs during its initialization
* wouldn't cause stack overflow and will be successfully installed.
* @library providers/recursive
* @build recursive.init.provider/impl.InetAddressUsageInGetProviderImpl
* @run testng/othervm InetAddressUsageInGetProviderTest
*/
public class InetAddressUsageInGetProviderTest {
@Test
public void testSuccessfulProviderInstantiationTest() throws Exception {
System.err.println(InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()));
}
}

View file

@ -0,0 +1,172 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
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;
import jdk.test.lib.net.IPSupport;
import jdk.test.lib.NetworkConfiguration;
import org.testng.annotations.Test;
import org.testng.Assert;
import org.testng.SkipException;
/*
* @test
* @summary Test that platform lookup characteristic value is correctly initialized from
* system properties affecting order and type of queried addresses.
* @library lib providers/simple /test/lib
* @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl
* jdk.test.lib.net.IPSupport LookupPolicyMappingTest
* @run testng/othervm LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=true LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack=false LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack -Djava.net.preferIPv6Addresses LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv4Stack LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv6Addresses=true LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv6Addresses=false LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv6Addresses=system LookupPolicyMappingTest
* @run testng/othervm -Djava.net.preferIPv6Addresses LookupPolicyMappingTest
*/
public class LookupPolicyMappingTest {
@Test
public void testSystemProperties() throws Exception {
// Check if platform network configuration matches the test requirements,
// if not throw a SkipException
checkPlatformNetworkConfiguration();
System.err.println("javaTest.org resolved to:" + Arrays.deepToString(
InetAddress.getAllByName("javaTest.org")));
// Acquire runtime characteristics from the test NSP
int runtimeCharacteristics = impl.SimpleResolverProviderImpl.lastLookupPolicy().characteristics();
// Calculate expected lookup policy characteristic
String preferIPv4Stack = System.getProperty("java.net.preferIPv4Stack");
String preferIPv6Addresses = System.getProperty("java.net.preferIPv6Addresses");
String expectedResultsKey = calculateMapKey(preferIPv4Stack, preferIPv6Addresses);
int expectedCharacteristics = EXPECTED_RESULTS_MAP.get(expectedResultsKey);
Assert.assertTrue(characteristicsMatch(
runtimeCharacteristics, expectedCharacteristics), "Unexpected LookupPolicy observed");
}
// Throws SkipException if platform doesn't support required IP address types
static void checkPlatformNetworkConfiguration() {
IPSupport.throwSkippedExceptionIfNonOperational();
IPSupport.printPlatformSupport(System.err);
NetworkConfiguration.printSystemConfiguration(System.err);
// If preferIPv4=true and no IPv4 - skip
if (IPSupport.preferIPv4Stack()) {
if (!IPSupport.hasIPv4()) {
throw new SkipException("Skip tests - IPv4 support required");
}
return;
}
}
record ExpectedResult(String ipv4stack, String ipv6addresses, int characteristics) {
ExpectedResult {
if (!IPSupport.hasIPv4()) {
characteristics = IPV6;
} else if (!IPSupport.hasIPv6()) {
characteristics = IPV4;
}
}
public String key() {
return calculateMapKey(ipv4stack, ipv6addresses);
}
}
/*
* Each row describes a combination of 'preferIPv4Stack', 'preferIPv6Addresses'
* values and the expected characteristic value
*/
private static List<ExpectedResult> EXPECTED_RESULTS_TABLE = List.of(
new ExpectedResult("true", "true", IPV4),
new ExpectedResult("true", "false", IPV4),
new ExpectedResult("true", "system", IPV4),
new ExpectedResult("true", "", IPV4),
new ExpectedResult("true", null, IPV4),
new ExpectedResult("false", "true", IPV4 | IPV6 | IPV6_FIRST),
new ExpectedResult("false", "false", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult("false", "system", IPV4 | IPV6),
new ExpectedResult("false", "", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult("false", null, IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult("", "true", IPV4 | IPV6 | IPV6_FIRST),
new ExpectedResult("", "false", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult("", "system", IPV4 | IPV6),
new ExpectedResult("", "", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult("", null, IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult(null, "true", IPV4 | IPV6 | IPV6_FIRST),
new ExpectedResult(null, "false", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult(null, "system", IPV4 | IPV6),
new ExpectedResult(null, "", IPV4 | IPV6 | IPV4_FIRST),
new ExpectedResult(null, null, IPV4 | IPV6 | IPV4_FIRST));
private static final Map<String, Integer> EXPECTED_RESULTS_MAP = calculateExpectedCharacteristics();
private static Map<String, Integer> calculateExpectedCharacteristics() {
return EXPECTED_RESULTS_TABLE.stream()
.collect(Collectors.toUnmodifiableMap(
ExpectedResult::key,
ExpectedResult::characteristics)
);
}
private static String calculateMapKey(String ipv4stack, String ipv6addresses) {
return ipv4stack + "_" + ipv6addresses;
}
private static boolean characteristicsMatch(int actual, int expected) {
System.err.printf("Comparing characteristics:%n\tActual: %s%n\tExpected: %s%n",
Integer.toBinaryString(actual),
Integer.toBinaryString(expected));
return (actual & (IPV4 | IPV6 | IPV4_FIRST | IPV6_FIRST)) == expected;
}
}

View file

@ -0,0 +1,88 @@
/*
* 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.
*
* 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.
*/
/*
* @test
* @summary check if LookupPolicy.of correctly handles valid and illegal
* combinations of characteristics bit mask flags.
* @run testng LookupPolicyOfTest
*/
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.net.spi.InetAddressResolver.LookupPolicy;
import java.util.List;
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;
public class LookupPolicyOfTest {
@Test(dataProvider = "validCharacteristics")
public void testValidCharacteristicCombinations(List<Integer> validCombination) {
LookupPolicy.of(bitFlagsToCharacteristicsValue(validCombination));
}
@Test(dataProvider = "invalidCharacteristics", expectedExceptions = IllegalArgumentException.class)
public void testInvalidCharacteristicCombinations(List<Integer> invalidCombination) {
LookupPolicy.of(bitFlagsToCharacteristicsValue(invalidCombination));
}
@DataProvider(name = "validCharacteristics")
public Object[][] validCharacteristicValue() {
return new Object[][]{
{List.of(IPV4)},
{List.of(IPV4, IPV4_FIRST)},
{List.of(IPV6)},
{List.of(IPV6, IPV6_FIRST)},
{List.of(IPV4, IPV6)},
{List.of(IPV4, IPV6, IPV4_FIRST)},
{List.of(IPV4, IPV6, IPV6_FIRST)},
// Custom flag values alongside to address type flags
// that could be used by custom providers
{List.of(IPV4, IPV6, 0x10)},
{List.of(IPV4, IPV6, 0x20)},
};
}
@DataProvider(name = "invalidCharacteristics")
public Object[][] illegalCharacteristicValue() {
return new Object[][]{
{List.of()},
{List.of(IPV4_FIRST)},
{List.of(IPV6_FIRST)},
{List.of(IPV4_FIRST, IPV6_FIRST)},
{List.of(IPV4, IPV6_FIRST)},
{List.of(IPV6, IPV4_FIRST)},
{List.of(IPV4, IPV6, IPV4_FIRST, IPV6_FIRST)},
};
}
private static int bitFlagsToCharacteristicsValue(List<Integer> bitFlagsList) {
return bitFlagsList.stream()
.reduce(0, (flag1, flag2) -> flag1 | flag2);
}
}

View file

@ -0,0 +1,2 @@
networkaddress.cache.ttl=0
networkaddress.cache.negative.ttl=0

View file

@ -0,0 +1,63 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.util.Arrays;
import org.testng.Assert;
import org.testng.annotations.Test;
import static impl.FaultyResolverProviderGetImpl.EXCEPTION_MESSAGE;
/*
* @test
* @summary Test that InetAddress fast-fails if custom provider fails to
* instantiate a resolver.
* @library providers/faulty
* @build faulty.provider/impl.FaultyResolverProviderGetImpl
* @run testng/othervm ProviderGetExceptionTest
*/
public class ProviderGetExceptionTest {
@Test
public void getByNameExceptionTest() {
String hostName = "test.host";
System.out.println("Looking up address for the following host name:" + hostName);
callInetAddressAndCheckException(() -> InetAddress.getByName(hostName));
}
@Test
public void getByAddressExceptionTest() {
byte[] address = new byte[]{1, 2, 3, 4};
System.out.println("Looking up host name for the following address:" + Arrays.toString(address));
callInetAddressAndCheckException(() -> InetAddress.getByAddress(address).getHostName());
}
private void callInetAddressAndCheckException(Assert.ThrowingRunnable apiCall) {
IllegalArgumentException iae = Assert.expectThrows(IllegalArgumentException.class, apiCall);
System.out.println("Got exception of expected type:" + iae);
Assert.assertNull(iae.getCause(), "cause is not null");
Assert.assertEquals(iae.getMessage(), EXCEPTION_MESSAGE);
}
}

View file

@ -0,0 +1,94 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.net.UnknownHostException;
import impl.ThrowingLookupsProviderImpl;
import static impl.ThrowingLookupsProviderImpl.RUNTIME_EXCEPTION_MESSAGE;
import org.testng.Assert;
import org.testng.annotations.Test;
/*
* @test
* @summary Test that only UnknownHostException is thrown if resolver
* implementation throws RuntimeException during forward or reverse lookup.
* @library providers/throwing
* @build throwing.lookups.provider/impl.ThrowingLookupsProviderImpl
* @run testng/othervm ResolutionWithExceptionTest
*/
public class ResolutionWithExceptionTest {
@Test
public void getByNameUnknownHostException() {
ThrowingLookupsProviderImpl.throwRuntimeException = false;
runGetByNameTest();
}
@Test
public void getByNameRuntimeException() {
ThrowingLookupsProviderImpl.throwRuntimeException = true;
runGetByNameTest();
}
@Test
public void getByAddressUnknownHostException() throws UnknownHostException {
ThrowingLookupsProviderImpl.throwRuntimeException = false;
runGetByAddressTest();
}
@Test
public void getByAddressRuntimeException() throws UnknownHostException {
ThrowingLookupsProviderImpl.throwRuntimeException = true;
runGetByAddressTest();
}
private void runGetByNameTest() {
// InetAddress.getByName() is expected to throw UnknownHostException in all cases
UnknownHostException uhe = Assert.expectThrows(UnknownHostException.class,
() -> InetAddress.getByName("doesnt.matter.com"));
// If provider is expected to throw RuntimeException - check that UnknownHostException
// is set as its cause
if (ThrowingLookupsProviderImpl.throwRuntimeException) {
Throwable cause = uhe.getCause();
if (cause instanceof RuntimeException re) {
// Check RuntimeException message
Assert.assertEquals(re.getMessage(), RUNTIME_EXCEPTION_MESSAGE,
"incorrect exception message");
} else {
Assert.fail("UnknownHostException cause is not RuntimeException");
}
}
}
private void runGetByAddressTest() throws UnknownHostException {
// getCanonicalHostName is not expected to throw an exception:
// if there is an error during reverse lookup operation the literal IP
// address String will be returned.
String literalIP = InetAddress.getByAddress(new byte[]{1, 2, 3, 4}).getCanonicalHostName();
Assert.assertEquals(literalIP, "1.2.3.4");
}
}

View file

@ -0,0 +1,95 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.net.SocketPermission;
import java.net.UnknownHostException;
import java.security.Permission;
import java.util.logging.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;
/*
* @test
* @summary Test that resolution of host name requires SocketPermission("resolve", <host name>)
* permission when running with security manager and custom resolver provider installed.
* @library lib providers/simple
* @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl
* ResolvePermissionTest
* @run testng/othervm -Dtest.dataFileName=nonExistentFile -Djava.security.manager=allow
* ResolvePermissionTest
*/
public class ResolvePermissionTest {
@Test
public void withResolvePermission() throws Exception {
testResolvePermission(true);
}
@Test
public void noResolvePermission() throws Exception {
testResolvePermission(false);
}
@SuppressWarnings("removal")
private void testResolvePermission(boolean grantResolvePermission) throws Exception {
// Set security manager which grants or denies permission to resolve 'javaTest.org' host
var securityManager = new ResolvePermissionTest.TestSecurityManager(grantResolvePermission);
try {
System.setSecurityManager(securityManager);
Class expectedExceptionClass = grantResolvePermission ?
UnknownHostException.class : SecurityException.class;
var exception = Assert.expectThrows(expectedExceptionClass, () -> InetAddress.getByName("javaTest.org"));
LOGGER.info("Got expected exception: " + exception);
} finally {
System.setSecurityManager(null);
}
}
static class TestSecurityManager extends SecurityManager {
final boolean allowJavaTestOrgResolve;
public TestSecurityManager(boolean allowJavaTestOrgResolve) {
this.allowJavaTestOrgResolve = allowJavaTestOrgResolve;
}
@Override
public void checkPermission(Permission permission) {
if (permission instanceof java.net.SocketPermission) {
SocketPermission sockPerm = (SocketPermission) permission;
if ("resolve".equals(sockPerm.getActions())) {
String host = sockPerm.getName();
LOGGER.info("Checking 'resolve' SocketPermission: " + permission);
if ("javaTest.org".equals(host) && !allowJavaTestOrgResolve) {
LOGGER.info("Denying 'resolve' permission for 'javaTest.org'");
throw new SecurityException("Access Denied");
}
}
}
}
}
private static final Logger LOGGER = Logger.getLogger(ResolvePermissionTest.class.getName());
}

View file

@ -0,0 +1,62 @@
/*
* 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.
*
* 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.
*/
import impl.DelegatingProviderImpl;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static impl.DelegatingProviderImpl.changeReverseLookupAddress;
import static impl.DelegatingProviderImpl.lastReverseLookupThrowable;
/*
* @test
* @summary checks delegation of illegal reverse lookup request to the built-in
* InetAddressResolver.
* @library providers/delegating
* @build delegating.provider/impl.DelegatingProviderImpl
* @run testng/othervm ReverseLookupDelegationTest
*/
public class ReverseLookupDelegationTest {
@Test
public void delegateHostNameLookupWithWrongByteArray() throws UnknownHostException {
// The underlying resolver implementation will ignore the supplied
// byte array and will replace it with byte array of incorrect size.
changeReverseLookupAddress = true;
String canonicalHostName = InetAddress.getByAddress(new byte[]{1, 2, 3, 4}).getCanonicalHostName();
// Output canonical host name and the exception thrown by the built-in resolver
System.err.println("Canonical host name:" + canonicalHostName);
System.err.println("Exception thrown by the built-in resolver:" + lastReverseLookupThrowable);
// Check that originally supplied byte array was used to construct canonical host name after
// failed reverse lookup.
Assert.assertEquals("1.2.3.4", canonicalHostName, "unexpected canonical hostname");
// Check that on a provider side the IllegalArgumentException has been thrown by the built-in resolver
Assert.assertTrue(lastReverseLookupThrowable instanceof IllegalArgumentException,
"wrong exception type is thrown by the built-in resolver");
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.
*
* 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.
*/
import org.testng.Assert;
import org.testng.annotations.Test;
import java.net.InetAddress;
import java.security.Permission;
import java.util.ServiceConfigurationError;
import java.util.logging.Logger;
/*
* @test
* @summary Test that instantiation of InetAddressResolverProvider requires "inetAddressResolverProvider"
* RuntimePermission when running with security manager.
* @library lib providers/simple
* @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl
* RuntimePermissionTest
* @run testng/othervm -Djava.security.manager=allow RuntimePermissionTest
*/
public class RuntimePermissionTest {
@Test
public void withRuntimePermission() throws Exception {
testRuntimePermission(true);
}
@Test
public void noRuntimePermission() throws Exception {
testRuntimePermission(false);
}
@SuppressWarnings("removal")
private void testRuntimePermission(boolean permitInetAddressResolver) throws Exception {
// Set security manager which grants all permissions + RuntimePermission("inetAddressResolverProvider")
var securityManager = new TestSecurityManager(permitInetAddressResolver);
try {
System.setSecurityManager(securityManager);
if (permitInetAddressResolver) {
InetAddress.getByName("javaTest.org");
} else {
ServiceConfigurationError sce =
Assert.expectThrows(ServiceConfigurationError.class,
() -> InetAddress.getByName("javaTest.org"));
LOGGER.info("Got ServiceConfigurationError: " + sce);
Throwable cause = sce.getCause();
Assert.assertTrue(cause instanceof SecurityException);
Assert.assertTrue(cause.getMessage().contains(RUNTIME_PERMISSION_NAME));
}
} finally {
System.setSecurityManager(null);
}
}
static class TestSecurityManager extends SecurityManager {
final boolean permitInetAddressResolver;
public TestSecurityManager(boolean permitInetAddressResolver) {
this.permitInetAddressResolver = permitInetAddressResolver;
LOGGER.info("inetAddressResolverProvider permission is " +
(permitInetAddressResolver ? "granted" : "not granted"));
}
@Override
public void checkPermission(Permission permission) {
if (permission instanceof RuntimePermission) {
LOGGER.info("Checking RuntimePermission: " + permission);
if (RUNTIME_PERMISSION_NAME.equals(permission.getName()) && !permitInetAddressResolver) {
LOGGER.info("Denying '" + RUNTIME_PERMISSION_NAME + "' permission");
throw new SecurityException("Access Denied: " + RUNTIME_PERMISSION_NAME);
}
}
}
}
private static final String RUNTIME_PERMISSION_NAME = "inetAddressResolverProvider";
private static final Logger LOGGER = Logger.getLogger(RuntimePermissionTest.class.getName());
}

View file

@ -0,0 +1,7 @@
# Test data file for InetAddressResolverProvider SPI tests
# Format: <IP address> <Host Name>
# If multiple IP addresses are required for host:
# multiple lines could be added
1.2.3.4 javaTest.org
[ca:fe:ba:be::1] javaTest.org

View file

@ -0,0 +1,27 @@
/*
* 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.
*
* 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.
*/
module test.library {
exports testlib;
requires java.logging;
}

View file

@ -0,0 +1,239 @@
/*
* 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 testlib;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver.LookupPolicy;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Comparator;
import static java.net.spi.InetAddressResolver.LookupPolicy.*;
public class ResolutionRegistry {
// Map to store hostName -> InetAddress mappings
private final Map<String, List<byte[]>> registry;
private static final int IPV4_RAW_LEN = 4;
private static final int IPV6_RAW_LEN = 16;
private static final Logger LOGGER = Logger.getLogger(ResolutionRegistry.class.getName());
public ResolutionRegistry() {
// Populate registry from test data file
String fileName = System.getProperty("test.dataFileName", "addresses.txt");
Path addressesFile = Paths.get(System.getProperty("test.src", ".")).resolve(fileName);
LOGGER.info("Creating ResolutionRegistry instance from file:" + addressesFile);
registry = parseDataFile(addressesFile);
}
private Map<String, List<byte[]>> parseDataFile(Path addressesFile) {
try {
if (addressesFile.toFile().isFile()) {
Map<String, List<byte[]>> resReg = new ConcurrentHashMap<>();
// Prepare list of hostname/address entries
List<String[]> entriesList = Files.readAllLines(addressesFile).stream()
.map(String::trim)
.filter(Predicate.not(String::isBlank))
.filter(s -> !s.startsWith("#"))
.map(s -> s.split("\\s+"))
.filter(sarray -> sarray.length == 2)
.filter(ResolutionRegistry::hasLiteralAddress)
.filter(Objects::nonNull)
.collect(Collectors.toList());
// Convert list of entries into registry Map
for (var entry : entriesList) {
String ipAddress = entry[0].trim();
String hostName = entry[1].trim();
byte[] addrBytes = toByteArray(ipAddress);
if (addrBytes != null) {
var list = resReg.containsKey(hostName) ? resReg.get(hostName) : new ArrayList();
list.add(addrBytes);
if (!resReg.containsKey(hostName)) {
resReg.put(hostName, list);
}
}
}
resReg.replaceAll((k, v) -> Collections.unmodifiableList(v));
// Print constructed registry
StringBuilder sb = new StringBuilder("Constructed addresses registry:" + System.lineSeparator());
for (var entry : resReg.entrySet()) {
sb.append("\t" + entry.getKey() + ": ");
for (byte[] addr : entry.getValue()) {
sb.append(addressBytesToString(addr) + " ");
}
sb.append(System.lineSeparator());
}
LOGGER.info(sb.toString());
return resReg;
} else {
// If file doesn't exist - return empty map
return Collections.emptyMap();
}
} catch (IOException ioException) {
// If any problems parsing the file - log a warning and return an empty map
LOGGER.log(Level.WARNING, "Error reading data file", ioException);
return Collections.emptyMap();
}
}
// Line is not a blank and not a comment
private static boolean hasLiteralAddress(String[] lineFields) {
String addressString = lineFields[0].trim();
return addressString.charAt(0) == '[' ||
Character.digit(addressString.charAt(0), 16) != -1 ||
(addressString.charAt(0) == ':');
}
// Line is not blank and not comment
private static byte[] toByteArray(String addressString) {
InetAddress address;
// Will reuse InetAddress functionality to parse literal IP address
// strings. This call is guarded by 'hasLiteralAddress' method.
try {
address = InetAddress.getByName(addressString);
} catch (UnknownHostException unknownHostException) {
LOGGER.warning("Can't parse address string:'" + addressString + "'");
return null;
}
return address.getAddress();
}
public Stream<InetAddress> lookupHost(String host, LookupPolicy lookupPolicy)
throws UnknownHostException {
LOGGER.info("Looking-up '" + host + "' address");
if (!registry.containsKey(host)) {
LOGGER.info("Registry doesn't contain addresses for '" + host + "'");
throw new UnknownHostException(host);
}
int characteristics = lookupPolicy.characteristics();
// Filter IPV4 or IPV6 as needed. Then sort with
// comparator for IPV4_FIRST or IPV6_FIRST.
return registry.get(host)
.stream()
.filter(ba -> filterAddressByLookupPolicy(ba, characteristics))
.sorted(new AddressOrderPref(characteristics))
.map(ba -> constructInetAddress(host, ba))
.filter(Objects::nonNull);
}
private static boolean filterAddressByLookupPolicy(byte[] ba, int ch) {
// If 0011, return both. If 0001, IPv4. If 0010, IPv6
boolean ipv4Flag = (ch & IPV4) == IPV4;
boolean ipv6Flag = (ch & IPV6) == IPV6;
if (ipv4Flag && ipv6Flag)
return true; // Return regardless of length
else if (ipv4Flag)
return (ba.length == IPV4_RAW_LEN);
else if (ipv6Flag)
return (ba.length == IPV6_RAW_LEN);
throw new RuntimeException("Lookup policy characteristics were improperly set. " +
"Characteristics: " + Integer.toString(ch, 2));
}
private static InetAddress constructInetAddress(String host, byte[] address) {
try {
return InetAddress.getByAddress(host, address);
} catch (UnknownHostException unknownHostException) {
return null;
}
}
public String lookupAddress(byte[] addressBytes) {
for (var entry : registry.entrySet()) {
if (entry.getValue()
.stream()
.filter(ba -> Arrays.equals(ba, addressBytes))
.findAny()
.isPresent()) {
return entry.getKey();
}
}
try {
return InetAddress.getByAddress(addressBytes).getHostAddress();
} catch (UnknownHostException unknownHostException) {
throw new IllegalArgumentException();
}
}
public boolean containsAddressMapping(InetAddress address) {
String hostName = address.getHostName();
if (registry.containsKey(hostName)) {
var mappedBytes = registry.get(address.getHostName());
for (byte[] mappedAddr : mappedBytes) {
if (Arrays.equals(mappedAddr, address.getAddress())) {
return true;
}
}
}
return false;
}
public static String addressBytesToString(byte[] bytes) {
try {
return InetAddress.getByAddress(bytes).toString();
} catch (UnknownHostException unknownHostException) {
return Arrays.toString(bytes);
}
}
private class AddressOrderPref implements Comparator<byte[]> {
private final int ch;
AddressOrderPref(int ch) {
this.ch = ch;
}
@Override
public int compare(byte[] o1, byte[] o2) {
// Compares based on address length, 4 bytes for IPv4,
// 16 bytes for IPv6.
return ((ch & IPV4_FIRST) == IPV4_FIRST) ?
Integer.compare(o1.length, o2.length) :
Integer.compare(o2.length, o1.length);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.stream.Stream;
public class WithBootstrapResolverUsageProvider extends InetAddressResolverProvider {
public static volatile long numberOfGetCalls;
@Override
public InetAddressResolver get(Configuration configuration) {
numberOfGetCalls++;
System.out.println("The following provider will be used by current test:" +
this.getClass().getCanonicalName());
System.out.println("InetAddressResolverProvider::get() called " + numberOfGetCalls + " times");
// We use different names to avoid InetAddress-level caching
doLookup("foo" + numberOfGetCalls + ".A.org");
// We need second call to test how InetAddress internals maintain reference to a bootstrap resolver
doLookup("foo" + numberOfGetCalls + ".B.org");
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy)
throws UnknownHostException {
return Stream.of(InetAddress.getByAddress(host, new byte[]{127, 0, 2, 1}));
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
return configuration.builtinResolver().lookupByAddress(addr);
}
};
}
// Perform an InetAddress resolution lookup operation
private static void doLookup(String hostName) {
try {
InetAddress.getByName(hostName);
} catch (UnknownHostException e) {
// Ignore UHE since the bootstrap resolver is used here
}
}
@Override
public String name() {
return "WithBootstrapResolverUsageProvider";
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module bootstrap.usage.provider {
exports impl;
requires java.logging;
provides InetAddressResolverProvider with impl.WithBootstrapResolverUsageProvider;
}

View file

@ -0,0 +1,68 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.stream.Stream;
public class DelegatingProviderImpl extends InetAddressResolverProvider {
public static volatile boolean changeReverseLookupAddress;
public static volatile Throwable lastReverseLookupThrowable;
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" +
this.getClass().getCanonicalName());
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException {
return configuration.builtinResolver().lookupByName(host, lookupPolicy);
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
try {
if (!changeReverseLookupAddress) {
return configuration.builtinResolver().lookupByAddress(addr);
} else {
// Deliberately supply address bytes array with wrong size
return configuration.builtinResolver().lookupByAddress(new byte[]{1, 2, 3});
}
} catch (Throwable t) {
lastReverseLookupThrowable = t;
throw t;
}
}
};
}
@Override
public String name() {
return "DelegatingProvider";
}
}

View file

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module delegating.provider {
exports impl;
provides InetAddressResolverProvider with impl.DelegatingProviderImpl;
}

View file

@ -0,0 +1,56 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.stream.Stream;
public class EmptyResultsProviderImpl extends InetAddressResolverProvider {
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" +
this.getClass().getCanonicalName());
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy)
throws UnknownHostException {
return Stream.empty();
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
return configuration.builtinResolver().lookupByAddress(addr);
}
};
}
@Override
public String name() {
return "EmptyForwardLookupResultsProvider";
}
}

View file

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module empty.results.provider {
exports impl;
provides InetAddressResolverProvider with impl.EmptyResultsProviderImpl;
}

View file

@ -0,0 +1,42 @@
/*
* 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.
*
* 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 impl;
import java.net.spi.InetAddressResolverProvider;
import java.net.spi.InetAddressResolver;
public class FaultyResolverProviderGetImpl extends InetAddressResolverProvider {
public static final String EXCEPTION_MESSAGE = "This provider provides nothing";
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" + this.getClass().getCanonicalName());
throw new IllegalArgumentException(EXCEPTION_MESSAGE);
}
@Override
public String name() {
return "faultyInetAddressResolverGet";
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module faulty.provider {
exports impl;
requires java.logging;
provides InetAddressResolverProvider with impl.FaultyResolverProviderGetImpl;
}

View file

@ -0,0 +1,63 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.stream.Stream;
public class InetAddressUsageInGetProviderImpl extends InetAddressResolverProvider {
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" + this.getClass().getCanonicalName());
String localHostName;
try {
localHostName = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
throw new RuntimeException("Provider failed to initialize");
}
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException {
if (host.equals(localHostName)) {
return configuration.builtinResolver().lookupByName(host, lookupPolicy);
} else {
throw new UnknownHostException(host);
}
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
return configuration.builtinResolver().lookupByAddress(addr);
}
};
}
@Override
public String name() {
return "ProviderWithInetAddressUsageInGet";
}
}

View file

@ -0,0 +1,30 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module recursive.init.provider {
exports impl;
requires java.logging;
provides InetAddressResolverProvider with impl.InetAddressUsageInGetProviderImpl;
}

View file

@ -0,0 +1,91 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolver.LookupPolicy;
import java.net.spi.InetAddressResolverProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Stream;
import testlib.ResolutionRegistry;
public class SimpleResolverProviderImpl extends InetAddressResolverProvider {
public static ResolutionRegistry registry = new ResolutionRegistry();
private static List<LookupPolicy> LOOKUP_HISTORY = Collections.synchronizedList(new ArrayList<>());
private static volatile long LAST_LOOKUP_TIMESTAMP;
private static Logger LOGGER = Logger.getLogger(SimpleResolverProviderImpl.class.getName());
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" + this.getClass().getCanonicalName());
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException {
LOGGER.info("Looking-up addresses for '" + host + "'. Lookup characteristics:" +
Integer.toString(lookupPolicy.characteristics(), 2));
LOOKUP_HISTORY.add(lookupPolicy);
LAST_LOOKUP_TIMESTAMP = System.nanoTime();
return registry.lookupHost(host, lookupPolicy);
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
LOGGER.info("Looking host name for the following address:" + ResolutionRegistry.addressBytesToString(addr));
return registry.lookupAddress(addr);
}
};
}
// Utility methods
public static LookupPolicy lastLookupPolicy() {
return lookupPolicyHistory(0);
}
public static long getLastLookupTimestamp() {
return LAST_LOOKUP_TIMESTAMP;
}
public static LookupPolicy lookupPolicyHistory(int position) {
if (LOOKUP_HISTORY.isEmpty()) {
throw new RuntimeException("No registered lookup policies");
}
if (position >= LOOKUP_HISTORY.size()) {
throw new IllegalArgumentException("No element available with provided position");
}
return LOOKUP_HISTORY.get(LOOKUP_HISTORY.size() - position - 1);
}
@Override
public String name() {
return "simpleInetAddressResolver";
}
}

View file

@ -0,0 +1,31 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module simple.provider {
exports impl;
requires java.logging;
requires test.library;
provides InetAddressResolverProvider with impl.SimpleResolverProviderImpl;
}

View file

@ -0,0 +1,73 @@
/*
* 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.
*
* 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 impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider;
import java.util.stream.Stream;
public class ThrowingLookupsProviderImpl extends InetAddressResolverProvider {
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" +
this.getClass().getCanonicalName());
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy)
throws UnknownHostException {
if (throwRuntimeException) {
System.err.println(name()+" forward lookup: throwing RuntimeException");
throw new RuntimeException(RUNTIME_EXCEPTION_MESSAGE);
} else {
System.err.println(name()+" forward lookup: throwing UnknownHostException");
throw new UnknownHostException();
}
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
if (throwRuntimeException) {
System.err.println(name()+" reverse lookup: throwing RuntimeException");
throw new RuntimeException(RUNTIME_EXCEPTION_MESSAGE);
} else {
System.err.println(name()+" reverse lookup: throwing UnknownHostException");
throw new UnknownHostException();
}
}
};
}
@Override
public String name() {
return "ThrowingLookupsProvider";
}
// Indicates if provider need to throw RuntimeException for forward and reverse lookup operations.
// If it is set to 'false' then UnknownHostException will thrown for each operation.
public static volatile boolean throwRuntimeException;
public static final String RUNTIME_EXCEPTION_MESSAGE = "This provider only throws exceptions";
}

View file

@ -0,0 +1,29 @@
/*
* 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.
*
* 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.
*/
import java.net.spi.InetAddressResolverProvider;
module throwing.lookups.provider {
exports impl;
provides InetAddressResolverProvider with impl.ThrowingLookupsProviderImpl;
}

View file

@ -0,0 +1,49 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import org.testng.annotations.Test;
import static org.testng.Assert.assertThrows;
/*
* @test
* @summary Test that InetAddressResolverProvider implementation can be installed to a class path.
* @library ../../lib
* @build test.library/testlib.ResolutionRegistry ClasspathResolverProviderImpl
* @run testng/othervm ClasspathProviderTest
*/
public class ClasspathProviderTest {
@Test
public void testResolution() throws Exception {
InetAddress inetAddress = InetAddress.getByName("classpath-provider-test.org");
System.err.println("Resolved address:" + inetAddress);
if (!ClasspathResolverProviderImpl.registry.containsAddressMapping(inetAddress)) {
throw new RuntimeException("InetAddressResolverProvider was not properly installed");
}
}
}

View file

@ -0,0 +1,67 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.spi.InetAddressResolverProvider;
import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolver.LookupPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Stream;
import testlib.ResolutionRegistry;
public class ClasspathResolverProviderImpl extends InetAddressResolverProvider {
public static ResolutionRegistry registry = new ResolutionRegistry();
private static List<LookupPolicy> LOOKUP_HISTORY = Collections.synchronizedList(new ArrayList<>());
private static Logger LOGGER = Logger.getLogger(ClasspathResolverProviderImpl.class.getName());
@Override
public InetAddressResolver get(Configuration configuration) {
System.out.println("The following provider will be used by current test:" + this.getClass().getCanonicalName());
return new InetAddressResolver() {
@Override
public Stream<InetAddress> lookupByName(String host, LookupPolicy lookupPolicy) throws UnknownHostException {
LOGGER.info("Looking-up addresses for '" + host + "'. Lookup characteristics:" +
Integer.toString(lookupPolicy.characteristics(), 2));
LOOKUP_HISTORY.add(lookupPolicy);
return registry.lookupHost(host, lookupPolicy);
}
@Override
public String lookupByAddress(byte[] addr) throws UnknownHostException {
LOGGER.info("Looking host name for the following address:" + ResolutionRegistry.addressBytesToString(addr));
return registry.lookupAddress(addr);
}
};
}
@Override
public String name() {
return "classpathINSP";
}
}

View file

@ -0,0 +1,7 @@
# Test data file for classpath origin type tests.
# Format: <IP address> <Host Name>
# If multiple IP addresses are required for host:
# multiple lines could be added
1.2.3.4 classpath-provider-test.org
[ca:fe:ba:be::1] classpath-provider-test.org

View file

@ -0,0 +1,49 @@
/*
* 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.
*
* 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.
*/
import java.net.InetAddress;
import org.testng.annotations.Test;
/*
* @test
* @summary Test that implementation of InetAddressResolverProvider can be installed to a module path.
* @library ../../lib ../../providers/simple
* @build test.library/testlib.ResolutionRegistry simple.provider/impl.SimpleResolverProviderImpl
* ModularProviderTest
* @run testng/othervm ModularProviderTest
*/
public class ModularProviderTest {
@Test
public void testResolution() throws Exception {
InetAddress inetAddress = InetAddress.getByName("modular-provider-test.org");
System.err.println("Resolved address:" + inetAddress);
if (!impl.SimpleResolverProviderImpl.registry.containsAddressMapping(inetAddress)) {
throw new RuntimeException("InetAddressResolverProvider was not properly installed");
}
}
}

View file

@ -0,0 +1,7 @@
# Test data file for tests in modularTests directory
# Format: <IP address> <Host Name>
# If multiple IP addresses are required for host:
# multiple lines could be added
1.2.3.4 modular-provider-test.org
[ca:fe:ba:be::1] modular-provider-test.org

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,11 +27,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.ProtocolFamily;
import java.net.Socket; import java.net.StandardProtocolFamily;
import java.net.SocketException; import java.nio.channels.SocketChannel;
import java.net.UnknownHostException;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
@ -49,19 +50,8 @@ public class IPSupport {
private static final boolean preferIPv6Addresses; private static final boolean preferIPv6Addresses;
static { static {
try { hasIPv4 = runPrivilegedAction(() -> isSupported(Inet4Address.class));
InetAddress loopbackIPv4 = InetAddress.getByAddress( hasIPv6 = runPrivilegedAction(() -> isSupported(Inet6Address.class));
new byte[] {0x7F, 0x00, 0x00, 0x01});
InetAddress loopbackIPv6 = InetAddress.getByAddress(
new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
hasIPv4 = runPrivilegedAction(() -> hasAddress(loopbackIPv4));
hasIPv6 = runPrivilegedAction(() -> hasAddress(loopbackIPv6));
} catch (UnknownHostException e) {
throw new AssertionError(e);
}
preferIPv4Stack = runPrivilegedAction(() -> Boolean.parseBoolean( preferIPv4Stack = runPrivilegedAction(() -> Boolean.parseBoolean(
System.getProperty("java.net.preferIPv4Stack"))); System.getProperty("java.net.preferIPv4Stack")));
preferIPv6Addresses = runPrivilegedAction(() -> Boolean.parseBoolean( preferIPv6Addresses = runPrivilegedAction(() -> Boolean.parseBoolean(
@ -71,14 +61,13 @@ public class IPSupport {
} }
} }
private static boolean hasAddress(InetAddress address) { private static boolean isSupported(Class<? extends InetAddress> addressType) {
try (Socket socket = new Socket()) { ProtocolFamily family = addressType == Inet4Address.class ?
socket.bind(new InetSocketAddress(address, 0)); StandardProtocolFamily.INET : StandardProtocolFamily.INET6;
try (var sc = SocketChannel.open(family)) {
return true; return true;
} catch (SocketException se) { } catch (IOException | UnsupportedOperationException ex) {
return false; return false;
} catch (IOException e) {
throw new UncheckedIOException(e);
} }
} }