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); } }