1.3 你亲手写过 nftables:五链、conntrack 状态、masquerade、DNAT。但没人会在路由器上一条条手写这些——OpenWRT 用 firewall4 提供一个更高层的抽象:zone(区域)。你把接口划进 lan / wan 等区域,设几条区域间的规则,fw4 就替你编译成 1.3 那种 nftables。这章讲清这个 zone 模型,以及它最终怎么变回你熟悉的 nftables——学完你既会用 OpenWRT 的方式配防火墙,也知道它背后生成了什么。
OpenWRT 的 firewall4(fw4)在 nftables 之上提供一个 zone(区域)模型:把接口分组成区域,按"区域"而非"单条规则"设策略;fw4 读 /etc/config/firewall,把它编译成 1.3 那样的 nftables 规则集。
1zone 模型:防火墙的核心抽象
1.3 你按接口 / 链一条条写规则,能用但繁琐——一台路由器有多个接口(LAN 几个口、WAN、guest、VPN…),逐个写易错。zone 把接口按信任级别分组:
input: ACCEPT
output: ACCEPT
input: REJECT
masq(SNAT)
每个 zone 有默认策略(对应 1.3 的 policy),分三个方向:input(到路由器本身、来自该区域的流量,1.3 的 INPUT 链)、output(路由器发往该区域,OUTPUT 链)、forward(该区域接口之间转发,FORWARD 链)。关键的思路转变:你不再想"这条规则挂哪个链",而是想"哪个区域默认怎样、哪些区域之间允许转发、有哪些例外",fw4 替你落到 1.3 的链和规则。
zone 像给接口打信任标签,策略按标签成对定义(from-zone → to-zone),而不是按单个接口——类似用角色 / 组管权限,而非给每个用户单独配,抽象高一档、好维护。每个区域的三方向默认策略 = 它的"基线",rule 是基线上的例外。
2三要素:zone / forwarding / rule
/etc/config/firewall 主要由三种段构成。zone 段(定义区域 + 三方向默认策略 + 绑定接口):
config zone
option name 'lan'
list network 'lan'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'ACCEPT'
config zone
option name 'wan'
list network 'wan' 'wan6'
option input 'REJECT' # 外网不能主动连路由器本身
option output 'ACCEPT'
option forward 'REJECT' # 外网不能主动转发进内网
option masq '1' # 出 wan 做 masquerade(SNAT,见 §3)
wan 的 input / forward 是 REJECT——这就是"外网主动连不进来"的默认防线(落 1.3 有状态防火墙 + IPv6 章那句"真正挡外部的是这条,不是 NAT")。forwarding 段(允许一个区域转发到另一个):
config forwarding
option src 'lan'
option dest 'wan' # 允许 LAN → WAN(内网能出外网)
只有这条、没有反向 wan→lan,所以内网能出、外网进不来。它对应 1.3 FORWARD 链里"允许 lan 到 wan"+ conntrack 放行回包。rule 段(基线之上的具体例外):
config rule
option name 'Allow-SSH-WAN'
option src 'wan'
option proto 'tcp'
option dest_port '22'
option target 'ACCEPT' # 破例:允许从 WAN 连本机 22(谨慎!)
这类似 1.3 里你手动加的 tcp dport 22 … accept。OpenWRT 默认已内置一批 rule(放行 DHCP、DNS、ICMP/ping、IPv6 的 RA 等)。
打开 LuCI 的"防火墙"页,那三个标签页"区域 / 端口转发 / 通信规则",正是这里的 zone / redirect / rule。网页点一点,底层就是改 /etc/config/firewall 的这几种段(2.2 的框架),再由 fw4 编译。
3NAT:masquerade 与端口转发
masquerade(SNAT,0.6):不用单独写规则,给 wan 区域加 option masq '1' 即可(§2 已见)。fw4 就在 nftables 的 postrouting 链上,为出 wan 的流量生成一条 masquerade——正是 1.3 你手写的 oifname "wan" masquerade。家用路由器的 NAT,在 OpenWRT 里就是"wan 区域打开 masq"。端口转发(DNAT,0.6)用 redirect 段:
config redirect
option name 'Game-Server'
option src 'wan'
option src_dport '25565' # 公网端口
option dest 'lan'
option dest_ip '192.168.1.50' # 内网目标(配 2.3 的静态租约!)
option dest_port '25565'
option proto 'tcp'
option target 'DNAT'
这就是 0.6 / 1.3 的端口转发:到 wan 口 25565 的 tcp,目的地址改写成 192.168.1.50:25565。fw4 把它编译成 nftables prerouting 链的 dnat 规则(1.3)。dest_ip 要指向稳定的内网 IP——所以先在 2.3 给它配静态租约。
同一件事你已见过三层:0.6 讲原理(DNAT 改目的、为什么在路由前)、1.3 手写 nftables 规则、2.4 用 redirect 段配。从概念到内核到配置界面,完全贯通。CGNAT 下它仍会失效(IPv6 章),因为运营商那层 NAT 先拦住了——这跟你在哪层配无关。
再强调一次(因为重要):wan 区域 input/forward=REJECT + 没有对应 redirect,才是真正挡住外部主动连接的东西;NAT(masq)只是地址转换的副产品,不是防火墙(IPv6 章)。IPv6 下没有 masq,但 wan forward=REJECT 依然把外部主动连接挡在外面——防护来自区域策略,不是 NAT。
4fw4 怎么编译成 nftables
fw4 不是常驻防火墙,而是个编译器:读 /etc/config/firewall 的 zone/forwarding/rule/redirect,生成一整套 1.3 那样的 nftables 规则装进内核。对照 2.2 的"配置→执行→内核":
- 读 firewall 配置(本章)+ 从 netifd 知道每个区域含哪些接口;
- 按模板生成 nftables:每个 zone 生成对应 input/forward 链和默认策略、每条 forwarding 生成转发放行、每条 rule/redirect 生成具体规则,并自动加上 conntrack 有状态放行(1.3 的
established,related accept)、masquerade 等; - 用 nftables 原子加载整套规则进内核(1.3 的 nft)。
想看它生成了什么:
fw4 print # 打印 fw4 将生成的完整 nftables(不实际加载)
nft list ruleset # 看内核里实际生效的规则(1.3 那个命令)
fw4 print 极有教学价值:你会亲眼看到自己写的几行 UCI zone 配置,被展开成几十行 1.3 风格的 nftables——链、hook、conntrack 状态、masquerade、dnat,全是 1.3 认识的东西。在 LuCI/UCI 配好 zone/rule,再 fw4 print 对照 1.3 你手写的规则:fw4 就是把"人类友好的区域模型"翻译成"内核认的 nftables"的翻译器。看懂这层翻译,你就同时掌握了两端。
这章把 1.3 和 OpenWRT 接上了:1.3 是手写 nftables(内核认的),2.4 是 zone 模型(人配的),fw4 是中间的编译器。你既能用 LuCI 三个标签页快速配,也能 fw4 print 看穿它、必要时插入自定义 nft 规则。Phase 3 自己造路由器时,可以选 fw4 这套,或直接手写 nftables——两条路你现在都懂。
本章小结
- zone 模型:把接口按信任分组(lan 高信任、wan 不可信),按"区域之间"设策略,而非逐条接口——比 1.3 手写更好维护。
- 三要素:zone(区域 + input/output/forward 默认策略 + 绑定接口)、forwarding(允许区域间转发,如 lan→wan)、rule(基线上的具体放行 / 拒绝)。
- NAT:wan 区域
masq '1'= masquerade(SNAT,0.6);redirect 段 = 端口转发(DNAT,0.6),dest_ip 指向 2.3 的静态租约。 - 真正挡外部的是 wan forward/input=REJECT + 无对应 redirect,不是 NAT(IPv6 章);IPv6 下无 masq 但依然靠区域策略防护。
- fw4 是编译器:把 zone/rule 编译成 1.3 那样的 nftables;
fw4 print能看到 UCI 展开成的完整 nftables——抽象在此落地,1.3 与 OpenWRT 在此接上。
动手练习
- 若有 OpenWRT:
cat /etc/config/firewall,找出 lan 和 wan 两个 zone,读它们的 input/output/forward 和 wan 的 masq;找出 lan→wan 的 forwarding。 - 跑
fw4 print,在输出里找到:masquerade 那条(SNAT)、ct state established,related accept那条(1.3)、以及 wan input 的默认 drop/reject。对照 1.3 你手写的规则。 - 思考题:为什么"外网连不进你的内网"?是 NAT 挡的,还是防火墙区域策略挡的?(区域策略:wan forward=REJECT + 无 redirect;NAT 只是地址转换。)
- 进阶:把端口转发的三层写到一起——0.6 的原理、1.3 的 nftables(
prerouting … dnat to)、2.4 的 redirect 段。给同一个"公网 25565 → 内网 .50:25565"分别写出三种表达。