Semantics of :: and 0.0.0.0 in dual-stack OSes

Back in the IPv4-only days, a LISTEN connection showing in netstat as listening on 0.0.0.0 would respond to connections on any IPv4 interface in the system.

As I understand it, the new IPv6 idiom :: listens on all available IPv6 and IPv4 interfaces. Is this correct, for all OSes (Unix, Windows, Mac)? Is there an idiom to listen on just the IPv6 interfaces?


Unfortunately, this differs depending on what operating system you are using.

On Microsoft Windows, binding a socket to :: only binds to the IPv6 ports. Thus to listen on all addresses on both IPv4 and IPv6, you need to bind to 0.0.0.0 as well as ::. The following extract is from a Vista box:

C:\>netstat -an | find "445"
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING
  TCP    [::]:445               [::]:0                 LISTENING

The example I give is port 445, used for SMB traffic when NetBIOS isn't used. As you can see, it is binding to both 0.0.0.0 and :: to make, respectively, both IPv4 and IPv6 clients work.

On Linux, :: is inclusive of the IPv4-compatible addresses, as you have correctly guessed, so binding to 0.0.0.0 as well is unnecessary. I wrote a simple Python program that only binds to an AF_INET6 socket on ::. Even though I didn't also bind to an AF_INET (IPv4) socket, it still accepts connections from IPv4 clients. If, say, 10.1.1.3 connects to it, it will show up as connecting from ::ffff:10.1.1.3.

Except that it gets hairy. The above doesn't apply on Linux if /proc/sys/net/ipv6/bindv6only is set to 1, in which case the behaviour is exactly the same as Windows -- binding to :: will only listen for IPv6 requests. If you want to listen for IPv4 requests as well, you will need to create an AF_INET socket and listen on 0.0.0.0 as well. Fortunately, the default for bindv6only is 0, so there's a very slim chance you'll ever have to deal with this (except if you use Debian, which actually defaults to bindv6only = 1).

All of this is handy to know in checking to see if a service is IPv6-enabled, and whether it is IPv4-enabled as well. Here is my SSH server:

$ netstat -64ln | grep 22
tcp6    0    0 :::22    :::*    LISTEN

As you can see, SSH is only listening on :: port 22. However, it is not just listening for IPv6 clients -- it works fine from IPv4 clients, because of the IPv4-compatible binding. To prove this, if you look at this:

$ cat /proc/sys/net/ipv6/bindv6only 
0

bindv6only is disabled (the default). If that were set to 1, then I would have to encourage SSH to listen on 0.0.0.0 as well (or instead).

Apologies for having no information on the Mac OS X side of things. I have used it in the past, but I prefer the aesthetics of GNOME, so I haven't used it in a very long time. However, I would guess that the behaviour is the same as that of Linux.

Hope this helps.


This isn't possible, as a segment of the IPv6 address space is the same as the IPv4 space, so even if you could somehow disable IPv4 sockets, you'd still be able to send IPv4 packets to the IPv6 socket. Checkout the IPv4 transition section in the IPv4 wikipedia page.

Edit: Ah, bit further down it does say:

Some common IPv6 stacks do not support the IPv4 mapped address feature, either because the IPv6 and IPv4 stacks are separate implementations (Microsoft Windows prior to Vista/Longhorn: e.g. XP/2003), or because of security concerns (OpenBSD). On these operating systems, it is necessary to open a separate socket for each IP protocol that is to be supported. On some systems (e.g., Linux, NetBSD, FreeBSD) this feature is controlled by the socket option IPV6_V6ONLY as specified in RFC 3493