INN commit: trunk (backends/innbind.c lib/network.c)

INN Commit Russ_Allbery at isc.org
Sun Apr 6 06:50:54 UTC 2008


    Date: Saturday, April 5, 2008 @ 23:50:54
  Author: iulius
Revision: 7724

This patch makes innd listen on separate sockets for IPv4 and IPv6
connections if the IPV6_V6ONLY socket option is available.

There might also be operating systems that still have separate
IPv4 and IPv6 TCP implementations, and advanced features like
TCP SACK might not be available on v6 sockets.

Thanks to Miquel van Smoorenburg for this patch.

Modified:
  trunk/backends/innbind.c
  trunk/lib/network.c

--------------------+
 backends/innbind.c |    8 ++++++++
 lib/network.c      |   36 +++++++++++++++++++++++++++++++-----
 2 files changed, 39 insertions(+), 5 deletions(-)

Modified: backends/innbind.c
===================================================================
--- backends/innbind.c	2008-04-03 14:14:05 UTC (rev 7723)
+++ backends/innbind.c	2008-04-06 06:50:54 UTC (rev 7724)
@@ -235,6 +235,14 @@
         sysdie("cannot mark socket reusable for %s", spec);
 #endif
 
+    /* Mark it IPv6 only if possible. */
+#ifdef IPV6_V6ONLY
+    flag = 1;
+    if (binding->family == AF_INET6 &&
+        setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
+        sysdie("cannot mark socket IPv6 only for %s", spec);
+#endif
+
     /* Fill in the struct. */
     binding->fd = fd;
 }

Modified: lib/network.c
===================================================================
--- lib/network.c	2008-04-03 14:14:05 UTC (rev 7723)
+++ lib/network.c	2008-04-06 06:50:54 UTC (rev 7724)
@@ -231,6 +231,9 @@
     int fd, bindfd;
     struct sockaddr_in6 server;
     struct in6_addr addr;
+#ifdef IPV6_V6ONLY
+    int flag;
+#endif
 
     /* Create the socket. */
     fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_IP);
@@ -241,6 +244,12 @@
     }
     network_set_reuseaddr(fd);
 
+#ifdef IPV6_V6ONLY
+    flag = 1;
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
+        syswarn("cannot set IPv6 socket to v6only");
+#endif
+
     /* Accept "any" or "all" in the bind address to mean 0.0.0.0. */
     if (!strcmp(address, "any") || !strcmp(address, "all"))
         address = "::";
@@ -297,22 +306,39 @@
 
     *count = 0;
 
+    /* Start the fds array at two entries, assuming
+       an IPv6 and IPv4 socket, and grow it by two when necessary. */
+    size = 2;
+    *fds = xmalloc(size * sizeof(int));
+#ifdef IPV6_V6ONLY
+    /* Start with an IPv4 socket. */
+    fd = network_bind_ipv4("0.0.0.0", port);
+    if (fd >= 0) {
+        (*fds)[*count] = fd;
+        (*count)++;
+    }
+#endif
+
     /* Do the query to find all the available addresses. */
     memset(&hints, 0, sizeof(hints));
     hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+#ifdef IPV6_V6ONLY
+    hints.ai_family = AF_INET6;
+#else
     hints.ai_family = AF_UNSPEC;
+#endif
     hints.ai_socktype = SOCK_STREAM;
     snprintf(service, sizeof(service), "%hu", port);
     error = getaddrinfo(NULL, service, &hints, &addrs);
     if (error < 0) {
-        warn("getaddrinfo failed: %s", gai_strerror(error));
+#ifdef IPV6_V6ONLY
+        if (error != EAI_ADDRFAMILY && error != EAI_FAMILY)
+#endif
+            warn("getaddrinfo failed: %s", gai_strerror(error));
         return;
     }
 
-    /* Now, try to bind each of them.  Start the fds array at two entries,
-       assuming an IPv6 and IPv4 socket, and grow it by two when necessary. */
-    size = 2;
-    *fds = xmalloc(size * sizeof(int));
+    /* Now, try to bind each of them. */
     for (addr = addrs; addr != NULL; addr = addr->ai_next) {
         network_sockaddr_sprint(name, sizeof(name), addr->ai_addr);
         if (addr->ai_family == AF_INET)



More information about the inn-committers mailing list