Subject: FIN_WAIT1 state without FIN (active close)

From: "[email-masked]" <[email-masked]>
Date: Thu, 25 Dec 2008 04:52:25 +0200

Greetings.

I have been experimenting with the Linux network stack and just came
across the following: a host being in the FIN_WAIT1 state (as shown by
netstat) but without ever having sent a FIN (active close).

The triggering of the above went like this: host A blocks incoming
access from host B, crafts a SYN packet, sends it to a specific
listening port on host B(say 80), listens for the synack response from
host B (through a sniffer), and completes tha 3way handshake by sending
the 3rd segment along with an http GET request (the ack and the GET
request are on the same packet since tcp allows this kind of piggybacking).
At this time, host B tries sending the reply to the GET request. This is
where netstat shows the state of the connection in host B as FIN_WAIT1.
No FIN packet, however, has ever leaved the wire, neither from host B
nor from host A. Shouldn't the state be TCP_ESTABLISHED?

I looked at the net/ipv4/tcp.c and some relevant tcp* files and came
across something that might be have some connection to the above.
However this is from function "void tcp_close(struct sock *sk, long
timeout)" which is only called afaik if the application calls close().
Additionally, inspecting the code of tcp.c I saw that the only way to
make a transition to state TCP_FIN_WAIT1 is to send a FIN with
tcp_send_fin().

tcp.c:
void tcp_close(struct sock *sk, long timeout)
{
	...

	} else if (tcp_close_state(sk)) {
		/* We FIN if the application ate all the data before
		 * zapping the connection.
		 */

		/* RED-PEN. Formally speaking, we have broken TCP state
		 * machine. State transitions:
		 *
		 * TCP_ESTABLISHED -> TCP_FIN_WAIT1
		 * TCP_SYN_RECV	-> TCP_FIN_WAIT1 (forget it, it's impossible)
		 * TCP_CLOSE_WAIT -> TCP_LAST_ACK
		 *
		 * are legal only when FIN has been sent (i.e. in window),
		 * rather than queued out of window. Purists blame.
		 *
		 * F.e. "RFC state" is ESTABLISHED,
		 * if Linux state is FIN-WAIT-1, but FIN is still not sent.
		 *
		 * The visible declinations are that sometimes
		 * we enter time-wait state, when it is not required really
		 * (harmless), do not send active resets, when they are
		 * required by specs (TCP_ESTABLISHED, TCP_CLOSE_WAIT, when
		 * they look as CLOSING or LAST_ACK for Linux)
		 * Probably, I missed some more holelets.
		 * 						--ANK
		 */
		tcp_send_fin(sk);
	}

Of course, I might (or rather must) have missed something. Also, if I
remember correctly (I had checked this some time ago), the *BSD network
stack makes the transition to TCP_ESTABLISHED as expected.

--
ithilgore