故障发现

今天更新了 WSL 版本后发现不能上网,更新后的版本如下:

PS C:\Users\jjl9807> wsl -v
WSL 版本: 2.1.5.0
内核版本: 5.15.146.1-2
WSLg 版本: 1.0.60
MSRDC 版本: 1.2.5105
Direct3D 版本: 1.611.1-81528511
DXCore 版本: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows 版本: 10.0.19045.4291

更新完成后启动 Debian,使用 sudo apt update 命令检查软件更新,出现如下报错:

错误:1 https://security.debian.org/debian-security bookworm-security InRelease
  暂时不能解析域名“security.debian.org”

使用 ping -c 4 baidu.com 检查网络连通性,结果如下:

jjl9807@debian:~$ ping -c 4 baidu.com
ping: baidu.com: 域名解析暂时失败

初步确定 WSL 的域名解析出现问题,使用 nslookup baidu.com 查看百度域名的 DNS 查询结果:

jjl9807@debian:~$ nslookup baidu.com
;; communications error to 172.18.32.1#53: timed out
;; communications error to 172.18.32.1#53: timed out
;; communications error to 172.18.32.1#53: timed out
;; no servers could be reached

可以看到多次查询均以超时告终,确定 WSL 的 DNS 服务发生异常。

排查过程

检查网络连通性

首先确认主机网络情况,主机使用的是路由器 192.168.1.1 提供的 DNS 服务,网络访问一切正常。

接着,由于 WSL 默认配置的 DNS 服务器就是主机地址,因此需要检查主机与 WSL 之间的连通性:

PS C:\Users\jjl9807> ping 172.18.32.168

正在 Ping 172.18.32.168 具有 32 字节的数据:
来自 172.18.32.168 的回复: 字节=32 时间<1ms TTL=64
来自 172.18.32.168 的回复: 字节=32 时间<1ms TTL=64
来自 172.18.32.168 的回复: 字节=32 时间<1ms TTL=64
来自 172.18.32.168 的回复: 字节=32 时间<1ms TTL=64

172.18.32.168 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 0ms,最长 = 0ms,平均 = 0ms

发现主机到 WSL 只能单向连通:

jjl9807@debian:~$ ping -c 4 172.18.32.1
PING 172.18.32.1 (172.18.32.1) 56(84) bytes of data.

--- 172.18.32.1 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3120ms

这里怀疑是 Windows 防火墙策略设置问题,在管理员模式下使用以下指令为 WSL 添加入站策略:

New-NetFirewallRule -DisplayName "WSL" -Direction Inbound  -InterfaceAlias "vEthernet (WSL)"  -Action Allow

再次检查,发现主机与 WSL 已经双向联通,但是 DNS 异常的问题依旧存在。

检查 DNS 配置

首先查看 WSL 的 DNS 配置:

jjl9807@debian:~$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.18.32.1

通过注释可以发现 DNS 配置是 WSL 自动生成的,默认设置主机为 DNS 服务器。接着使用以下命令查看 WSL 能否正常使用路由器提供的 DNS 服务:

jjl9807@debian:~$ nslookup baidu.com 192.168.1.1
Server:         192.168.1.1
Address:        192.168.1.1#53

Name:   baidu.com
Address: 110.242.68.66
Name:   baidu.com
Address: 39.156.66.10

发现系统能够正常使用路由器提供的 DNS 服务,查看主机 53 号端口确认主机并没有提供或转发 DNS 服务,显然问题就出在 WSL 的默认 DNS 配置上。

问题解决

方案一

这里可以按照 /etc/resolv.conf 文件注释中提示的那样设置 /etc/wsl.conf 文件并且手动指定 DNS 服务器地址,但是很不优雅,在安装了多个 Linux 发行版或者主机网络环境变化的情况下需要重复配置。

方案二

通过查询WSL 配置文档发现 WSL 2 提供了 dnsProxy 配置项:默认为 true,在 NAT 模式下将 Linux 中的 DNS 服务器配置为主机上的 NAT。 设置为 false 会将 DNS 服务器从 Windows 镜像到 Linux。

因此,在 %UserProfile% 目录下创建 .wslconfig 文件并写入以下内容:

# Settings apply across all Linux distros running on WSL 2
[wsl2]
dnsProxy=false

然后重启 WSL,发现 Linux 已经和主机使用相同的 DNS 服务器,域名解析和网络访问恢复正常:

jjl9807@debian:~$ nslookup baidu.com
Server:         192.168.1.1
Address:        192.168.1.1#53

Name:   baidu.com
Address: 39.156.66.10
Name:   baidu.com
Address: 110.242.68.66