iptables recent模块不支持真正的指数级惩罚,而是通过多阶段独立列表(如scan-1、scan-2)配合递进式时间窗口与阈值实现渐进加重封禁,需严格排序规则并叠加connlimit、状态过滤等增强防护。

iptables 的 recent 模块本身不支持“指数级惩罚”这种高级语义——它没有计数累加、评分衰减、动态权重或时间倍增机制。所谓“指数级惩罚”,实际是通过多阶段 --name 列表 + 递进式时间窗口 + 阈值组合,模拟出“越反复越严、越久越重”的效果。核心不是数学上的指数函数,而是行为强度与封禁时长/粒度的非线性映射。
用多个独立列表实现渐进式加重封禁
不能靠单个列表“自动升级”,必须显式定义不同严重等级的独立名单,彼此隔离、互不干扰:
-
轻度试探(60秒内5次SYN)→ 记入
scan-1,封300秒
iptables -A INPUT -p tcp --syn -m recent --name scan-1 --set
iptables -A INPUT -p tcp --syn -m recent --name scan-1 --rcheck --seconds 60 --hitcount 5 -j DROP -
中度扫描(600秒内20次SYN)→ 记入
scan-2,封1800秒
iptables -A INPUT -p tcp --syn -m recent --name scan-2 --set
iptables -A INPUT -p tcp --syn -m recent --name scan-2 --rcheck --seconds 600 --hitcount 20 -j DROP -
重度反复(1小时触发两次
scan-2)→ 手动转入长期黑名单
需配合日志+脚本:监听/proc/net/xt_recent/scan-2变化,发现同一IP多次命中后,用iptables -I INPUT -s X.X.X.X -j DROP插入永久规则
关键操作细节:顺序、匹配与避免误判
所有阶段规则必须按“检查封禁 → 触发升级 → 记录放行”严格排序,且 --set 必须在 --rcheck 后出现(否则首次包就写入,导致 --hitcount 始终从1开始算):
- 先检查是否已在任一黑名单:
iptables -A INPUT -m recent --name scan-1 --rcheck --seconds 300 -j DROP
iptables -A INPUT -m recent --name scan-2 --rcheck --seconds 1800 -j DROP - 再判断是否达到当前阶段阈值(注意
--rcheck和--set同条规则中位置):
iptables -A INPUT -p tcp --syn -m recent --name scan-1 --set -m recent --name scan-1 --rcheck --seconds 60 --hitcount 5 -j DROP - 最后记录未达阈值的合法SYN:
iptables -A INPUT -p tcp --syn -m recent --name scan-1 --set -j ACCEPT
补充防护增强真实惩罚力度
仅靠 recent 封禁仍可能被绕过。需叠加以下机制,让“反复试探成本”真正呈指数上升:
-
并发控制:用
connlimit限制单IP半开连接数,使扫描器无法维持大量探测会话
iptables -A INPUT -p tcp --syn -m connlimit --connlimit-above 3 -j REJECT --reject-with tcp-reset -
状态过滤:丢弃非法TCP标志组合(如 SYN+FIN),这类包在慢扫中高频出现
iptables -A INPUT -p tcp --tcp-flags ALL SYN,FIN -j DROP -
日志联动:为每个阶段添加
-j LOG,输出到/var/log/messages,供外部脚本提取IP并调用ipset或写入/etc/hosts.deny
验证与排错要点
模块是否生效、规则是否命中,全看内核接口:
- 确认模块已加载:
lsmod | grep xt_recent,无输出则运行modprobe xt_recent - 查看各列表实时状态:
cat /proc/net/xt_recent/scan-1,输出类似src=203.0.113.42 ttl: 297表示该IP正被跟踪,ttl值随时间递减 - 若某IP始终不进入列表,检查是否漏了
--syn或--state NEW条件,或规则位置被更早的ACCEPT提前放行

















