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