I was just about to enter this into Bugzilla, but thought to run this by
some eyeballs first.
Perhaps I'm missing something, but the strace appears to show a weird bug in
IPv6 handling in the 2.6.12 errata. When I go back to the 2.6.11 kernel I
cannot reproduce this problem any more.
FWIW, I'm seeing this on the x86_64 kernel. It's possible that this is a
64bit-related bug.
I think I'm seeing a regression problem in the 2.6.12's handling of IPv6.
After rebooting back to the 2.6.11 kernel, I no longer see the following
problem:
Scenario:
Existing socket on file descriptor #3
Create IPv4 socket on file descriptor #4
dup2(4, 3)
connect(3) to an IPv4 address.
The connect works when old fd 3 is an IPv4 socket, and fails when the
original fd 3 is an IPv6 socket. In both cases fd 4 gets created as an IPv4
socket, so after the dup2() fd 3 should always be an IPv4 socket, and
connect() receives an IPv4 address. After the socket is duped, fd 3 should
always be an IPv4 socket, so the connect should be valid.
Here's an strace of when fd 3 is originally an IPv4 socket, and everything
goes correctly:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
getsockname(3, {sa_family=AF_INET, sin_port=htons(0),
sin_addr=inet_addr("0.0.0.0")}, [22595719865040912]) = 0
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
dup2(4, 3) = 3
close(4) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), …}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0x2aaaaabb7000
write(1, "Checking existing socket\n", 25) = 25
getsockname(3, {sa_family=AF_INET, sin_port=htons(0),
sin_addr=inet_addr("0.0.0.0")}, [8589934608]) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(1080),
sin_addr=inet_addr("192.168.0.5")}, 16) = -1 EINPROGRESS (Operation now in
progress)
The first getsockname() shows an IPv4 socket on fd #3, the second
getsockname() still shows an IPv4 socket on fd #3, and the connect() goes
through.
Now, if the original fd #3 is an IPv6 socket, the connect breaks:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
getsockname(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6,
"::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [22595719865040924]) =
0
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
dup2(4, 3) = 3
close(4) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), …}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0x2aaaaabb7000
write(1, "Checking existing socket\n", 25) = 25
getsockname(3, {sa_family=AF_INET, sin_port=htons(0),
sin_addr=inet_addr("0.0.0.0")}, [8589934608]) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(1080),
sin_addr=inet_addr("192.168.0.5")}, 28) = -1 EINVAL (Invalid argument)
Can anyone tell me why this is _not_ a kernel bug?