sing-box 1.14.0-alpha.39 的核心变化是:TUN、WireGuard、Tailscale 这类 L3 inbound 的 TCP/UDP 流量,可以在 pre-match 阶段直接转到 WireGuard / Tailscale endpoint。你现在要排查的第一件事:连接有没有在 L3 被转走,而不是先改 DNS、MTU 或整份订阅。
先把边界说清楚:本文按 github.com release 和文档推导配置检查口径,未在 root Android / jailbroken iOS 复测。1.14.0-alpha.39 和 1.14.0-alpha.40 都是预发布线;生产环境先保留 1.13 稳定配置,另存一份最小 JSON 做验证。不要在唯一可用配置上直接动刀。
你现在到底是在排哪一种问题?
同样是“开 TUN 后 WireGuard 不通”,原因可能完全不同。先把现象压成一类,别一边改 endpoint key,一边改 DNS,一边换 route final。
| 错误表现 | 更可能原因 | 先检查什么 |
|---|---|---|
sing-box check 直接报 unknown field | core 版本不是 1.14 alpha,或配置写了当前版本不认识的字段 | sing-box version 和报错字段所在段落 |
ping 某个 WireGuard allowed IP 有回应,网页域名不通 | ICMP 已能走 L3,但 TCP/UDP 没在 pre-match 命中 | route rule 的 network、preferred_by、目标 tag |
| IP 直连通,域名访问失败 | DNS / FakeIP / resolve 顺序问题 | debug 日志里是否出现 resolve 或 DNS 查询 |
| TUN 开启后所有连接卡住 | 路由回环或 WireGuard 握手流量也进了 TUN | WG endpoint 地址是否被排除,默认接口是否正确 |
日志显示走了 proxy、selector、socks-out | 你走的是普通 proxy outbound,不是 L3 forwarding | route 命中的 outbound tag 类型 |
1.14.0-alpha.40 配置里用了 bridge,但 WireGuard 仍不通 | bridge 只解决直接从 L3 出接口,不等于 WG endpoint 配好 | 先回到 WireGuard endpoint 的 key、address、allowed_ips |
不看日志的排查都是玄学。这里至少要拿到三样东西:sing-box version、sing-box check -c 输出、一次固定目标的 debug 日志。
1.14 alpha 和 1.13 稳定线差在哪里?
官方 release notes 的时间线很短,但别读错:
| 版本 | 官方变化 | 排查含义 |
|---|---|---|
1.13.0 | route rule 的 network 增加 icmp,L3 inbound 的 ICMP 可被路由到 Direct、WireGuard、Tailscale | ping 通了,不代表 TCP/UDP 也在 L3 forwarding |
1.14.0-alpha.39 | 在 1.13.0 ICMP proxy support 基础上,TUN / WireGuard / Tailscale 的 TCP、UDP 可直接 forward 到 WireGuard / Tailscale endpoint | 本文的核心功能点从这里开始 |
1.14.0-alpha.40 | 新增 bridge outbound,作为 direct 的 L3 对应物 | 用于把 L3 流量直接发出接口,不是 WireGuard endpoint 的替代品 |
所以第一条命令必须先跑:
sing-box version
看到 1.13.x 时,别继续排 TCP/UDP 的 L3 forwarding。你最多验证 ICMP 相关行为,生产配置继续留在 1.13 稳定线更稳。看到 1.14.0-alpha.39 或更新,才进入下面的 pre-match 和 route 排查。
怎么判断自己真的走了 L3 forwarding?
L3 forwarding 的证据不是“能打开网页”。网页能打开也可能只是 TUN 把连接转成 L4 proxy 后走了普通 outbound。
更可靠的判断是三条:
- 入口来自 L3 inbound:
inbounds[].type是tun,或来源是 WireGuard / Tailscale inbound。 - route 在 pre-match 阶段就能决定去向:规则只依赖当时可用的信息,例如
network、ip_cidr、preferred_by、FakeIP resolve 后得到的目的地址。 - 目标是支持 L3 forwarding 的 endpoint 或 outbound:
WireGuard / Tailscale endpoint,或者 alpha.40 之后的bridgeoutbound。
下面这份 JSON 是排查用骨架。把 endpoint 地址、key、allowed IP 换成你自己的值;不要把示例私钥拿去运行。
{
"log": {
"level": "debug",
"timestamp": true
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "sb-tun0",
"address": [
"172.19.0.1/30"
],
"mtu": 1408,
"auto_route": true,
"strict_route": true,
"stack": "system"
}
],
"endpoints": [
{
"type": "wireguard",
"tag": "wg-ep",
"system": false,
"mtu": 1408,
"address": [
"10.66.66.2/32"
],
"private_key": "REPLACE_WITH_BASE64_PRIVATE_KEY",
"peers": [
{
"address": "198.51.100.10",
"port": 51820,
"public_key": "REPLACE_WITH_BASE64_PUBLIC_KEY",
"allowed_ips": [
"10.66.66.0/24",
"192.0.2.0/24"
],
"persistent_keepalive_interval": 25
}
]
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"auto_detect_interface": true,
"rules": [
{
"inbound": [
"tun-in"
],
"network": [
"tcp",
"udp",
"icmp"
],
"preferred_by": [
"wg-ep"
],
"action": "route",
"outbound": "wg-ep"
}
],
"final": "direct"
}
}
这段里最值得看的是 preferred_by: ["wg-ep"]。官方 route rule 文档写到,preferred_by 对 WireGuard 会匹配 peer 的 allowed IP。也就是说,你不是用域名规则硬塞进 WG,而是让 WireGuard endpoint 自己的路由偏好参与匹配。
如果你的配置里 route 命中的是 selector、socks、http、shadowsocks 这类普通 outbound,那就不是这次 release notes 说的 L3 forwarding。它可能能用,但排查方向不同。
为什么 ping 通了,TCP/UDP 还是不通?
ping 只能说明 ICMP 这条线有信号。官方 route rule 文档在 1.13.0 处写得很明确:ICMP echo 可以通过新的 icmp network 匹配,并从 TUN / WireGuard / Tailscale inbound 路由到 Direct、WireGuard、Tailscale outbound。
1.14.0-alpha.39 才把 TCP/UDP 也放进 L3 forwarding 的讨论里。排查时别把 ping 10.66.66.1 当成全协议通过。
验证命令分三类跑,目标要固定:
sing-box check -c ./tun-wg-l3.json
ping -c 4 10.66.66.1
curl -4 --connect-timeout 5 http://192.0.2.10:8080/
ping 通但 curl 不通时,先看 network 规则有没有包含 tcp / udp,再看 debug 日志里 TCP 连接有没有在 pre-match 阶段命中 wg-ep。如果日志直接落到 final: direct,不是 WireGuard key 的问题,是 route 没匹配。
DNS 和 FakeIP 会怎样搅乱判断?
Pre-match 的限制是:连接还没建立。TCP 没有连接数据,UDP 只有第一个包。如果规则需要更多数据,pre-match 会停在那条规则。
这就是 DNS / FakeIP 容易误导人的地方。官方 Pre-match 文档还专门提醒:FakeIP 目的地址需要在 pre-match 做 resolve,否则连接会被拒绝。
排查时可以先避开域名,拿 WireGuard peer 的 allowed IP 里一个明确地址测试。等 IP 路径确认后,再加域名和 FakeIP。
如果必须测域名,route 里要让 resolve 出现在会影响 L3 forwarding 的规则之前。配置写法会随你的 DNS 结构变化,下面只展示顺序意图:
{
"route": {
"rules": [
{
"domain_suffix": [
"example.net"
],
"action": "resolve"
},
{
"domain_suffix": [
"example.net"
],
"action": "route",
"outbound": "wg-ep"
}
],
"final": "direct"
}
}
这不是让你把所有域名都强行 resolve。它的用途是排除一种误判:你以为 WireGuard endpoint 不工作,其实连接在 FakeIP 阶段已经被拒了。
怎么分清普通 proxy outbound 和 WireGuard endpoint?
看配置位置。当前 sing-box 里 WireGuard 有两套容易混淆的文档:
| 写法 | 位置 | 当前判断 |
|---|---|---|
outbounds[].type = "wireguard" | configuration/outbound/wireguard/ | 官方页面已标废弃,排查新配置时只拿来理解旧文件 |
endpoints[].type = "wireguard" | configuration/endpoint/wireguard/ | 1.11.0 起的 endpoint 模型,本文按这个口径排查 |
outbounds[].type = "bridge" | configuration/outbound/bridge/ | alpha.40 新增,直接把 L3 流量从接口发出 |
outbounds[].type = "socks" / http / 其它 proxy | outbounds[] | 这是 L4 proxy 路径,不是 alpha.39 说的 L3 forwarding |
最小判断方法:route 命中的目标 tag 如果只存在于 endpoints[],并且是 wireguard / tailscale,才继续按 L3 forwarding 查。命中的目标如果是普通 outbound,就按传统 proxy 路径查 DNS、selector、节点连通性。
这里不要被字段名骗了。outbound 这个 rule action 字段是历史命名,官方 Pre-match 文档在支持目标里写的是 WireGuard / Tailscale endpoints。排查时以 tag 实际指向的对象为准。
路由回环先查哪里?
TUN 到 WireGuard 最常见的硬卡点是回环:WireGuard 握手包本来要去 peer 的公网地址,却也被 TUN 默认路由抓进 sing-box,最后自己套自己。
先查三项:
route.auto_detect_interface是否开启,或你是否用default_interface/bind_interface指定了真实物理接口。- WireGuard peer 的
address是否被 TUN 路由覆盖。 route_exclude_address或系统路由里,是否有 peer endpoint 的明确出口。
Linux 上可以看:
ip route get 198.51.100.10
ip rule
macOS 上可以看:
route -n get 198.51.100.10
netstat -rn
Windows 上可以看:
route print
198.51.100.10 是示例 peer 地址,换成你的 WireGuard server IP。期望结果是:去 peer 公网地址的握手流量走物理网卡,不先进 sb-tun0。如果这一步错了,后面所有 TCP/UDP L3 forwarding 都会像坏了一样。
日志里要抓哪几行?
把日志临时调到 debug,只复现一个目标。别把整晚日志塞进来,排错的人看不动,你自己也看不动。
{
"log": {
"level": "debug",
"output": "tun-wg-l3.log",
"timestamp": true
}
}
抓 30 秒就够,重点搜这些词:
| 日志线索 | 它说明什么 | 下一步 |
|---|---|---|
wg-ep | route 最终命中了 WireGuard endpoint | 再查 peer allowed_ips 和握手 |
direct | 连接落到了兜底 | 查 preferred_by、ip_cidr 或 network |
resolve | pre-match 做了 DNS 解析 | 看 FakeIP 是否仍被拒 |
sniff 后停住 | TCP pre-match 拿不到足够数据 | 暂时移走依赖 sniff 的规则 |
no such outbound | tag 引用不存在 | 查 route.rules[].outbound 拼写 |
operation not permitted | 权限不足 | 查管理员、root、网络扩展或 VPN 授权 |
如果你看到 selector 或普通 outbound tag,先别继续改 WireGuard。那说明当前连接没有走到 endpoint;把 route 规则改到最小,再复现同一个 IP。
生产环境怎么保留 1.13 配置?
不要把 1.14 alpha 当作“升级越新越好”。正确做法是两份文件并行:
config-1.13-stable.json
config-1.14-alpha-l3-test.json
config-1.13-stable.json 只做日常使用,不动。config-1.14-alpha-l3-test.json 只放一个 TUN inbound、一个 WireGuard endpoint、一个 direct fallback、一个 route 规则。它能通过 sing-box check,再去看日志和路由表。
最后再做一次降级验证:
sing-box run -c ./config-1.13-stable.json
只要 1.14 alpha 的排查还没完成,1.13 稳定配置就是你的退路。alpha.40 的 bridge outbound 值得单独测,但别把它和 WireGuard endpoint 问题混在同一次修改里。
相关阅读
- sing-box 1.14 alpha.40:bridge outbound 与 L3 转发
- sing-box 最新 release 比对:DNS/route 迁移项要看 v1.14 alpha 与 v1.13 稳定版
- sing-box TUN 日志排查:DNS、route 与 fake-ip 怎么对应
这篇到这里就够了。下一步只做一件事:拿你的 sing-box version、最小 JSON、sing-box check 输出和 30 秒 debug 日志,对照上面的三条证据线判断当前路径。先证明它走没走 L3,再谈要不要调 DNS、MTU 或 route。