firewalld rich-rule 不生效的根本原因是规则匹配按插入顺序从上到下执行,先匹配的规则(如宽泛 drop)会阻止后续更精确的 accept 规则执行;--list-all-zones 不显示真实匹配顺序,应使用 --zone=xxx --list-rich-rules 查看实际顺序。

firewalld rich-rule 为什么加了不生效?
根本原因:rich-rule 的优先级由添加顺序决定,但 firewall-cmd --list-all-zones 默认不显示规则顺序或隐式优先级,容易误判“已添加就一定生效”。实际中,同 zone 内多条 rich-rule 会按插入顺序从上到下匹配,一旦某条匹配成功(accept/drop),后续规则直接跳过——哪怕你后来加的 rule 更“精确”。
- 常见错误现象:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.10.5" port port="22" protocol="tcp" accept'加完后仍连不上,而firewall-cmd --list-all-zones看似有这条规则 - 真实原因:前面可能有一条更宽泛的
drop规则(比如拒绝整个子网),它先命中,后面允许的 rich-rule 根本没机会执行 - 验证方法:用
firewall-cmd --zone=public --list-rich-rules查看当前运行时规则列表(注意不是--list-all-zones),输出顺序即匹配顺序 - 临时解决:删掉冲突规则再重加;长期建议统一用
--permanent操作 +firewall-cmd --reload,避免 runtime 和 permanent 不一致
firewall-cmd --list-all-zones 显示的 rich-rule 顺序不可信
firewall-cmd --list-all-zones 只是把每个 zone 的 rich-rule 做了归类展示,并不保证输出顺序与实际匹配顺序一致。它可能按字母、时间戳或内部哈希排序,和 iptables 链里真实的规则位置完全脱钩。
- 使用场景:适合快速检查某个 zone 是否启用了 rich-rule 功能、有没有漏加 --permanent,但绝不能用来调试匹配逻辑
- 正确做法:对目标 zone 单独查,例如
firewall-cmd --zone=public --list-rich-rules(runtime)或firewall-cmd --permanent --zone=public --list-rich-rules(permanent) - 参数差异:
--list-all-zones是全局概览,无 zone 上下文;带--zone=xxx的才是真实链式结构视图 - 性能影响:无关,只是显示逻辑不同;但依赖
--list-all-zones排查问题会导致反复 reload 浪费时间
如何安全调整 rich-rule 优先级
firewalld 不支持像 iptables 那样用 -I 插入指定位置,rich-rule 只能靠“先删后加”来控制顺序。这意味着必须手动管理规则 ID 或语义标签,否则极易错乱。
- 最容易踩的坑:用
--remove-rich-rule时没写全内容(比如少了个空格、protocol 大小写不对),结果删不掉,却以为删成功了,再加新规则导致重复或错序 - 实操建议:给每条 rich-rule 加注释说明用途,例如在 rule 后追加
comment="allow-ssh-from-admin"(需 firewalld ≥ v0.9.0),虽然不改变优先级,但方便 grep 定位 - 删除前务必确认:先用
firewall-cmd --zone=public --list-rich-rules | grep -n "192.168.10.5"找到行号,再用该完整字符串去删 - 兼容性注意:RHEL 8/CentOS 8 默认 firewalld 版本支持 comment,但 RHEL 7.9 及更早版本不支持 rich-rule comment,删规则只能靠肉眼比对原始命令
zone 切换导致 rich-rule “消失”的真相
rich-rule 是绑定到具体 zone 的,不是全局策略。如果你把接口从 public 切到 trusted,之前在 public 里加的所有 rich-rule 就自动失效——firewall-cmd --list-all-zones 仍会列出 public zone 下的规则,但它对当前流量已无意义。
- 常见错误现象:改完 zone 后服务不通,查
--list-all-zones发现规则“还在”,怀疑是 bug - 关键判断点:运行
firewall-cmd --get-active-zones看当前接口实际归属哪个 zone,再针对性查那个 zone 的 rich-rule - 参数差异:
--zone=xxx是显式指定作用域,而--list-all-zones是被动展示所有 zone 的配置快照,二者视角完全不同 - 容易被忽略的地方:Docker、libvirt 等工具可能自动创建并分配 zone(如
docker0接口常被划入dockerzone),这些 zone 的 rich-rule 很少有人主动检查










