Repository: netty/netty
Issue: Netty DNS resolver fails to resolve computer's name on Windows

When running on a VM with Windows 10, Netty DNS resolver cannot resolve computer's name.

### Expected behavior
When on Windows, Netty DNS resolver is able to resolve the computer's name

### Actual behavior
The current implementation throws an exception when one tries to resolve the computer's name

```
Caused by: java.net.UnknownHostException: failed to resolve 'DESKTOP-BHE9K15' after 2 queries 
	at io.netty.resolver.dns.DnsResolveContext.finishResolve(DnsResolveContext.java:1013)
	at io.netty.resolver.dns.DnsResolveContext.tryToFinishResolve(DnsResolveContext.java:966)
	at io.netty.resolver.dns.DnsResolveContext.query(DnsResolveContext.java:414)
	at io.netty.resolver.dns.DnsResolveContext.tryToFinishResolve(DnsResolveContext.java:938)
	at io.netty.resolver.dns.DnsResolveContext.access$700(DnsResolveContext.java:63)
	at io.netty.resolver.dns.DnsResolveContext$2.operationComplete(DnsResolveContext.java:467)
```

### Minimal yet complete reproducer code (or URL to code)

```
public class Application {

    public static void main(String[] args) throws Exception {
        // JDK
        InetAddress[] addresses = InetAddress.getAllByName("DESKTOP-BHE9K15");
        System.out.println(Arrays.asList(addresses));

        // JDK
        InetAddress localhost = InetAddress.getLocalHost();
        System.out.println(localhost);

        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            List<InetSocketAddress> result =
                    DefaultAddressResolverGroup.INSTANCE
                            .getResolver(group.next())
                            .resolveAll(InetSocketAddress.createUnresolved("DESKTOP-BHE9K15", 80))
                            .get();
            System.out.println("Netty DefaultAddressResolverGroup " + result);

            DnsNameResolverBuilder builder = new DnsNameResolverBuilder(group.next())
                    .channelType(NioDatagramChannel.class);
            DnsNameResolver resolver = builder.build();
            resolver.resolveAll("DESKTOP-BHE9K15")
                    .get();
        }
        finally {
            group.shutdownGracefully();
        }
    }
}
```

when the above code is executed, the result is:

```
[DESKTOP-BHE9K15/IPv4, DESKTOP-BHE9K15/IPv6]
DESKTOP-BHE9K15/IPv4
Netty DefaultAddressResolverGroup [DESKTOP-BHE9K15/IPv4:80, DESKTOP-BHE9K15/[IPv6]:80]
Exception in thread "main" java.util.concurrent.ExecutionException: java.net.UnknownHostException: failed to resolve 'DESKTOP-BHE9K15' after 2 queries 
```

### Netty version
4.1.63.Final

### JVM version (e.g. `java -version`)
java 11

### OS version (e.g. `uname -a`)
Windows 10

Issue comments:
Is it possible to have a solution similar to the one for `localhost`?

https://github.com/netty/netty/blob/6724786dcc9fa38ba516dab97a04e2bbc17e81d9/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java#L684-L697
@violetagg not sure what you are suggesting... can you maybe do a PR to show the idea ?
@normanmaurer I see two options but none of them is good enough.

- To use `System.getenv("COMPUTERNAME")` and implement it in a way `localhost` is handled, but we use environment variable which I don't think is reliable and secure.
- Another option is to use `InetAddress.getLocalHost().getHostName()` but this is blocking

Wdyt?
I don't like both of them
@violetagg couldn't we just call `InetAddress.getLocalHost().getHostName()` once in a static block ?
> @violetagg couldn't we just call `InetAddress.getLocalHost().getHostName()` once in a static block ?

Yep and then apply the solution for `localhost`
@violetagg can you do a PR ?
> @violetagg can you do a PR ?

ok

Pull request review comments:
Let add WINDOWS to the field name to make it clear this is only used on windows 
done

Patch that resolved the issue:
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 bf594db0627..a3a514f2039 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
@@ -91,6 +91,7 @@ public class DnsNameResolver extends InetNameResolver {
 
     private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsNameResolver.class);
     private static final String LOCALHOST = "localhost";
+    private static final String WINDOWS_HOST_NAME;
     private static final InetAddress LOCALHOST_ADDRESS;
     private static final DnsRecord[] EMPTY_ADDITIONALS = new DnsRecord[0];
     private static final DnsRecordType[] IPV4_ONLY_RESOLVED_RECORD_TYPES =
@@ -127,6 +128,14 @@ public class DnsNameResolver extends InetNameResolver {
                 LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
             }
         }
+
+        String hostName;
+        try {
+            hostName = PlatformDependent.isWindows() ? InetAddress.getLocalHost().getHostName() : null;
+        } catch (Exception ignore) {
+            hostName = null;
+        }
+        WINDOWS_HOST_NAME = hostName;
     }
 
     static {
@@ -686,10 +695,14 @@ private InetAddress resolveHostsFileEntry(String hostname) {
             return null;
         } else {
             InetAddress address = hostsFileEntriesResolver.address(hostname, resolvedAddressTypes);
-            if (address == null && PlatformDependent.isWindows() && LOCALHOST.equalsIgnoreCase(hostname)) {
+            if (address == null && PlatformDependent.isWindows() &&
+                    (LOCALHOST.equalsIgnoreCase(hostname) ||
+                            (WINDOWS_HOST_NAME != null && WINDOWS_HOST_NAME.equalsIgnoreCase(hostname)))) {
                 // If we tried to resolve localhost we need workaround that windows removed localhost from its
                 // hostfile in later versions.
                 // See https://github.com/netty/netty/issues/5386
+                // Need a workaround for resolving the host (computer) name in case it cannot be resolved from hostfile
+                // See https://github.com/netty/netty/issues/11142
                 return LOCALHOST_ADDRESS;
             }
             return address;


Test patch:
diff --git a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
index 3ba8f7aecae..bd16d47ba19 100644
--- a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
+++ b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
@@ -110,8 +110,10 @@
 import static io.netty.handler.codec.dns.DnsRecordType.AAAA;
 import static io.netty.handler.codec.dns.DnsRecordType.CNAME;
 import static io.netty.handler.codec.dns.DnsRecordType.SRV;
+import static io.netty.resolver.dns.DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
 import static io.netty.resolver.dns.DnsServerAddresses.sequential;
 import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assumptions.assumeThat;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.hasSize;
@@ -319,6 +321,18 @@ public class DnsNameResolverTest {
                 StringUtil.EMPTY_STRING);
     }
 
+    private static final String HOST_NAME;
+
+    static {
+        String hostName;
+        try {
+            hostName = PlatformDependent.isWindows() ? InetAddress.getLocalHost().getHostName() : null;
+        } catch (Exception ignore) {
+            hostName = null;
+        }
+        HOST_NAME = hostName;
+    }
+
     private static final TestDnsServer dnsServer = new TestDnsServer(DOMAINS_ALL);
     private static final EventLoopGroup group = new NioEventLoopGroup(1);
 
@@ -743,6 +757,34 @@ public void testResolveEmptyIpv6() {
         testResolve0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
     }
 
+    @Test
+    public void testResolveLocalhostIpv4() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isNotEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolve0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, "localhost");
+    }
+
+    @Test
+    public void testResolveLocalhostIpv6() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolve0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, "localhost");
+    }
+
+    @Test
+    public void testResolveHostNameIpv4() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isNotEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolve0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, HOST_NAME);
+    }
+
+    @Test
+    public void testResolveHostNameIpv6() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolve0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, HOST_NAME);
+    }
+
     @Test
     public void testResolveNullIpv4() {
         testResolve0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, null);
@@ -776,6 +818,34 @@ public void testResolveAllEmptyIpv6() {
         testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
     }
 
+    @Test
+    public void testResolveAllLocalhostIpv4() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isNotEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, "localhost");
+    }
+
+    @Test
+    public void testResolveAllLocalhostIpv6() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, "localhost");
+    }
+
+    @Test
+    public void testResolveAllHostNameIpv4() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isNotEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, HOST_NAME);
+    }
+
+    @Test
+    public void testResolveAllHostNameIpv6() {
+        assumeThat(PlatformDependent.isWindows()).isTrue();
+        assumeThat(DEFAULT_RESOLVE_ADDRESS_TYPES).isEqualTo(ResolvedAddressTypes.IPV6_PREFERRED);
+        testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, HOST_NAME);
+    }
+
     @Test
     public void testCNAMEResolveAllIpv4() throws IOException {
         testCNAMERecursiveResolve(true);