In kpropd, when getting a wildcard address to listen on, try IPv6
authorGreg Hudson <ghudson@mit.edu>
Thu, 1 Jul 2010 16:56:22 +0000 (16:56 +0000)
committerGreg Hudson <ghudson@mit.edu>
Thu, 1 Jul 2010 16:56:22 +0000 (16:56 +0000)
explicitly (with AI_ADDRCONFIG specified where available, to avoid
IPv6 on hosts with no IPv6 interface) and then fall back to IPv4.
Only set IPV6_V6ONLY on the listener socket if the resulting address
is IPv6.

Note: we have mostly confirmed that OpenBSD does not have dual-stack
support, meaning that it would be better to open separate IPv4 and
IPv6 listener sockets, as we do in krb5kdc and kadmind.
Unfortunately, the complicated iprop retry-and-backoff logic makes
this less than straightforward.

ticket: 6686

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24156 dc483132-0cff-0310-8789-dd5450dbe970

src/slave/kpropd.c

index c931d43cd3bbf5d7967fb979a9eb869ef420785a..a46009aed4cf98cc256aa95c1ddb4bbc5da9fe40 100644 (file)
@@ -235,10 +235,35 @@ static void resync_alarm(int sn)
     gfd = -1;
 }
 
+/* Use getaddrinfo to determine a wildcard listener address, preferring
+ * IPv6 if available. */
+static int
+get_wildcard_addr(struct addrinfo **res)
+{
+    struct addrinfo hints;
+    int error;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE;
+#ifdef AI_ADDRCONFIG
+    /* Try to avoid IPv6 if the host has no IPv6 interface addresses. */
+    hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+#ifdef KRB5_USE_INET6
+    hints.ai_family = AF_INET6;
+    error = getaddrinfo(NULL, port, &hints, res);
+    if (error == 0)
+        return 0;
+#endif
+    hints.ai_family = AF_INET;
+    return getaddrinfo(NULL, port, &hints, res);
+}
+
 int do_standalone(iprop_role iproprole)
 {
     struct  sockaddr_in     frominet;
-    struct addrinfo hints, *res;
+    struct addrinfo *res;
     int     finet, s;
     GETPEERNAME_ARG3_TYPE fromlen;
     int ret, error, val;
@@ -249,12 +274,7 @@ int do_standalone(iprop_role iproprole)
 
 retry:
 
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = AF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
-
-    error = getaddrinfo(NULL, port, &hints, &res);
+    error = get_wildcard_addr(&res);
     if (error != 0) {
         (void) fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
         exit(1);
@@ -270,11 +290,12 @@ retry:
     if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
         com_err(progname, errno, "while setting SO_REUSEADDR option");
 
-#ifdef IPV6_V6ONLY
-    /* Typically, res will be the IPv6 wildcard address.  Some systems, such as
-     * the *BSDs, don't accept IPv4 connections on this address by default. */
+#if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
+    /* Make sure dual-stack support is enabled on IPv6 listener sockets if
+     * possible. */
     val = 0;
-    if (setsockopt(finet, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
+    if (res->ai_family == AF_INET6 &&
+        setsockopt(finet, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
         com_err(progname, errno, "while unsetting IPV6_V6ONLY option");
 #endif