在一台用作旁路由的 Armbian 上同时运行 sing-box 和 WireGuard。旁路由本机可以解析内网域名,下游终端将其设为 DNS 服务器却始终超时。最终发现问题不在 DNS 匹配规则,而在 sing-box 向上游 DNS 发出的流量选错了出口接口。
本文示例地址均为重写后的示意值,不是原始网络配置;保留了私有网络的拓扑关系与协议行为。
网络拓扑与现象
| 角色 | 示例地址 | 作用 |
|---|---|---|
| 下游终端 | 192.168.10.20 | DNS 客户端 |
| 旁路由 LAN | 192.168.10.254 / eth0 | sing-box DNS 监听地址 |
| 旁路由 WireGuard | 10.77.0.11 / wg0 | 隧道客户端 |
| 内网 DNS | 10.77.0.1:53 | WireGuard 对端 DNS |
拓扑如下:
终端 192.168.10.20
│ DNS 查询
▼
旁路由 192.168.10.254:53 (sing-box DNS 入站)
│ 期望:由 wg0 向 10.77.0.1:53 查询
▼
WireGuard 对端 DNS 10.77.0.1:53
内网测试域名采用 service.home.arpa(示例)。现象是:
- 旁路由本机解析该域名正常;
- 下游明确指定旁路由的 LAN IP 为 DNS 时,连续超时;
- sing-box 监听 UDP 53,相关入站路由规则已确认正常。
第一步:确认入站请求到达
在旁路由抓下游终端的 DNS 流量:
sudo tcpdump -i eth0 -nn -K -l \
'host 192.168.10.20 and udp port 53'
观察到同一个 DNS Transaction ID 的请求每隔几秒重试,但没有对应的成功响应。这说明客户端确实把查询交给了旁路由,但处理链路没有完成。
检查监听端口:
sudo ss -lnup | grep ':53 '
可以确认 sing-box 监听旁路由 LAN IP 的 UDP 53。
第二步:分别观察 LAN 和 WireGuard 出口
不要一开始就打印所有 DNS 流量。可以开两个终端,分别观察:
# LAN:只看该下游终端
sudo tcpdump -i eth0 -nn -K -l 'host 192.168.10.20 and udp port 53'
# WireGuard:只看目标 DNS
sudo tcpdump -i wg0 -nn -K -l 'host 10.77.0.1 and udp port 53'
然后从下游发起一次明确的查询:
nslookup -type=A service.home.arpa 192.168.10.254
本案例中发现:下游的请求确实到达了 LAN,但 sing-box 对 DNS 上游的新查询却从 eth0 发出,源地址是 LAN IP,而不是从 wg0 使用 WireGuard IP 发出。
关键区别: DNS 规则“选择某个上游服务器”与操作系统/应用“通过哪个接口连接那个服务器”是两件事。即使规则命中正确,只要实际出口错误,请求仍可能超时。
第三步:为 sing-box DNS 上游绑定接口
故障时的上游配置类似:
{
"type": "udp",
"tag": "internal-dns",
"server": "10.77.0.1"
}
修复后:
{
"type": "udp",
"tag": "internal-dns",
"server": "10.77.0.1",
"bind_interface": "wg0"
}
bind_interface 作用于该 DNS 服务器的网络拨号,使它使用指定接口。在有 TUN、策略路由和 WireGuard 的环境中,比单纯依赖系统自动选路更明确。
检查配置、重启服务(修改为自己实际的配置路径):
sudo sing-box check -c /etc/sing-box/config.json
sudo systemctl restart sing-box
之后再次查询并抓 wg0:
sudo tcpdump -i wg0 -nn -K -l 'host 10.77.0.1 and udp port 53'
应看到 wg0 上的请求及对应响应。本案例实际加上 bind_interface 后,下游 DNS 查询恢复正常。
旁支现象:A 记录成功后又出现 NXDOMAIN
排查时还遇到另一类现象:某个内网名称通过 CNAME 最终指向单标签主机名,A 查询正常返回地址,但随后对终点主机名发起的 AAAA 查询返回 NXDOMAIN。这属于另一个尚需单独定位的解析异常,不能把它当成此次下游查询超时的原因。
如果看到类似现象,应分别执行:
dig @<DNS服务器地址> service.home.arpa A
dig @<DNS服务器地址> service.home.arpa AAAA
并检查 CNAME 是否指向意料之外的单标签名称,以及本地解析器与上游 DNS 的返回是否一致。
排障要点
- 按 客户端 → 旁路由入站 → 上游出口 → 上游响应 → 客户端响应 分段抓包。
- 验证的是报文的实际出口接口和源 IP,不能只看 DNS 配置中的
server字段。 - 只收到客户端请求、不见匹配的响应时,优先检查上游出口;不必立即修改已经验证正确的路由规则。
- 若 TCPdump 提示
bad udp cksum,本机发包时可能是网卡 checksum offload 的结果;-K可关闭抓包时的校验和检查。 home.arpa是家庭网络使用的特殊用途域名;不要把实际公网域名、设备名称、内网地址和隧道拓扑原样发布到公开博客。
结论: 最终故障点是 sing-box 对内网 DNS 的上游 UDP 查询从 LAN 接口发出,未走 WireGuard。给相应的 DNS 上游服务器设置 bind_interface: "wg0" 后修复。