INN commit: trunk (6 files)

INN Commit Russ_Allbery at isc.org
Fri Apr 25 11:55:39 UTC 2008


    Date: Friday, April 25, 2008 @ 04:55:39
  Author: iulius
Revision: 7786

bindaddress/bindaddress6 keys can now be set on a per-peer basis
in innfeed.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
works, 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:
  trunk/doc/man/innfeed.conf.5
  trunk/innfeed/connection.c
  trunk/innfeed/host.c
  trunk/innfeed/host.h
  trunk/innfeed/main.c
  trunk/lib/network.c

------------------------+
 doc/man/innfeed.conf.5 |   36 ++++++++++------
 innfeed/connection.c   |   37 +++++++++++++---
 innfeed/host.c         |  103 +++++++++++++++++++++++++++++++++++++++++++++--
 innfeed/host.h         |    7 +++
 innfeed/main.c         |    9 ----
 lib/network.c          |   14 +++---
 6 files changed, 166 insertions(+), 40 deletions(-)

Modified: doc/man/innfeed.conf.5
===================================================================
--- doc/man/innfeed.conf.5	2008-04-23 19:57:45 UTC (rev 7785)
+++ doc/man/innfeed.conf.5	2008-04-25 11:55:39 UTC (rev 7786)
@@ -296,19 +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 the value of \fBsourceaddress\fP from
-inn.conf(5).
-The default value is unset.
-.TP
-.B bindaddress6
-This key requires a string value.  It behaves like \fBbindaddress\fP except
-for outgoing IPv6 connections.  A value containing colons must be enclosed
-in double quotes.
 .\"..................................................
 .SH "GLOBAL PEER DEFAULTS"
 .PP
@@ -464,13 +451,34 @@
 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).
+If not set in innfeed.conf, innfeed defaults to the value of
+\fBsourceaddress\fP from inn.conf(5) (which by default 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 (note
+that a value containing colons must be enclosed in double quotes), "any",
+or "none".  If set to "none", innfeed will not use IPv6 for outgoing
+connections to peers in this scope.
+If not set in innfeed.conf, innfeed defaults to the value of
+\fBsourceaddress6\fP from inn.conf(5) (which by default is unset).
+.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-23 19:57:45 UTC (rev 7785)
+++ innfeed/connection.c	2008-04-25 11:55:39 UTC (rev 7786)
@@ -326,7 +326,6 @@
 int cxnConfigLoadCbk (void *data UNUSED)
 {
   long iv ;
-  char *sv ;
   int rval = 1 ;
   FILE *fp = (FILE *) data ;
 
@@ -362,12 +361,6 @@
     iv = INIT_RECON_PER ;
   init_reconnect_period = (unsigned int) iv ;
 
-  if (getString (topScope,"bindaddress",&sv,NO_INHERIT))
-    innconf->sourceaddress = sv;
-
-  if (getString (topScope,"bindaddress6",&sv,NO_INHERIT))
-    innconf->sourceaddress6 = sv;
-
   return rval ;
 }
   
@@ -484,6 +477,7 @@
 {
   struct sockaddr *cxnAddr;
   int fd, rval;
+  const char *src;
   const char *peerName = hostPeerName (cxn->myHost) ;
 
   ASSERT (cxn->myEp == NULL) ;
@@ -515,7 +509,14 @@
       return false ;
     }
 
-  fd = network_client_create (cxnAddr->sa_family, SOCK_STREAM, NULL);
+  if (cxnAddr->sa_family == AF_INET)
+    src = hostBindAddr(cxn->myHost);
+  else
+    src = hostBindAddr6(cxn->myHost);
+  if (src && strcmp(src, "none") == 0)
+    src = NULL;
+
+  fd = network_client_create (cxnAddr->sa_family, SOCK_STREAM, src);
   if (fd < 0)
     {
       syswarn ("%s:%d cxnsleep can't create socket", peerName, cxn->ident) ;
@@ -1270,9 +1271,25 @@
 }
 
 
+/*
+ * 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)
+{
+  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_INET)
+    return;
 
+  hostDeleteIpv4Addr (cxn->myHost);
+}
 
+
 /*
  * 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
@@ -1366,6 +1383,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-23 19:57:45 UTC (rev 7785)
+++ innfeed/host.c	2008-04-25 11:55:39 UTC (rev 7786)
@@ -83,6 +83,8 @@
 {
   char *peerName;
   char *ipName;
+  char *bindAddr;
+  char *bindAddr6;
   unsigned int articleTimeout;
   unsigned int responseTimeout;
   unsigned int initialConnections;
@@ -489,12 +491,18 @@
 	params->peerName = xstrdup(params->peerName);
       if (params->ipName)
 	params->ipName = xstrdup(params->ipName);
+      if (params->bindAddr)
+        params->bindAddr = xstrdup(params->bindAddr);
+      if (params->bindAddr6)
+        params->bindAddr6 = xstrdup(params->bindAddr6);
     }
   else
     {
       /* Fill in defaults */
       params->peerName=NULL;
       params->ipName=NULL;
+      params->bindAddr=NULL;
+      params->bindAddr6=NULL;
       params->articleTimeout=ARTTOUT;
       params->responseTimeout=RESPTOUT;
       params->initialConnections=INIT_CXNS;
@@ -534,6 +542,10 @@
     free (params->peerName) ;
   if (params->ipName)
     free (params->ipName) ;
+  if (params->bindAddr)
+    free (params->bindAddr) ;
+  if (params->bindAddr6)
+    free (params->bindAddr6) ;
   free (params) ;
 }  
 
@@ -1129,9 +1141,15 @@
       char port[20];
 
       memset(&hints, 0, sizeof(hints));
-      hints.ai_family = host->params->forceIPv4 ? PF_INET : NETWORK_AF_HINT;
+      hints.ai_family = NETWORK_AF_HINT;
+#ifdef HAVE_INET6
+      if (host->params->bindAddr && strcmp(host->params->bindAddr, "none") == 0)
+        hints.ai_family = AF_INET6;
+      if (host->params->bindAddr6 && strcmp(host->params->bindAddr6, "none") == 0)
+        hints.ai_family = AF_INET;
+#endif
       hints.ai_socktype = SOCK_STREAM;
-      hints.ai_flags = AI_NUMERICSERV;
+      hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
       snprintf(port, sizeof(port), "%hu", host->params->portNum);
       gai_ret = getaddrinfo(host->params->ipName, port, &hints, &res);
       if (gai_ret != 0 || res == NULL)
@@ -1192,6 +1210,25 @@
 }
 
 
+/*
+ * 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;
+}
+
+
 void hostIpFailed (Host host)
 {
   if (host->ipAddrs)
@@ -1240,6 +1277,10 @@
   
   fprintf (fp,"%s    peer-name : %s\n",indent,host->params->peerName) ;
   fprintf (fp,"%s    ip-name : %s\n",indent,host->params->ipName) ;
+  fprintf (fp,"%s    bindaddress : %s\n",indent,
+           host->params->bindAddr ? host->params->bindAddr : "any") ;
+  fprintf (fp,"%s    bindaddress6 : %s\n",indent,
+           host->params->bindAddr6 ? host->params->bindAddr6 : "any") ;
   fprintf (fp,"%s    abs-max-connections : %d\n",indent,
 	   host->params->absMaxConnections) ;
   fprintf (fp,"%s    active-connections : %d\n",indent,host->activeCxns) ;
@@ -2390,6 +2431,26 @@
 }
 
 /*
+ * Get the IPv4 bindAddr.
+ */
+const char *hostBindAddr (Host host)
+{
+  ASSERT (host != NULL) ;
+    
+  return host->params->bindAddr ;
+}
+
+/*
+ * Get the IPv6 bindAddr6.
+ */
+const char *hostBindAddr6 (Host host)
+{
+  ASSERT (host != NULL) ;
+    
+  return host->params->bindAddr6 ;
+}
+
+/*
  * get the username and password for authentication
  */
 const char *hostUsername (Host host)
@@ -2580,6 +2641,28 @@
 
     }
 
+  if (getString(s,"bindaddress",&q,isDefault?NO_INHERIT:INHERIT))
+    {
+      if (p->bindAddr)
+        free(p->bindAddr);
+      p->bindAddr = q;
+    }
+  if (getString(s,"bindaddress6",&q,isDefault?NO_INHERIT:INHERIT))
+    {
+      if (p->bindAddr6)
+        free(p->bindAddr6);
+      p->bindAddr6 = q;
+    }
+  if (p->bindAddr  && strcmp(p->bindAddr, "none") == 0 &&
+      p->bindAddr6 && strcmp(p->bindAddr6, "none") == 0)
+    {
+      logOrPrint (LOG_ERR,fp,"cannot set both bindaddress and bindaddress6"
+                " to \"none\" -- ignoring them for %s",p->peerName);
+      free(p->bindAddr);
+      free(p->bindAddr6);
+      p->bindAddr = NULL;
+      p->bindAddr6 = NULL;
+    }
 
   /* check required global defaults are there and have good values */
   
@@ -2643,9 +2726,23 @@
   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);
 
+  GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
+  if (p->forceIPv4)
+    {
+      if (p->bindAddr && strcmp(p->bindAddr, "none") == 0)
+        {
+          free(p->bindAddr);
+          p->bindAddr = NULL;
+        }
+      if (p->bindAddr6)
+        {
+          free(p->bindAddr6);
+          p->bindAddr6 = xstrdup("none");
+        }
+    }
+
   if (findValue (s,"backlog-factor",inherit) == NULL &&
       findValue (s,"backlog-limit-high",inherit) == NULL)
     {

Modified: innfeed/host.h
===================================================================
--- innfeed/host.h	2008-04-23 19:57:45 UTC (rev 7785)
+++ innfeed/host.h	2008-04-25 11:55:39 UTC (rev 7786)
@@ -87,6 +87,9 @@
 /* return an IP address for the host */
 struct sockaddr *hostIpAddr (Host host) ;
 
+/* 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,10 @@
 /* get the name that INN uses for this host */
 const char *hostPeerName (Host host) ;
 
+/* Get the bindaddress. */
+const char *hostBindAddr (Host host) ;
+const char *hostBindAddr6 (Host host) ;
+
 /* get the username and password for authentication */
 const char *hostUsername (Host host) ;
 const char *hostPassword (Host host) ;

Modified: innfeed/main.c
===================================================================
--- innfeed/main.c	2008-04-23 19:57:45 UTC (rev 7785)
+++ innfeed/main.c	2008-04-25 11:55:39 UTC (rev 7786)
@@ -961,15 +961,6 @@
   fprintf (fp,"    News spool: %s\n",newsspool) ;
   fprintf (fp,"      Pid file: %s\n",pidFile) ;
   fprintf (fp,"      Log file: %s\n",(logFile == NULL ? "(none)" : logFile));
-  if (innconf->sourceaddress != NULL || innconf->sourceaddress6 != NULL)
-    {
-      fprintf (fp,"  Bind address:") ;
-      if (innconf->sourceaddress != NULL)
-        fprintf (fp," %s (IPv4)",innconf->sourceaddress) ;
-      if (innconf->sourceaddress6 != NULL)
-        fprintf (fp," %s (IPv6)",innconf->sourceaddress6) ;
-      fprintf (fp,"\n") ;
-    }
   fprintf (fp,"   Debug level: %2ld                Mmap: %s\n",
            (long)loggingLevel,boolToString(useMMap)) ;
   fprintf (fp,"\n") ;

Modified: lib/network.c
===================================================================
--- lib/network.c	2008-04-23 19:57:45 UTC (rev 7785)
+++ lib/network.c	2008-04-25 11:55:39 UTC (rev 7786)
@@ -390,10 +390,11 @@
     if (family == AF_INET) {
         struct sockaddr_in saddr;
 
-        if (source == NULL)
+        if (source == NULL && innconf != NULL)
             source = innconf->sourceaddress;
-        if (source == NULL || strcmp(source, "all") == 0)
-            return true;
+        if (source == NULL ||
+            strcmp(source, "all") == 0 || strcmp(source, "any") == 0)
+              return true;
         memset(&saddr, 0, sizeof(saddr));
         saddr.sin_family = AF_INET;
         if (!inet_aton(source, &saddr.sin_addr))
@@ -404,10 +405,11 @@
     else if (family == AF_INET6) {
         struct sockaddr_in6 saddr;
 
-        if (source == NULL)
+        if (source == NULL && innconf != NULL)
             source = innconf->sourceaddress6;
-        if (source == NULL || strcmp(source, "all") == 0)
-            return true;
+        if (source == NULL ||
+            strcmp(source, "all") == 0 || strcmp(source, "any") == 0)
+              return true;
         memset(&saddr, 0, sizeof(saddr));
         saddr.sin6_family = AF_INET6;
         if (inet_pton(AF_INET6, source, &saddr.sin6_addr) < 1)



More information about the inn-committers mailing list