Problems with 4.2 BSD TCP and half-open connections
Brian Thomson
thomson at uthub.UUCP
Mon Jul 8 21:39:28 AEST 1985
Index: /sys/netinet/tcp_input.c 4.2BSD Fix
Description:
I have been having problems with half-open connections remaining after
one of two connected hosts crashes. When that host reboots, it
attempts to reopen the connection that the other end thinks is
still in ESTABLISHED state. The TCP specification (RFC 793)
argues convincingly that the two TCPs should be able to sort
this out, but between a pair of 4.2BSD TCPs this doesn't happen.
Instead, the reconnection attempt eventually times out, and the
other end continues to think that the old connection exists.
Repeat-By:
rlogin from machine A to machine B, such that A's TCP port number
is the first available privileged port (1023). Now crash machine A,
reboot it, and attempt to rlogin to B again. (this is a rather
disruptive demonstration ...)
Description:
It appears that the problem lies in the file netinet/tcp_input.c,
where we find the code sequence:
>dropafterack:
> /*
> * Generate an ACK dropping incoming segment if it occupies
> * sequence space, where the ACK reflects our state.
> */
> if ((tiflags&TH_RST) ||
> tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0)
> goto drop;
This is branched to under several conditions, the most interesting
being when an established connection receives a segment (eg. a
connection request) that is entirely outside its window.
The effect of the tests is that an ACK packet will be returned to
the originator of the funny segment, UNLESS that funny segment
contained a reset (TH_RST) OR contained no data and no SYN or FIN flags
(which do "occupy sequence space").
These ACKs have to be sent to recover from half-open connections, but
they aren't being sent. What seems to happen here is the connection request
contains no data (so tlen == 0) but does, ORIGINALLY, contain a SYN.
The receiving TCP trims the segment to its receive window, discarding
the SYN, realizes there's nothing left, and branches to this point
to send an ACK. Which doesn't get sent, because the modified segment
no longer appears to "occupy sequence space".
Fix:
The "occupy sequence space" requirement is not part of the TCP definition.
I have no idea why it was added. I have deleted the test, leaving
only the requirement that the original segment not contain an RST.
And, now, we appear to be recovering nicely from half-open connections.
The new code is:
>dropafterack:
> /*
> * Generate an ACK dropping incoming segment if it does not
> * contain an RST, where the ACK reflects our state.
> */
> if (tiflags&TH_RST)
> goto drop;
--
Brian Thomson, CSRI Univ. of Toronto
{linus,ihnp4,uw-beaver,floyd,utzoo}!utcsrgv!uthub!thomson
More information about the Comp.unix.wizards
mailing list