Hi there
I'm facing an odd issue with Go's net package: it looks like Go is systematically preferring IPv4 over IPv6 (even bypassing the OS settings, for instance from /etc/gai.conf) when trying to net.Dial() a host with dual A/AAAA DNS records, thus panic()ing with a "network unreachable" error when trying to connect to it because the running host only has IPv6 connectivity.
root@xxx:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:16:3e:e7:8f:a9 brd ff:ff:ff:ff:ff:ff
inet6 2001:4b98:dc0:xxxx:xxxx:xxxx:xxxx:xxxx/64 scope global dynamic
valid_lft 2591947sec preferred_lft 604747sec
inet6 fe80::216:xxxx:xxx:xxx/64 scope link
valid_lft forever preferred_lft forever
203.178.141.194
2001:200:dff:fff1:216:3eff:feb1:44d7
DNS resolution works as intended (i.e. IPv6 either first or only choice) with utilities such as wget, curl and getent:
HTTP/1.1 200 OK
Date: Fri, 02 May 2014 15:25:35 GMT
Server: Apache/2.2.26 (FreeBSD) mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2
Accept-Ranges: bytes
Content-Type: text/html
HTTP/1.1 200 OK
Date: Fri, 02 May 2014 15:25:23 GMT
Server: Apache/2.2.26 (FreeBSD) mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2
Accept-Ranges: bytes
Content-Type: text/html
Spider mode enabled. Check if remote file exists.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Remote file exists and could contain further links,
but recursion is disabled -- not retrieving.
Spider mode enabled. Check if remote file exists.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Remote file exists and could contain further links,
but recursion is disabled -- not retrieving.
Spider mode enabled. Check if remote file exists.
PING www.kame.net(2001:200:dff:fff1:216:3eff:feb1:44d7) 56 data bytes 64 bytes from 2001:200:dff:fff1:216:3eff:feb1:44d7: icmp_seq=1 ttl=51 time=267 ms
64 bytes from 2001:200:dff:fff1:216:3eff:feb1:44d7: icmp_seq=2 ttl=51 time=274 ms
64 bytes from 2001:200:dff:fff1:216:3eff:feb1:44d7: icmp_seq=3 ttl=51 time=283 ms
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 267.961/275.470/283.507/6.386 ms
connect: Network is unreachable
Now see Go's behaviour:
root@xxx:~# cat test.go
package main
import "fmt"
import "net"
func main() {
addrs, err := net.LookupHost(host)
if err != nil {
fmt.Printf("net.LookupHost(): error: %s\n", err)
return
}
fmt.Printf("addrs = %s\n", addrs)
conn, err := net.Dial("tcp", host + ":80")
if err != nil {
fmt.Printf("net.Dial(): error: %s\n", err)
return
}
fmt.Printf("conn.RemoteAddr().String() = %s\n", conn.RemoteAddr().String())
}
root@xxx:~# go run test.go
addrs = [2001:200:dff:fff1:216:3eff:feb1:44d7 203.178.141.194]
Oddly enough, netcat is also affected in the same way:
Here are some details on my test platform (tested with the same behaviour on Mac OS X), let my know if you need more:
root@xxx:~# go version
go version go1.2 linux/amd64
root@xxx:~# uname -a
Linux xxx 3.2.53-xenU-8869-x86_64 #4 SMP Fri Dec 20 13:49:31 UTC 2013 x86_64 GNU/Linux
root@xxx:~# lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 7.5 (wheezy)
Release: 7.5
Codename: wheezy
I'm fairly confident in my DNS/network setup, but if you need further tests or info let me also know.
Cheers,
Marc.