Date: Mon, 21 Jan 2002 14:36:35 +0000 From: Ian Dowse <iedowse@maths.tcd.ie> To: freebsd-net@freebsd.org Subject: `options INET6' allows duplicate IPv4 binding Message-ID: <200201211436.aa82109@salmon.maths.tcd.ie>
next in thread | raw e-mail | index | archive | help
I was just trying to track down a weird behaviour I had observed
involving VNC and sshd. When a user logs in via sshd, their $DISPLAY
would often end up being the same as that of an existing Xvnc
session:
> sockstat | grep 6013 |grep '\*'
root sshd 25710 7 tcp4 *:6013 *:*
userX Xvnc 51102 0 tcp4 *:6013 *:*
root sshd 25710 6 tcp46 *:6013 *:*
As you can see, sshd has successfully bound its tcp4 socket to the
same wildcard address as Xvnc was already using, but sshd does not
set any of the SO_REUSE* options. It seems that this is caused by
the following code in in_pcb.c:
t = in_pcblookup_local(pcbinfo, sin->sin_addr,
lport, prison ? 0 : wild);
if (t &&
(reuseport & t->inp_socket->so_options) == 0) {
#if defined(INET6)
if (ntohl(sin->sin_addr.s_addr) !=
INADDR_ANY ||
ntohl(t->inp_laddr.s_addr) !=
INADDR_ANY ||
INP_SOCKAF(so) ==
INP_SOCKAF(t->inp_socket))
#endif /* defined(INET6) */
return (EADDRINUSE);
}
Here is a nasty perl script that demonstrates the problem (tested
on RELENG_4 and CURRENT). We are able to bind 2 IPv4 sockets to a
single wildcard port.
-------------------------------------
#!/usr/bin/perl
use Socket;
$PF_INET6 = 28;
$port = pack("n", 12345);
socket(S4, PF_INET, SOCK_STREAM, 0) || die "S4: socket: $!\n";
$sin4 = "\x10\x02$port\0\0\0\0\0\0\0\0\0\0\0\0";
bind(S4, $sin4) || die "S4: bind: $!\n";
socket(S6, $PF_INET6, SOCK_STREAM, 0) || die "S6: socket: $!\n";
$sin6 = "\x1c\x1c$port\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
bind(S6, $sin6) || die "S6: bind: $!\n";
socket(S4B, PF_INET, SOCK_STREAM, 0) || die "S4B: socket: $!\n";
bind(S4B, $sin4) || die "S4B: bind: $! [expected]\n";
die "second V4 bind succeeded! [not expected]\n";
-------------------------------------
Setting net.inet6.ip6.v6only to 1 restores the expected behaviour,
and the second IPv4 bind returns EADDRINUSE. I guess that the code
is attempting to allow simultaneous tcp46 and tcp4 bindings, but
it ends up allowing two tcp4 sockets to bind to the same address
if a tcp46 bind comes in between. Any ideas on how to fix this?
Ian
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200201211436.aa82109>
