目录
一、半连接队列和全连接队列的概念
-
半连接队列:服务端收到客户端发送的 SYN 包时,内核会将该连接加入半连接 SYN 队列,并向客户端返回响应
-
全连接队列:服务端收到客户端发送的 ACK + SYN 包时,会从半连接队列中移除该连接,创建一个新的完全连接,加入全连接 accept 队列,等待进程调用 accept 函数取出全连接
二、全连接队列溢出
- 查看全连接队列情况:ss 命令
- Recv-Q:当前全连接队列的大小
- Send-Q:允许的全连接队列最大大小
-
全连接队列溢出:大量请求打到服务器,如果请求数量超过 TCP 全连接队列的大小,就会丢弃后面的连接(默认策略,可以修改策略为向客户端发送 RST 复位报文,告诉客户端连接建立失败),导致服务器请求数量上不去
-
查看全连接队列是否溢出:netstat -s 可以查看丢掉的 TCP 连接,如果丢弃数量在变大说明某段时间内发生了全连接队列溢出(是个累计值,不是大于 0 就代表当前全连接队列溢出了,持续变大有上升趋势才能说明溢出,半连接队列查看溢出情况也是如此)
-
调大全连接队列的大小:修改 Linux 内核参数 somaxconn 和 backlog(全连接队列大小是两者的最小值)
-
丢弃策略
- tcp_abort_on_overflow = 0:丢弃连接,客户端会重发带有 ACK 的请求,收不到服务端的 ACK 就会重发,如果服务端只是暂时繁忙,忙完就会收到大量客户端重发的带有 ACK 的请求,还可以继续处理(全连接队列有空位时),继续建立完全连接
- tcp_abort_on_overflow = 1:给客户端响应 RST 复位报文,报告连接建立失败,只有肯定全连接队列会长时间溢出时才将策略设置为 1,尽快通知客户端,否则就 设置为 0,可以增大连接建立的成功率
三、半连接队列溢出
-
查看半连接队列情况:没有命令可以直接查看,但是可以通过查看服务端处于 SYN_RECV 状态的 TCP 连接,就是 TCP 的半连接数量
-
半连接队列溢出:客户端发送大量 SYN 请求,但是一直不回复 ACK,服务端就会出现大量处于 SYN_RECV 的 TCP 导致半连接队列溢出,无法处理后续的正常的请求,也就是SYN 洪泛、SYN 攻击、DDos 攻击
-
调大半连接队列的大小 TODO
4. 如何防止洪泛攻击?
- 增大半连接队列:同时增大全连接队列,因为半连接队列的大小会受到全连接的队列大小的影响(半连接队列的大小具体要看源码)
- 开启 tcp_syncookies 功能,在发生溢出时不会丢弃连接,而是根据 syncookies 判断连接是否建立成功
- 减少 SYN+ACK 重传次数:收到 SYN 攻击时,就会有大量处于 SYN_RECV 状态的 TCP 连接,处于这个状态的 TCP 连接会重传 SYN+ACK 报文,当重传次数达到上限就会断开连接,减少重传次数,加快断开连接的速度