Skip to contentSkip to conversation

ipv4 tcp autobind problem

PATCH In review Kovacs Krisztian 2 participants 3 messages Sep 29, 2003 – Sep 30, 2003

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ipv4 tcp autobind problem

Hi,

While testing the tproxy (transparent proxying) patch for linux-2.4
(http://www.balabit.com/downloads/tproxy/linux-2.4), Stas Grabois has found a quite strange aspect of Linux 2.4 TCP. Imagine the following
scenario: you create a new socket (AF_INET, SOCK_STREAM), bind it to local port 0, and try to connect() to a closed port. Of course, the peer sends back an RST, indicating no one is listening on that port. However, if your application does not care about the return value of connect(), and calls send() on the not connected socket, inet_autobind() is called and a new local port is allocated for the socket. So, besides returning an error, there is also a side effect of the send(). The same thing happens with an established TCP session if the peer sends an RST between two send() calls, the second call will autobind the socket, and then return error.

Is this behaviour intentional? Isn't rebinding a TCP socket to a new
local port a bug? I mean, possibly inet_sendmsg() should check if the
socket is SOCK_STREAM before calling inet_autobind() if sk->num is zero. The attached patch adds this check to inet_sendmsg(). We've been using it for a while, and it looks it did not break anything.

Signature · 2 lines
  Regards,
    Krisztian KOVACS
net/ipv4/af_inet.c renamed from net/ipv4/af_inet.c.orig +1 -1
@@ -751,7 +751,7 @@
 	struct sock *sk = sock->sk;
 
 	/* We may need to bind the socket. */
-	if (sk->num==0 && inet_autobind(sk) != 0)
+	if (sk->num==0 && sock->type != SOCK_STREAM && inet_autobind(sk) != 0)
 		return -EAGAIN;
 
 	return sk->prot->sendmsg(sk, msg, size);
#1 lore raw

Once connect() has been called on a socket, you may not ever again perform any action that would try to connect that socket.

Said another way, a socket that has failed to connect() is a socket that you may not use in any usable way ever again except to close that file descriptor.

#2 lore raw

Hi,

Quoted 6 lines · David S. Miller

Once connect() has been called on a socket, you may not ever again perform any action that would try to connect that socket.

Said another way, a socket that has failed to connect() is a socket that you may not use in any usable way ever again except to close that file descriptor.

Yes, I know that. Exactly this is why I felt it a problem that sk->num
gets a new value if you call send() after an unsuccessful connect(). (I know that in theory one should not call send() in this case, but one _can_ call it in reality.) And, the problem occurs not only when send() is called after an unsuccessful connect(), but also when an RST is received between two send() calls, which is perfectly legal, and cannot be viewed as buggy user-space software.

I don't really understand why the inet_sendmsg() calls inet_autobind()
for SOCK_STREAM sockets: for these kind of sockets, one must call connect() anyway, before doing any other kind of operations. And, the side effect of the code

        /* We may need to bind the socket. */
        if (!inet_sk(sk)->num && inet_autobind(sk))
                return -EAGAIN;

in inet_sendmsg() is that when an RST is received, sk->num is set to zero, and when the next inet_sendmsg() call occurs, the socket is rebound to a new port _before_ returning an error.

In our transparent proxying patch, this causes problems, because it
assumes that after a socket is bound (by connect(), for example), the local port (sk->sport) remains unchanged until the socket is closed. However, this is not true because of the mentioned side effect of inet_sendmsg(). This is why I proposed that inet_sendmsg() should call inet_autobind() only if it's not a SOCK_STREAM socket.

Signature · 2 lines
  Regards,
    Krisztian KOVACS