0%

如何查看 Linux 的半连接队列、全连接队列?

全连接队列大小和半连接队列大小如何设置?

全连接大小:全连接大小取决于 backlogsomaxconn 的最小值,也就是 min(backlog, somaxconn)

  • somaxconn 是 Linux 内核参数,默认 128,可通过 /proc/sys/net/core/somaxconn 进行配置
  • backloglisten(int sockfd, int backlog) 函数中的参数 backlog

半连接队列大小:通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 来设置

如何查看当前全连接队列和半连接队列的大小?

  1. 查看半连接队列:
1
2
netstat -antp | grep SYN_RECV | wc -l
233 # 表示半连接状态的 TCP 连接有 233 个
  1. 查看全连接队列
1
2
3
4
ss -lnt | grep 6080

State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 :::6080 :::*
  • -l 显示正在 Listen 的 socket
  • -n 不解析服务名称
  • -t 只显示 tcp
  • Recv-Q 完成三次握手并等待服务端 accept() 的 TCP 全连接总数
  • Send-Q 全连接队列大小

如何查看全连接半连接溢出?

netstat -s | grep SYN 如果开启了 tcp_syncookies,那么当半队列溢出的时候, 95045 SYN cookies sent 这一行会一直变大。

netstat -s | grep overflowed 直接查看全链接队列是否有溢出,数字一直变大就是有溢出。

netstat -s | egrep "listen|LISTEN"

1
2
3
4
# 半连接队列溢出次数
104625 SYNs to LISTEN sockets dropped
# 全连接队列溢出的次数
7102 times the listen queue of a socket overflowed

全连接半连接溢出后如何处理?

全连接队列满

当全连接队列已满就会根据 tcp_abort_on_overflow 策略进行处理。Linux 可通过 /proc/sys/net/ipv4/tcp_abort_on_overflow 进行配置。

  • tcp_abort_on_overflow=0,服务端 accept 队列满了的时候,客户端发来 ack,服务端直接丢弃该 ACK,此时服务端处于 SYN_RCVD 状态,客户端处于 ESTABLISHED 状态。在该状态下服务端会重传 SYN-ACK 报文。超过 tcp_synack_retries 次后,服务端不再重传,后续也不会有任何动作。此时如果客户端再发送数据过来,服务端会返回 RST

  • tcp_abort_on_overflow=1,服务端 accept 队列满了,客户端发来 ack,服务端直接返回 RST 通知 client,表示废掉这个握手过程和这个连接,client 会报 connection reset by peer

半连接队列满

如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;

net.ipv4.tcp_syncookies=1 表示开启 tcp_syncookies。开启后,服务端会生成一个 cookie,通过 SYN+ACK 报文返回给客户端,然后收到客户端下一个 ACK 报文后会校验 cookie,如果是服务端生成的,则直接放入 accept 队列。

开启 tcp_syncookies 可防范 SYN 攻击。

syn flood

Linux 下默认会进行 5 次重发 SYN-ACK 包,总共耗时大概一分钟。由于 SYN-ACK 超时需要 63 秒,那么就给攻击者一个攻击服务器的机会,攻击者在短时间内发送大量的 SYN 包给服务端,用于耗尽服务端的 SYN 队列。为了应对 SYN 攻击的问题,linux 提供了几个 TCP 参数:tcp_syncookiestcp_synack_retriestcp_max_syn_backlogtcp_abort_on_overflow

Linux 实现了一种称为 SYN cookie 的机制,通过 net.ipv4.tcp_syncookies 控制,设置为 1 表示开启。简单说 SYNcookie 就是将连接信息编码在ISN(initialsequencenumber)中返回给客户端,这时服务端不需要将半连接保存在队列中,而是利用客户端随后发送的 ACK 带回的 ISN 还原连接信息,以完成连接的建立,避免了半连接队列被攻击 SYN 包填满。

SYN 半连接队列的大小是由 /proc/sys/net/ipv4/tcp_max_syn_backlog 这个内核参数控制的,有些内核似乎也受 listen 的 backlog 参数影响,取的是两个值的最小值。当这个队列满了,不开启 syncookies 的时候,服务端会丢弃新来的 SYN 包,而客户端在多次重发 SYN 包得不到响应而返回(connection timeout)错误。但是,当服务端开启了 syncookies=1,那么 SYN 半连接队列就没有逻辑上的最大值了,并且 /proc/sys/net/ipv4/tcp_max_syn_backlog 设置的值也会被忽略。