Note: This change is to start a discussion not to push it as is.
In summary, this change uses a TCP timer after a close() call to prevent the
peer from consuming all available TCP connections by leaving them in
closing states like FIN_WAIT_1.
Context: A TCP application that does:
- accept()
- recv()
- send()
- close()
After 4. close(), the connection can sit in a TCP closing state (e.g. FIN_WAIT1)
long enough to consume all available TCP connections / mbufs.
Note:
FIN_WAIT_2 and TIME_WAIT closing states already have timeout / maximum
protection. This is unchanged.
Questions and Answers:
a. What is a better TCP application behavior? Follow [1] advices with:
- accept()
- recv()
- send()
- Wait for read() == 0 condition
- If got read() == 0 -> close()
- If timeout: Set SO_LINGER = 0 + close() to force reset the connection
Sadly we don't control all TCP application socket usage.
b. Why it is not happening on Linux?
Linux has net.ipv4.tcp_max_orphans. An orphan connection is a connection
on which close() has been called on i.e. the application did "orphan" it.
Once the maximum is reached, the connection is destroyed at close() time, no
timeout, no recycling, just destroyed in place. Ruthless, but does the job.
c. What kind of client can produce these long-lived FIN_WAIT_1 connections?
A TCP client that opens a TCP connection, sends a valid TCP request and,
never sends a FIN.
[1] Security Assessment of the Transmission Control Protocol (TCP)
https://www.gont.com.ar/papers/tn-03-09-security-assessment-TCP.pdf