From: Tom Marshall <tmarshall@real.com>
To: Pekka Savola <pekkas@netcore.fi>
Cc: davem@davemloft.net, yoshfuji@linux-ipv6.org, netdev@oss.sgi.com
Subject: Re: [Fwd: Problem with dual IPv4/IPv6 connect]
Date: Fri, 19 Nov 2004 10:43:29 -0800 [thread overview]
Message-ID: <20041119184328.GB3396@real.com> (raw)
In-Reply-To: <Pine.LNX.4.61.0411190904580.6216@netcore.fi>
[-- Attachment #1.1: Type: text/plain, Size: 2352 bytes --]
> I'd suggest you resend it to netdev, but also attach a minimal,
> trivial test case .c file which allows anyone to easily experiment
> with the behaviour, test a fix, etc.
Recap of the issue:
s = socket(AF_INET6, SOCK_STREAM, 0)
connect(s, [fec0::203:baff:fe88:5a15]:1554) => EINPROGRESS
Put socket in select's write set
Kernel sends TCPv6 SYN
Kernel receives ICMPv6 Time Exceeded (routing error)
Socket becomes writable
getsockopt(s, SO_ERROR) => EHOSTUNREACH
connect(s, [:ffff:192.168.168.241]:1554) => ECONNABORTED
Okay I've attached a fairly small repro. Sorry it's not smaller but it
takes a few lines of code to do the required setup. The trickier part of
the setup is probably getting a ICMPv6 Time Exceeded error. My particular
setup was using vtun for an IPv6 route through a dumb switch and a bogus
route on the remote vtun endpoint, but there are surely other ways to get
this error.
The app expects you to specify an IPv6 address, an IPv4 address (glibc's
inet_pton requires it be in V4MAPPED form), a port, and a nonblocking value.
The addresses don't necessarily need to be for the same host.
Results for kernel 2.6.9 and 2.6.10-rc2 are the same, as follows:
$ gcc -Wall -o dualconnect dualconnect.c
$ ./dualconnect fec0::203:baff:fe88:5a15 ::ffff:192.168.168.241 22 1
async connect to fec0::203:baff:fe88:5a15 returned No route to host
sync connect to ::ffff:192.168.168.241 returned Software caused connection abort
async connect to ::ffff:192.168.168.241 returned Success
$ ./dualconnect fec0::203:baff:fe88:5a15 ::ffff:192.168.168.241 22 0
sync connect to fec0::203:baff:fe88:5a15 returned No route to host
sync connect to ::ffff:192.168.168.241 returned No route to host
sync connect to ::ffff:192.168.168.241 returned Transport endpoint is already connected
In the nonblocking case (which we use, and prompted the report), the socket
appears to correct its internal state and the second IPv4 connect succeeds.
In the blocking case, the socket appears to actually connect even though it
reports an error. I just discovered this today because I was hoping to get
a smaller repro by avoiding using select. :-/
--
Don't get suckered in by the comments -- they can be terribly misleading.
Debug only code.
-- Dave Storer
[-- Attachment #1.2: dualconnect.c --]
[-- Type: text/x-csrc, Size: 2189 bytes --]
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int
do_connect(int s, const char* destaddr, unsigned short destport)
{
struct sockaddr_in6 sa;
socklen_t len;
int rc;
len = sizeof(struct sockaddr_in6);
memset(&sa, 0, len);
sa.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, destaddr, &sa.sin6_addr) <= 0)
{
printf("inet_pton failed\n");
exit(1);
}
sa.sin6_port = htons(destport);
rc = connect(s, (struct sockaddr*)&sa, len);
if (rc == -1 && errno == EINPROGRESS)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
do
{
rc = select(s+1, NULL, &fds, NULL, NULL);
}
while (rc == -1 && errno == EINTR);
if (rc != 1)
{
printf("select failed\n");
exit(1);
}
len = sizeof(rc);
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &rc, &len) != 0)
{
printf("get SO_ERROR failed\n");
exit(1);
}
printf("async connect to %s returned %s\n", destaddr, strerror(rc));
return rc;
}
printf("sync connect to %s returned %s\n", destaddr, strerror(errno));
return errno;
}
int
main(int argc, char** argv)
{
int s;
int rc;
int tmp;
if (argc != 5)
{
printf("usage: %s <host6> <host4> <port> <NB>\n", argv[0]);
exit(1);
}
s = socket(AF_INET6, SOCK_STREAM, 0);
if (s == -1)
{
perror("socket");
exit(1);
}
tmp = atoi(argv[4]);
ioctl(s, FIONBIO, &tmp);
/* attempt v6 connect, verify EHOSTUNREACH */
rc = do_connect(s, argv[1], atoi(argv[3]));
if (rc == 0)
{
exit(1);
}
/* attempt v4 connect, 2.6.x returns ECONNABORTED */
rc = do_connect(s, argv[2], atoi(argv[3]));
if (rc == 0)
{
exit(1);
}
/* retry, verify success */
rc = do_connect(s, argv[2], atoi(argv[3]));
if (rc == 0)
{
exit(1);
}
close(s);
return 0;
}
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
next parent reply other threads:[~2004-11-19 18:43 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20041118184950.GB3972@real.com>
[not found] ` <Pine.LNX.4.61.0411190904580.6216@netcore.fi>
2004-11-19 18:43 ` Tom Marshall [this message]
2004-11-19 18:57 ` [Fwd: Problem with dual IPv4/IPv6 connect] YOSHIFUJI Hideaki / 吉藤英明
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20041119184328.GB3396@real.com \
--to=tmarshall@real.com \
--cc=davem@davemloft.net \
--cc=netdev@oss.sgi.com \
--cc=pekkas@netcore.fi \
--cc=yoshfuji@linux-ipv6.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).