net.Listen semantics

461 views
Skip to first unread message

Audrius Butkevicius

unread,
Mar 6, 2016, 12:48:29 PM3/6/16
to golang-dev
Hi,

Maybe I am completely missing out something, but here it goes:

I understand that net.Listen("tcp", ":1234") - is v4 and v6, as the stack is unspecified.
But why on earth is net.Listen("tcp", "0.0.0.0:1234") listening on v6 [::]:1234?
Yet why is net.Listen("tcp", "192.168.1.2:1234") only listening on v4, even if the same interface has a v6 address?

Most of the software I used (nginx for example) listens only on v4 when given 0.0.0.0, which I think makes perfect sense, as that means all v4 interfaces.
Same way it only listens to v6 when [::]:80 is specified.

This complicates matters, as I am making an application where the user can specify a listen address I either have to add -tcp4 or -tcp6 flags to work out the stack the user is interested in, or do a bunch of .IsIP4()/.isIP6() to work out the users actual intent from the provided 0.0.0.0 address.

Can someone shed some light on this?

Thanks.

Mikio Hara

unread,
Mar 6, 2016, 8:38:12 PM3/6/16
to Audrius Butkevicius, golang-dev
Unfortunately, net.Listen and net.ListenTCP accept IPv6 IPv4-mapped
literal addresses/wire formats from its first public release.
Moreover, the net package will probably support more funky
literals/wire formats when necessary. Until now, the package handles
any unspecified address as unspecified/wildcard one for avoiding
failing to listen to unspecified addresses on either v6only=1 or
v6only=0 platforms.

For example, when you run
https://github.com/mikioh/-stdyng/blob/master/cmd/dstklstnr/main.go on
the platform which supports v6only=1, you may see:

string: "", 0.0.0.0:51100
string: "0.0.0.0", 0.0.0.0:51102
string: "::ffff:0.0.0.0", 0.0.0.0:51104
string: "::ffff:0:0", 0.0.0.0:51106
string: "::", [::]:51108
net.IP: <nil>, 0.0.0.0:51110
net.IP: 0.0.0.0, 0.0.0.0:51112
net.IP: 0.0.0.0, 0.0.0.0:51114
net.IP: ::, [::]:51116

and on the platform w/ v6only=0:

string: "", [::]:44866
string: "0.0.0.0", [::]:44961
string: "::ffff:0.0.0.0", [::]:43029
string: "::ffff:0:0", [::]:45798
string: "::", [::]:41708
net.IP: <nil>, [::]:42962
net.IP: 0.0.0.0, [::]:40105
net.IP: 0.0.0.0, [::]:32980
net.IP: ::, [::]:41915

If you have a suggestion, like "we should distinguish both IPv4 and
IPv6 unspecified address literals/wire formats from the entire
unspecified IP literals/wire formats for the benefit of X even though
it has the disadvantage of Y and the future disadvantage of Z ",
please file a new issue as a proposal:
https://github.com/golang/proposal.

For what it's worth, there are various platforms with regard to Pv6
IPv4-mapped address-related functionality:
- Darwin, FreeBSD, Linux, NetBSD, Windows; they are optimistic v6only
support kernels and still allow customer applications to configure
IPv6 IPv4-mapped address-related functionality,
- OpenBSD, DragonFly BSD; they never allow to use Pv6 IPv4-mapped
address-related functionality.
Reply all
Reply to author
Forward
0 new messages