linux 网络错误 Possible SYN flooding on port xxxx. Sending cookies 解决方法

SYN flooding

Possible SYN flooding on port 80. Sending cookies.

最近线上服务器总是产生这样的日志。

看上去有点吓人,但并没有发生DDOS攻击。很奇怪。

这个日志是在说什么呢?从字面上理解是说在80端口可能发生SYN泛洪,正在发送cookies。

三次握手

说SYN泛洪之前要先说下TCP三次握手。

1. 客户端发送SYN(进入SYNC_SENT状态)

2. 服务端返回SYN+ACK(进入SYNC_RECV状态)

3. 客户端发送ACK(进入ESTABLISHED状态)

如果客户端在第3步时不发送ACK给服务端,那么服务端的socket就会处于SYNC_RECV状态。

如果系统中有很多处于SYNC_RECV的socket,那么服务器可能遭受到了DDOS攻击,即所谓的SYN泛洪。

TCP状态机的变迁

backlog

80是http服务的标准端口。http服务调用listen来监听80端口,然后调用accept来建立新的连接。

listen有个很重要的参数叫backlog. 用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. See tcp(7) for more information.
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.

意思就是backlog指定的是已经进入ESTABLISHED状态的sockets(等待被accept)的队列长度,这里称之为accept队列。

而未进入ESTABLISHED状态的sockets的最大队列长度则由/proc/sys/net/ipv4/tcp_max_syn_backlog来指定,这里称之为SYN队列。

在SYN队列中的连接在接收到ACK后,移交到accept队列,接着由`accept`系统调用移出accept队列。

当启用syncookies时,那么队列没有逻辑上的最大长度限制。恩。终于提到cookies了。这个先放一下后面再讲。

如果backlog大于/proc/sys/net/core/somaxconn,则backlog被截断为后者的值。默认为128。

详细参考《linux tcp socket 请求队列大小参数 backlog 简介》

https://blog.csdn.net/whatday/article/details/107740002

流量识别

使用netstat -s来查看SYNs to LISTEN sockets dropped是否持续增长。

使用tcpdump抓包,如果有很多SYN,服务端回复了SYN+ACK,但客户端没有回复ACK,那么这可能就是恶意流量。

如果恶意流量很大导致服务不可用,需要联系网络团队或服务供应商来提供基础防护和流量封堵。

如果流量是正常流量的话,那么需要调大内核参数net.core.maxconn 和 net.ipv4.tcp_max_syn_backlog

查看:

sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog

输出:

net.core.somaxconn = 128
net.ipv4.tcp_max_syn_backlog = 128

调节到2048:

sysctl -w net.core.somaxconn=2048 net.ipv4.tcp_max_syn_backlog=2048

输出:

net.core.somaxconn = 2048
net.ipv4.tcp_max_syn_backlog = 2048

查看是否生效:

sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog

输出:

net.core.somaxconn = 2048
net.ipv4.tcp_max_syn_backlog = 2048

持久化到配置文件,下次重启自动生效:

echo "net.core.somaxconn = 2048" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog = 2048" >> /etc/sysctl.conf

与之对应的listen函数的backlog参数也要一起调大。

-   rc = listen(sockfd, 128);    /* old line */
+   rc = listen(sockfd, 2048);   /* new line */
    if (rc < 0)
    {
        perror("listen() failed");
        close(sockfd);
        exit(-1);
    }

SYN Cookies

SYN Cookies是一种机制,在服务器遭受短暂的DDOS攻击或者服务器accept新连接速度较慢时,还能正常建立连接。

关于SYN Cookies的原理可以参考这里 SYN Cookies 。

SYN Cookies的应用允许服务器当SYN队列被填满时避免丢弃连接。相反,服务器会表现得像SYN队列扩大了一样。服务器会返回适当的SYN+ACK响应,但会丢弃SYN队列条目。如果服务器接收到客户端随后的ACK响应,服务器能够使用编码在TCP序号内的信息重构SYN队列条目。

算法实现原理

发起一个 TCP 连接时,客户端将一个 TCP SYN 包发送给服务器。作为响应,服务器将 TCP SYN + ACK 包返回给客户端。此数据包中有一个序号(sequence number,TCP头中的第二个32 bit),它被 TCP 用来重新组装数据流。根据 TCP 规范,由端点发送的第一个序号可以是由该端点决定的任何值。SYN Cookies 是根据以下规则构造的初始序号:

  • 令 t 为一个缓慢递增的时间戳(通常为 time() >> 6 ,提供 64 秒的分辨率);
  • 令 m 为服务器会在 SYN 队列条目中存储的最大分段大小(maximum segment size,简称为 MSS);
  • 令 s 为一个加密散列函数对服务器和客户端各自的 IP 地址和端口号以及 t 进行运算的结果。返回得到的数值 s 必须是一个24位值。

初始 TCP 序号,也就是所谓的 SYN cookie,按照如下算法得到:

  • 头五位:t mod 32;
  • 中三位:m 编码后的数值;
  • 末24位:s 本身;

注:由于 m 必须用 3 位进行编码,服务器在启用了 SYN Cookie 时只能为 m 发送八种不同的数值。

根据 TCP 规范,当客户端发回 TCP ACK 包给服务器以响应服务器的 SYN + ACK 包时,客户端必须使用由服务器发送的初始序号加1作为数据包中的确认号。服务器接着从确认号中减去 1 以便还原向客户端发送的原始 SYN Cookie。

接下来服务器进行以下检查:

  • 根据当前的时间以及 t 来检查连接是否过期。
  • 重新计算 s 来确认这是不是一个有效的 SYN Cookie。
  • 从 3 位编码中解码 m,以便之后用来重建 SYN 队列条目。在此之后,连接照常进行。

内核代码

最后贴一段打印日志的代码(内核版本4.12)。

文件:net/ipv4/tcp_input.c

/*
 * Return true if a syncookie should be sent
 */
static bool tcp_syn_flood_action(const struct sock *sk,
                 const struct sk_buff *skb,
                 const char *proto)
{
    struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
    const char *msg = "Dropping request";
    bool want_cookie = false;
    struct net *net = sock_net(sk);

#ifdef CONFIG_SYN_COOKIES
    if (net->ipv4.sysctl_tcp_syncookies) {
        msg = "Sending cookies";
        want_cookie = true;
        __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
    } else
#endif
        __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);

    if (!queue->synflood_warned &&
        net->ipv4.sysctl_tcp_syncookies != 2 &&
        xchg(&queue->synflood_warned, 1) == 0)
        pr_info("%s: Possible SYN flooding on port %d. %s.  Check SNMP counters.\n",
            proto, ntohs(tcp_hdr(skb)->dest), msg);

    return want_cookie;
}

 

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syncookies = 1net.ipv4.tcp_syn
最新发布
03-17

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值