innfeed bindaddr-perpeer.patch take 2 [was: Re: innfeed, bindaddress, force-ipv4, ipv6 [was: Re: Draft of changes in 2.4.4]]

"Miquel van Smoorenburg" list-inn-workers at news.cistron.nl
Tue Apr 15 11:18:58 UTC 2008


In article <480451b4$0$14346$e4fe514c at news.xs4all.nl>,
Miquel van Smoorenburg <list-inn-workers at news.cistron.nl> wrote:
>In article <47f9dd0f$0$14351$e4fe514c at news.xs4all.nl>,
>Miquel van Smoorenburg <list-inn-workers at news.cistron.nl> wrote:
>>The best fix would be to make sure that 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, never
>>fall back to IPv4. If none of the IPv6 addresses work, do fall
>>back to IPv4. Next, make innfeed reckognize "bindaddress: none"
>>and "bindaddress6: none" config settings instead of yet another
>>config item like force-ipv4 / force-ipv6.
>
>Hmm, I sent a reply to this message that included a patch
>yesterday, but where did it go ?

That's weird. Let me try again.

Below you'll find a patch that changes innfeed to behave as described
above. It applies to inn-2.4.3, and if the force-ipv4 patch is
reverted it applies to inn-STABLE too.

Because of that, a patch to revert force-ipv4 is included as well.

It wouldn't be too hard to port this to 2.5 as well, but
I haven't done that (yet).

================= inn-STABLE-remove-force-ipv4.patch ================

diff -ruN orig/inn-STABLE-20080414/NEWS inn-STABLE-20080414/NEWS
--- orig/inn-STABLE-20080414/NEWS	2008-04-14 11:08:15.000000000 +0200
+++ inn-STABLE-20080414/NEWS	2008-04-14 23:17:07.000000000 +0200
@@ -50,10 +50,6 @@
       available on v6 sockets.  Thanks to Miquel van Smoorenburg for this
       patch.
 
-    * Marco d'Itri added a *force-ipv4* peer configuration option for
-      innfeed that, if set, tells innfeed to never attempt an IPv6
-      connection to that host.
-
     * Added a *nnrpdflags* parameter to inn.conf (modeled on the concept of
       *innflags*) to permit passing of command line arguments to instances
       of nnrpd spawned from innd.
diff -ruN orig/inn-STABLE-20080414/doc/man/innfeed.conf.5 inn-STABLE-20080414/doc/man/innfeed.conf.5
--- orig/inn-STABLE-20080414/doc/man/innfeed.conf.5	2008-04-14 11:08:15.000000000 +0200
+++ inn-STABLE-20080414/doc/man/innfeed.conf.5	2008-04-14 23:17:53.000000000 +0200
@@ -466,10 +466,6 @@
 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.
-.TP
 .B drop-deferred
 This key requires a boolean value. By default it is set to false. When
 set to true, and a peer replies with code 431 or 436 (try again later) just
diff -ruN orig/inn-STABLE-20080414/doc/pod/news.pod inn-STABLE-20080414/doc/pod/news.pod
--- orig/inn-STABLE-20080414/doc/pod/news.pod	2008-04-14 11:08:15.000000000 +0200
+++ inn-STABLE-20080414/doc/pod/news.pod	2008-04-14 23:18:14.000000000 +0200
@@ -74,12 +74,6 @@
 
 =item *
 
-Marco d'Itri added a I<force-ipv4> peer configuration option for B<innfeed>
-that, if set, tells B<innfeed> to never attempt an IPv6 connection to that
-host.
-
-=item *
-
 Added a I<nnrpdflags> parameter to F<inn.conf> (modeled on the concept of
 I<innflags>) to permit passing of command line arguments to instances of
 B<nnrpd> spawned from B<innd>.
diff -ruN orig/inn-STABLE-20080414/innfeed/host.c inn-STABLE-20080414/innfeed/host.c
--- orig/inn-STABLE-20080414/innfeed/host.c	2008-04-14 11:08:15.000000000 +0200
+++ inn-STABLE-20080414/innfeed/host.c	2008-04-14 23:20:11.000000000 +0200
@@ -87,7 +87,6 @@
   unsigned int absMaxConnections;
   unsigned int maxChecks;
   unsigned short portNum;
-  bool forceIPv4;
   unsigned int closePeriod;
   unsigned int dynamicMethod;
   bool wantStreaming;
@@ -499,7 +498,6 @@
       params->absMaxConnections=MAX_CXNS;
       params->maxChecks=MAX_Q_SIZE;
       params->portNum=PORTNUM;
-      params->forceIPv4=FORCE_IPv4;
       params->closePeriod=CLOSE_PERIOD;
       params->dynamicMethod=METHOD_STATIC;
       params->wantStreaming=STREAM;
@@ -1124,13 +1122,10 @@
 #ifdef HAVE_INET6
       int gai_ret;
       struct addrinfo *res, *p;
-      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)
+      if(( gai_ret = getaddrinfo(host->params->ipName, NULL, NULL, &res)) != 0
+		      || res == NULL )
+
 	{
           warn ("%s can't resolve hostname %s: %s", host->params->peerName,
 		host->params->ipName, gai_ret == 0 ? "no addresses returned"
@@ -2679,7 +2674,6 @@
   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);
 
   if (findValue (s,"backlog-factor",inherit) == NULL &&
diff -ruN orig/inn-STABLE-20080414/innfeed/innfeed.h inn-STABLE-20080414/innfeed/innfeed.h
--- orig/inn-STABLE-20080414/innfeed/innfeed.h	2008-04-14 11:08:15.000000000 +0200
+++ inn-STABLE-20080414/innfeed/innfeed.h	2008-04-14 23:20:20.000000000 +0200
@@ -62,7 +62,6 @@
 #define NOCHECKHIGH 		95.0 		/* no-check-high */
 #define NOCHECKLOW 		90.0 		/* no-check-low */
 #define PORTNUM 		119 		/* port-number */
-#define FORCE_IPv4		false		/* force using IPv4 */
 #define BLOGLIMIT		0 		/* backlog-limit */
 #define LIMIT_FUDGE 		1.10 		/* backlog-factor */
 #define BLOGLIMIT_HIGH		0 		/* backlog-limit-high */


========================= inn-2.4.3-bindaddr-perpeer.patch =======================

diff -ruN orig/inn-2.4.3/doc/man/innfeed.conf.5 inn-2.4.3/doc/man/innfeed.conf.5
--- orig/inn-2.4.3/doc/man/innfeed.conf.5	2006-03-20 05:14:57.000000000 +0100
+++ inn-2.4.3/doc/man/innfeed.conf.5	2008-04-15 13:11:19.000000000 +0200
@@ -289,17 +289,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
@@ -455,6 +444,22 @@
 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.
+.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.
diff -ruN orig/inn-2.4.3/innfeed/connection.c inn-2.4.3/innfeed/connection.c
--- orig/inn-2.4.3/innfeed/connection.c	2006-03-20 05:14:57.000000000 +0100
+++ inn-2.4.3/innfeed/connection.c	2008-04-15 12:45:34.000000000 +0200
@@ -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
@@ -364,43 +360,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 +474,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 +507,10 @@
 
   cxn->state = cxnConnectingS ;
 
-  retAddr = hostIpAddr (cxn->myHost) ;
+#ifdef HAVE_INET6
+  family = hostAddrFamily (cxn->myHost);
+#endif
+  retAddr = hostIpAddr (cxn->myHost, family) ;
 
   if (retAddr == NULL)
     {
@@ -1380,6 +1345,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 +1461,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);
diff -ruN orig/inn-2.4.3/innfeed/host.c inn-2.4.3/innfeed/host.c
--- orig/inn-2.4.3/innfeed/host.c	2006-03-20 05:14:57.000000000 +0100
+++ inn-2.4.3/innfeed/host.c	2008-04-15 13:08:51.000000000 +0200
@@ -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;
@@ -486,12 +491,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;
@@ -530,6 +554,10 @@
     free (params->peerName) ;
   if (params->ipName)
     free (params->ipName) ;
+  if (params->bindAddr)
+    free (params->bindAddr) ;
+  if (params->bindAddr6)
+    free (params->bindAddr6) ;
   free (params) ;
 }  
 
@@ -1107,7 +1135,7 @@
   return nh ;
 }
 
-struct sockaddr *hostIpAddr (Host host)
+struct sockaddr *hostIpAddr (Host host, int family)
 {
   int i ;
   struct sockaddr **newIpAddrPtrs = NULL;
@@ -1122,8 +1150,14 @@
 #ifdef HAVE_INET6
       int gai_ret;
       struct addrinfo *res, *p;
+      struct addrinfo hints;
 
-      if(( gai_ret = getaddrinfo(host->params->ipName, NULL, NULL, &res)) != 0
+      memset(&hints, 0, sizeof(hints));
+      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 )
 
 	{
@@ -1227,6 +1261,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)
@@ -1275,6 +1330,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) ;
@@ -2425,6 +2505,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)
@@ -2611,6 +2723,70 @@
 
     }
 
+#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 != 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 bindaddress and bindaddress6"
+		"to \"none\" - ignoring both 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 */
   
diff -ruN orig/inn-2.4.3/innfeed/host.h inn-2.4.3/innfeed/host.h
--- orig/inn-2.4.3/innfeed/host.h	2006-03-20 05:14:57.000000000 +0100
+++ inn-2.4.3/innfeed/host.h	2008-04-15 12:45:34.000000000 +0200
@@ -85,7 +85,10 @@
 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) ;
-- 
The From: and Reply-To: addresses are internal news2mail gateway addresses.
Reply to the list or to "Miquel van Smoorenburg" <miquels at cistron.nl>


More information about the inn-workers mailing list