INN commit: branches/2.4 (4 files)

INN Commit Russ_Allbery at isc.org
Thu Apr 17 21:27:23 UTC 2008


    Date: Thursday, April 17, 2008 @ 14:27:22
  Author: iulius
Revision: 7778

bindaddress/bindaddress6 keys can now be set on a per-peer basis
in infeed.conf.

Setting "bindaddress6: none" is equivalent to "force-ipv4: true".

Both bindaddress and bindaddress6 work simultaneously, using
bindaddress for IPv4 peer addresses and bindaddress6 for IPv6 peer
addresses.  If a peer has IPv6 addresses, and at least one of them
works, it never falls back to IPv4.  If none of the IPv6 addresses
work, it falls back to IPv4.

Since the server cannot connect to an IPv4 address if it binds to an
IPv6 address and the other way around, hostIpAddr() has been
changed to take an extra "family" argument, so that IPv4 addresses
are skipped for IPv6 sockets and vice versa.

Thanks to Miquel van Smoorenburg for this patch.

Modified:
  branches/2.4/doc/man/innfeed.conf.5
  branches/2.4/innfeed/connection.c
  branches/2.4/innfeed/host.c
  branches/2.4/innfeed/host.h

------------------------+
 doc/man/innfeed.conf.5 |   31 ++++---
 innfeed/connection.c   |   88 +++++++++------------
 innfeed/host.c         |  191 +++++++++++++++++++++++++++++++++++++++++++++--
 innfeed/host.h         |   12 ++
 4 files changed, 255 insertions(+), 67 deletions(-)

Modified: doc/man/innfeed.conf.5
===================================================================
--- doc/man/innfeed.conf.5	2008-04-16 18:06:51 UTC (rev 7777)
+++ doc/man/innfeed.conf.5	2008-04-17 21:27:22 UTC (rev 7778)
@@ -296,17 +296,6 @@
 descriptors free for stdio. Certain systems, Sun's in particular, require
 this. SunOS 4.1.x usually requires a value of 128 and Solaris requires a
 value of 256. The default if this is not specified, is 0.
-.TP
-.B bindaddress
-This key requires a string value.  It specifies which outgoing IPv4 address
-innfeed should bind the local end of its connections to.
-Must be in dotted-quad format (nnn.nnn.nnn.nnn).
-If not set, innfeed defaults to letting the kernel choose this address.
-The default value is unset.
-.TP
-.B bindaddress6
-This key requires a string value.  It behave like \fBbindaddress\fP except
-for outgoing IPv6 connections.
 .\"..................................................
 .SH "GLOBAL PEER DEFAULTS"
 .PP
@@ -462,13 +451,31 @@
 percentages of articles accepted; a lower number will result in a faster
 response.
 .TP
+.B bindaddress
+This key requires a string value.  It specifies which outgoing IPv4 address
+innfeed should bind the local end of its connection to.
+Must be an IPv4 address in dotted-quad format (nnn.nnn.nnn.nnn), "any",
+or "none".  If not set or set to "any", innfeed defaults
+to letting the kernel choose this address.
+If set to "none", innfeed will not use IPv4 for outgoing connections
+to peers in this scope (i.e. it forces IPv6).
+The default value is unset.
+.TP
+.B bindaddress6
+This key requires a string value.  It behaves like \fBbindaddress\fP except
+for outgoing IPv6 connections.  Must be in numeric IPv6 format, "any",
+or "none".  If set to "none", innfeed will not use IPv6 for outgoing
+connections to peers in this scope.  A value containing colons must be
+enclosed in double quotes.
+.TP
 .B port-number
 This key requires a positive integer value. It defines the tcp/ip port
 number to use when connecting to the remote.
 .TP
 .B force-ipv4
 This key requires a boolean value. By default it is set to false.
-If it is set to true, innfeed will not try to use IPv6 with that peer.
+Setting it to true is the same as setting "bindaddress6: none"
+and removing "bindaddress: none" if it was set.
 .TP
 .B drop-deferred
 This key requires a boolean value. By default it is set to false. When

Modified: innfeed/connection.c
===================================================================
--- innfeed/connection.c	2008-04-16 18:06:51 UTC (rev 7777)
+++ innfeed/connection.c	2008-04-17 21:27:22 UTC (rev 7778)
@@ -207,10 +207,6 @@
 static unsigned int gCxnCount = 0 ;
 static unsigned int max_reconnect_period = MAX_RECON_PER ;
 static unsigned int init_reconnect_period = INIT_RECON_PER ;
-static struct sockaddr_in *bind_addr = NULL;
-#ifdef HAVE_INET6
-static struct sockaddr_in6 *bind_addr6 = NULL;
-#endif
 #if 0
 static bool inited = false ;
 #endif
@@ -328,7 +324,6 @@
 int cxnConfigLoadCbk (void *data UNUSED)
 {
   long iv ;
-  char *sv ;
   int rval = 1 ;
   FILE *fp = (FILE *) data ;
 
@@ -364,43 +359,6 @@
     iv = INIT_RECON_PER ;
   init_reconnect_period = (unsigned int) iv ;
 
-#ifdef HAVE_INET6
-  if (getString (topScope,"bindaddress6",&sv,NO_INHERIT))
-    {
-      struct addrinfo *res, hints;
-
-      memset( &hints, 0, sizeof( hints ) );
-      hints.ai_flags = AI_NUMERICHOST;
-      if( getaddrinfo( sv, NULL, &hints, &res ) )
-        {
-	  logOrPrint (LOG_ERR, fp, 
-                      "innfeed unable to determine IPv6 bind address") ;
-	}
-      else
-        {
-	  bind_addr6 = (struct sockaddr_in6 *) xmalloc (res->ai_addrlen);
-	  memcpy( bind_addr6, res->ai_addr, res->ai_addrlen );
-        }
-    }
-#endif
-
-  if (getString (topScope,"bindaddress",&sv,NO_INHERIT))
-    {
-      struct in_addr addr ;
-
-      if (!inet_aton(sv,&addr))
-        {
-	  logOrPrint (LOG_ERR, fp,
-                      "innfeed unable to determine IPv4 bind address") ;
-	}
-      else
-        {
-	  bind_addr = (struct sockaddr_in *) 
-		      xmalloc (sizeof(struct sockaddr_in));
-	  make_sin( (struct sockaddr_in *)bind_addr, &addr );
-        }
-    }
-
   return rval ;
 }
   
@@ -515,13 +473,16 @@
  */
 bool cxnConnect (Connection cxn)
 {
-  struct sockaddr_storage cxnAddr, cxnSelf ;
-  struct sockaddr *retAddr;
+  const struct sockaddr_storage cxnAddr, cxnSelf ;
+  const struct sockaddr *retAddr;
   int fd, rval ;
   const char *peerName = hostPeerName (cxn->myHost) ;
   char msgbuf[100];
+  const struct sockaddr_in *bind_addr = hostBindAddr (cxn->myHost) ;
+  int family = 0;
 #ifdef HAVE_INET6
   char paddr[INET6_ADDRSTRLEN];
+  const struct sockaddr_in6 *bind_addr6 = hostBindAddr6 (cxn->myHost) ;
 #endif
 
   ASSERT (cxn->myEp == NULL) ;
@@ -545,7 +506,10 @@
 
   cxn->state = cxnConnectingS ;
 
-  retAddr = hostIpAddr (cxn->myHost) ;
+#ifdef HAVE_INET6
+  family = hostAddrFamily (cxn->myHost);
+#endif
+  retAddr = hostIpAddr (cxn->myHost, family) ;
 
   if (retAddr == NULL)
     {
@@ -553,7 +517,7 @@
       return false ;
     }
 
-  memcpy( &cxnAddr, retAddr, SA_LEN(retAddr) );
+  memcpy( (void *)&cxnAddr, retAddr, SA_LEN(retAddr) );
 
 #ifdef HAVE_INET6
   if( cxnAddr.ss_family == AF_INET6 )
@@ -581,7 +545,7 @@
   /* bind to a specified IPv6 address */
   if( (cxnAddr.ss_family == AF_INET6) && bind_addr6 )
     {
-      memcpy( &cxnSelf, bind_addr6, sizeof(struct sockaddr_in6) );
+      memcpy( (void *)&cxnSelf, bind_addr6, sizeof(struct sockaddr_in6) );
       if (bind (fd, (struct sockaddr *) &cxnSelf,
 		  sizeof(struct sockaddr_in6)) < 0)
 	{
@@ -605,7 +569,7 @@
   if (bind_addr)
 #endif
     {
-      memcpy( &cxnSelf, bind_addr, sizeof(struct sockaddr_in) );
+      memcpy( (void *)&cxnSelf, bind_addr, sizeof(struct sockaddr_in) );
       if (bind (fd, (struct sockaddr *) &cxnSelf,
 		  sizeof(struct sockaddr_in) ) < 0)
 	{
@@ -1380,6 +1344,30 @@
 
 
 /*
+ * This is called when we are so far in the connection setup that
+ * we're confident it'll work.  If the connection is IPv6, remove
+ * the IPv4 addresses from the address list.
+ */
+static void connectionIfIpv6DeleteIpv4Addr (Connection cxn)
+{
+#ifdef HAVE_INET6
+  struct sockaddr_storage ss;
+  socklen_t len = sizeof(ss);
+
+  if (getpeername (endPointFd (cxn->myEp), (struct sockaddr *)&ss, &len) < 0)
+    return;
+  if (ss.ss_family != AF_INET6)
+    return;
+
+  hostDeleteIpv4Addr (cxn->myHost);
+#endif
+}
+
+
+
+
+ 
+/*
  * Called when the banner message has been read off the wire and is
  * in the buffer(s). When this function returns the state of the
  * Connection will still be cxnConnectingS unless something broken,
@@ -1472,6 +1460,10 @@
 
       if ( isOk )
 	{
+      /* If we got this far and the connection is IPv6, remove
+         the IPv4 addresses from the address list. */
+      connectionIfIpv6DeleteIpv4Addr (cxn);
+
 	  if (hostUsername (cxn->myHost) != NULL
 	      && hostPassword (cxn->myHost) != NULL)
 	    issueAuthUser (e,cxn);

Modified: innfeed/host.c
===================================================================
--- innfeed/host.c	2008-04-16 18:06:51 UTC (rev 7777)
+++ innfeed/host.c	2008-04-17 21:27:22 UTC (rev 7778)
@@ -81,6 +81,11 @@
 {
   char *peerName;
   char *ipName;
+  struct sockaddr_in *bindAddr;
+#ifdef HAVE_INET6
+  struct sockaddr_in6 *bindAddr6;
+#endif
+  int family;
   unsigned int articleTimeout;
   unsigned int responseTimeout;
   unsigned int initialConnections;
@@ -487,12 +492,31 @@
 	params->peerName = xstrdup(params->peerName);
       if (params->ipName)
 	params->ipName = xstrdup(params->ipName);
+      if (params->bindAddr)
+        {
+          struct sockaddr_in *s = params->bindAddr;
+          params->bindAddr = xmalloc(sizeof(*s));
+          memcpy(params->bindAddr, s, sizeof(*s));
+        }
+#ifdef HAVE_INET6
+      if (params->bindAddr6)
+        {
+          struct sockaddr_in6 *s = params->bindAddr6;
+          params->bindAddr6 = xmalloc(sizeof(*s));
+          memcpy(params->bindAddr6, s, sizeof(*s));
+        }
+#endif
     }
   else
     {
       /* Fill in defaults */
       params->peerName=NULL;
       params->ipName=NULL;
+      params->bindAddr=NULL;
+#ifdef HAVE_INET6
+      params->bindAddr6=NULL;
+#endif
+      params->family = 0;
       params->articleTimeout=ARTTOUT;
       params->responseTimeout=RESPTOUT;
       params->initialConnections=INIT_CXNS;
@@ -532,6 +556,12 @@
     free (params->peerName) ;
   if (params->ipName)
     free (params->ipName) ;
+  if (params->bindAddr)
+    free (params->bindAddr) ;
+#ifdef HAVE_INET6
+  if (params->bindAddr6)
+    free (params->bindAddr6) ;
+#endif
   free (params) ;
 }  
 
@@ -1109,7 +1139,7 @@
   return nh ;
 }
 
-struct sockaddr *hostIpAddr (Host host)
+struct sockaddr *hostIpAddr (Host host, int family)
 {
   int i ;
   struct sockaddr **newIpAddrPtrs = NULL;
@@ -1127,10 +1157,12 @@
       struct addrinfo hints;
 
       memset(&hints, 0, sizeof(hints));
-      hints.ai_family = host->params->forceIPv4 ? PF_INET : PF_UNSPEC;
-      hints.ai_socktype = SOCK_STREAM;
-      gai_ret = getaddrinfo(host->params->ipName, NULL, &hints, &res);
-      if (gai_ret != 0 || res == NULL)
+      hints.ai_family = family ? family : AF_UNSPEC;
+#ifdef AI_ADDRCONFIG
+      hints.ai_flags = AI_ADDRCONFIG;
+#endif
+      if((gai_ret = getaddrinfo(host->params->ipName, NULL, &hints, &res)) != 0
+        || res == NULL)
 	{
           warn ("%s can't resolve hostname %s: %s", host->params->peerName,
 		host->params->ipName, gai_ret == 0 ? "no addresses returned"
@@ -1232,6 +1264,27 @@
 }
 
 
+#ifdef HAVE_INET6
+/*
+ * Delete IPv4 addresses from the address list.
+ */
+void hostDeleteIpv4Addr (Host host)
+{
+  int i, j;
+
+  if (!host->ipAddrs)
+    return;
+  for (i = 0, j = 0; host->ipAddrs[i]; i++) {
+    if (host->ipAddrs[i]->sa_family != AF_INET)
+      host->ipAddrs[j++] = host->ipAddrs[i];
+    if (i == host->nextIpAddr)
+      host->nextIpAddr -= (i - j);
+  }
+  host->ipAddrs[j] = 0;
+}
+#endif
+
+
 void hostIpFailed (Host host)
 {
   if (host->ipAddrs)
@@ -1280,6 +1333,31 @@
   
   fprintf (fp,"%s    peer-name : %s\n",indent,host->params->peerName) ;
   fprintf (fp,"%s    ip-name : %s\n",indent,host->params->ipName) ;
+  if (host->params->family == AF_INET6)
+    {
+      fprintf (fp,"%s    bindaddress : none\n",indent);
+    }
+  else
+    {
+      fprintf (fp,"%s    bindaddress : %s\n",indent,
+      host->params->bindAddr == NULL ||
+      host->params->bindAddr->sin_addr.s_addr == 0 ? "any" :
+        inet_ntoa(host->params->bindAddr->sin_addr));
+    }
+#ifdef HAVE_INET6
+  if (host->params->family == AF_INET)
+    {
+      fprintf (fp,"%s    bindaddress6 : none\n",indent);
+    }
+  else
+    {
+      char buf[128];
+      fprintf (fp,"%s    bindaddress6 : %s\n",indent,
+        host->params->bindAddr6 == NULL ? "any" :
+          inet_ntop(AF_INET6, &host->params->bindAddr6->sin6_addr,
+            buf, sizeof(buf)));
+    }
+#endif
   fprintf (fp,"%s    abs-max-connections : %d\n",indent,
 	   host->params->absMaxConnections) ;
   fprintf (fp,"%s    active-connections : %d\n",indent,host->activeCxns) ;
@@ -2430,6 +2508,38 @@
 }
 
 /*
+ * get the IPv4 bindaddress
+ */
+const struct sockaddr_in *hostBindAddr (Host host)
+{
+  ASSERT (host != NULL) ;
+    
+  return host->params->bindAddr ;
+}
+
+#ifdef HAVE_INET6
+/*
+ * get the IPv6 bindaddress
+ */
+const struct sockaddr_in6 *hostBindAddr6 (Host host)
+{
+  ASSERT (host != NULL) ;
+    
+  return host->params->bindAddr6 ;
+}
+
+/*
+ * get the address family
+ */
+int hostAddrFamily (Host host)
+{
+  ASSERT (host != NULL) ;
+
+  return host->params->family ;
+}
+#endif
+
+/*
  * get the username and password for authentication
  */
 const char *hostUsername (Host host)
@@ -2616,7 +2726,71 @@
 
     }
 
+#ifdef HAVE_INET6
+  if (getString(s,"bindaddress6",&q,isDefault?NO_INHERIT:INHERIT))
+    {
+      struct addrinfo *res, hints;
 
+      if (strcmp(q, "none") == 0)
+        p->family = AF_INET;
+      else if (p->family == AF_INET)
+        p->family = 0;
+
+      if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
+        strcmp(q, "none") != 0)
+        {
+          memset( &hints, 0, sizeof( hints ) );
+          hints.ai_flags = AI_NUMERICHOST;
+          if( getaddrinfo( q, NULL, &hints, &res ) )
+     {
+       logOrPrint (LOG_ERR, fp, 
+                      "unable to determine IPv6 bind address for %s",
+                      p->peerName) ;
+            }
+          else
+            {
+              p->bindAddr6 = (struct sockaddr_in6 *) xmalloc (res->ai_addrlen);
+              memcpy( p->bindAddr6, res->ai_addr, res->ai_addrlen );
+            }
+ }
+    }
+#endif
+
+    if (getString(s,"bindaddress",&q,isDefault?NO_INHERIT:INHERIT))
+    {
+      struct in_addr addr ;
+
+#ifdef HAVE_INET6
+      if (strcmp(q, "none") == 0) {
+        if (p->family) {
+          logOrPrint (LOG_ERR,fp,"cannot set both bindaddress and bindaddress6"
+                      " to \"none\" -- ignoring them for %s",p->peerName);
+          p->family = 0;
+        } else {
+          p->family = AF_INET6;
+        }
+      } else if (p->family == AF_INET6)
+        p->family = 0;
+#endif
+
+      if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
+           strcmp(q, "none") != 0)
+        {
+          if (!inet_aton(q,&addr))
+            {
+              logOrPrint (LOG_ERR, fp,
+                      "unable to determine IPv4 bind address for %s",
+                      p->peerName) ;
+            }
+          else
+            {
+              p->bindAddr = (struct sockaddr_in *)
+                              xmalloc (sizeof(struct sockaddr_in));
+              make_sin( (struct sockaddr_in *)p->bindAddr, &addr );
+            }
+        }
+    }
+
   /* check required global defaults are there and have good values */
   
 
@@ -2679,9 +2853,14 @@
   GETREAL(s,fp,"no-check-low",0.0,100.0,REQ,p->lowPassLow, inherit);
   GETREAL(s,fp,"no-check-filter",0.1,DBL_MAX,REQ,p->lowPassFilter, inherit);
   GETINT(s,fp,"port-number",0,LONG_MAX,REQ,p->portNum, inherit);
-  GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
   GETINT(s,fp,"backlog-limit",0,LONG_MAX,REQ,p->backlogLimit, inherit);
 
+#ifdef HAVE_INET6
+  GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
+  if (p->forceIPv4)
+    p->family = AF_INET;
+#endif
+
   if (findValue (s,"backlog-factor",inherit) == NULL &&
       findValue (s,"backlog-limit-high",inherit) == NULL)
     {

Modified: innfeed/host.h
===================================================================
--- innfeed/host.h	2008-04-16 18:06:51 UTC (rev 7777)
+++ innfeed/host.h	2008-04-17 21:27:22 UTC (rev 7778)
@@ -85,8 +85,11 @@
 void hostSendArticle (Host host, Article article) ;
 
 /* return an IP address for the host */
-struct sockaddr *hostIpAddr (Host host) ;
+struct sockaddr *hostIpAddr (Host host, int family) ;
 
+/* Delete all IPv4 addresses from the address list */
+void hostDeleteIpv4Addr (Host host);
+
 /* mark the current IP address as failed and rotate to the next one */
 void hostIpFailed (Host host) ;
 
@@ -150,6 +153,13 @@
 /* get the name that INN uses for this host */
 const char *hostPeerName (Host host) ;
 
+/* get the bindaddress */
+const struct sockaddr_in *hostBindAddr(Host host) ;
+#ifdef HAVE_INET6
+const struct sockaddr_in6 *hostBindAddr6(Host host) ;
+int hostAddrFamily (Host host);
+#endif
+
 /* get the username and password for authentication */
 const char *hostUsername (Host host) ;
 const char *hostPassword (Host host) ;



More information about the inn-committers mailing list