隧道起来了,内网也能打开,可打印机的名字却解析不了。或者反过来:本地名称还能用,而公司网络里的一切都超时。两种症状出自同一个地方,即 VPN 客户端在连接时重写过的解析器列表。

先有意识地修好列表,再单独处理 push 机制。路由是第三个话题,不是这里要修的东西。

应用实际使用的是哪一份列表

Windows 是按接口级设置解析的,而不是按某个对话框显示的内容,所以要从每个接口的有效列表开始。别名比显示名称更重要,因为下面每条命令都针对某个接口。别名弄错,修复就会落到错误的网卡上。它看起来能用,直到下次重连时隧道自己的条目又回来了。

问题在于哪些服务器排到了前面,以及它们是以静态条目的形式出现,还是来自 DHCP 租约。这两点决定了你能用哪种修复。

netsh interface ipv4 show dnsservers
Get-DnsClientServerAddress -AddressFamily IPv4

读取隧道网卡和物理网卡的输出,并记下各自的所有地址。静态条目可以通过策略或脚本删除;由 DHCP 提供的条目绑定在租约上,会重新回来,这会改变你该选择的修复。远端网络的名字由通告的解析器负责,本地局域网的名字由物理网卡负责,查询则发往先被查阅的那份列表。

删掉被推送的服务器,或者把它们排到后面

如果隧道内部没有任何东西需要它们,就删掉被推送的服务器,因为物理网卡自己的解析器会重新接手。只有当远端网络拥有只有它的服务器才能应答的区域时才保留,并且在这种情况下把本地解析器放在它们前面。下面两条命令覆盖了两种选择,所以要挑符合情况的那条,而不是两条都跑。

netsh interface ipv4 delete dnsservers name="Corp VPN" address=all validate=no
netsh interface ipv4 add dnsservers name="Corp VPN" address=172.16.20.1 index=1 validate=no

索引 1 先被查阅,因此被推送的地址仍然可用,但不再是每个查询的默认答案。validate=no 标志会跳过一项可达性探测,这项探测在隧道尚未稳定时常失败,所以要用 show 命令确认结果,而不是相信退出码。

在依赖它之前,有两个限制值得了解。Windows 不会删除通过 netsh 经 DHCP 得到的服务器,这些值会以 DhcpNameServer 的形式留在接口的注册表项下,所以改注册表是最后手段,且下次租约后必须重新检查。网卡的绑定顺序也不是可靠的排序机制,因为 VPN 客户端可以把自己的条目插到列表最前面。

可以在哪一步过滤 push

更好的修复是在它生效之前就把选项去掉。Community OpenVPN 客户端可以按名称过滤被推送的指令,这样服务器的配置就不必改动。

pull-filter ignore "dhcp-option DNS "

末尾的空格属于匹配内容,过滤器针对的是选项名而不是服务器地址。如果配置文件里还有 block-outside-dns 指令,去掉它改变的是防泄漏而不是名称解析,所以要把这件事分开决定,而不是把两处修改捆在一起。

对某一个顽固的主机名来说,在 Windows 的 hosts 文件里加一行比给整台机器重排解析器更稳。它对下一个人也是不可见的,所以要写在记录这台机器配置的地方。

让修复在重连之后依然有效

名称解析必须验证两次,一次针对指定的服务器,一次用应用实际采用的形式。这一组能把解析器顺序问题和完全不应答的服务器区分开。跳过第一项检查,两个原因就会缠在一起。

Resolve-DnsName intranet.corp.example -Server 172.16.20.1
Resolve-DnsName printer.lan

重新连接隧道并重复这两条命令。手动改过的东西只能撑到下一次连接,因为客户端在拉起网卡时会重建解析器状态。把 netsh 那几行放进客户端支持的连接脚本里,让脚本成功退出,并在它执行前留一小段等待。在脚本之后应用 DNS 的客户端无论如何都会覆盖结果。

如果修复之后公网名称能解析而内部名称仍然失败,解析器列表就不再是嫌疑对象了。查询很可能根本没到服务器,这说明问题在路由或防火墙规则,而不是另一项 DNS 设置。把接口别名和你最终确定的地址记下来,因为这两者在不同机器上都不一样,而且都不会自己扛过重建。

相关文章