From 9fef4ba1bf27b61c004fcecb43d446113db2d623 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 10 Aug 2016 11:53:59 +0900 Subject: [PATCH] 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 --- .../src/main/java/io/netty/util/NetUtil.java | 27 +++++++++++++++++-- .../netty/resolver/dns/DnsNameResolver.java | 25 +++++++++-------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/common/src/main/java/io/netty/util/NetUtil.java b/common/src/main/java/io/netty/util/NetUtil.java index 5ac18a353a..b990d0e988 100644 --- a/common/src/main/java/io/netty/util/NetUtil.java +++ b/common/src/main/java/io/netty/util/NetUtil.java @@ -118,16 +118,24 @@ public final class NetUtil { 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"); + /** + * {@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 */ private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class); static { + logger.debug("-Djava.net.preferIPv4Stack: {}", IPV4_PREFERRED); + logger.debug("-Djava.net.preferIPv6Addresses: {}", IPV6_ADDRESSES_PREFERRED); + 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}; @@ -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 Java SE + * networking properties */ public static boolean isIpV4StackPreferred() { 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 Java SE + * networking properties + */ + public static boolean isIpV6AddressesPreferred() { + return IPV6_ADDRESSES_PREFERRED; + } + /** * Creates an byte[] based on an ipAddressString. No error handling is * performed here. diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java index a9d592eb8c..cfb7a78e1c 100644 --- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java @@ -70,21 +70,24 @@ public class DnsNameResolver extends InetNameResolver { private static final String LOCALHOST = "localhost"; 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 { - // Note that we did not use SystemPropertyUtil.getBoolean() here to emulate the behavior of JDK. - if (Boolean.getBoolean("java.net.preferIPv6Addresses")) { - 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; + if (NetUtil.isIpV4StackPreferred()) { + DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[] { InternetProtocolFamily.IPv4 }; 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; + } } }