1、正常情况下当服务器收到 SYN
后,会立刻回复 SYN+ACK
,出现新连接,需要建立一个半连接的队列来维护未完成的握手信息。如果队列溢出则不能接受新的连接,比如 SYN 泛洪攻击。
(1)tcp_max_syn_backlog
半连接队列大小由参数 tcp_max_syn_backlog
决定:
$ cat /proc/sys/net/ipv4/tcp_max_syn_backlog
128
(2)tcp_syncookies
队列满了之后,不一定会丢弃连接,可以打开 tcp_syncookies
功能:
0 表示关闭,
2 表示无条件使用,
1 则表示仅当 SYN 半连接队列放不下时再用它。
由于 cookie 占用序列号的空间,导致TCP
可选功能失效,所以应该设置为 1
。
$ cat /proc/sys/net/ipv4/tcp_syncookies
1
(3)实验:模拟 SYN Flood 攻击
(A)客户端丢弃掉第三次握手的ACK
的报文,这样服务端收不到ACK
就只能处于半连接队列:
sudo iptables -A OUTPUT -p tcp -d 192.168.136.131 -m tcp --tcp-flags ACK ACK -j DROP
(B)在服务端把半连接队列设置小一些,
(C)关闭 tcp_syncookies
,
$ sudo sh -c "echo 2 > /proc/sys/net/ipv4/tcp_max_syn_backlog"
$ sudo sh -c "echo 0 > /proc/sys/net/ipv4/tcp_syncookies"
(D)在客户端循环发送多个请求:
$ for i in {1..9}; do ssh 192.168.136.131 & done
(E)这样就可以在服务端观察半连接队列溢出情况了:
$ netstat -s | grep "SYNs to LISTEN"
36 SYNs to LISTEN sockets dropped
(4)tcp_synack_retries
服务端发送 SYN+ACK
后,如果没有收到 ACK
,就会一直重发 SYN+ACK
。重发次数由 tcp_synack_retries
决定:
$ cat /proc/sys/net/ipv4/tcp_synack_retries
5
耗时:默认重发 5 次,总耗时是 1+2+4+8+16+32=63 秒。
(5)tcp_abort_on_overflow
服务器收到 ACK
后,会把连接从 半连接队列移出,移入 accept 队列,等待进程调用 accept
函数把连接取出。如果进程不能及时调用 accept
函数,就会造成 accept 队列溢出,连接被丢弃。
如果设置了 tcp_abort_on_overflow
为 1,会向客户端发送 RST
通知客户端,默认是 0,不通知客户,等客户重发请求,如果那时 accept 队列没有满,则可以建立连接。
$ cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0
$ cat /proc/sys/net/core/somaxconn
128
设置 accept 队列的长度:可以通过 上面的somaxconn
,也可以通过 int listen(int sockfd, int backlog);
的第二个参数 backlog
来设置。
网友评论