Why can net.Dial be very slow on a hostname defined in /etc/hosts?

402 views
Skip to first unread message

Peng Yu

unread,
Feb 22, 2021, 3:22:46 PM2/22/21
to golang-nuts
Hi,

I run the following go program using net.Dial(). Depending on whether
I specify a local hostname (defined in /etc/hosts) or an IP. I get
very different runtimes.

But `ping mymachine.local` resolves the hostname to an IP address
instantaneously. So the two calls of the go program should have the
same runtimes.

Can anybody reproduce the same runtime problem? Does anybody know what
is wrong with the implementation of net.Dial()? Thanks.

$ ./main mymachine.local:22
2021/02/22 14:14:25 before
2021/02/22 14:14:30 after
$ ./main 192.168.1.104:22
2021/02/22 14:14:30 before
2021/02/22 14:14:30 after
$ cat main.go
package main
import (
"net"
"log"
"os"
)

func main() {
dialAddr := os.Args[1]
log.Println("before")
_, err := net.Dial("tcp", dialAddr)
log.Println("after")
if err != nil {
log.Fatalln(err)
}
}

--
Regards,
Peng

Ian Lance Taylor

unread,
Feb 22, 2021, 11:38:27 PM2/22/21
to Peng Yu, golang-nuts
Which version of Go are you using? What operating system are you running on?

It is possible that are running into https://golang.org/issue/35305,
which is fixed in 1.16.

Ian

Peng Yu

unread,
Feb 23, 2021, 12:11:41 AM2/23/21
to Ian Lance Taylor, golang-nuts
I tried 1.16.

$ go version
go version go1.16 darwin/amd64

The problem still exists. When I change mymachine.local to
mymachine_local, the problem is gone. So somehow, this is related to
host resolution? It might try to DNS lookup the hostname, when it can
not find it via DNS then it look up in /etc/hosts?
--
Regards,
Peng

Shulhan

unread,
Feb 23, 2021, 12:19:39 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts


> On 23 Feb 2021, at 12.11, Peng Yu <peng...@gmail.com> wrote:
>
> I tried 1.16.
>
> $ go version
> go version go1.16 darwin/amd64
>
> The problem still exists. When I change mymachine.local to
> mymachine_local, the problem is gone. So somehow, this is related to
> host resolution? It might try to DNS lookup the hostname, when it can
> not find it via DNS then it look up in /etc/hosts?

I see that you run macOS. In the macOS, the local TLD is resolved using multicast DNS. You can try search for "macos local TLD".

Ian Lance Taylor

unread,
Feb 23, 2021, 12:21:04 AM2/23/21
to Peng Yu, golang-nuts
On Mon, Feb 22, 2021 at 9:11 PM Peng Yu <peng...@gmail.com> wrote:
>
> I tried 1.16.
>
> $ go version
> go version go1.16 darwin/amd64
>
> The problem still exists. When I change mymachine.local to
> mymachine_local, the problem is gone. So somehow, this is related to
> host resolution? It might try to DNS lookup the hostname, when it can
> not find it via DNS then it look up in /etc/hosts?

On Darwin I believe that by default we pass DNS lookups to the C
library. So I think that what you are seeing is the behavior of the C
library. Try setting the environment variable GODEBUG=netdns=go.

Ian

robert engels

unread,
Feb 23, 2021, 12:32:49 AM2/23/21
to Ian Lance Taylor, Peng Yu, golang-nuts
-- 
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAOyqgcUSpK7sVTcz8-Yy83rGuatMrOn4qqFNA_205_bdUy6taQ%40mail.gmail.com.

Peng Yu

unread,
Feb 23, 2021, 12:41:19 AM2/23/21
to Ian Lance Taylor, golang-nuts
I don’t understand why ping does not have the same problem. Ping is not based on C library?
--
Regards,
Peng

robert engels

unread,
Feb 23, 2021, 12:49:21 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts
It looks like the Go runtime implements its own DNS client on *unix platforms including OSX.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

robert engels

unread,
Feb 23, 2021, 12:52:00 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts
Still, if you follow that article I referred you to it may fix your issue - as the resolv.conf is auto-generated on OSX and includes hostname mappings.

robert engels

unread,
Feb 23, 2021, 12:54:44 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts
There is also this note in the /etc/resolv.conf file:

#
# macOS Notice
#
# This file is not consulted for DNS hostname resolution, address
# resolution, or the DNS query routing mechanism used by most
# processes on this system.

but the Go DNS client uses resolv.conf for its configuration - that may be the source of the problem. But there is also this code in the stdlib:

// avoidDNS reports whether this is a hostname for which we should not
// use DNS. Currently this includes only .onion, per RFC 7686. See
// golang.org/issue/13705. Does not cover .local names (RFC 6762),
// see golang.org/issue/16739.
func avoidDNS(name string) bool {
if name == "" {
return true
}
if name[len(name)-1] == '.' {
name = name[:len(name)-1]
}
return stringsHasSuffixFold(name, ".onion")
}
so Go issue 16739 might help.

Peng Yu

unread,
Feb 23, 2021, 8:57:32 AM2/23/21
to robert engels, Ian Lance Taylor, golang-nuts
This does not answer the question why net.Dial can not be made with
the same behavior as ping on MacOSX. If the C library behaves
differently on MacOSX and Linux, then the C library should not be
relied on in this case. I just want to use /etc/hosts but not
resolve.conf.

On 2/22/21, robert engels <ren...@ix.netcom.com> wrote:
> It looks like the Go runtime implements its own DNS client on *unix
> platforms including OSX.
>
>> On Feb 22, 2021, at 11:40 PM, Peng Yu <peng...@gmail.com> wrote:
>>
>> I don’t understand why ping does not have the same problem. Ping is not
>> based on C library?
>>
>> On Mon, Feb 22, 2021 at 11:20 PM Ian Lance Taylor <ia...@golang.org
>> <mailto:ia...@golang.org>> wrote:
>> On Mon, Feb 22, 2021 at 9:11 PM Peng Yu <peng...@gmail.com
>> <mailto:peng...@gmail.com>> wrote:
>> >
>> > I tried 1.16.
>> >
>> > $ go version
>> > go version go1.16 darwin/amd64
>> >
>> > The problem still exists. When I change mymachine.local to
>> > mymachine_local, the problem is gone. So somehow, this is related to
>> > host resolution? It might try to DNS lookup the hostname, when it can
>> > not find it via DNS then it look up in /etc/hosts?
>>
>> On Darwin I believe that by default we pass DNS lookups to the C
>> library. So I think that what you are seeing is the behavior of the C
>> library. Try setting the environment variable GODEBUG=netdns=go.
>>
>> Ian
>>
>>
>> > On 2/22/21, Ian Lance Taylor <ia...@golang.org <mailto:ia...@golang.org>>
>> > wrote:
>> > > On Mon, Feb 22, 2021 at 12:22 PM Peng Yu <peng...@gmail.com
>> > > <mailto:peng...@gmail.com>> wrote:
>> > >>
>> > >> I run the following go program using net.Dial(). Depending on
>> > >> whether
>> > >> I specify a local hostname (defined in /etc/hosts) or an IP. I get
>> > >> very different runtimes.
>> > >>
>> > >> But `ping mymachine.local` resolves the hostname to an IP address
>> > >> instantaneously. So the two calls of the go program should have the
>> > >> same runtimes.
>> > >>
>> > >> Can anybody reproduce the same runtime problem? Does anybody know
>> > >> what
>> > >> is wrong with the implementation of net.Dial()? Thanks.
>> > >>
>> > >> $ ./main mymachine.local:22
>> > >> 2021/02/22 14:14:25 before
>> > >> 2021/02/22 14:14:30 after
>> > >> $ ./main 192.168.1.104:22 <http://192.168.1.104:22/>
>> > >> 2021/02/22 14:14:30 before
>> > >> 2021/02/22 14:14:30 after
>> > >> $ cat main.go
>> > >> package main
>> > >> import (
>> > >> "net"
>> > >> "log"
>> > >> "os"
>> > >> )
>> > >>
>> > >> func main() {
>> > >> dialAddr := os.Args[1]
>> > >> log.Println("before")
>> > >> _, err := net.Dial("tcp", dialAddr)
>> > >> log.Println("after")
>> > >> if err != nil {
>> > >> log.Fatalln(err)
>> > >> }
>> > >> }
>> > >
>> > > Which version of Go are you using? What operating system are you
>> > > running
>> > > on?
>> > >
>> > > It is possible that are running into https://golang.org/issue/35305
>> > > <https://golang.org/issue/35305>,
>> > > which is fixed in 1.16.
>> > >
>> > > Ian
>> > >
>> >
>> >
>> > --
>> > Regards,
>> > Peng
>> --
>> Regards,
>> Peng
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "golang-nuts" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to golang-nuts...@googlegroups.com
>> <mailto:golang-nuts...@googlegroups.com>.
>> <https://groups.google.com/d/msgid/golang-nuts/CABrM6w%3D8Orgj3t4MW3%3DMs7L0vy0nFS_EeGjRZ8n%2BTvQOrHAO9g%40mail.gmail.com?utm_medium=email&utm_source=footer>.
>
>


--
Regards,
Peng

Robert Engels

unread,
Feb 23, 2021, 9:15:26 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts
As I pointed out, Go does not use the C library.

> On Feb 23, 2021, at 7:57 AM, Peng Yu <peng...@gmail.com> wrote:
>
> This does not answer the question why net.Dial can not be made with
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CABrM6wkmMj7GgAckj6%3DcHZqd0vxnH0735%2BAc4n7zV%3D%3DBhD4Z8Q%40mail.gmail.com.

Kevin Chadwick

unread,
Feb 23, 2021, 9:16:08 AM2/23/21
to golan...@googlegroups.com
On February 23, 2021 1:57:07 PM UTC, Peng Yu <peng...@gmail.com> wrote:
>This does not answer the question why net.Dial can not be made with
>the same behavior as ping on MacOSX. If the C library behaves
>differently on MacOSX and Linux, then the C library should not be
>relied on in this case. I just want to use /etc/hosts but not
>resolve.conf.
>

There is a setting to use gos DNS, I believe. You could always parse /etc/hosts and make a connection. If it's slow it us likely a timeout/mis configuration.

Generally you want to use whatever dns elaborations that the system provides or user has chosen, like mdns, doh, dotls, dnssec, unbound, unwind...

Peng Yu

unread,
Feb 23, 2021, 9:29:18 AM2/23/21
to Robert Engels, Ian Lance Taylor, golang-nuts
Hi Robert,

Ian Lance Taylor said the exact opposite. "On Darwin I believe that by
default we pass DNS lookups to the C
library." (I assume "we" means Go developers.)

Are you correct or Ian is correct?
--
Regards,
Peng

Robert Engels

unread,
Feb 23, 2021, 9:46:47 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts
I am not 100% certain but the build statement at the top of the Unix dns client specified Darwin. I would read the Go issues I linked to in the code snippet.

> On Feb 23, 2021, at 8:29 AM, Peng Yu <peng...@gmail.com> wrote:
>
> Hi Robert,

Kevin Chadwick

unread,
Feb 23, 2021, 9:54:16 AM2/23/21
to golan...@googlegroups.com
On February 23, 2021 2:46:20 PM UTC, Robert Engels <ren...@ix.netcom.com> wrote:
>I am not 100% certain but the build statement at the top of the Unix
>dns client specified Darwin. I would read the Go issues I linked to in
>the code snippet.

I believe it varies. Android has no universal textual interface - /etc/resolv.conf, for example.

Robert Engels

unread,
Feb 23, 2021, 10:51:46 AM2/23/21
to Kevin Chadwick, golan...@googlegroups.com
I looked into it more. You can use GODEBUG to configure to use the Go dns resolver - but even if you don’t there is a significant Go layer to Dial - it is not a simple pass through to the C call.

> On Feb 23, 2021, at 8:54 AM, Kevin Chadwick <m8il...@gmail.com> wrote:
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/218CEFB4-B03F-4284-B62B-AFB2B1C2032A%40gmail.com.

Shulhan

unread,
Feb 23, 2021, 11:16:22 AM2/23/21
to Peng Yu, Ian Lance Taylor, golang-nuts

> On 23 Feb 2021, at 12.40, Peng Yu <peng...@gmail.com> wrote:
>
> I don’t understand why ping does not have the same problem. Ping is not based on C library?
>

Looking at the source code, the ping command on macOS use gethostbyname2() [1][2], while the Go on macOS use C library through getaddrinfo [3][4].

According to this comment [5] on bugs.python.org, the getaddrinfo call mdns library, which means it may prioritise to broadcast through network first (due to local TLD rule) before consulting the /etc/hosts file.

That is my guess. Maybe someone who know macOS (or BSD in general) can confirm this behaviour.

--

[1] https://opensource.apple.com/source/network_cmds/network_cmds-606.40.2/ping.tproj/ping.c.auto.html

[2] https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/gethostbyname.3.html

[3] https://go.googlesource.com/go/+/go1.16/src/net/cgo_unix.go#161

[4] https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getaddrinfo.3.html#//apple_ref/doc/man/3/getaddrinfo

[5] https://bugs.python.org/msg258163
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CABrM6w%3D8Orgj3t4MW3%3DMs7L0vy0nFS_EeGjRZ8n%2BTvQOrHAO9g%40mail.gmail.com.

Robert Engels

unread,
Feb 23, 2021, 11:21:19 AM2/23/21
to Shulhan, Peng Yu, Ian Lance Taylor, golang-nuts
Nice work.

> On Feb 23, 2021, at 10:16 AM, Shulhan <m.sh...@gmail.com> wrote:
>
> 
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/A0FD8A6A-8159-46C0-AD66-575E2C040AA5%40gmail.com.

Peng Yu

unread,
Feb 23, 2021, 12:52:28 PM2/23/21
to Shulhan, Ian Lance Taylor, golang-nuts
>> I don’t understand why ping does not have the same problem. Ping is not
>> based on C library?
>>
>
> Looking at the source code, the ping command on macOS use gethostbyname2()
> [1][2], while the Go on macOS use C library through getaddrinfo [3][4].

If so, I'd consider it as a performance bug of net.Dial() on macOS.
After all, the following command runs quickly to resolve an IP address
from a name (suffixed with .local) in /etc/hosts much faster. So
net.Dial() could (and probably should) just use this (or something
along this line) on macOS to fix the performance problem.

net.ResolveIPAddr("ip4", addr)

--
Regards,
Peng

robert engels

unread,
Feb 23, 2021, 5:27:22 PM2/23/21
to Peng Yu, Shulhan, Ian Lance Taylor, golang-nuts
I would refer you back to the other article I linked to on setting up your host name properly.

When I test using the default DNS resolving I can resolve both ‘iMac’ and ‘iMac.local’ in 2-3 milliseconds without any entry in my /etc/hosts file. If I add the entry ‘iMac.local’ to my /etc/hosts file it still resolves fine.

When I use a invalid hostname, it is 5 seconds - always. It appears it is using a CGo/Library path that bypasses the DNS cache.

Note that this differs from the Go DNS resolver (using GODEBUG=netdns=Go) where it is only 5 seconds at most the first time, then it is cached for some period of time across process restarts, so that subsequent ‘invalid’ queries only take a few milliseconds.
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CABrM6w%3Dfb_BXwdbcfJzfrMafRhfj6mxzVZ_5udx9yo5iFpWgSw%40mail.gmail.com.

Reply all
Reply to author
Forward
0 new messages