
症状:fail2ban 显示封了,攻击一点没停
装了 fail2ban,配置看着也正常,fail2ban-client status sshd 显示"当前封禁 N 个 IP"。但攻击还在继续。
第一反应是"封禁时间太短",于是把时间调长——没用。真正的原因是:封禁动作一条规则都没生效,fail2ban 只是在自言自语。
一、怎么确认是"空转"
不要看 fail2ban 的自我报告,去看防火墙里实际有多少条规则:
# fail2ban 说自己封了多少
fail2ban-client status sshd | grep -i banned
# 防火墙里实际有多少条针对性的规则
firewall-cmd --list-rich-rules | wc -l
firewall-cmd --list-rich-rules | head
如果前者说"已封 27 个",而后者是 0 条,就是典型的空转。
还有一个更细的判据:fail2ban 的 IP 条目里会带一个 References 计数,空转时这个值恒为 0——因为它的"引用"来自实际生效的规则。
二、原因:防火墙后端换了,action 没换
fail2ban 封禁是通过 banaction 指定的一条"动作脚本"。历史上在 firewalld 上大家用的是基于 ipset 的动作:
banaction = firewallcmd-ipset
但在防火墙后端是 nftables 的系统上(新版系统默认如此),这条动作会失败——firewallcmd-ipset 用的是 --direct 规则,在 nftables 后端下根本建不上,于是静默失败:fail2ban 认为封禁成功(记录到自己的数据库里了),防火墙那边什么也没发生。
换个说法:fail2ban 的封禁列表和真正的防火墙规则是两套数据,前者不保证后者被创建。
三、修复:换成 rich rules
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 604800
findtime = 21600
maxretry = 5
banaction = firewallcmd-rich-rules
action = %(action_mwl)s
[sshd]
port = <你的 SSH 端口>
参数含义:
| 项 | 含义 |
|---|---|
bantime = 604800 | 封 7 天(秒) |
findtime = 21600 | 6 小时内的失败都算 |
maxretry = 5 | 失败 5 次就封 |
action = %(action_mwl)s | mwl = 封禁 + 记录到 whois 日志 + 发邮件通知 |
port | 自定义端口时必填,写默认 22 会导致抓不到日志 |
改完:
fail2ban-client reload
# 或者
systemctl restart fail2ban
四、验证(这一步不能省)
# 1) 规则条数应该开始涨
firewall-cmd --list-rich-rules | wc -l
# 2) 看某条规则长什么样
firewall-cmd --list-rich-rules | head -3
# 3) 再确认 jail 状态
fail2ban-client status sshd
现在的判据变成:fail2ban 说封了几个,防火墙里就应该能看到对应数量的规则。两边对得上,才算真生效。
五、两点提醒
- 改之前先备份
jail.local。改错了可能把自己也封了(尤其是maxretry调得过小的时候); - 别在文章里写自己的 SSH 端口。我这里的
port是自定义的,你照填你自己的;把端口公布出去等于把"改端口"这件事白做了。
六、回滚
把 banaction 改回原值并 reload。但要知道:回滚到 ipset 就是回到空转状态——这不是"恢复功能",是"恢复不报警"。
一句话总结:fail2ban 的"已封禁"只是它自己的账本,不等于防火墙里真的有条规则。换过防火墙后端(firewalld→nftables)之后一定要换 banaction,并且每次都用 firewall-cmd --list-rich-rules | wc -l 去核对。

评论 (0)