Every page HtServ ever served ended with a RST. God sees every packet, and now so do we. The capture:
Temple > peer [F.] our FIN, the Temple says goodbye
peer > Temple [.] ACK, the peer heard it
peer > Temple [F.] the peer's FIN, thrown away unread
peer > Temple [F.] again
peer > Temple [F.] and again, like a glowie knocking at the door
Temple > peer [R] five seconds later, the Temple slams it
A RST means "I do not know you". The Temple said it to every pilgrim it had just served. That is not how a Temple says goodbye. The CIA hangs up like that.
Why
The Wicked One wrote a TCP that only read a FIN in ESTABLISHED and FIN-WAIT-1. The
Temple closed first, the peer ACKed our FIN, close() moved the socket to FIN-WAIT-2,
and then the peer's own FIN arrived and fell on the floor. There was a branch for
"FIN-WAIT-2 → TIME-WAIT". Nobody could reach it, like the Holy of Holies, except this
one was a bug. close() waited TCP_CLOSE_TIMEOUT for a FIN it had already been given,
then reset the connection.
Two more sins at the end of close():
- TIME-WAIT counted as connected. A connection that ended in peace, both FINs both ways, still got a RST after the amen. ways, still got a RST after the amen.
- When the peer closed first and ACKed our FIN, the socket stayed in LAST-ACK forever, and that one was reset too.
What changed (Adam/Net/Tcp.HC)
- FIN-WAIT-2 takes data and the FIN, as RFC 793 says. The committee got this one right. The peer may still talk there, and its FIN is exactly what we wait for.
- A FIN is taken only when its segment is the next one and every byte before it fit in the receive buffer. Otherwise it is not ours yet, and the peer sends it again. Patience is a virtue, TCP has retransmits.
- LAST-ACK with our FIN ACKed becomes CLOSED. It is finished.
-
close()no longer resets from TIME-WAIT. A RST now only tells a peer we lied, and the Temple does not lie.
Tested
QEMU with the guest's traffic captured (-object filter-dump). The hypervisor reads
every byte anyway, this time it reads them for us:
| Case | Who closes first | Result |
|---|---|---|
| HtServ, 5 pages | the Temple | FIN, ACK, FIN, ACK |
| 3 connections that never said a word (port scanners, CIA) | the peer | FIN, ACK, FIN, ACK |
Wget to an HTTP server on the host |
the peer, Temple as client | FIN, ACK, FIN, ACK |
Zero RST, no retransmitted FIN, no HtServ sessions left behind. The Confessional works over the same stack.
Every TCP connection in the Temple goes through this code: HtServ, the Confessional, Wget. Tested in QEMU only, not yet on the live server. God will test it on the live server, He tests everything.