内核中的两个存放连接信息的队列。存放的连接元数据,四元组、MSS、window scale 等。
其用途简单来说:
- 收到 SYN 以后放进 SYN queue(半连接队列)
- 收到 ACK 以后放进 Accept Queue(全连接队列)
- 用户进程调用
accept()
以后,从 Accept Queue 中取出
1. SYN Queue 溢出时行为
1.1. SYN Cookie 机制
SYN Queue 溢出时 linux 的行为与 SYN Cookie 这个用于对抗 SYN flood 攻击的机制有关。
SYN Cookie 原理:设计出一个可逆的 hash 函数,可以基于时间戳、四元组等 TCP 连接信息算出 hash 值,并作为 SYN+ACK 报文的序列号。如果 peer 是正常的客户端,则下个发送过来的 ACK 是这个序列号 +1,将其减一即可逆推出所有的 TCP 元数据,直接放入 Accept Queue 即可。
这样一来,SYN_RCVD 状态的 socket 就可以不必放入 SYN queue 中,防止被打爆。
1.2. 溢出行为
由内核参数控制。
net.ipv4.tcp_syncookies = 0
,表示关闭 SYN Cookie 机制,如果 SYN 队列已满,那么新到的 SYN 报文将被丢弃。net.ipv4.tcp_syncookies = 1
,表示 SYN Cookie 机制仅在 SYN 队列满时才正式启用。net.ipv4.tcp_syncookies = 2
,表示无条件启用 SYN Cookie 机制。
1.3. 修改 SYN Queue 大小
net.ipv4.tcp_max_syn_backlog
2. Accept Queue 溢出时行为
2.1. 溢出行为
由内核参数 net.ipv4.tcp_abort_on_overflow
控制。
net.ipv4.tcp_abort_on_overflow = 0
,(默认),会丢弃 peer 发来的第三次握手的 ACK,而重传第二次握手时的 SYN+ACK 。net.ipv4.tcp_abort_on_overflow = 1
,则会直接向 peer 发送 RST。
2.1.1. 为何要重传 SYN+ACK?
- 协议规定:由于 Accept Queue 满,这个 socket 只能继续待在 SYN Queue 中,即还是处于 SYN_RECV 状态,此时只能回复 SYN+ACK。
- 有利于状态机恢复:另一方面,peer 收到重复的 SYN+ACK 时,会认为是丢包,故会重传 ACK。如果下一个 ACK 到来时,Accept Queue 又有空间了,则可以正常完成握手、放入队列中。
2.2. 典型溢出现象
默认情况下,内核参数 net.ipv4.tcp_abort_on_overflow
是 0。此时如果发生 SYN Queue 溢出,则 server 一直在发送 SYN+ACK,client 一直在发送 ACK(+PSH)。
2.3. 修改 Accept Queue 大小
由 net.core.somaxconn
和 socket 的 backlog
参数中的最小值决定。