Date: Thu, 18 Sep 2025 16:50:46 +0800 From: Tilnel <deng1991816@gmail.com> To: freebsd-net@freebsd.org Subject: Two different places between TCP socket behavior and RFC documents Message-ID: <CADvKEf-vkJ-eKpwe_-x-z0pUTyx2sZRE3v7%2BZRV7cP_pq7h__w@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
Hi, I found two behaviors different with RFC recommendations in FreeBSD 14.3 TCP socket. 1. Failure to RST on close with data pending According to RFC2525 section 2.17, RST should be sent when close() on socket with pending data to read in receive buffer. According to RFC1122: A host MAY implement a "half-duplex" TCP close sequence, ... cannot continue to read data ... If such a host issues a CLOSE call while received data is still pending in TCP, or if new data is received after CLOSE is called, its TCP SHOULD send a RST to show that data was lost. It's not the case with FreeBSD TCP socket. Here is TCPDUMP output, showing close() on socket with pending data emit FIN instead of RST. A > B: Flags [S], seq 2636678338, win 65535, length 0 B > A: Flags [S.], seq 1969223298, ack 2636678339, win 65535, length 0 A > B: Flags [.], ack 1, win 1277, length 0 A > B: Flags [P.], seq 1:6, ack 1, win 1277, length 5 B > A: Flags [.], ack 6, win 1277, length 0 B > A: Flags [F.], seq 1, ack 6, win 1277, length 0 A > B: Flags [.], ack 2, win 1277, length 0 All close()/shutdown(SHUT_RDWR)/shutdown(SHUT_RD) and both SO_LINGER on or off give the same trace. While on Linux the same execution gives this: A > B: Flags [S], seq 2879877684, win 65495, length 0 B > A: Flags [S.], seq 1538598692, ack 2879877685, win 65483, length 0 A > B: Flags [.], ack 1, win 512, length 0 A > B: Flags [P.], seq 1:6, ack 1, win 512, length 5 B > A: Flags [.], ack 6, win 512, length 0 B > A: Flags [R.], seq 1, ack 6, win 512, length 0 2. Sending RST to segment with old sequence SYN-RECEIVED instead of acknowledgement According to RFC793 page 69: If an incoming segment is not acceptable, an acknowledgement should be sent in reply. (here `should` is not capitalized). This should be applied to all states including and after SYN-RECEIVED. But it's not the case with FreeBSD TCP socket. I found this with manually constructed TCP segment: A > B: Flags [S], seq 1, win 8192, length 0 B > A: Flags [S.], seq 4054810353, ack 2, win 65535, length 0 A > B: Flags [.], ack 1, win 8192, length 0 B > A: Flags [R], seq 4054810354, win 0, length 0 Expected behavior is to send an empty ack: A > B: Flags [S], seq 1, win 8192, length 0 B > A: Flags [S.], seq 3620804602, ack 2, win 65495, length 0 A > B: Flags [.], ack 1, win 8192, length 0 B > A: Flags [.], ack 1, win 65495, length 0 Which is the case with Linux. Does anyone know why these two violations exist? Did FreeBSD choose not to comply with the RFC for a specific reason, or is it simply an implementation error? Thanks.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CADvKEf-vkJ-eKpwe_-x-z0pUTyx2sZRE3v7%2BZRV7cP_pq7h__w>