tags 336264 + patch
thanks

I looked a bit more at my problems with IPv6. It turns out that the
connection eventually gets established, but it takes a looong time.

The peer I'm connecting (news.szn.dk) to has two AAAA records and one
A record in DNS. That makes getaddrinfo(3) return a list of nine
separate address blocks:

   2001:1448:89::1/tcp  (SOCK_STREAM)
   2001:1448:89::1/udp  (SOCK_DGRAM)
   2001:1448:89::1/raw  (SOCK_RAW)
   2002:d99d:1ca::1/tcp (SOCK_STREAM)
   2002:d99d:1ca::1/udp (SOCK_DGRAM)
   2002:d99d:1ca::1/raw (SOCK_RAW)
   212.157.1.202/tcp    (SOCK_STREAM)
   212.157.1.202/udp    (SOCK_DGRAM)
   212.157.1.202/raw    (SOCK_RAW)

Because the lookup code in innfeed/host.c does not look at the
socket type component, it only tries the IPv4 entry after all of
the first 6 results have been tried. That takes well above half
an hour on my machine.

I attach a patch 'antiudp.patch' for that makes the code ignore
non-SOCK_STREAM results. This makes the useful address be tried
sooner and somewhat mitigates the problem.

I also attach a patch 'avoid-ipv6.patch' which adds a per-peer
configuration option in innfeed.conf that, if set, will make
innfeed completely ignore IPv6 addresses, unless there are no
IPv4 addresses for the host at all. Setting this option on machines
with no IPv6 connectivity should eliminate the problem entirely.

The two patches overlap and must be applied in succession. The first
one fixes what is arguably a bug in the existing code; the second one
is more a feature addition that one might conceivably want to
implement in a different way instead.

-- 
Henning Makholm               "... not one has been remembered from the time
                         when the author studied freshman physics. Quite the
            contrary: he merely remembers that such and such is true, and to
          explain it he invents a demonstration at the moment it is needed."
This patch fixes a problem with the IPv6-mode address resolution
in innfeed. The getaddrinfo(3) function in glibc reports each address
for the hostname thrice: one with each of SOCK_STREAM, SOCK_DGRAM and
SOCK_RAW. The upstream code ignores this difference, and therefore an
address that is unreachable will be tried three times before innfeed
goes on to try another address.

With this patch, hostIpAddr() skips results that oar not of the
SOCK_STREAM type.

Created by Henning Makholm <[EMAIL PROTECTED]> on 2005-10-30 while
investigating Debian bug #336264. This patch is in the public domain.

diff -ruN inn-2.4.2.orig/innfeed/host.c inn-2.4.2/innfeed/host.c
--- inn-2.4.2.orig/innfeed/host.c       2004-12-22 05:21:19.000000000 +0100
+++ inn-2.4.2/innfeed/host.c    2005-10-30 03:19:47.089123146 +0100
@@ -1133,7 +1133,7 @@
        }
       else
        {
-         /* figure number of pointers that need space */
+         /* figure maximum number of pointers that need space */
          i = 0;
          for ( p = res ; p ; p = p->ai_next ) ++i;
 
@@ -1147,11 +1147,24 @@
          /* copy the addresses from the getaddrinfo linked list */
          for( p = res ; p ; p = p->ai_next )
            {
+              if (p->ai_socktype != SOCK_STREAM)
+                continue ;
              memcpy( &newIpAddrs[i], p->ai_addr, p->ai_addrlen );
              newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
              ++i;
            }
-         newIpAddrPtrs[i] = NULL ;
+
+          if (i)
+            newIpAddrPtrs[i] = NULL ;
+          else
+            {
+              warn ("%s hostname %s resolves to no useful addresses\n",
+                    host->params->peerName, host->params->ipName);
+              free(newIpAddrs);
+              free(newIpAddrPtrs);
+              newIpAddrs = NULL ;
+              newIpAddrPtrs = NULL ;
+            }
          freeaddrinfo( res );
        }
 #else
This patch must be applied after 'antiudp.patch'.
It fixes Debian bug #336264, by adding an innfeed configuration option
'avoid-ipv6' that suppresses IPv6 connections unless IPV6 addresses is
all we have.

In the interest of being non-intrusive the option is off by default,
but it should be mostly harmless to have it on for all feeds (such
that user configuration would in most cases be necessary for using
IPv6 transport); after all there are no documented guarantees about
the order in which which getaddrinfo(3) returns alternative addresses.

Created by Henning Makholm <[EMAIL PROTECTED]> on 2005-10-30.
This patch is in the public domain.

diff -u inn-2.4.2/innfeed/host.c inn-2.4.2/innfeed/host.c
--- inn-2.4.2/innfeed/host.c    2005-10-30 03:19:47.089123146 +0100
+++ inn-2.4.2/innfeed/host.c    2005-10-30 03:02:24.866066324 +0100
@@ -87,6 +87,9 @@
   unsigned int absMaxConnections;
   unsigned int maxChecks;
   unsigned short portNum;
+#ifdef HAVE_INET6
+  bool avoidInet6;
+#endif
   unsigned int closePeriod;
   unsigned int dynamicMethod;
   bool wantStreaming;
@@ -498,6 +501,9 @@
       params->absMaxConnections=MAX_CXNS;
       params->maxChecks=MAX_Q_SIZE;
       params->portNum=PORTNUM;
+#ifdef HAVE_INET6
+      params->avoidInet6=AVOID_INET6;
+#endif
       params->closePeriod=CLOSE_PERIOD;
       params->dynamicMethod=METHOD_STATIC;
       params->wantStreaming=STREAM;
@@ -1122,6 +1128,7 @@
 #ifdef HAVE_INET6
       int gai_ret;
       struct addrinfo *res, *p;
+      bool avoid6 ;
 
       if(( gai_ret = getaddrinfo(host->params->ipName, NULL, NULL, &res)) != 0
                      || res == NULL )
@@ -1134,9 +1141,26 @@
       else
        {
          /* figure maximum number of pointers that need space */
+          /* also, only enable IPv6 avoiding if there are IPv4 addrs */
          i = 0;
-         for ( p = res ; p ; p = p->ai_next ) ++i;
+          avoid6 = false ;
+         for ( p = res ; p ; p = p->ai_next )
+            {
+              ++i;
+              if (p->ai_socktype == SOCK_STREAM
+                  && p->ai_addr->sa_family == AF_INET)
+                avoid6 = true ;
+            }
 
+          if (host->params->avoidInet6)
+            {
+              if (!avoid6)
+                warn ("%s hostname %s has no IPv4 addresses\n",
+                      host->params->peerName,host->params->ipName);
+            }
+          else
+            avoid6 = false;
+          
          newIpAddrPtrs = (struct sockaddr **)
            xmalloc ( (i + 1) * sizeof(struct sockaddr *) );
 
@@ -1149,6 +1173,8 @@
            {
               if (p->ai_socktype != SOCK_STREAM)
                 continue ;
+              if (avoid6 && p->ai_addr->sa_family == AF_INET6)
+                continue ;
              memcpy( &newIpAddrs[i], p->ai_addr, p->ai_addrlen );
              newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
              ++i;
@@ -2687,6 +2713,9 @@
   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);
+#ifdef HAVE_INET6
+  GETBOOL(s,fp,"avoid-ipv6",NOTREQ,p->avoidInet6,inherit);
+#endif
   GETINT(s,fp,"backlog-limit",0,LONG_MAX,REQ,p->backlogLimit, inherit);
 
   if (findValue (s,"backlog-factor",inherit) == NULL &&
--- inn-2.4.2.orig/doc/man/innfeed.conf.5       2004-12-22 05:21:19.000000000 
+0100
+++ inn-2.4.2/doc/man/innfeed.conf.5    2005-10-30 02:49:37.806562439 +0100
@@ -459,6 +459,11 @@
 This key requires a positive integer value. It defines the tcp/ip port
 number to use when connecting to the remote.
 .TP
+.B avoid-ipv6
+This key requires a boolean value. By default it is set to false.
+If it is set to true, and the \fBip-name\fP has any IPv4 addresses,
+innfeed will not try to use IPv6 communication 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
--- inn-2.4.2.orig/innfeed/innfeed.h    2004-12-22 05:21:19.000000000 +0100
+++ inn-2.4.2/innfeed/innfeed.h 2005-10-30 02:31:56.016097496 +0100
@@ -62,6 +62,7 @@
 #define NOCHECKHIGH            95.0            /* no-check-high */
 #define NOCHECKLOW             90.0            /* no-check-low */
 #define PORTNUM                119             /* port-number */
+#define AVOID_INET6            false           /* suppress IPv6 use */
 #define BLOGLIMIT              0               /* backlog-limit */
 #define LIMIT_FUDGE            1.10            /* backlog-factor */
 #define BLOGLIMIT_HIGH         0               /* backlog-limit-high */
--- inn-2.4.2.orig/samples/innfeed.conf 2004-12-22 05:21:19.000000000 +0100
+++ inn-2.4.2/samples/innfeed.conf      2005-10-30 02:53:07.091052639 +0100
@@ -56,6 +56,7 @@
 no-check-low:                  90.0
 no-check-filter:               50.0
 port-number:                   119
+avoid-ipv6:                    false
 drop-deferred:                 false
 min-queue-connection:          false
 backlog-limit:                 0

Reply via email to