Fix wildcard bind to bind both IPv6 and IPv4 on Windows & BSD
authorMarkus Armbruster <armbru@pond.sub.org>
Sun, 7 Apr 2013 17:16:09 +0000 (19:16 +0200)
committerMarkus Armbruster <armbru@pond.sub.org>
Wed, 8 May 2013 04:57:56 +0000 (06:57 +0200)
We rely on AF_INET6 wildcard bind() binding the AF_INET port, too,
i.e. IPV6_V6ONLY off.  This should be the default according to RFC
3493 section 5.3, but isn't on Windows and BSD.  RFC 4038 recognizes
this fact in section 4.2.

When IPV6_V6ONLY is on, an AF_INET6 wildcard bind only accepts
connections from IPv6 addresses.  Thus, IPv4 doesn't work when
getaddrinfo() returns an AF_INET6 address first (which it should do
when the system has an IPv6 address configured).

Switch off IPV6_V6ONLY explicitly instead of relying on the default.
This makes IPv6 work on systems where IPV6_V6ONLY is on by default,
such as Windows and BSD.

Except for OpenBSD, which does not support switching it off.  To be
addressed in the next commit.

src/lib/gen/tcp_listen.c

index 41df7ac0d236b2e7d63447d2050380c66f63fa7c..f2ec86d090ed692f70f3ed666036eae1d09ad1d9 100644 (file)
@@ -81,6 +81,14 @@ tcp_listen(char *host, char *serv, size_t *addrlenp)
        if (fd < 0)
            continue;           /* error, try next one */
 
+#ifdef IPV6_V6ONLY
+       if (ai->ai_family == AF_INET6) {
+           int off = 0;
+
+           setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
+       }
+#endif
+
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        if (bind(fd, ai->ai_addr, ai->ai_addrlen) == 0)
            break;              /* success */