一、引言
前一篇换成 ZTNet 后,终于能在控制台里维护flow rules。我想做的事不复杂:管理员照常全网通,其他成员只给他需要的服务地址和端口,顺手把 ping 也关掉。下面这份规则按我正在使用的rulesSource改写,业务身份合并成了一个guest,IP 也做了混淆;拿它拆一遍,比只看语法文档更容易知道 capability 到底怎么落地。
二、正文
(一)先给一份可用的 rulesSource
下面保留了实际规则的结构:开头丢掉无关的二层流量,中间定义 admin 和 guest,末尾补上 ARP、DNS、TCP 返回流量。为了符合本篇“guest 不能 ping”的目标,ICMP 放行保持注释;排障时有需要再打开。
# 只处理 IPv4、ARP、IPv6,其他以太网类型直接丢弃
drop
not ethertype ipv4
and not ethertype arp
and not ethertype ipv6
;
# 管理员身份:不限制目标地址、端口和协议
cap admin
id 100
accept;
;
# 受限身份:所有业务用例都收在 guest 里
cap guest
id 104
# Node-RED 管理页
accept ipdest 10.23.2.19/32 and dport 1880;
# 另一套业务服务
accept ipdest 10.23.2.20/32 and dport 8000;
# 家庭服务的管理端口
accept ipdest 10.23.1.254/32 and dport 3000;
# V Rising 服务端端口
accept ipdest 10.23.1.11/32 and dport 9876;
# TeamSpeak 语音、查询和文件传输端口
accept ipdest 10.23.1.12/32 and dport 9987,10011,30033;
# 这些机器只在 guest 身份下可访问,端口不另作限制
accept ipdest 10.23.1.21/32;
# 另一台只允许 guest 访问的机器
accept ipdest 10.23.1.22/32;
# 家庭网段中的服务节点
accept ipdest 10.23.2.27/32;
# 另一台家庭服务节点
accept ipdest 10.23.2.38/32;
# 这个服务只开放两个 Web 端口
accept ipdest 10.23.5.4/32 and dport 7999,8080;
# 只允许 guest 访问的其他节点
accept ipdest 10.23.2.52/32;
accept ipdest 10.23.2.51/32;
;
# 保留 ARP,否则局域网二层发现会出问题
accept ethertype arp;
# guest 默认不允许 ping;排障需要时才取消下一行注释
# accept ipprotocol icmp4;
# 允许 DNS 查询
accept dport 53;
# 放行已经建立的 TCP 连接返回流量,否则通信会变成单向
accept chr tcp_ack;
# 不写最终 accept;,未命中的流量保持默认 drop(二)这份规则怎么读
ZeroTier flow rules 是网络内的流量过滤规则,不是 ZTNet 自己发明的一套防火墙。ZTNet 做的事,是把控制器里的 rulesSource 和 capability 放进 Web UI,省得每次都绕开控制台去改。
这篇只留两种身份:admin 全放行,guest 只访问指定服务。示例把原本分散在多个 capability 里的业务用例收进了 guest,IP 也换成 10.23.x.x,所以它适合解释写法,不要直接替换到自己的网络。
第一段 drop 先把不需要处理的以太网类型过滤掉。之后看 capability:成员拿到 admin 时,accept; 直接全放行;拿到 guest 时,只能命中列出来的 ipdest 和 dport。
ipdest 10.23.1.21/32; 这种写法只限制目标机器,不限制端口;ipdest 10.23.5.4/32 and dport 7999,8080; 则把机器和端口一起限制住。两种写法混在一个 capability 里很常见,关键是先把服务清单列明白,别写完才猜哪条规则放开了什么。
末尾三条容易漏:ARP 负责二层发现,DNS 让域名还能解析,chr tcp_ack 放行 TCP 的返回包。最后没有 accept; 兜底,未命中的流量按默认 drop 处理;这也是 guest 只能碰到白名单服务的原因。
(三)先在 ZTNet 找到 Flow Rules
网络详情页往下翻,可以看到折叠起来的 Flow Rules。展开后编辑,保存前确认规则没有写错,最后点击 Save Change。

这一步只负责写规则,成员还不会立刻获得权限。capability 定义出来后,还要到成员的 Options 里勾选。
(四)把 capability 勾给成员
规则写完并保存后,打开成员行右边的 OPTIONS。在 Flow Rules 的 Capabilities 区域,可以勾选刚才定义的 admin 或 guest;勾完关闭弹窗,权限就跟着成员走。

我只保留了两组身份:需要全网管理权限的设备给 admin,其他设备按用途给 guest。后面再加服务,不需要给每个成员复制一份规则,只改 guest 的白名单即可。
(五)改完怎么验证
先把原始 rulesSource 复制出来,再从一个 guest 成员开始测。该通的服务要能打开,不在白名单里的地址和端口应当连不上;如果保持了上面的注释状态,ping 也不会通过。TCP 服务还要实际登录或请求一次,不能只看端口探测,否则很难发现漏掉 tcp_ack 后的单向通信。
规则没按预期生效时,先检查成员是否真的勾上了正确的 capability,再回头看规则顺序和目标地址。确认问题后直接恢复保存的 rulesSource,比在生产规则上连续叠加临时例外省事得多。
三、总结
这套规则没有多复杂:admin 全放行,guest 收拢所有服务白名单,基础流量单独放行,剩下的交给默认 drop。ZTNet 的价值不在于替我写规则,而是把 rulesSource 和 capability 都放到了同一个页面里;以后给人开服务,改规则和勾身份都不用再绕开控制台。