在 Linux 旁路由上同时运行 UFW 和 sing-box TUN 时,可能出现一种容易误判的故障:sing-box 本机运行正常,但局域网设备通过旁路由访问互联网失败。即使放行了当时被拦截的 TCP 端口,重启 sing-box 后问题也可能再次出现。
本文记录一种实际观察到的原因和待回归验证的修复方式。示例均使用文档保留地址,不对应真实网络。
环境和症状
- Linux 旁路由,LAN 接口为
eth0,地址192.0.2.1(仅作示例)。 - 下游终端
192.0.2.20,使用旁路由作为 IPv4 网关。 - sing-box 的 TUN 接口名为
tun0,开启auto_route和auto_redirect。 - UFW 默认拒绝未经允许的入站流量。
sing-box 的关键配置:
{
"type": "tun",
"interface_name": "tun0",
"auto_route": true,
"auto_redirect": true
}
故障期间日志类似:
[UFW BLOCK] IN=eth0 OUT= SRC=192.0.2.20 DST=192.0.2.1 PROTO=TCP DPT=24461 SYN
DPT=24461 只是一次运行时观察到的动态端口,不应该把它永久写死在 UFW 里。OUT= 为空,提示包正在进入本机的 INPUT 路径,而不只是穿过 FORWARD 路径。
追踪 NAT 重定向
检查 sing-box 监听:
sudo ss -lntup | grep sing-box
检查 nftables:
sudo nft -a list ruleset | grep -n -C 8 -E 'redirect|tproxy'
故障场景中能看到类似规则:
meta l4proto tcp redirect to :24461
# 内部端口不允许直接连接
tcp dport 24461 ct status ! dnat reject with tcp reset
也就是说,sing-box 先将目标 TCP 连接重定向到本机监听端口,再由 UFW 的 INPUT 规则决定是否允许。将这一类流量当成普通 FORWARD 包去放行,通常无法消除观察到的 INPUT 拦截。
修复思路:匹配 DNAT 连接,而不是动态端口
对于明确可信的单个下游终端,可以临时尝试:
sudo iptables -I ufw-before-input 1 \
-i eth0 \
-s 192.0.2.20/32 \
-d 192.0.2.1 \
-p tcp \
-m conntrack --ctstate DNAT \
-j ACCEPT
注意把示例 IP 和接口替换为实际值。DNAT 属于 --ctstate 的有效虚拟状态;不是 --ctstatus,后者会报错 Bad ctstatus "DNAT"。
这条规则仍有安全边界:它匹配符合条件的 DNAT TCP 连接,而不仅是 sing-box 创建的连接。因此应该限制来源和入口接口,不要为了省事全局放行 INPUT。
验证
在下游设备运行:
curl -4 -v --connect-timeout 5 https://www.cloudflare.com/
在旁路由观察规则计数和拦截日志:
sudo iptables -L ufw-before-input -n -v --line-numbers
sudo journalctl -k --since '10 minutes ago' --grep='UFW BLOCK' --no-pager
如计数上升、联网恢复,并且 sing-box 重启、内部端口发生变化后仍正常,才可认为此方法适用于当前部署。
持久化
确认验证成功后,先备份:
sudo cp -a /etc/ufw/before.rules /etc/ufw/before.rules.bak
sudo nano /etc/ufw/before.rules
在 *filter 区域中,所有链定义之后、现有 ufw-before-input 处理规则之前添加:
-A ufw-before-input -i eth0 -s 192.0.2.20/32 -d 192.0.2.1 -p tcp -m conntrack --ctstate DNAT -j ACCEPT
检查并重载:
sudo iptables-restore --test < /etc/ufw/before.rules
sudo ufw reload
回滚时用备份恢复文件并 sudo ufw reload。临时测试规则也可以通过 iptables -D 携带与插入时完全一致的匹配参数删除。
注意事项
- 不要直接使用
ufw default allow routed或关闭整个 UFW 作为长期方案。 - 此方案主要针对 IPv4 TCP 重定向后的 INPUT 拦截,不是对所有 UDP、IPv6 或 WireGuard 故障的通用修复。
- 其他明确配置的 API、DNS、SOCKS 等监听端口,应继续按实际用途限制访问来源。
- UFW 与 sing-box 都可能修改 nftables;如果规则匹配计数增加但连接仍失败,还应检查其他 base chain 的 hook 优先级及后续丢弃规则。