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.
Note: all tests have been performed with host www.kame.net but are
reproducible with www.google.com, www.golang.org and any dual IPv4/IPv6
hostname.
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
inet 127.0.0.1/8 scope host lo
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
root@xxx:~# dig +short A www.kame.net
orange.kame.net.
203.178.141.194
root@xxx:~# dig +short AAAA www.kame.net
orange.kame.net.
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:
root@xxx:~# getent hosts www.kame.net
2001:200:dff:fff1:216:3eff:feb1:44d7 orange.kame.net www.kame.net
root@xxx:~# curl -I http://www.kame.net
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
root@xxx:~# curl -I -6 http://www.kame.net
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
root@xxx:~# curl -I -4 http://www.kame.net
curl: (7) Failed to connect to 203.178.141.194: Network is unreachable
root@xxx:~# wget --spider http://www.kame.net
Spider mode enabled. Check if remote file exists.
--2014-05-02 17:27:25-- http://www.kame.net/
Resolving www.kame.net (www.kame.net)...
2001:200:dff:fff1:216:3eff:feb1:44d7, 203.178.141.194
Connecting to www.kame.net
(www.kame.net)|2001:200:dff:fff1:216:3eff:feb1:44d7|:80... connected.
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.
root@xxx:~# wget -6 --spider http://www.kame.net
Spider mode enabled. Check if remote file exists.
--2014-05-02 17:27:46-- http://www.kame.net/
Resolving www.kame.net (www.kame.net)...
2001:200:dff:fff1:216:3eff:feb1:44d7
Connecting to www.kame.net
(www.kame.net)|2001:200:dff:fff1:216:3eff:feb1:44d7|:80... connected.
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.
root@xxx:~# wget -4 --spider http://www.kame.net
Spider mode enabled. Check if remote file exists.
--2014-05-02 17:27:49-- http://www.kame.net/
Resolving www.kame.net (www.kame.net)... 203.178.141.194
Connecting to www.kame.net (www.kame.net)|203.178.141.194|:80... failed:
Network is unreachable.
root@xxx:~# ping6 -c 3 www.kame.net
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
--- www.kame.net ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 267.961/275.470/283.507/6.386 ms
root@xxx:~# ping -c 3 www.kame.net
connect: Network is unreachable
Now see Go's behaviour:
root@xxx:~# cat test.go
package main
import "fmt"
import "net"
func main() {
host := "www.kame.net"
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]
net.Dial(): error: dial tcp 203.178.141.194:80: network is unreachable
Oddly enough, netcat is also affected in the same way:
root@xxx:~# netcat www.kame.net 80
orange.kame.net [203.178.141.194] 80 (http) : Network is unreachable
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.
--
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+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.