最新消息:

Linux SYN Backlog and somaxconn

kernel admin 3758浏览 0评论

SYN 包攻击是网络上比较老的一种攻击方式。在 Linux 中,可以通过开启 net.ipv4.tcp_syncookies = 1 来抵抗这种攻击。那么,在开启 syncookies 之后,Linux 系统做了些什么?如何做的?这是本文试图整理的内容。

以下是一组常见的 syncookies 在 sysctl.conf 中的配置:

net.ipv4.tcp_syncookies = 1 #开启 syncookies 功能
net.ipv4.tcp_max_syn_backlog = 262144 # 最大 SYN 缓冲内存大小
net.ipv4.tcp_synack_retries = 2 # SYN ACK 重试次数
net.ipv4.tcp_syn_retries = 2 # SYN 重试次数

在 TCP 的队列上,常见的有两种实现方式。

1. BSD:单队列。当系统收到一个 SYN 包,其回复 SYN/ACK 包,并将该连接加入队列中。当对应的 ACK 包收到后,在队列中将此连接的状态改为 ESTABLISHED 并交给对应的后端程序处理。所以在这个队列中,包有两个状态:SYN RECEIVED 和 ESTABLISHED。
2. Linux:Linux 采用了双队列。一个存放 SYN 的队列(半连接队列)[以下简称为 syn q],一个存放已经完成连接的队列[以下简称为 accept q][somaxconn]。所以,当一个连接的状态是 SYN RECEIVED 时,他会被放在 SYN 队列中。当它的状态变为 ESTABLISHED 时,他会被转移到另一个队列。所以后端的应用程序只从已完成的连接的队列中获取请求。

所以,在第一种模式下,当这个仅有的队列塞满 SYN 状态的连接后,系统就会丢包。迫使客户端再次发 SYN 请求。

而在 Linux 系统中,man page 有如下解释:

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog.

这表示有一个由系统控制大小的 syn q,和一个由应用控制大小的 accept q。

所以,我们发现了有这么几个问题需要探讨:

  1. 当 accept q 满了,syn q 中有连接完成时,需要转移进 accept q,该做什么样的处理?
  2. 当 syn q 满了,系统还在不断的收到 SYN 包时,怎么处理?

Q1 , 当 accept q 满了,syn q 中有连接完成时,需要转移进 accept q,该做什么样的处理?

在源码 net/ipv4/tcp_minisocks.c 中,这个行为是由 tcp_check_req 函数控制的:

child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
if (child == NULL)
goto listen_overflow;

再来看一眼 listen_overflow:

listen_overflow:
if (!sysctl_tcp_abort_on_overflow) {
inet_rsk(req)->acked = 1;
return NULL;
}

这说明除非设置了 /proc/sys/net/ipv4/tcp_abort_on_overflow 为 1 ,不然的话系统什么都不做。但是这个什么都不做,并不代表系统真的什么都不做了。当系统忽略了最后的 ACK,而系统中还有一个 net.ipv4.tcp_synack_retries 设置时,Linux 会重新发送 SYN ACK 包。而客户端收到多个 SYN ACK 包,则会认为之前的 ACK 丢包了。于是促使客户端再次发送 ACK ,在 accept q 有空闲的时候最终完成连接。若 accept q 始终满员,则最终客户端收到 RST 包。

同时 accept q 满了,对 syn q 也有影响,在代码 net/ipv4/tcp_ipv4.c :

/* Accept backlog is full. If we have already queued enough
* of warm entries in syn queue, drop request. It is better than
* clogging syn queue with openreqs with exponentially increasing
* timeout.
*/
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
goto drop;
}

这说明如果 accept q 满了,系统会开始检查 SYN 包收到的频率,并且做出限制。如果达到了其定义的限制(我还不知道是如何定义的),变开始丢弃 syn q 中的包。我个人根据观察到的现象认为,其必须要满足 syn q 也已经被塞满这个条件,才会丢包。

Q2,当 syn q 满了,系统还在不断的收到 SYN 包时,怎么处理?

在系统 syncookies=1 时,syn q 满了以后,系统会对 SYN 返回 syncookie 包。所返回的 SYN ACK 包会产生一个新的标志位 want_cookie。这个标志位默认为 0 ,但当要验证 cookies 时,want_cookie 会设置为 1.
发送的 cookie 数值是通过 cookie_v4_init_sequence() 函数计算出来的,在包发送出去后不维护该连接在服务器上的状态。这么做应该是为了节约服务器资源,毕竟其目的是为了判断对方是否是恶意攻击。
客户端拿到 cookie 数值后,通过计算,返回 cookies 数值,服务端获取到返回计算该数值是否合法。从而决定是否建立连接。

通过以上逻辑我们可以发现,一旦 accept q 满了,系统层面就非常容易发生丢包的情况。
在 man listen 能看到:

The behavior of the backlog argument on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely established sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for incomplete sockets can be set using /proc/sys/net/ipv4/tcp_max_syn_backlog. When syncookies are enabled there is no logical maximum length and this setting is ignored.
If the backlog argument is greater than the value in /proc/sys/net/core/somaxconn, then it is silently truncated to that value; the default value in this file is 128. In kernels before 2.4.25, this limit was a hard coded value, SOMAXCONN, with the value 128.

accept q 受限于 “backlog” 和 “SOMAXCONN” , 所以在系统中 backlog (net.core.netdev_max_backlog?) 和 net.core.somaxconn 都要放到一个合适的数值。同时在各类应用 listen 时,通常也有自定义的 listen backlog , 如 apache 、nginx 。在 Linux 上,apache 和 nginx 都默认将 backlog 设置为 511,如果你的 SOMAXCONN 小于 511,则会应用 SOMAXCONN 的配置。在大多数现代服务器硬件上,511 并不是一个足够的数值,多半需要调整。

Q need A
有多少种情况,系统会开始拒绝 syn q 接受包?有多少种情况系统会丢弃 syn q 中的包?

参考文章:
How TCP backlog works in Linux
SYN cookies机制下连接的建立
linux诡异的半连接(SYN_RECV)队列长度
Nginx 性能优化之net.core.somaxconn

转载请注明:爱开源 » Linux SYN Backlog and somaxconn

您必须 登录 才能发表评论!