firewalld rich rule 不生效的首要原因是 zone 绑定错误,需先用 firewall-cmd --get-active-zones 确认网卡所属 zone,再检查该 zone 的 rich rule 并确保 --reload 生效。

firewalld rich rule 不生效,先确认 zone 绑定是否正确
rich rule 生效的前提是它所属的 zone 确实被应用在对应网卡或源地址上。很多人直接用 firewall-cmd --add-rich-rule 添加规则,却没检查该规则加到了哪个 zone——默认是 public,但如果你的接口实际属于 trusted 或自定义 zone,规则就完全不会触发。
查当前接口绑定的 zone:firewall-cmd --get-active-zones
再查该 zone 的所有 rich rule:firewall-cmd --zone=your-zone-name --list-rich-rules
- 如果
--get-active-zones没输出你的接口,说明它走的是 default zone(通常是public),但得确认firewall-cmd --get-default-zone - 如果接口出现在多个 zone 下(比如用了
--permanent但没重载),以运行时 zone 为准,--runtime-to-permanent不会自动同步 rich rule - 临时添加的 rich rule 不带
--permanent,重启 firewalld 后消失;永久添加后必须firewall-cmd --reload才生效
rich rule 中的 source address 写法影响匹配优先级
firewalld 的 rich rule 是按“从上到下”顺序匹配的,但真正决定是否命中的是 source 和 destination 的 CIDR 精确度,而非添加顺序。比如你写了两条规则:
rule family="ipv4" source address="192.168.1.0/24" accept rule family="ipv4" source address="192.168.1.100" accept
实际生效的是更具体的那条(即后者),因为 firewalld 底层用的是 nftables,其链匹配逻辑优先选最长前缀匹配(LPM),不是简单顺序执行。
-
source address写成单 IP(如192.168.1.100)比写成/32更稳妥,某些版本对/32解析有 bug - 不要混用
source和destination在同一条 rule 里限制双向流量,firewalld rich rule 默认只管入向;出向需额外加rule ... destination ...并确保 zone 的target不是DEFAULT_DROP - 若使用
ipset,务必确认 ipset 已存在且加载进内核:ipset list your-set-name,否则 rich rule 会静默失败
检查 runtime 规则是否真落到 nftables 链里
firewalld 是 nftables 前端,rich rule 最终要编译成 nft 表项。如果没生效,最直接的办法是绕过 firewalld 查底层:
看当前生效的 nft ruleset:nft list ruleset | grep -A5 -B5 "firewalld"
- rich rule 一般落在
inet firewalld filter_IN_XXX链(XXX 是 zone 名),若找不到对应 rule,说明 firewalld 没成功下发 - 常见原因:rule 语法错误(比如漏写
family="ipv4")、zone 名拼错、或firewall-cmd --reload时因语法问题回滚了整个 zone 配置(此时journalctl -u firewalld里会有 “Failed to apply rules”) - 临时调试可手动加一条 nft rule 测试通路:
nft add rule inet firewalld filter_INPUT ip saddr 192.168.1.100 accept,若通了,说明是 firewalld 解析或 zone 绑定问题
zone target 设置为 DROP 时 rich rule 可能被跳过
每个 zone 的 target 决定了默认策略。如果 zone 的 target 是 REJECT 或 DROP(可通过 firewall-cmd --zone=xxx --get-target 查),那么 rich rule 必须显式 accept,且不能依赖“默认放行”。但更隐蔽的问题是:当 target = DROP 时,firewalld 会把所有非 rich rule 的流量直接丢弃,而 rich rule 若因语法/顺序/匹配失败没触发,结果就是全拒。
- 建议调试期先设为
firewall-cmd --zone=xxx --set-target=ACCEPT,确认 rich rule 能触发后再调回严格模式 -
target=DEFAULT_DROP是最严格的,它会让所有未显式accept的包走到最后一条 drop 规则;此时 rich rule 的位置无关紧要,但必须 100% 匹配条件 - 注意:修改 target 后必须
--reload,仅--runtime-to-permanent不生效
真正卡住的地方往往不在 rule 本身,而在 zone 是否接管了流量、nftables 是否收到指令、以及 target 如何兜底。别急着改 rule 内容,先用 firewall-cmd --get-active-zones 和 nft list ruleset 对齐预期和现实。










