一位用户反馈,内网主机名通过 VPN 解析不了。同一台笔记本上的第二个反馈说,泄漏测试仍显示查询由本地解析器应答。这两件事听起来像一个故障,其实是两个,证据也不同,而针对第一个的常规修法会让第二个更糟。动手改任何设置之前,先把它们分开。

两个症状并非同一个故障

内网名称解析失败,说明这个询问发到了没有答案的地方。查询离开隧道,说明即使答案就在手边,询问也发错了地方。这是两种相反的故障:一个是缺少答案,另一个是多出来的目的地。

陷阱在于:把办公网解析器加到所有地方,能修好第一个,却必然造成第二个。反过来,把公共解析器加到所有地方,结果正好相反。

把两次观察连同时间戳一起记下来,然后按顺序做完下面四项检查。

哪块网卡的解析器接到询问

在 Windows 上,DNS 客户端按网卡绑定顺序选择服务器,隧道网卡并不会自动排在第一位。打开网卡的高级设置,把远程访问连接移到物理网卡之上,然后重新连接,让改动在新的会话中生效。

绑定顺序只是前半件事。客户端还必须知道哪些名称属于那块网卡,而这是后缀问题,不是顺序问题。

把正常机器在隧道建立时抓取的 ipconfig /all 输出和笔记本的并排放在一起。正常机器的办公网卡会显示一个连接专用 DNS 后缀,而笔记本的隧道网卡可能什么都没显示。这一差异解释了一整类“服务器就在那儿,名字照样失败”的反馈:没有后缀,短名就永远不会补全为办公网解析器所服务的那个区域。

短名先要后缀,才谈得上路由

输入不带限定的主机名,等于让解析器去猜一个域。猜的依据是挂在连接上的后缀列表,如果这个列表是空的,查询就以单标签形式发出,任何私有区域都匹配不上。

把正常机器的后缀复制到 VPN 网卡 IPv4 属性的 DNS 选项卡里,然后重新连接。在 Linux 上,对等物是隧道链路上的搜索域,systemd-resolved 按链路而非全局暴露它。

在笔记里把这两项设置分开记。后缀改变的是问什么,解析器地址改变的是问谁。在一项出错时去修另一项,得到的结果看起来就像随机。

先直接问解析器,再问名字

直接向办公网解析器发查询,能把名称问题和路径问题分开,因为它完全绕过了客户端的解析器选择。

nslookup intranet.corp.example 10.20.0.53
nslookup intranet
resolvectl status

第一条命令向指定服务器查询一个完全限定的名称。如果它有应答,说明解析器和到它的路径都没问题,故障在解析器选择或后缀上。如果超时,说明地址是错的或不可达,问题在路由而不是 DNS。第二条命令展示短名会遇到什么,第三条则打印 systemd 主机上按链路划分的解析器配置。

要留意泛解析应答,有些网络对未知名称就返回这种结果。看起来合理的应答并不能证明是目标服务器答的,所以要把返回的地址和内部服务实际使用的地址做比较。如果地址属于停放页或代理,那解析器确实答了,但答案从来不是你的。分清这一点,能省下追查一条其实一直在正常工作的隧道的一小时。

在 Linux 上,会重写 /etc/resolv.conf 的 VPN 客户端会完全替换本地解析器。vpnc 提供 DNSUpdate no 来阻止这一行为,而 systemd-resolved 可以只把列出的域路由到隧道链路。两种做法都能把公共名称留在本地解析器上,同时把内网名称送到办公网。

泄漏是一条规则,不是一个勾选项

名称解析是发往 53 端口的 UDP 交换,所以一条承载网页流量却不承载 UDP 的隧道,会把查询留在物理路径上。验证办法是:在解析一个公共名称的同时,在物理网卡上抓包。如果该接口上出现了可读形式的查询,说明隧道没有承载它。

sudo tcpdump -ni eth0 -c 20 'udp port 53'
resolvectl query example.com

如果查询以可读形式出现在那个接口上,隧道就没有承载它。修法是一条规则:只允许访问 53 端口到 VPN 推送的解析器,丢弃其他目的地;再加上客户端配置,不要悄悄丢掉推送的那个选项。

最后这一点比看上去更重要。用 route-nopull 启动 OpenVPN,被推送的 DNS 选项会随路由一起消失,除非把拉取过滤器放宽以保留它。而忽略 dhcp-option DNS 的客户端会继续用原来的设置。服务器端的任何改动都需要新会话才生效,因为解析器列表是在隧道建立时下发的,而过期的会话会一直显示旧状态。

关闭工单之前,先记录你实际观察到的是哪种故障。缺少内网答案和查询逃出隧道需要不同的修法,而修好前者的后缀改动可能悄悄加重后者。下一位接手工单的人会相信标签,所以请把标签写准。

相关文章