Scapy实时捕获SYN包并按源IP分桶计数可识别SYN洪水,需配合时间窗口清理、阈值校准与iptables精准封禁,避免误判正常高并发;关键在每秒统计各src_ip的SYN数量、用快照遍历字典、及时更新last_cleanup时间戳,并验证封禁规则生效。

直接用 scapy 实时捕获 + 简单计数就能识别多数SYN洪水类DDoS,但必须配合时间窗口清理和阈值校准,否则误报率极高。
用 sniff() 捕获TCP包并统计SYN频率
核心是只关注 TCP 层的 S 标志位,且每秒统计每个源IP的SYN包数量。不能用全局计数器,必须按 src_ip 分桶,否则会把正常高并发用户误判为攻击者。
-
filter="tcp"足够,不用写"tcp[tcpflags] & tcp-syn != 0"这类BPF语法——scapy的packet['TCP'].flags == 'S'更直观可靠 - 避免在回调函数里做耗时操作(如调用
subprocess封IP),先记入字典,由主循环定期处理 - 务必用
time.time()控制清理周期,别依赖sniff的timeout参数,它不精确
syn_counter 字典的生命周期管理容易出错
常见错误是只清空字典却不重置 last_cleanup 时间戳,导致后续10秒内所有新SYN都被累积进旧桶;或者用 for ip in syn_counter: 直接遍历时修改字典,触发 RuntimeError: dictionary changed size during iteration。
- 清理时用
list(syn_counter.keys())构造快照副本再遍历 - 每次清理后必须更新
last_cleanup = time.time() - 封禁IP后要
del syn_counter[ip],不能只clear()全局清空——否则正常用户刚发一个SYN就被漏掉
iptables 封禁命令在不同Linux发行版行为不一致
iptables -A INPUT -s {ip} -j DROP 在CentOS 7+默认生效,但在Ubuntu 22.04+可能因nftables后端导致规则不持久或不生效。
立即学习“Python免费学习笔记(深入)”;
- 执行前加
which iptables确认路径,避免被alias或wrapper干扰 - 生产环境必须加
-w参数防止并发写冲突:iptables -w -A INPUT -s {ip} -j DROP - 封禁后建议立即验证:
iptables -L INPUT -n | grep {ip},别假设命令返回0就成功
真正难的不是检测逻辑,而是区分“突发合法流量”和“攻击流量”——比如电商秒杀时真实用户的SYN峰值可能超过阈值,但源IP分布广;而SYN洪水通常集中在几十个伪造IP上。这点靠单点计数解决不了,得引入IP地理熵、TTL分布、TCP窗口值等维度,但那已超出脚本级防御范畴。


















