chain postrouting1 {
type nat hook postrouting priority 100; policy accept;
ip saddr 192.168.0.0/16 oifname pppoe-wan masquerade
通过第一行我们知道,这条链作用于 postrouting
阶段,作用是进行 NAT,优先级为 100,允许未经处理的包通过。第二行则对来自 192.168.0.0/16
的包进行处理,如果它出口网卡 oifname
是 pppoe-wan
,那么就对它进行掩蔽 ( masquerade
) 。这是 PPPoE 上网时比较重要的一个操作,修改包的来源 IP,假装这个包来自拨号的设备,避免将内网地址暴露给外部,也避免了上级网关发现拨号 IP 与数据包的 IP 不一致,导致包被丢弃。
最后可能还需要说明,关于分号的使用,nftables 并不严格, 似乎 行末分号的有无并不会影响配置。在 链的配置 中,nftables 官方说:
Important: nft re-uses special characters, such as curly braces and the semicolon. If you are running these commands from a shell such as bash, all the special characters need to be escaped.
这是整个官方 wiki 中唯一提及分号的部分,我不太确定这个模棱两可的 re-uses 具体是需要还是不需要,从实际配置中看来 似乎 与 Kotlin 这类不严格要求分号的语言类似,若一行中存在两条规则,例如 type filter …… ; policy accept;
,则需要在各条结束后加上分号,若没有则不需要。如此看来,大部分时候按照习惯来即可。
Netfilter hooks , prerouting
阶段目标地址转换 ( dstnat
) 的优先级为 -100
,我们既可以直接写 -100
,又可以使用 dstnat
这个关键词。以防万一,我们也可以用一个更高优先级的规则,例如 dstnat - 5
,保证我们这条链发生在其他链之前。
第二步是对包进行判断,这一步相关文档在官方 wiki Expressions: Matching packets 部分,不过其实通过本文前一节就能知道,我们首先需要判断 ip
,如果它的 dport
是 8022
,说明这个包可以被转发。以防万一,我们还可以进一步对包的来源进行判断,例如我只希望允许来自 ZeroTier 的流量,而我的 ZeroTier 在 10.244.0.0/16
网段,那么再加一个 saddr
进行判断。如果没有判断目标地址听起来有点不靠谱,我们还可以再加一个 daddr
,仅当明确访问位于 10.244.1.1
的路由器时才响应。
第三步就是进行目标地址转换了。同样查阅官方 wiki,NAT 相关的操作在 Performing NAT ,其中提到只有 nat
类型的链才能执行 NAT,以及目标地址转换的关键词是 dnat to
,我们在后面加上目标 IP 和端口,即 192.168.1.100:22
,就完成了这条链的配置:
chain redirect_to_internal {
type nat hook prerouting priority dstnat - 5; policy accept;
ip saddr 10.0.0.0/8 daddr 10.244.1.1 tcp dport 8022 counter dnat to 192.168.1.100:22
聪明的读者可以注意到,这里我们中间还多了一个 counter
:这是 nftables 用来统计转发数据包量的工具。像这样放在规则中间,判断之后、操作之前,就能够对通过判断的数据包进行计数 ( counter
),便于判断规则是否生效,通过 OpenWrt 的防火墙管理页面或者 nft list ruleset
命令,都能看到规则的统计数据。
大功告成,现在赶紧把文件保存为 /etc/nftables.d/11-redirect.nft
,再 service firewall restart
看看效果吧!
官方 wiki 是个不错的选择,无论是配置过程中遇到问题还是希望进行更复杂的配置,都能在官方 wiki 找到详尽的说明。各大 Linux 发行版在它们的 wiki 中一般也会包含 nftables 相关页面,介绍对应发行版的相关配置,例如 OpenWrt 的 Firewall overview 或者 Debian 的 nftables 。
这篇文章起笔于 2023 年 9 月,到写下这里已经 12 月,我的鸽子之魂熊熊燃烧,好在最终还是没有让这篇博客变成废稿。本来希望做一些更复杂的配置文件示例及解释,不过作为入门来说似乎过于复杂,不如在基础部分多啰唆几句,将其余部分留给读到这里的读者。可惜,直到最后我也没有搞清楚学校防火墙到底从什么地方检测出多设备,决定干脆直接将流量加密后转发出校,借此规避特征检测,当然这就是另一个故事了。总之,配网愉快~