Windows 解析内部主机毫无怨言,而同一个名字在隧道建立的那一刻就在 WSL 内失败。常见的修法是把公共解析器写进发行版,这能让普通浏览恢复正常,却让工作主机名变得无法解析。这等于用一种故障换另一种,还掩盖了真正出问题的层。在添加或删除任何解析器行之前,先弄清三层中哪一层在失败。

先排除路由故障

在两侧查询完全相同的完全限定名,而不是两个看起来相似的名字。同一个字符串在 Windows 成功、在 WSL 失败,是两条解析路径的签名,很少有别的现象能如此干净地产生这种模式。如果 WSL 连该服务已知的数字地址都访问不到,那就同时存在路由或过滤问题。那种情况下 DNS 工作不会揭示它,一下午都会花在错误的层上。

三种症状覆盖了大多数情况,每一种指向不同的地方。打开配置文件之前,先读对应的那一行:

Symptom inside WSLLikely layerWhere to look
Private name fails while public browsing worksResolver pathTunneling mode and the Windows build
A name that worked yesterday fails todayStale overrideGenerated resolver file, immutable flag, shell profile
The name resolves but the service does notRouting or filteringThe resolved address and the path to it

中间那一行常被误读,因为弄坏它的改动是几周前做的,当时看起来成功了。第三行常被误判,因为能解析的名字让人觉得网络健康。两行都会把你送到下面不同的章节。

DNS 隧道有版本下限

Microsoft 记录了一种 WSL 网络模式,它通过虚拟化通道把 DNS 请求隧道到 Windows 解析器。在受支持的 Windows 11 版本上它默认开启,这就是同一企业网络里两台机器表现不同的原因。变量是内部版本号,不是企业策略。

WSL 网络指南 介绍了该模式以及支持它的版本。这个功能重要,因为企业 DNS 策略通常放在 Windows 解析器里,而继承 Windows 路径的发行版也一并继承了策略。向公共解析器提问的发行版没有通往私有名的路由,配置再整洁也没用。正是这个机制解释了整个症状,也解释了为什么公共解析器绕行方案会失败。

改任何东西之前先读内部版本号。从较新安装复制来的设置,不能证明较旧的安装实现了它。把版本号记在改动旁边,因为两台机器的差异几乎总是版本,而不是策略。

旧的覆盖比它解决的问题活得更久

更早的做法 会禁用生成的解析器文件、硬编码名称服务器,或者用不可变属性锁住文件。这些改动在当初促使它们出现的连接问题消失之后很久仍然留在原处,通常也正是较新设置看起来毫无作用的原因。它们还会以 shell 配置文件的形式在重装发行版后存活,每次登录都重写该文件。最后一种最难发现,因为从人人都会检查的那个文件里根本看不见它。

去找手写的解析器文件、它上面的不可变属性,以及重写它的启动脚本。编辑前先检查不可变标志,因为写入被锁文件时的失败方式读起来像权限问题。之后再检查 shell 配置文件,因为那里的脚本会在你修好几秒内把旧内容恢复回来。

删除覆盖有后果,所以要记下删了什么、为什么删。真正需要静态解析器做别的事情的发行版,在生成文件回来时会坏掉。

两个文件,两种不同的角色

两个配置文件放在不同位置、控制不同东西,把它们混在一起就会产生作用在错误层上的修改。Windows 侧的文件设置虚拟机属性,而发行版侧的文件设置该发行版如何构建自己的解析器配置。两者互不覆盖,所以必须一致。

对于支持该功能的安装,Windows 侧的片段很短。那一侧的全部改动就是它:

[wsl2]
dnsTunneling=true

该片段属于 Windows 用户配置文件,作用于虚拟机而不是单个发行版。隧道还要求发行版没有禁用解析器生成,所以发行版侧的文件必须别去动这个行为。只改一个不改另一个,模式会悄悄什么都不做,这也是这项修复被报告为失败的最常见方式。要在同一个会话里检查两个文件,因为相隔数周做的两次修改是没人能归因的两次修改。

重启,然后从两侧查询

这些设置只在环境启动时读取,所以运行中的发行版里新开的 shell 不会重新加载它们。要关闭环境而不是重启 shell,并且先保存正在做的工作,因为每个发行版都会随之停止。仅这一处遗漏就解释了大多数“改动无效”的报告。

然后从两侧问同一个问题。输出还会显示发行版最终用的是哪个解析器:

wsl.exe --shutdown
wsl.exe -e sh -c 'cat /etc/resolv.conf'
wsl.exe -e sh -c 'getent hosts files.corp.example'
wsl.exe -e powershell -Command 'Resolve-DnsName files.corp.example'

第一条命令结束环境,第二条显示发行版现在用哪个解析器,最后两条向每一侧提出同一个问题。要比较答案,而不是设置的状态。在两个文件都正确、干净重启之后仍然失败的查询,指向企业解析器策略,而那个对话另有负责人。

相关文章