Debian 12下Firewalld运行时IPSet条目无法正确删除的问题咨询
你遇到的这个情况并不是bug,而是Firewalld运行时配置与内核IPSet同步机制导致的预期行为,下面我来详细解释并给出解决方案:
问题原因分析
当你将IPSet关联到drop zone后,Firewalld会在内核层面维护这个IPSet的引用,同时Firewalld自身会维护一份运行时状态缓存。有时候直接使用firewall-cmd操作运行时IPSet条目时,虽然命令返回success,但Firewalld的缓存和内核实际的IPSet状态可能没有及时同步,导致条目看起来仍然存在。
另外需要注意:Firewalld的**运行时(runtime)和永久(permanent)**配置是完全分离的——你在运行时添加的条目只会存在于当前会话,不会写入永久配置;而删除操作如果只针对运行时,理论上应该生效,但缓存同步问题会导致显示异常。
解决方案
1. 直接操作内核IPSet(推荐用于fail2ban场景)
既然Firewalld的IPSet最终是基于内核的ipset模块实现的,你可以绕过Firewalld的命令,直接用ipset工具操作内核中的IPSet,这样可以确保修改立即生效,而且完全不需要重载Firewalld:
- 添加条目:
ipset add myipset 1.2.3.4 - 删除条目:
ipset del myipset 1.2.3.4 - 查看当前内核中的IPSet条目:
ipset list myipset
这种方式非常适合fail2ban的动态IP封禁场景,因为操作轻量、无延迟,不会带来系统负载问题。
2. 修正Firewalld的操作方式
如果你坚持使用Firewalld的命令,需要确保操作明确指向运行时状态,并且可以强制同步缓存:
- 删除条目时,明确指定只操作运行时(虽然默认是运行时,但显式指定更可靠):
firewall-cmd --ipset=myipset --remove-entry=1.2.3.4 --runtime - 之后可以用以下命令强制刷新规则并查看运行时条目:
firewall-cmd --reload-rules firewall-cmd --ipset=myipset --get-entries --runtime
--reload-rules只会重载防火墙规则,不会重启Firewalld服务,负载比完整--reload小很多,但还是不如直接用ipset命令高效。
3. 针对fail2ban的配置调整
如果你要将这个IPSet用于fail2ban,建议修改fail2ban的action配置文件,替换掉原来调用firewall-cmd的逻辑,改用直接调用ipset命令的action模板。这样每次封禁/解封IP时,都会直接操作内核IPSet,不会出现同步问题,也完全避免了重载Firewalld的需求。
备注:内容来源于stack exchange,提问作者John David Ravenscroft




