Linux syn cookies / tcp_tw_recycle / tcp_tw_reuse 的防 SYN flood 配置风险

2次阅读

开启syncookies后丢包是因为其仅在syn队列溢出时触发,若somaxconn或应用backlog过小,syn包会在触发前被直接丢弃;同时syncookies禁用tcp扩展选项,可能导致部分客户端握手失败。

Linux syn cookies / tcp_tw_recycle / tcp_tw_reuse 的防 SYN flood 配置风险

syn cookies 开启后为什么反而丢包?

开启 net.ipv4.tcp_syncookies=1 是应对 SYN flood 的常规操作,但它只在内核判定“SYN 队列溢出”时才激活——不是一开就全程启用。如果服务器本身连接数高、net.core.somaxconn 或应用层 listen backlog 设得太小,SYN 包还没到 syncookies 触发阈值就被直接丢弃,现象看起来像“开了没用”甚至更差。

  • 确认是否真触发:抓包看是否有大量 SYN 发出但无 SYN+ACK 回复,同时 netstat -s | grep -i "syn"Syncookies sent 计数是否上升
  • 必须同步调大:net.core.somaxconn(内核级)和应用 listen() 的 backlog 参数(如 nginxlisten ... backlog=4096),否则 syncookies 根本没机会介入
  • 注意:syncookies 会禁用 TCP 扩展选项(如时间戳、SACK),若客户端依赖这些(如某些 NAT 后的移动设备),可能握手失败或吞吐下降

tcp_tw_recycle 已被彻底移除,别再配它

net.ipv4.tcp_tw_recycle=1linux 4.12+ 内核中已被删除,任何尝试写入该参数的操作都会报错 Invalid argument。它曾试图通过快速回收 TIME-WAIT 连接缓解端口耗尽,但严重依赖客户端 IP 时间戳单调递增,在 NAT 环境下会导致连接被静默拒绝——这是历史坑,不是配置技巧。

  • 检查是否还在用:运行 sysctl net.ipv4.tcp_tw_recycle,返回 Error: permission denied 或直接报错即说明内核已移除
  • 替代方案只有两个:调大本地端口范围(net.ipv4.ip_local_port_range)、缩短 TIME-WAIT 持续时间(net.ipv4.tcp_fin_timeout,但不推荐低于 30 秒)
  • 如果看到文档或脚本里还写这行,一律删掉,它现在只起反作用

tcp_tw_reuse 不是万能开关,得看场景

net.ipv4.tcp_tw_reuse=1 允许内核将处于 TIME-WAIT 状态的 socket 重用于新 outgoing 连接,但仅限于客户端场景(即本机主动发起连接),且要求对端时间戳严格递增。它对服务端监听连接完全无效。

  • 生效前提:必须搭配 net.ipv4.tcp_timestamps=1(默认开启),否则直接忽略
  • 典型适用:本机作为 http 客户端高频调用外部 API,且后端支持时间戳——此时可减少端口耗尽风险
  • 典型失效:本机是 Web 服务器,用户浏览器连你,tcp_tw_reuse 对这些 incoming 连接不起作用
  • 副作用:在有多个出口 NAT 或负载均衡的环境里,不同客户端时间戳可能冲突,导致连接被拒绝(错误常表现为 Connection refused 或超时)

真正有效的 SYN flood 防御组合

单靠 sysctl 参数无法根治 SYN flood,它们只是内核层面的缓冲策略。攻击流量到达网卡后,已经消耗了中断、软中断和内存资源。关键在于把过滤点前移到更早环节。

  • 硬件/网络层优先:在交换机或云厂商 SLB 上开启 SYN proxy 或连接数限制(如 AWS Security Group 的 connection tracking 限速)
  • 主机防火墙兜底:用 iptables 做速率限制,例如 iptables -A input -p tcp --syn -m connlimit --connlimit-above 50 -j DROP
  • 避免滥用 tcp_syncookies:它应是最后防线,而不是日常配置;长期高并发下,更应优化应用连接池、升级 TLS 握手复用(如 TLS 1.3 early data)

TIME-WAIT 和 syncookies 的行为高度依赖具体内核版本和网络拓扑,同一配置在 IDC 物理机、K8s Pod、云函数里效果可能完全不同——别背参数,先看 ss -snetstat -s 输出的实际连接状态分布。

text=ZqhQzanResources