tcp四次挥手相关选项
1、tcp_orphan_retries
主动方发送 FIN
后处于 FIN_WAIT1
状态,收到 ACK
后转为 FIN_WAIT2
。如果收不到对方返回的 ACK
,内核会定时重发 FIN
报文,其中重发次数由 tcp_orphan_retries
参数控制,默认值是 0
表示 8
次:
$ cat /proc/sys/net/ipv4/tcp_orphan_retries
0
2、TCP 报文有序发送,当发送缓冲区还有数据没发送时,FIN
报文也不能提前发送。
因为TCP 有流控功能,当接收方将接收窗口设为 0 时,发送方就不能再发送数据。
所以,当攻击者下载大文件时,就可以通过将接收窗口设为 0,导致 FIN
报文无法发送,进而导致连接一直处于 FIN_WAIT1
状态。
解决方案是调整 tcp_max_orphans
参数:
$ cat /proc/sys/net/ipv4/tcp_max_orphans
4096
如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST
复位报文强制关闭。
3、FIN_WAIT_2
TCP 进入FIN_WAIT_2 状态后,如果迟迟收不到对端的 FIN 包,就会一直消耗系统资源。 为了防止这种开销,linux 设置了这个状态的超时时间 tcp_fin_timeout,默认为 60s,超过这个时间就会自动销毁该连接,可以工具实际情况调小。
$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60
4、TIME-WAIT 超时时间
如果没有 TIME-WAIT
,而最后一个ACK
刚好丢包或延迟了,等我们复用该端口时,假设刚才延迟的ACK
报文到达了,新连接就可能被旧的 FIN
报文错误的关闭了。
MSL
全称是 Maximum Segment Lifetime(报文段最大生存时间)。
Linux下 MSL
的值为 30
秒,TIME-WAIT
是 2MSL
,所以 TIME-WAIT
是 60
秒。
定义在:
https://elixir.bootlin.com/linux/v5.0/source/include/net/tcp.h#L121
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
为什么是 2
倍的 MSL
,这样可以允许报文丢失一次,如果 ACK
丢了,对方重发的 FIN
会在第 2
个 MSL
内到达。
5、TIME_WAIT 数量
当 TIME_WAIT 数量超过tcp_max_tw_buckets
参数时,新关闭的连接就不再经历 TIME_WAIT
而直接关闭,当服务器的并发连接增多时可以适当调大该参数:
$ cat /proc/sys/net/ipv4/tcp_max_tw_buckets
4096
6、复用 TIME_WAIT 的连接
可以考虑设置为 1 来打开复用:
$ cat /proc/sys/net/ipv4/tcp_tw_reuse
0