内网 wiki 在 Edge 里能打开,可发行版里的 git clone 却会超时。人们通常把这一条观察读成「VPN 把 WSL2 挡住了」,接下来一小时都花在改 /etc/resolv.conf 上。更有用的解读是:WSL2 从一开始就没有宿主机的网络路径——它跑在一台工具虚拟机里,有自己的网卡、自己的路由,以及 Windows 为它生成的 resolver 文件。后面的一切都取决于这三样里你真正缺的是哪一个。

这台 VM 有自己的协议栈、跃点和 resolver

在默认 NAT 模式下,发行版位于一个虚拟交换机之后,经宿主机访问互联网,但看不到宿主机的网卡。ip addr 只显示一个带私有地址的接口,ip route 显示的是经该交换机的默认路由,/etc/resolv.conf 则是 Windows 生成、指向某个 stub resolver 的文件。Windows 那边起了 VPN 客户端,这些都不会变。

所以「浏览器能用」什么都证明不了。浏览器用的是宿主机的协议栈、隧道和宿主机的 resolver 策略。你的 shell 用的是另一套栈,只是碰巧共用一块物理网卡。顺利时两者一致,而一旦 VPN 装上过滤器、改写 DNS 列表,或给虚拟交换机的子网加一条路由,两者立刻分道扬镳。

两个测试就能判定你在哪个世界,而且必须在发行版里执行:

getent hosts example.com
curl -sS -m 8 -o /dev/null -w "%{http_code}\n" 1.1.1.1
ip route
cat /etc/resolv.conf

字面地址能通、域名却失败,是 resolver 的问题。域名和地址一起失败,是链路问题,改多少 resolver 都碰不到它。接下来看 Windows 这边:Get-NetAdapter | Get-DnsClientServerAddress 和 route print -4 会显示隧道是否占住了 VM 所在的子网。

误区一:公司 DNS 服务器能解决

改 resolver 文件是老生常谈,大约一半情况下是对的。它对的时候理由很具体:生成的文件指向一个只认识公网域名的 resolver,所以即使链路正常,查 intranet.example.internal 也会返回不存在。

把 VPN 的服务器钉死,意味着不让 Windows 重新生成这个文件,因为手写的文件在下次启动时会被覆盖:

[network]
generateResolvConf = false

把它保存为 /etc/wsl.conf,从 Windows 执行 wsl --shutdown,然后启动发行版,把 /etc/resolv.conf 写成隧道服务器在前、公共 resolver 只作兜底。这是有维护成本的长期改动:文件不再跟随宿主机,公司 DNS 地址一变,发行版还在问旧地址。得有人对这份文件负责。

故障范围更大时它也无能为力。如果 curl 访问 1.1.1.1 超时,那就是隧道客户端在过滤虚拟交换机,或把 VM 的子网路由进了隧道,正确的 resolver 只会给你一串仍然到不了的域名。

误区二:改跃点能一劳永逸

域名能解析、流量却从物理网卡出去时,杠杆是接口跃点。给 VPN 网卡高开销,给 WSL 交换机低开销:

Get-NetAdapter | Where-Object InterfaceDescription -Match "AnyConnect" | Set-NetIPInterface -InterfaceMetric 4000
Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" | Set-NetIPInterface -InterfaceMetric 1

然后记住:很多客户端版本每次连接都会重建隧道网卡,跃点会回到默认值。一次性命令是一种会悄悄过期的修法,通常过个周末就失效,工单回来时写着「上周还好好的」。用 VPN 事件触发的计划任务,或用户连上后运行的脚本,才是这种修法的诚实版本。

同样的过期规律也适用于为某一个顽固前缀添加的主机路由。它们作为诊断有价值,能告诉你问题是单个目的地还是整条链路,但它们不是架构。

误区三:一种修法包打所有 Windows 版本

ApproachWhat it actually does
Resolver pinFixes private names only; no effect on path failures
Sidecar distributionForwards traffic over a socket to a helper VM, so the switch's filter no longer matters
Mirrored networkingGives the distribution the host's interface set; also enables DNS tunnelling

wsl-vpnkit 是 sidecar 模式:一个小发行版掌管宿主机侧的路径,并通过虚拟套接字替其他发行版转发,应用流量就不再依赖被过滤的交换机。它需要标准路径可用,也就是把 networkingMode 和 dnsTunneling 这两个覆盖项从 %UserProfile%\.wslconfig 里去掉,在每个能用的发行版里恢复 generateResolvConf = true,并在登录时启动服务。

镜像模式是 Windows 11 22H2 及以后的内置替代方案,只需一个设置加一次关机:

[wsl2]
networkingMode=mirrored

在发行版里,ip addr 就会列出宿主机的网卡,隧道也可能出现在其中;DNS 隧道会把查询经 Windows 的 resolver 转发,即使客户端改写了 DNS 列表。它不是万能的:某些过滤驱动仍会丢掉镜像路径,Hyper-V 防火墙规则可能需要显式放行。微软的 WSL 网络指南是应用为更新版本写的配方前应核对自己版本的那一页。

每次改动后测三件事

每台机器只选一种机制并写下来,因为两者叠加效果很差。镜像模式之上再套 sidecar 会让转发翻倍;.wslconfig 里残留旧 sidecar 条目的镜像宿主机,往往在升级之后而不是之前出问题。

无论选哪种,验收测试都是发行版里同样的三个请求:一个内部域名、一个公网域名和一个裸地址。然后在断开并重新连接隧道之后、在 wsl --shutdown 之后再各做一遍。只有内部域名失败是 resolver 策略;内部和公网域名一起失败而地址仍通,仍是 resolver 策略;全部失败就是链路。

如果一个内部主机失败而其余正常,别再盯着 resolver,去找该前缀缺失的路由。如果一切正常直到下次重连,你找到的是一个依赖运行时状态的修法,必须自动重新应用,或换成上面两种机制之一。

相关文章