在一台用作旁路由的 Armbian 上同时运行 sing-box 和 WireGuard。旁路由本机可以解析内网域名,下游终端将其设为 DNS 服务器却始终超时。最终发现问题不在 DNS 匹配规则,而在 sing-box 向上游 DNS 发出的流量选错了出口接口。

本文示例地址均为重写后的示意值,不是原始网络配置;保留了私有网络的拓扑关系与协议行为。

网络拓扑与现象

角色示例地址作用
下游终端192.168.10.20DNS 客户端
旁路由 LAN192.168.10.254 / eth0sing-box DNS 监听地址
旁路由 WireGuard10.77.0.11 / wg0隧道客户端
内网 DNS10.77.0.1:53WireGuard 对端 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 的返回是否一致。

排障要点

  1. 按 客户端 → 旁路由入站 → 上游出口 → 上游响应 → 客户端响应 分段抓包。
  2. 验证的是报文的实际出口接口和源 IP,不能只看 DNS 配置中的 server 字段。
  3. 只收到客户端请求、不见匹配的响应时,优先检查上游出口;不必立即修改已经验证正确的路由规则。
  4. 若 TCPdump 提示 bad udp cksum,本机发包时可能是网卡 checksum offload 的结果;-K 可关闭抓包时的校验和检查。
  5. home.arpa 是家庭网络使用的特殊用途域名;不要把实际公网域名、设备名称、内网地址和隧道拓扑原样发布到公开博客。

结论: 最终故障点是 sing-box 对内网 DNS 的上游 UDP 查询从 LAN 接口发出,未走 WireGuard。给相应的 DNS 上游服务器设置 bind_interface: "wg0" 后修复。