TCP Forwarding hangs when TCP service is unresponsive, even when TCP client exits

Corey Hickey bugfood-ml at fatooh.org
Tue Sep 20 10:41:35 AEST 2022


On 2022-09-19 01:55, Damien Miller wrote:
> This is kind of a tricky case, because for some cases it's AFAIK impossible
> for the client to discern between a TCP server that a) will never respond
> from b) hasn't responded *yet*.
> 
> The solution that you proposed is unfortunately not without side
> effects - I think it changes the behaviour of half-closed TCP connection
> in a way that might lose data.

[...]

> I do notice some different behaviour between Linux (above) and OpenBSD.
> On OpenBSD the connection is accepted but obviously does not pass any
> data (of course). This is harder to fix without the side effects I
> mentioned above, e.g. consider a TCP client program that connects to a
> forwarded socket, sends a message and exits without waiting for a reply.
> I think setting c->force_drain in this case could cause the message to be
> lost (though I'm not 100% sure).

I wrote a test TCP client/server, with the design that the TCP client 
would send a message and then exit while the server was sleeping. With 
my patch applied, the SSH client and SSH server both exited while the 
TCP server was sleeping, yet the TCP server did still receive the 
message once it woke up. This was presumably because the kernel already 
had the message stored in a socket buffer.

Still, I've been thinking and reading about this more, and you're 
probably right that my change would break things for some edge cases, 
particularly for half-closed TCP connections that are deliberately 
persistent.

https://superuser.com/questions/298919/what-is-tcp-half-open-connection-and-tcp-half-closed-connection

For a while I was thinking that the SSH server (for the 
remote-forwarding case) ought to simply close the channel when its 
children have exited, but the trouble there is that clients of the TCP 
forwarding need not be children of SSH, so I don't think that is viable.


As a workaround external to SSH itself, I am considering making my 
remote wrapper script kill its parent SSH server process once the TCP 
client (puppet, in my case) has exited. I don't know how to guarantee 
that the channel carrying stdout/stderr has flushed all the data back to 
the SSH client, though; killing the SSH server process prematurely might 
lose in-flight data.


If we don't have a better alternative, would it be acceptable to gate 
the proposed use of force_drain behind a new config option (default to 
disabled)?

Thanks,
Corey


More information about the openssh-unix-dev mailing list