iptables recent模块不支持指数惩罚,但可通过多阶段独立列表(如ssh-stage1/2/3)实现渐进式封禁:轻度异常仅记录,中度累计达15次封5分钟,重度达30次封30分钟,时间窗口与阈值递增,效果近似指数增长。

iptables recent 模块本身不支持指数惩罚——它没有内置的“惩罚倍增”逻辑,不能自动把封禁时长从300秒变成600秒、再变成1200秒。它的设计是静态时间窗口 + 固定阈值:--seconds N --hitcount M 对应一个确定的封禁周期,超时即清空,无状态延续。
但你可以用 多阶段独立列表 + 递进式规则链,在内核层面模拟出“触发次数越多、封禁越久”的效果,实现近似指数增长的响应行为。关键不是让一条规则变长,而是让不同严重程度的IP落入不同层级的黑名单。
多阶段recent列表实现渐进式封禁
每个阶段用独立 --name(如 ssh-stage1、ssh-stage2、ssh-stage3),对应不同时间窗口与命中条件,且后一阶段依赖前一阶段的“持续违规”:
-
✅ Stage 1(轻度异常):60秒内 ≥5次新SSH连接 → 记入
ssh-stage1iptables -A INPUT -p tcp --dport 22 -m state --state NEW \ -m recent --name ssh-stage1 --set
-
✅ Stage 2(中度升级):已在
ssh-stage1中,且过去 600秒内累计 ≥15次 → 升级至ssh-stage2(封300秒)iptables -A INPUT -p tcp --dport 22 -m state --state NEW \ -m recent --name ssh-stage1 --rcheck --seconds 600 --hitcount 15 \ -m recent --name ssh-stage2 --set \ -j DROP
-
✅ Stage 3(重度惩罚):已在
ssh-stage2中,且过去 1800秒内累计 ≥30次 → 升级至ssh-stage3(封1800秒)iptables -A INPUT -p tcp --dport 22 -m state --state NEW \ -m recent --name ssh-stage2 --rcheck --seconds 1800 --hitcount 30 \ -m recent --name ssh-stage3 --set \ -j DROP
-
✅ 最终拦截:命中任一高阶黑名单,立即丢弃
iptables -A INPUT -p tcp --dport 22 -m state --state NEW \ -m recent --name ssh-stage2 --rcheck --seconds 300 -j DROP iptables -A INPUT -p tcp --dport 22 -m state --state NEW \ -m recent --name ssh-stage3 --rcheck --seconds 1800 -j DROP
⚠️ 注意:所有
--rcheck规则必须放在对应--set规则之后;--rcheck --seconds X的X值要 ≥ 封禁时长,否则条目未过期就匹配不到。
为什么这算“类指数”?
- 第一次密集攻击 → 进 stage1(仅记录,不封)
- 持续骚扰(如每天试5次,连试3天)→ 累计达15次 → 进 stage2(封5分钟)
- 若解封后继续扫 → 再达30次 → 进 stage3(封30分钟)
- 时间窗口拉长(60s → 600s → 1800s),阈值提高(5→15→30),封禁时长跃升(0→300→1800秒)
- 实际效果接近:违规频次翻倍 → 封禁时长×6
配合自动降级与验证
不用清理:条目超时自动失效(
/proc/net/xt_recent/ssh-stage*中 ttl 归零即消失)-
查看状态:
cat /proc/net/xt_recent/ssh-stage2 # 显示被关进第二层的IP及剩余时间 lsmod | grep xt_recent # 确保模块已加载
-
建议加一条兜底限速(防绕过):
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
不复杂但容易忽略顺序和命名隔离。










