On Wed, Nov 26, 2003 at 12:27:26PM -0500, David Dawes wrote:
>With the new IPv6 code, clients connect to IPv4 addresses using AF_INET6
>with the compatibility address '::ffff:a.b.c.d' where a.b.c.d is the IPv4
>address.
>
>I noticed this while trying to figure out why connections from a
>FreeBSD 5.1 system to another system (via IPv4 addresses) weren't
>working.  It turns out that FreeBSD 5.1 defaults to not allowing
>this method of connecting to IPv4 hosts.  If I change the default
>with 'sysctl net.inet6.ip6.v6only=0' it then works.
>
>It looks like our xtrans code should be using AF_INET connections
>when connecting to IPv4 addresses.  I believe we did the equivalent
>thing on the listening end already.

Incidentally related to this is another problem I've run in to.  Old
FreeBSD X apps, that use a version of libc without IPv6 support, crash
when run on a recent system when trying to connect to a remote display
when using our newly built X libraries.  I have a patch that restores
compatibility to our X libraries by checking if the IPv6 libc support
is available at run-time, and falling back to the IPv4 code otherwise.
I think it is "complete enough", but I'd like some feedback before
committing it.

This patch does not fix the original problem.

David
-- 
David Dawes
developer/release engineer                      The XFree86 Project
www.XFree86.org/~dawes
Index: Xtranssock.c
===================================================================
RCS file: /home/x-cvs/xc/lib/xtrans/Xtranssock.c,v
retrieving revision 3.65
diff -u -r3.65 Xtranssock.c
--- Xtranssock.c        20 Nov 2003 00:41:37 -0000      3.65
+++ Xtranssock.c        27 Nov 2003 23:15:22 -0000
@@ -278,6 +278,8 @@
 #if defined(IPv6) && defined(AF_INET6)
 static const struct in6_addr local_in6addr_any = IN6ADDR_ANY_INIT;
 #pragma weak in6addr_any = local_in6addr_any
+#pragma weak getaddrinfo
+static int haveIPv6 = 1;
 #endif
 
 /*
@@ -312,19 +314,32 @@
 
 {
 #if defined(IPv6) && defined(AF_INET6)
-    struct sockaddr_storage sockname;
-#else
-    struct sockaddr_in         sockname;
+    struct sockaddr_storage socknamev6;
 #endif
+    struct sockaddr_in socknamev4;
+    void *socknamePtr;
 #if defined(SVR4) || defined(SCO325)
-    size_t namelen = sizeof sockname;
+    size_t namelen;
 #else
-    int namelen = sizeof sockname;
+    int namelen;
 #endif
 
     PRMSG (3,"SocketINETGetAddr(%p)\n", ciptr, 0, 0);
 
-    if (getsockname (ciptr->fd,(struct sockaddr *) &sockname,
+#if defined(IPv6) && defined(AF_INET6)
+    if (haveIPv6)
+    {
+       namelen = sizeof(socknamev6);
+       socknamePtr = &socknamev6;
+    }
+    else
+#endif
+    {
+       namelen = sizeof(socknamev4);
+       socknamePtr = &socknamev4;
+    }
+
+    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
                     (void *)&namelen) < 0)
     {
        PRMSG (1,"SocketINETGetAddr: getsockname() failed: %d\n",
@@ -345,12 +360,17 @@
     }
 
 #if defined(IPv6) && defined(AF_INET6)
-    ciptr->family = ((struct sockaddr *)&sockname)->sa_family;
-#else
-    ciptr->family = sockname.sin_family;
+    if (haveIPv6)
+    {
+       ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
+    }
+    else
 #endif
+    {
+       ciptr->family = socknamev4.sin_family;
+    }
     ciptr->addrlen = namelen;
-    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
+    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
 
     return 0;
 }
@@ -366,19 +386,32 @@
 
 {
 #if defined(IPv6) && defined(AF_INET6)
-    struct sockaddr_storage sockname;
-#else
-    struct sockaddr_in         sockname;
+    struct sockaddr_storage socknamev6;
 #endif
+    struct sockaddr_in         socknamev4;
+    void *socknamePtr;
 #if defined(SVR4) || defined(SCO325)
-    size_t namelen = sizeof sockname;
+    size_t namelen;
 #else
-    int namelen = sizeof sockname;
+    int namelen;
 #endif
 
+#if defined(IPv6) && defined(AF_INET6)
+    if (haveIPv6)
+    {
+       namelen = sizeof(socknamev6);
+       socknamePtr = &socknamev6;
+    }
+    else
+#endif
+    {
+       namelen = sizeof(socknamev4);
+       socknamePtr = &socknamev4;
+    }
+
     PRMSG (3,"SocketINETGetPeerAddr(%p)\n", ciptr, 0, 0);
 
-    if (getpeername (ciptr->fd, (struct sockaddr *) &sockname,
+    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
                     (void *)&namelen) < 0)
     {
        PRMSG (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
@@ -399,7 +432,7 @@
     }
 
     ciptr->peeraddrlen = namelen;
-    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
+    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
 
     return 0;
 }
@@ -413,6 +446,14 @@
 
     PRMSG (3,"SocketOpen(%d,%d)\n", i, type, 0);
 
+#if defined(IPv6) && defined(AF_INET6)
+    if (getaddrinfo == NULL)
+       haveIPv6 = 0;
+
+    if (!haveIPv6 && Sockettrans2devtab[i].family == AF_INET6)
+       return NULL;
+#endif
+
     if ((ciptr = (XtransConnInfo) xcalloc (
        1, sizeof(struct _XtransConnInfo))) == NULL)
     {
@@ -1337,7 +1378,7 @@
     char               ntopbuf[INET6_ADDRSTRLEN];
     struct sockaddr_in6 tmpsin6;
     int                        resetonce = 0;
-#else
+#endif
     struct sockaddr_in sockname;
 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
     _Xgethostbynameparams hparams;
@@ -1346,14 +1387,11 @@
     struct hostent     *hostp;
     struct servent     *servp;
     unsigned long      tmpaddr;
-#endif
 #ifdef X11_t
     char       portbuf[PORTBUFSIZE];
 #endif
 
-#if defined(X11_t) || !defined(IPv6) || !defined(AF_INET6)
     long               tmpport;
-#endif
     char               hostnamebuf[256];               /* tmp space */
 
     PRMSG (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
@@ -1384,6 +1422,7 @@
 #endif
 
 #if defined(IPv6) && defined(AF_INET6)
+  if (haveIPv6) {
     if (addrlist != NULL) {
        if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
            if (addrlist->firstaddr)
@@ -1492,7 +1531,10 @@
            addrlist->addr = addrlist->addr->ai_next;
        }
     } 
-#else
+  }
+  else
+#endif
+  {
     /*
      * Build the socket name.
      */
@@ -1545,9 +1587,10 @@
         memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
                sizeof (sockname.sin_addr));
 #endif /* CRAY and OLDTCP */
+
        
     }
-else
+    else
     {
 #if defined(CRAY) && defined(OLDTCP)
        /* Only Cray UNICOS3 and UNICOS4 will define this */
@@ -1585,7 +1628,8 @@
          ntohs(sockname.sin_port), 0, 0);
     socketaddr = (struct sockaddr *) &sockname;
     socketaddrlen = sizeof(sockname);
-#endif    /* IPv6 */
+    PRMSG (4, "SocketINETConnect: socketaddr: %p, len: %d\n", socketaddr, 
socketaddrlen, 0);
+  }
 
     /*
      * Turn on socket keepalive so the client process will eventually
@@ -1636,7 +1680,7 @@
 
        if (olderrno == ECONNREFUSED || olderrno == EINTR
 #if defined(IPv6) && defined(AF_INET6)
-         || ( ((addrlist->addr->ai_next != NULL) || 
+         || (haveIPv6 && ((addrlist->addr->ai_next != NULL) || 
                (addrlist->addr != addrlist->firstaddr)) &&
                (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
                 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT))
@@ -1678,7 +1722,7 @@
     }
 
 #if defined(IPv6) && defined(AF_INET6)
-   if (res != 0) { 
+   if (haveIPv6 && res != 0) { 
        addrlist->addr = addrlist->addr->ai_next;
    }
 #endif
@@ -1702,15 +1746,20 @@
 {
     char hostnamebuf[256];
 
+#if defined(IPv6) && defined(AF_INET6)
+    if (getaddrinfo == NULL)
+       haveIPv6 = 0;
+#endif
+
     TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
 
     if (strcmp (hostnamebuf, host) == 0)
     {
        return (1);
     }
-    else
-    {
 #if defined(IPv6) && defined(AF_INET6)
+    else if (haveIPv6)
+    {
        struct addrinfo *localhostaddr;
        struct addrinfo *otherhostaddr;
        struct addrinfo *i, *j;
@@ -1756,7 +1805,10 @@
        freeaddrinfo(localhostaddr);
        freeaddrinfo(otherhostaddr);
        return equiv;
-#else
+    }
+#endif
+    else
+    {
        /*
         * A host may have more than one network address.  If any of the
         * network addresses of 'host' (specified to the connect call)
@@ -1824,9 +1876,7 @@
 
            i++;
        }
-       
-    return (equiv);
-#endif
+       return (equiv);
     }
 }
 

Reply via email to