理解 nftables 框架:表、链、规则和集合

从概念层面梳理 nftables 框架:table、family、chain、rule、set、map 和 verdict map 分别解决什么问题,以及它们如何组合成可维护的防火墙规则。

学习 nftables 时,容易一开始就陷入命令细节:怎么添加规则、怎么删除 handle、怎么写端口匹配。命令当然重要,但如果先把框架概念理清楚,后面读规则、排查问题和设计规则集都会轻松很多。

可以把 nftables 理解成一套分层结构:

  • table 负责隔离规则空间。
  • family 决定规则处理哪类网络协议。
  • chain 决定规则在什么阶段执行。
  • rule 负责具体匹配和动作。
  • setmapverdict map 用来减少重复规则,让规则集更易维护。

下面按概念逐层说明。

table:规则的命名空间

table 是 nftables 里最外层的规则容器。不同 table 之间相互隔离,因此常见做法是把一组相关规则放进同一个 table。

例如,你可以把过滤规则、NAT 规则或自定义测试规则分开放。这样做的好处是边界清晰:调试时知道自己在改哪一组规则,清理时也不容易误删无关内容。

table 本身不会直接处理数据包。真正参与数据包处理的是 table 里面的 chain 和 rule。

family:规则面对哪类协议

创建 table 时需要选择 family。它决定这张表里的规则适用于哪类数据包。

常见 family 可以这样理解:

  • ip:只处理 IPv4。
  • ip6:只处理 IPv6。
  • inet:同时处理 IPv4 和 IPv6。
  • arp:处理 ARP。
  • bridge:处理桥接层流量。
  • netdev:更靠近网络设备入口,适合较早阶段处理流量。

日常写普通防火墙规则时,inet 很常用。它可以把 IPv4 和 IPv6 规则放在同一个 table 里,避免维护两套结构相似的规则。

chain:规则执行的位置

chain 是 rule 的列表。数据包进入某个 hook 后,会按顺序经过 chain 里的规则。

chain 大致可以分为两类:

  1. 基本 chain:挂到内核网络路径的某个 hook 上,会被数据包流程主动调用。
  2. 常规 chain:不直接挂 hook,需要被其他规则跳转调用。

基本 chain 通常会指定几个关键属性:

  • type:这条 chain 的用途,例如 filternatroute
  • hook:挂在哪个处理阶段,例如 preroutinginputforwardoutputpostrouting
  • priority:同一个 hook 上有多条 chain 时,谁先执行。
  • policy:没有规则匹配时的默认动作,常见是 acceptdrop

理解 chain 的关键是:规则不是“随便写在哪里都能生效”。同一条规则放在 inputforwardoutput,含义完全不同。

rule:匹配条件加动作

rule 是 nftables 里真正做判断的地方。它通常由两部分组成:

  • 匹配条件:例如源 IP、目标 IP、协议、端口、接口、连接状态。
  • 动作:例如 acceptdroprejectcounterjumpreturn

规则会按顺序求值。数据包命中某条会终止流程的动作后,就不会继续执行后面的规则。没有命中时,则继续往下走,直到 chain 结束或触发默认策略。

这也是为什么规则顺序很重要:更具体的规则通常要放在更宽泛的规则前面,否则可能永远没有机会被执行。

set:把一组值放在一起

如果有很多 IP、端口或接口需要匹配,直接写多条规则会很难维护。set 用来把一组同类型的值集中管理。

例如,一组可信 IP、一组禁止访问的端口、一组需要限速的地址,都可以放进 set。规则只需要判断某个值是否属于这个 set。

set 的好处是:

  • 规则数量更少。
  • 可读性更好。
  • 后续增删元素更方便。

当规则里出现大量重复条件时,通常就该考虑用 set。

map:把匹配值映射成结果

map 可以理解成“查表”。它根据一个输入值返回一个结果。

例如,不同端口映射到不同标记,不同地址映射到不同处理参数,都可以通过 map 表达。相比写多条 if/else 式规则,map 更集中,也更容易维护。

set 关心的是“是否在集合里”,map 关心的是“这个值对应什么结果”。

verdict map:把匹配值映射成动作

verdict map 是 map 的一个重要用法:它把匹配值映射成 verdict,也就是规则动作。

例如,不同 IP 段可以对应 acceptdrop 或跳转到不同 chain。这样可以把很多分支判断压缩到一个结构里。

当规则集开始变复杂时,verdict map 很有用。它能减少重复规则,也能把策略表达得更像一张表,而不是一长串判断语句。

从概念看规则设计

设计 nftables 规则时,可以按这个顺序思考:

  1. 先确定规则属于哪个 family
  2. 再决定放进哪个 table
  3. 然后选择合适的 hookchain
  4. 最后编写具体 rule
  5. 如果重复条件很多,再引入 setmapverdict map

这样写出来的规则会更容易维护,也更容易排错。

小结

nftables 的概念并不复杂,但层级很重要:

  • table 管规则边界。
  • family 管协议范围。
  • chain 管执行位置。
  • rule 管匹配和动作。
  • set、map、verdict map 管复杂度。

先理解这些概念,再去看具体命令,会比直接背命令更稳。尤其是在规则集变多以后,概念清楚能帮助你判断:问题到底出在协议范围、执行阶段、规则顺序,还是匹配条件本身。

参考

记录并分享
使用 Hugo 构建
主题 StackJimmy 设计