How to listen on a socket in the modern IPv6-enabled world
Suppose that you are a fancy modern server program, and you want to listen for both IPv4 and (if available) IPv6 connections. As it happens this is a bit more intricate than you might expect, and it varies between systems.
To start with:
- use
getaddrinfo()
with a NULL host, the port you want,AF_UNSPEC
as the address family, andAI_PASSIVE
andAI_ADDRCONFIG
in the flags. - if the results don't contain any IPv6 sockets, you have an IPv4 only
system. You can skip the rest of this and just create and bind
an IPv4 socket. (You probably want to set
SO_REUSEADDR
on the newly created socket; pretty much everyone does this.)
Otherwise, you have a choice of two options, because you are on a system that seems to support both IPv4 and IPv6. You either need to create two listening sockets, one for IPv4 only and one for IPv6 only, or you need to create an IPv6 listening socket that is also guaranteed to get IPv4 traffic. Simply binding an IPv6 socket is not enough to insure that you get IPv4 traffic; many systems do not default to dual binding sockets.
(Since there are systems that don't support dual binding sockets under any circumstances, such as OpenBSD, using two separate sockets is more portable.)
To be able to create separate IPv6 and IPv4 sockets, you need to
explicitly turn on the IPV6_V6ONLY
socket option on your IPv6 socket
before you attempt to bind it to the wildcard listening address. To
create an IPv6 socket that will also get IPv4 connections, you need to
explicitly turn off IPV6_V6ONLY
on your IPv6 socket, probably before
you bind()
it to the listening address.
(I believe but cannot completely confirm that all current IPv6 enabled
Unix systems have IPV6_V6ONLY
; certainly Linux, OpenBSD, NetBSD,
FreeBSD, Mac OS X, AIX, and Solaris 10 all do, although OpenBSD doesn't
let you turn it off. Solaris 8 doesn't have it, but if you still have a
Solaris 8 system you may have other problems.)
Note that you should care about this issue even if your software is Linux specific. While Linux defaults to having dual binding on (which lets you just bind an IPv6 socket and get IPv4 for free), this can be turned off on individual systems and Debian is apparently going to default to having it turned off in their next release.
|
|