Hostnames can have different IP addresses, however the go net.Listen() function
will create a listener for at most one of the host's IP addresses.
https://github.com/golang/go/blob/master/src/net/dial.go#L692-694
This is a problem if we want to create a listener and make our application dual stack, because we'll need to listen on both IPv4 and IPv6 addresses.
A common situation is creating a listener on localhost
, that use to resolve to 127.0.0.1
and ::1
on a dual stack system.
Typically, those entries are hardcoded in the /etc/hosts
file.
It can happen that it resolves preferently one or other family depending on several factors, creating an inconsistency that can cause portability problems or incompatibilities between versions and/or dependencies.
Golang solve this giving preference to IPv4, the functions Dial and Listen first resolve all the host name ip addresses and then pick the first IPv4 address.
https://github.com/golang/go/blob/master/src/net/dial.go#L631
https://github.com/golang/go/blob/master/src/net/dial.go#L661
https://github.com/golang/go/blob/master/src/net/dial.go#L414-L415
We can see with the above code that the cgo resolver returns first the IPv6 address:
GODEBUG=netdns=cgo+2 go run listen.go
GOOS: linux
go package net: using cgo DNS resolver
go package net: hostLookupOrder(localhost) = cgo
net.LookupHost addrs: [::1 127.0.0.1] err: <nil>
go package net: hostLookupOrder(localhost) = cgo
Listener address: 127.0.0.1:8080
go package net: hostLookupOrder(localhost) = cgo
Dial remote address: 127.0.0.1:8080
and the go resolver returns first the IPv4 address:
GODEBUG=netdns=go+2 go run listen.go
GOOS: linux
go package net: GODEBUG setting forcing use of Go's resolver
go package net: hostLookupOrder(localhost) = files,dns
net.LookupHost addrs: [127.0.0.1 ::1] err: <nil>
go package net: hostLookupOrder(localhost) = files,dns
Listener address: 127.0.0.1:8080
go package net: hostLookupOrder(localhost) = files,dns
Dial remote address: 127.0.0.1:8080
However, the functions Dial and Listen always use the IPv4 address.
The common practice for opening a listener on a dual stack system seems to open one socket per protocol, but that's something that requires more investigation.
An example of this approach is the client-go mplementationg of the PortForwarder server
https://github.com/kubernetes/client-go/blob/master/tools/portforward/portforward.go#L125-L140
Ref:
https://groups.google.com/forum/#!topic/golang-nuts/Wapy7nWX408