在 TCP 三次握手的过程中,Linux 内核会维护两个队列,分别是:
- 半连接队列 (SYN Queue)(内核代码体现的是逻辑上的队列)
- 全连接队列 (Accept Queue)
正常的 TCP 三次握手过程:
1、客户端向服务端发送 SYN 发起握手,客户端进入 SYN_SENT 状态
2、服务端收到客户端的SYN请求后,服务端进入 SYN_RECV 状态,此时内核会将连接存储到半连接队列(SYN Queue),并向 客户端回复 SYN+ACK
3、客户端收到 服务端的 SYN+ACK 后,客户端回复 ACK 并进入 ESTABLISHED 状态
4、服务端收到 客户端的 ACK 后,内核将连接从半连接队列(SYN Queue)中取出,添加到全连接队列(Accept Queue),服务端进入 ESTABLISHED 状态
5、服务端应用进程调用 accept 函数时,将连接从全连接队列(Accept Queue)中取出
半连接队列和全连接队列都有长度大小限制,超过限制时内核会将连接 Drop 丢弃或者返回 RST 包
全连接队列溢出处理:
内核参数:/proc/sys/net/ipv4/tcp_abort_on_overflow设值
0 :如果全连接队列满了,那么 server 扔掉 client 发过来的 ack ,默认值;
1 :如果全连接队列满了,server 发送一个 reset 包给 client,表示废弃这个握手过程和这个连接;
防御 SYN 攻击的方法:
- 增大半连接队列;
- 开启 tcp_syncookies 功能
- 减少 SYN+ACK 重传次数
- https://webhostinggeeks.com/howto/tcp-keepalive-recommended-settings-and-best-practices/
- https://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
- https://www.ibm.com/docs/en/db2/9.7?topic=ctkp-configuring-operating-system-tcpip-keepalive-parameters-high-availability-clients
- https://veithen.io/2014/01/01/how-tcp-backlog-works-in-linux.html
- https://www.man7.org/linux/man-pages/man2/listen.2.html
- https://blog.cloudflare.com/syn-packet-handling-in-the-wild/
- http://arthurchiao.art/blog/tcp-listen-a-tale-of-two-queues/
- https://unix.stackexchange.com/questions/729323/what-type-of-queue-is-tcp-accept-queue-in-linux-fifo-lifo-other
- https://developer.aliyun.com/article/804896
- https://www.cnblogs.com/xiaolincoding/p/12995358.html?spm=a2c6h.12873639.article-detail.9.2358564bQEWG6Q
- https://man7.org/linux/man-pages/man7/tcp.7.html
- https://www.cnblogs.com/alchemystar/p/13175276.html