Disable IPv6 address lookups when -Djava.net.preferIPv4Stack=true

Motivation:

According to the Oracle documentation:

> java.net.preferIPv4Stack (default: false)
>
> If IPv6 is available on the operating system, the underlying native
> socket will be an IPv6 socket. This allows Java applications to connect
> to, and accept connections from, both IPv4 and IPv6 hosts.
>
> If an application has a preference to only use IPv4 sockets, then this
> property can be set to true. The implication is that the application
> will not be able to communicate with IPv6 hosts.

which means, if DnsNameResolver returns an IPv6 address, a user (or
Netty) will not be able to connect to it.

Modifications:

- Move the code that retrieves java.net.prefer* properties from
  DnsNameResolver to NetUtil
- Add NetUtil.isIpV6AddressesPreferred()
- Revise the API documentation of NetUtil.isIpV*Preferred()
- Set the default resolveAddressTypes to IPv4 only when
  NetUtil.isIpv4StackPreferred() returns true

Result:

- Fixes #5657
This commit is contained in:
Trustin Lee 2016-08-10 11:53:59 +09:00 committed by Norman Maurer
parent 064c0d7826
commit 9fef4ba1bf
2 changed files with 39 additions and 13 deletions

View File

@ -118,16 +118,24 @@ public final class NetUtil {
private static final int IPV4_SEPARATORS = 3; private static final int IPV4_SEPARATORS = 3;
/** /**
* {@code true} if ipv4 should be used on a system that supports ipv4 and ipv6. * {@code true} if IPv4 should be used even if the system supports both IPv4 and IPv6.
*/ */
private static final boolean IPV4_PREFERRED = Boolean.getBoolean("java.net.preferIPv4Stack"); private static final boolean IPV4_PREFERRED = Boolean.getBoolean("java.net.preferIPv4Stack");
/**
* {@code true} if an IPv6 address should be preferred when a host has both an IPv4 address and an IPv6 address.
*/
private static final boolean IPV6_ADDRESSES_PREFERRED = Boolean.getBoolean("java.net.preferIPv6Addresses");
/** /**
* The logger being used by this class * The logger being used by this class
*/ */
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class); private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
static { static {
logger.debug("-Djava.net.preferIPv4Stack: {}", IPV4_PREFERRED);
logger.debug("-Djava.net.preferIPv6Addresses: {}", IPV6_ADDRESSES_PREFERRED);
byte[] LOCALHOST4_BYTES = {127, 0, 0, 1}; byte[] LOCALHOST4_BYTES = {127, 0, 0, 1};
byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
@ -278,12 +286,27 @@ public final class NetUtil {
} }
/** /**
* Returns {@code true} if ipv4 should be prefered on a system that supports ipv4 and ipv6. * Returns {@code true} if IPv4 should be used even if the system supports both IPv4 and IPv6. Setting this
* property to {@code true} will disable IPv6 support. The default value of this property is {@code false}.
*
* @see <a href="https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html">Java SE
* networking properties</a>
*/ */
public static boolean isIpV4StackPreferred() { public static boolean isIpV4StackPreferred() {
return IPV4_PREFERRED; return IPV4_PREFERRED;
} }
/**
* Returns {@code true} if an IPv6 address should be preferred when a host has both an IPv4 address and an IPv6
* address. The default value of this property is {@code false}.
*
* @see <a href="https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html">Java SE
* networking properties</a>
*/
public static boolean isIpV6AddressesPreferred() {
return IPV6_ADDRESSES_PREFERRED;
}
/** /**
* Creates an byte[] based on an ipAddressString. No error handling is * Creates an byte[] based on an ipAddressString. No error handling is
* performed here. * performed here.

View File

@ -70,21 +70,24 @@ public class DnsNameResolver extends InetNameResolver {
private static final String LOCALHOST = "localhost"; private static final String LOCALHOST = "localhost";
private static final InetAddress LOCALHOST_ADDRESS; private static final InetAddress LOCALHOST_ADDRESS;
static final InternetProtocolFamily[] DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[2]; static final InternetProtocolFamily[] DEFAULT_RESOLVE_ADDRESS_TYPES;
static final String[] DEFAULT_SEACH_DOMAINS; static final String[] DEFAULT_SEACH_DOMAINS;
static { static {
// Note that we did not use SystemPropertyUtil.getBoolean() here to emulate the behavior of JDK. if (NetUtil.isIpV4StackPreferred()) {
if (Boolean.getBoolean("java.net.preferIPv6Addresses")) { DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[] { InternetProtocolFamily.IPv4 };
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv6;
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv4;
LOCALHOST_ADDRESS = NetUtil.LOCALHOST6;
logger.debug("-Djava.net.preferIPv6Addresses: true");
} else {
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv4;
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv6;
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4; LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
logger.debug("-Djava.net.preferIPv6Addresses: false"); } else {
DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[2];
if (NetUtil.isIpV6AddressesPreferred()) {
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv6;
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv4;
LOCALHOST_ADDRESS = NetUtil.LOCALHOST6;
} else {
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv4;
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv6;
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
}
} }
} }