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>