你连上隧道、打开一个内部面板,某个名字就解析到一个从没见过的地址。或者反过来:浏览器还能用,而命令行工具突然什么都解析不出来。两种结果都来自同一个变化,人们通常用一句“VPN 用了自己的 DNS”来解释,但这句话既不足以定位问题,也不足以验证。那句话里藏着两个问题:这个配置文件应当接管哪些查询,以及你的机器到底有没有把它们发给分配到的解析器。把这两个问题分开,就是整套方法,因为混在一起测试,两个方向都会给出自信的错误答案。

为什么配置文件要提供解析器

在隧道里,远端后面的名字通常解析到只存在于该网络的地址。像 corp.internal 这样的私有区域没有公共委派,因此为它服务的解析器必须能从隧道内部访问。同一机制还服务第二个目的:当查询本来会经运营商发出时,远端的解析器会把查询留在加密路径内。所以 DNS 服务器地址是作为连接策略的一部分下发的,而不是你在机器上一次性选定的全局设置。

地址本身什么也说明不了。解析器只有在有路由可达时才能应答,而最常见的故障就是只有在隧道建立时才可达的解析器。隧道断开而策略仍在时,查询会发往没有路径的地址,症状是超时而不是明确的报错。这个区别在读下一份测试结果时很关键,因为超时会把人们引向根本无关的传输设置。

先比较两种设计,再比较返回结果

全隧道与分离 DNS 会带来相反的预期,两者都不是故障。全隧道下每个查询都可能转到运营商或企业解析器,因此连接后公共域名答得不一样是正常的。分离 DNS 下只有列表中的域走私有解析器,其余保持本地;Windows 上域名列表在 Name Resolution Policy Table 中,macOS 在 DNS 设置的匹配域中,systemd-resolved 主机则在每条链路的路由域中。

这才是首先要做的比较,因为它决定什么算缺陷。分离 DNS 下,从新解析器应答的公共域名值得追查,而正常应答的内部域名说明系统在正常工作。全隧道下,仍由运营商解析器应答的公共域名才是异常。微软关于 VPN 名称解析的文档描述了这条规则在 Windows 上的顺序,包括匹配的策略条目如何先于适配器自身的服务器被采用。

房间里还有第三个容易被忘掉的解析器。浏览器的安全 DNS 会自行解析,并且在隧道改动了操作系统策略之后仍可能继续应答,所以页面能打开只证明浏览器解析器能用,并不证明配置文件已生效。只看浏览器显示的结果,有一半时间在测错的层。

用单一变量记录基线

改隧道。同一步里不要连名字、工具或搜索后缀一起改。选一个你有权查询的名字,记下用了哪个应用,再写下返回的地址或确切的错误。Windows 上 Get-DnsClientServerAddress -AddressFamily IPv4 打印每个适配器的服务器,Get-DnsClientNrptPolicy 打印策略条目;使用 systemd-resolved 的 Linux 上 resolvectl status 显示每条链路的 DNS 服务器与路由域;macOS 上 scutil --dns 打印系统实际会遵循的解析器顺序。

然后通过客户端常规控件连上,重复完全相同的命令。保留第一次输出而不是凭记忆,因为对比才是重点,清缓存之后的第二次读数已经是另一种测量。如果基线是浏览器在前台时取的,而连接后的运行发生在终端里,你比较的是两个解析器,而不是同一个解析器的两种状态。

显式查询与应用查询是两种测试

用 nslookup name 10.20.0.1 或 dig @10.20.0.1 name 向指定服务器提问,只证明一件事:你点名的那台服务器在可达时会应答。它完全绕过选择逻辑,因此无法告诉你系统是否会为这个名字选中它。用它测分配到的解析器是否可达,不要用它测策略。

经本地解析器的查询才真正走到选择。resolvectl query name 走同一套路由域规则并报告是哪种协议应答,Windows 的 Resolve-DnsName 会经过策略表与客户端缓存,scutil --dns 则显示一次查询会遵循的顺序。两种都跑,并分列记录。显式查询成功而应用查询失败,是路由或选择的问题,不是解析器拒绝工作。

缓存挡在你和答案之间。操作系统、本地存根解析器、浏览器和负缓存都持有结果,所以不发出任何一个包,查询也可能成功。清任何东西之前先记下结果:ipconfig /flushdns、resolvectl flush-caches,macOS 上是 sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder。这一步先别做大规模网络重置,它会毁掉你还在收集的证据。

这个差别意味着什么

对比记录下来的两行,在动任何设置之前先给变化归类。

Observation after connectMost likely causeNext step
Answer moves to a private address rangeExpected under split DNS or a private zoneConfirm the suffix is in the effective policy, then test the service
Lookup times out while connected, works after disconnectThe assigned resolver has no route from this machineProbe it with an explicit query, then re-read the policy
Internal name fails, public names workWrong namespace or a suffix missing from the policyQuery the fully qualified name and check the domain list per platform
Internal name returns a public addressSplit DNS not applied; a public resolver answeredCheck browser secure DNS first, then the per-link domain list

有一行值得强调。名字能解析不等于服务能用,DNS 成功只说明找到了地址。它对转发、防火墙规则,以及账号是否有权使用该服务都一无所知,所以最后要用真实应用去测,而不是假设故障自己走了。

恢复基线并验证

用客户端自己的控件断开,而不是杀掉进程,然后重读同样三条命令。每条链路的服务器、策略条目和测试名的应答都应回到先前写下的基线。干净断开后仍残留策略条目是真实缺陷,值得记录;这也是手改自动生成的解析器文件属坏习惯的原因:文件会被重写而改动消失,或者改动存活下来并把一个已经没有路由的解析器钉住。

按顺序走一遍这份清单。先判断配置文件实现了哪种设计,再评判任何结果。两次运行都固定名字、工具与后缀。把显式查询与应用查询分开。读生效的策略,而不只是应答。写完对比之后再清缓存。用真实应用验证,然后重启一次,确认断开状态依旧干净。

相关文章