你在酒店房间里打开笔记本,启动客户端,输入内部文件服务器的名称,却什么也没得到。隧道显示已连接,而 ping 同一子网内的地址仍然有回应,说明传输本身没问题。失败的只是名称,而这个缺口把问题收窄到两处:客户端问的是哪个解析器,以及它拿到的应答能否沿隧道返回。修好一处而跳过另一处,故障只会换个地方出现。

在改动任何配置文件之前,先确认客户端如何处理这个名称。在 Linux 上,resolvectl query files.corp.example 会显示是哪个链路、哪个解析器给出了应答。在 Windows 上,Resolve-DnsName files.corp.example 会显示做出应答的服务器以及它返回的地址。

先读懂应答,再动手修改

如果名称在几毫秒内就返回 NXDOMAIN,说明查询根本没有到达你的区域,而是某个公共解析器或酒店解析器代答的。如果过了很长时间才返回,说明路上有设备丢掉了 UDP 53 端口,客户端最终退回了备用方案。如果返回的地址正确,但连接仍然卡住,说明解析没问题,你的问题在路由或服务本身。

这种三分法能省下一小时的猜测。它还会告诉你到底要不要动 VPN:一个能解析到正确私有地址的名称,已经证明了解析器那条路,剩下的工作都在数据路径上。

从隧道内部下发解析器

客户端分成两类。一类可以在建立连接时由服务器指定解析器;另一类把设置留在本地文件里,任何网关都无法远程更改。

OpenVPN 属于第一类。在服务器端,push "dhcp-option DNS 10.8.0.53" 和 push "dhcp-option DOMAIN corp.example" 会沿控制通道下发,但只有客户端配置里仍然启用 pull 时才有效。一个手动改过、带着 pull-filter ignore "dhcp-option" 的客户端永远看不到这两行,而正是这一行解释了多得惊人的「服务器推送了,但我的笔记本不同意」的案例。

WireGuard 属于第二类,因为这套协议根本没有选项协商。解析器和搜索域写进客户端自己的 [Interface] 块里,形如 DNS = 10.8.0.53, corp.example。wg-quick 会通过 resolvconf 或 systemd-resolved 应用它,而在 Windows 上官方客户端安装的是只存在于隧道期间的 NRPT 规则:Get-DnsClientNrptPolicy 会列出这些规则,因此这是快速判断客户端有没有真正应用你的文件的办法。

IPsec/IKEv2 介于两者之间。strongSwan 的 attr 插件可以返回从池中取出的 DNS 服务器,Windows 客户端通常也会接受,但把自家名字服务器钉死的配置文件会胜过网关提供的一切。在 Linux 客户端上,等价的手动步骤是先 resolvectl dns wg0 10.8.0.53,再 resolvectl domain wg0 '~corp.example';两者都会随接口一起消失,这正是隧道范围内设置应有的行为。

限定后缀范围,而不是把所有查询都吞进来

把客户端的整份解析器列表指向内部服务器很容易,而且通常是错的。那样所有公共名称都会经你数据中心的出口解析,CDN 返回的是远处的地址,一次解析器故障就会把用户的浏览一起拖下水。

只把私有后缀送进去。在 systemd-resolved 上,以 ~ 开头的域只用于路由,因此 ~corp.example 的意思是:该后缀下的查询走这条链路的服务器,而其他一切继续使用物理网络。Windows 用限定在命名空间上的 NRPT 规则做同样的事,macOS 则用 /etc/resolver/ 目录下的补充解析器文件。

多播名称需要单独的答案。.local 名称按设计是链路本地的(RFC 6762),而点到点的 tun 接口并不承载那个多播组,所以再加一个公共解析器也不会把它们发布出去,问内部单播解析器只会得到 NXDOMAIN。像 avahi 工作在反射模式下的反射器可以桥接两个网段,但那是服务端的决定,任何客户端都无法要求。如果打印机或 NAS 必须能按名称访问,那就在你的区域里给它加一条 A 记录。

证明应答能够返回

一个指向不可达地址的正确应答,在检查路由之前,看起来和解析器故障一模一样。问内核这条应答会走哪里:ip route get 10.20.5.20 会给出接口,更有用的是它将要使用的源地址。

要盯住解析器的地址本身。一个 DNS = 10.8.0.53 旁边配着 AllowedIPs = 10.20.0.0/16 的客户端,会把查询从物理网卡发出去,然后在那里悄无声息地掉掉,因为解析器并不在隧道声明的任何前缀里。这种不匹配是这一整块最常见的一类单因故障,而且除非你把 DNS 设置和允许的前缀逐行比对,否则它完全不可见。

重叠的网段会导致相反方向的故障。应答是对的,路由也存在,但它指向了错误的主机,因为家里的 192.168.0.0/24 比隧道到同一网段的路由更具体。把一侧重新编号,或者推送一条更窄的路由,然后确认服务主机的防火墙和回程路径;strongSwan 关于 转发 的说明涵盖了这条路径的 sysctl 一侧。

证书是另一层身份校验,人们却常常怪到 DNS 头上。如果浏览器报的是名称不匹配而不是解析错误,说明查询早已成功,需要修的是证书里的 SAN。请用名称去测试 HTTPS,永远不要用裸 IP。

从客户端复测,而不是从网关

要在用户抱怨的那个应用里测试,因为命令行查询并不能证明浏览器走的是同一条路。Chrome 的安全 DNS 和 Firefox 的 network.trr.mode 可以完全绕过系统解析器,一旦如此,私有名称要么直接失败,要么泄漏到公共解析器。把 resolvectl query 的结果和手动执行的 dig @10.8.0.53 files.corp.example 对比,就能知道是哪种情况。

然后把连接断开再重连,才算修好。手动加在接口上的设置会随接口一起消失,而一个只因为残留的本地改动才看起来正确的配置文件,下次开机就会失效。

给下一台机器的简短清单:名称经隧道解析器解析成功、后缀是被限定的而不是全局的、解析器地址落在允许的前缀里、应答里的主机在服务端口上应答、证书覆盖了用户输入的名称。

相关文章