最常见原因是规则挂载的 hook 和 priority 与数据包实际经过的网络栈路径不一致:每条规则仅在指定 hook(如 input、forward)和 priority 位置生效,且仅对对应方向及协议栈阶段的包可见。

为什么 nftables 规则加载成功却完全不匹配流量
最常见原因是规则挂载的 hook 和 priority 与实际数据包经过的网络栈路径不一致。nftables 不是“全局生效”,每条规则只在指定 hook(如 input、forward、prerouting)和优先级位置生效,且仅对对应方向、协议栈阶段的包可见。
典型误判场景:
- 在
inputhook 写规则想拦截外部访问本机的 TCP 连接,但目标端口已被 conntrack 或早期 netfilter 模块(如 nf_nat)提前处理或跳过 - 在
forward中加规则,但容器或 bridge 流量根本没走 host 的 forward 链(例如使用host.docker.internal或 IPv6 SLAAC 场景) - 用
prerouting做 DNAT,但规则 priority 太高(如 -300),被nf_conntrack(默认 priority -200)之后才执行,导致连接跟踪已建立,DNAT 失效
nft list ruleset 看不到你的规则?检查 hook 和 priority 是否被覆盖
nft list ruleset 输出中,每条 chain 都明确标注了 type filter hook input priority 0 这类信息。如果规则“加载成功”但没出现在输出里,大概率是:你重复声明了同名 chain,后加载的覆盖了前一个;或者用了错误的 family(inet vs ip vs ip6),导致规则落在另一个 namespace 下。
实操建议:
- 用
nft list ruleset -a查看 handle 编号,确认规则是否真被插入到目标 chain 底部 - 检查 chain 定义是否带
type filter hook input priority 0,而不是漏写priority——省略时默认为 0,但很多内核模块(如nf_tables_ipv4)注册的内置 chain 是priority -200,0 反而排在它们之后 - 避免混用
inet(双栈)和ip(IPv4 only)family:IPv6 流量不会匹配ipfamily 的inputchain,即使规则语法完全一样
抓包验证 packet path:哪个 hook 实际收到了这个包
光看规则列表不够,必须确认数据包到底走到哪一级。推荐用 tcpdump + nft monitor trace 联合定位:
- 先用
tcpdump -i any port 80确认包确实到达 host(排除路由、网卡、offload 问题) - 再开一个终端运行
nft monitor trace,然后发测试请求——你会看到每条匹配的规则 handle、hook 名称、priority 数值,甚至跳转 chain 的完整路径 - 若 trace 输出里完全没出现你的规则 handle,说明包没走到那个 hook,或在更早的 priority 被
accept/drop终止了
注意:nft monitor trace 默认只显示被规则显式 trace 的包,需先给 chain 加 meta nftrace set 1 才能开启全量追踪(临时调试可用,线上慎用)。
priority 数值越小真的越早执行?别被直觉骗了
priority 是按数值升序执行的:-300 比 -200 更早,0 比 100 更早。但关键陷阱在于——不同 hook 的 priority 空间是独立的,且内核模块注册的内置 chain 有固定优先级,比如:
-
nf_conntrack:prerouting priority -200,output priority -200 -
nf_nat:prerouting priority -100,output priority -100 - 你自己定义的 filter chain 若设为
priority 0,在 prerouting 中就排在 nat 之后,此时做 DNAT 已无效
所以不是“随便设个负数就行”,而是要查清依赖模块的 priority(cat /proc/net/nf_tables_hooks 或翻内核文档),再决定你的规则该插在哪一档。比如做早期包标记,用 priority -300;做最终过滤,用 priority 100 更安全。
真正容易被忽略的是:同一 priority 下多条规则的执行顺序,取决于它们插入的先后(handle 递增),而不是你在 nft 命令里写的顺序。批量加载时务必用 nft -f 并确保 chain 创建和 rule 插入在同一个事务里。








