一条规则就能让已准入的 VPN 池无法访问某个目标网段,而不干扰网关做的其他事情。规则本身很短;决定它是否生效的是它所在的钩子和它在链中的位置。这两处弄错,得到的防火墙看起来正确,行为却不一致。先从规则看到数据包时数据包在做什么入手。

这条规则究竟匹配了什么

规则同时匹配三件事:入站接口、源前缀和目标前缀。三者都为真时丢弃才生效,这正是它足够窄的原因。把它当作一个表达式来读,比当作三条独立策略更容易。

接口匹配把转发的客户端流量与网关自身的连接区分开来。没有它,只写源池的规则也会影响网关自己从该地址发出的数据包(如果确有这种情况)。源前缀把策略限定在已准入客户端,目标前缀把它限定在一个网段。请把规则读作交集,而不是清单。

动手之前先把三个值写下来:隧道接口名、服务器下发的池,以及你打算拒绝的前缀。其中任何一个写错,得到的都是一条能干净解析却什么都不保护的规则。把这三个值和规则一起记在变更记录里。

钩子决定了规则作用于谁

netfilter 链挂在钩子上,钩子决定了链究竟能看到哪些数据包。forward 钩子看到的是经网关路由的流量,而这正是客户端到目标的流量。链里其他内容面向的是另一批对象。

input 钩子看到的是发往网关本身的流量,因此放在那里的规则管的是它自身服务的访问,而不是转发。output 钩子看到的是网关自己产生的流量,与客户端池策略的需要正好相反。链名是写规则的人随手起的标签,所以不要从名字推断钩子。先确认链挂在哪里,再假设它能匹配什么。

HookTraffic it seesRight for this policy
inputAddressed to the gatewayNo, that is the host's own services
forwardRouted through the gatewayYes, for client-to-destination traffic
outputGenerated by the gatewayNo, that is the opposite direction

读一下挂载点是一行就能完成的检查,它能避免规则落进一条永远看不到该数据包的链。

把规则放在宽泛 accept 之前

规则按顺序求值,第一个判决即生效。链中靠前的宽泛 accept 会为它匹配到的数据包结束求值,因此之后追加的 drop 对它们永远不会执行。正是这条顺序规则,让一条看似正确的规则毫无效果。

把规则插到 accept 之前,而不是追加到末尾。如果链里已经有针对隧道接口的通用 accept,新规则必须排在它前面,否则只是装饰。要看最终顺序,而不是你编辑的文件,因为由多个文件拼装的规则集可能与其中任何一个都不一致。然后用池里的测试数据包确认。

sudo nft list chain inet filter forward
sudo nft insert rule inet filter forward iifname "tun0" ip saddr 10.90.0.0/24 ip daddr 198.51.100.0/24 drop
sudo nft -c -f /etc/nftables.conf

第三条命令只解析文件而不应用,能在语法错误变成故障之前抓住它们。应用时要准备回滚方案,因为 forward 链里一条错规则可能切断你正在使用的隧道。

已有连接不理会你的新规则

规则出现之前建立的 conntrack 表项会继续匹配先前的接受。这就是为什么新的 drop 有时看起来对新连接有效,而对正在测试的那条毫无作用。

读一下链顶部的状态匹配。如果它在你的规则之前接受 established 和 related 流量,那么已在进行的连接会一直流动到关闭。对应急规则来说这通常正是想要的行为,但当你期待立即切断时就会觉得混乱。部署前先决定你要哪种效果。复用已打开连接的测试会给你错误的结论。

sudo conntrack -L -s 10.90.0.14 -d 198.51.100.20
sudo nft list ruleset | grep -n -A3 'ct state'

第一条命令显示连接是否存在,第二条显示早期的状态规则是否仍在接受它。两条都是只读的,在事故处理期间可以安全执行。

这条规则不是什么

它不是域名黑名单,不是 IPv6 策略,也不是针对单个应用账号的限制。

这些都各自需要自己的机制。域名拦截必须解析名字,而数据包过滤器不做这件事。IPv6 流量需要自己的匹配,因为 ip 表达式对 ip6 数据包什么也没说。应用层限制属于服务或经过认证的代理,而不属于前缀匹配。把需求分开,正是避免让一条窄规则承担四项工作的原因。

这条规则给出的约定很精确:从已准入池到某一个目标前缀的流量被拒绝,而无关的网关流量保持原有策略。把这句话写在规则旁边,下一个人就知道它是做什么的。

相关文章