Repository: netty/netty
Issue: Disable IPv6 address lookups when -Djava.net.preferIPv4Stack=true
Labels: defect

According to [the Oracle documentation](http://docs.oracle.com/javase/8/docs/technotes/guides/net/ipv6_guide/):

> 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.

Perhaps a more sensible default when `-Djava.net.preferIPv4Stack=true` is specified is not to send an AAAA query at all.


Issue comments:
@trustin so you will look into it ?

Yes

Ok cool thx

> Am 09.08.2016 um 16:22 schrieb Trustin Lee notifications@github.com:
> 
> Yes
> 
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub, or mute the thread.

I believe a vert.x user observed this issue when running his program in google cloud (and trying to connect to www.googleapis.com) https://groups.google.com/d/topic/vertx/7xTo_a_lOWk/discussion

would be worth mentioning this issue in the group thread for the record @alexlehm 

and perhaps create a corresponding issue in Vert.x project ?

Fixed by https://github.com/netty/netty/pull/5659


Pull request review comments:
![CRITICAL](https://raw.githubusercontent.com/SonarCommunity/sonar-github/master/images/severity-critical.png) Make this array "private". [![rule](https://raw.githubusercontent.com/SonarCommunity/sonar-github/master/images/rule.png)](https://garage.netty.io/sonarqube/coding_rules#rule_key=squid%3AS1873)

False positive? It's referenced by `DnsNameResolverBuilder`.

@trustin I think the rule only checks the local scope, the suggestion from Sonarqube is that the elements are mutable even though the field is final and so its better to make it private if it is used only in the class or provide a getter that copies, but this is not applicable to this example


Patch that resolved the issue:
diff --git a/common/src/main/java/io/netty/util/NetUtil.java b/common/src/main/java/io/netty/util/NetUtil.java
index 5ac18a353a0..b990d0e9889 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 Integer run() {
     }
 
     /**
-     * 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() {
         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
      * 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 a9d592eb8c8..cfb7a78e1ca 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;
+            }
         }
     }
 


Test patch: