Windows VPN 解析到错误的 DNS 服务器:度量、绑定顺序还是后缀
Windows 里有三种机制在挑选 DNS 解析器,它们的失效方式各不相同。按命名空间范围、全局顺序,或修法能否挺过重连来判断。
Windows 客户端可能隧道工作正常、携带了公司内网的解析器,却仍然把内部名称发往家用路由器。决定哪台服务器应答的有三种不同机制,它们的失效方式各不相同。不必三个都修:症状会告诉你问题出在哪一个。下面的决策树只需几分钟,能避免常见的结局:改了度量、重排了注册表、又加了一条 NRPT 规则,三样同时落地,没人知道是哪一项起了作用。
三种机制在决定,通常只有一种出了问题
接口度量决定某一地址族下各适配器的排序。Tcpip\Linkage 下的绑定顺序是一份全机范围的接口标识列表,旧代码路径仍会读取它。名称解析策略表(NRPT)把某个命名空间绑定到指定服务器,后缀列表则决定短名到底会不会被展开。三者互不相干,所以 VPN 适配器上正确的解析器,会输给别处一个过时的偏好。
| What you see | Mechanism to check | First command |
|---|---|---|
| Every name is slow, public names sometimes wrong | Global adapter order: metric, then Linkage | Get-NetIPInterface |
| Internal names resolve to a public address | The query left through the home resolver, not the tunnel | Resolve-DnsName intranet.corp.example -Type A, then the same query with -Server 10.20.0.10 |
| Only corp.example names fail, public names fine | Namespace binding: NRPT or suffix | Get-DnsClientNrptRule |
| Short name fails, fully qualified name works | Suffix list on the adapter, with the corporate suffix ahead of other entries, or pushed by the server | Get-DnsClientGlobalSetting |
| Works, then breaks after a reconnect | Runtime setting that was never persisted | Get-VpnConnection for the stored profile, then Get-NetIPInterface again after a reconnect |
这三种机制都不是隧道另一侧的事。如果 VPN 下发的服务器本来就解析不了这个名字,客户端这边的任何设置都只是装饰,所以第一个判断是:直接向它提问时,解析器本身能否应答。
判断一:下发的解析器到底能不能应答?
显式向该服务器提问,再与普通查询对比。两个答案之间的差距,把选择问题与可达性问题分开,这也是这里最快的分岔:
Resolve-DnsName intranet.corp.example -Server 10.20.0.10 -Type A
Resolve-DnsName intranet.corp.example -Type A
如果前者成功、后者失败,说明解析器可达,是 Windows 选错了,请往下看命名空间与顺序两个判断。如果前者也失败,客户端上做什么都没用:检查 UDP 与 TCP 53 能否经隧道到达该服务器、服务器上的主机防火墙是否丢弃了地址池、以及服务器自身的转发器是否健康。
在这个分岔上停下。对一个根本不可达的解析器套用 NRPT 规则,只会用更多需要回滚的配置制造同样的故障,还会把真正的问题藏进一条看起来很权威的规则后面。
判断二:一个命名空间,还是所有查询?
范围决定用什么工具。只有公司名称失败时,绑定命名空间,而不是重排整台机器:一条 NRPT 规则把该后缀送往隧道解析器,其余一切照旧。所有查询都受影响时,问题出在全局适配器偏好,这时该从度量下手,因为它不改动任何服务器设置。
按地址族、在两个接口上分别设好度量,然后确认顺序:
Get-NetIPInterface | Select-Object ifIndex, InterfaceAlias, AddressFamily, InterfaceMetric
Set-NetIPInterface -InterfaceIndex 11 -InterfaceMetric 1 -AddressFamily IPv4
Set-NetIPInterface -InterfaceIndex 11 -InterfaceMetric 1 -AddressFamily IPv6
把 11 换成上面一行里隧道适配器的 ifIndex;如果 11 其实是 LAN 适配器,同一条命令降的就是错的那条路。反过来抬高 LAN 适配器,从另一侧也能得到同样的顺序:netsh int ip set interface interface="Ethernet" metric=15,第二个地址族则用 netsh int ipv6 set interface interface="Ethernet" metric=15,因为 int ip 只影响 IPv4。
绑定顺序是最后手段,而不是第一步。HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage 里保存着设备标识的 Bind 列表,把隧道标识挪到最前确实会改变先问哪个适配器,但它是全机范围的注册表值,没有按命名空间划分的范围。改之前先导出,改完之后重连隧道,让顺序在客户端预期的状态下生效。
只有一个命名空间时,优先用更窄的工具:
Add-DnsClientNrptRule -Namespace ".corp.example" -NameServers 10.20.0.10
Get-DnsClientNrptRule | Select-Object Namespace, NameServers
判断三:这个修法能不能挺过一次重连?
一个撑到下次拨号重连就失效的度量,其实从来没有被保存过。L2TP/IPsec 等连接配置文件在连接启动时会重新生成,所以保存的值住在电话簿条目里,名为 IpInterfaceMetric,而不只是在活动接口上。有些环境正是为了这个才用脚本写这个字段;另一些则从管理策略下发偏好,根本不动端点。
缓存和注册是另一层。隧道起来之后再跑这两条,能修掉过期记录并重新注册客户端,但两者都不会重排适配器:
ipconfig /registerdns
ipconfig /flushdns
同一层里还有一个开关。在物理适配器上关掉动态注册,客户端就不会用错误的名字去通告它 VPN 侧的地址,这与上面的刷新是两回事。
IPv6 在判断里值得单独一行。如果物理适配器持有全局 IPv6 地址,而隧道只承载 IPv4,Windows 可能让名称解析走未进隧道的路径。这一族要单独检查,因为给 IPv4 设的度量对它什么也没说:
Get-NetIPInterface -AddressFamily IPv6 | Select-Object ifIndex, InterfaceAlias, InterfaceMetric
在 LAN 适配器上关掉 IPv6,这条路连同协议一起消失;改 IPv6 接口上的度量、或给公司命名空间加一条 NRPT 规则,则保留该地址族并修正偏好。除非你已认定那条链路不该有 IPv6,否则选窄的那个。
用点名的方式验证,并只保留一个负责人
要用能报告当前生效来源的工具来验证,而不只是看页面能不能打开:
ipconfig /all
Get-DnsClientServerAddress -AddressFamily IPv4
Resolve-DnsName fileserver.corp.example -Server 10.20.0.10 -Type A
然后把过滤与选择分开,因为从应用程序里看,两者一模一样。OpenVPN 的 block-outside-dns 会阻断其他适配器上的 53 端口;它并不选择解析器。如果现在所有查询都失败,可能是过滤器挡住了唯一可达的服务器;如果配置好的解析器被忽略,那就是顺序或命名空间规则错了。同时改这两样,会让被阻断的查询和被忽略的查询再也分不清。
DNS 策略只留一个负责人:VPN 配置文件、一条管理策略、或一条 NRPT 规则,不要两样并存。收尾之前:
- 下发的解析器在被明确指定时能应答,普通查询也确实在用它。
- 你改的那条规则或度量覆盖了真正承载查询的那个地址族。
- 设置在断开并重连之后依然有效,或者你已经把它移进了保存的配置文件。
- 只有一种机制是权威的,其余保持原样。
要把顺序当成环境状态,而不是一件做完就结束的事。重连之后要复查,碰到改动网络栈的 Windows 更新之后也要复查,因为两者都可能把物理适配器重新顶到前面。