VPN 的 DNS 能用,.local 名称却仍然失败:到底谁在解析?
.local 名称可能完全绕过 VPN 的解析器。比较三条解析路径,然后声明域,而不是重排 nsswitch。
同一 VPN 上的两台机器,同样的主机名,却只有一台能解析:差别通常不在隧道,而在于究竟是哪个解析器作出了回答。在 Linux 桌面上,这个名字可能经过名称服务开关、systemd-resolved 的 stub,或者应用自带的解析器,而它们对同一后缀各自套用自己的规则。规则的分歧点就在这个后缀上,因为 .local 并不是中性的标签。在改变任何东西的运行顺序之前,先弄清楚出问题的程序实际走的是哪条路径。
两个解析器,两种答案
传统的 glibc 查找会沿 nsswitch.conf 中的 hosts: 行逐一询问各个模块,直到有一个给出答案。通过 stub 监听器与 systemd-resolved 通信的客户端则改为询问单一进程,而该进程会应用按链路划分的策略以及它自己的特殊情况。自带解析器、或链接了这类库的应用,可以把两者都绕过。因此一个主机名在一台机器上可能有三类所有者,而只有其中一类知道 VPN 到底想做什么。
在动手改动之前先确认所有者,因为三者的修法各不相同。同一桌面上的浏览器和命令行工具可以合理地得出不同结果,而这种不一致恰恰是线索,不是缺陷。如果浏览器能解析而工具不能,你调试的是解析器路径,而不是 VPN 路由。单独确认路由,免得把路由故障误判为名称服务故障。两者一致时,故障在主机上游,此处的解析器配置不值得再改一次。
究竟是哪条命令实际询问了解析器
两条只读命令回答的是相关问题,把它们对比起来,比读配置更快定位问题。使用真实的内部名称,并让输出保持私密,因为内部记录终究是内部的。两条命令都要在出问题的程序所处的同一会话中运行:
getent ahosts files.corp.local
resolvectl query files.corp.local
resolvectl status第一条通过已配置的模块发问,这是一般程序的真实体验。第二条直接询问 systemd-resolved,并报告应答的链路、协议和服务器。按地址去问公司服务器,只能证明服务器持有该记录,因为它并不能说明应用是否真的问过。读一读承载 VPN 的那条链路以及它声明的域,再把这个列表和出错名称的后缀对照。
为什么 .local 会跳过你的单播区域
systemd-resolved 的参考文档 指出以 .local 结尾的多标签名称,在启用 mDNS 时通常会走多播 DNS,而不是普通的单播 DNS。RFC 6762 把这段命名空间留给链路本地多播,所以公司区域里即使有一条正确记录,也可能永远不会为这个后缀被查询。隧道完全可以把解析器路由到位,却仍然在这场竞争中落败。从缓存里 ping 通,并不能说明刚刚发生的那次查询。
有一个有据可查的例外,它能解决大多数这类情况:当某条链路把该后缀声明为搜索域或路由域时,守护进程会把它留在单播路径上,跳过多播的特殊处理。这是按链路生效的策略,而不是全局偏好。同一台 VPN 服务器下的两台机器,可能因为一个网络配置文件声明了该域、另一个没有而表现不同,所以要读当前生效的配置,而不是你记得改过的那份。
窄例外胜过全局重排
对于无法改名的既有区域,让解析器和 VPN 的负责人在承载它的连接上声明该域。为这一个后缀加一条路由域记录,再加上预期的服务器地址,就是一次有明确负责人的小改动,而且它随链路存在,不落在手工编辑的文件里。
它在断开后仍然有效,因为链路恢复时链路策略会重新应用。编辑共享的 nsswitch.conf 是诱人但更昂贵的替代方案,因为它会改变机器上每个名称的查找行为,连本地发现也不例外。关掉多播守护进程同样不等价:它去掉了本地行为,却没有任何解析器因此学会公司区域。如果这项服务是新建而非继承,就把它放到你组织控制的子域下,彻底避开这场竞争。名称被固化在固件里或印在标签上时,选窄例外;客户端仍在你手里时,选新子域。
改动之后要证明什么
用应用自身的查找来证明修复,而不是用你为测试装上的工具,并清掉任何可能代它作答的缓存。然后确认解析器路径和提供答案的链路。最后检查本地发现是否与改动前一致,因为最先被忽略、最后被察觉的往往就是那台不再出现的打印机。下面三条命令按这个顺序检查名称、路径和 TLS 身份:
getent ahosts files.corp.local
resolvectl query files.corp.local
curl -sv --max-time 5 https://files.corp.local/ 2>&1 | head -n 20地址对了但证书错了,严格的客户端依然会失败,所以解析通了之后还要检查应用期望的名称。确认服务接受来自 VPN 地址的连接,而不只是办公网段。把域的范围、服务器和负责人写进该连接的文档。否则下一个遇到这个故障的人,会去抓你刚刚避开的同一次全局修改。