WSL2 DNS 解析故障排查与解决方案
问题现象
- WSL2(Ubuntu)中所有域名解析失败:
$ curl -I https://github.com curl: (6) Could not resolve host: github.com $ ping www.baidu.com ^C # 请求超时无响应 - 但直接
ping外网 IP 正常:$ ping 8.8.8.8 64 bytes from 8.8.8.8: icmp_seq=1 ttl=103 time=172 ms
排查过程
1. 检查基本配置
- 确认
/etc/resolv.conf配置:$ cat /etc/resolv.conf nameserver 8.8.8.8 nameserver 1.1.1.1 /etc/wsl.conf已设置自动生成 DNS,配置正常。
2. 检查网关与路由
- 查看路由表:
$ ip route default via 172.26.192.1 dev eth0 # 正常 - 测试网关连通性:
$ ping 172.26.192.1 # 网关可通
3. 测试 UDP 53 端口
- 检查 DNS 请求出口:
结果:请求可发出,但无应答,表明回程包被拦截。$ timeout 2 bash -c "echo >/dev/udp/8.8.8.8/53" && echo "开放" || echo "阻塞" 开放
4. 检查 Windows 端口占用
- Windows 管理员终端执行:
关键输出:netstat -ano | findstr ":53 "UDP 0.0.0.0:53 *:* 3704 - 查询占用进程:
输出:tasklist /svc /FI "PID eq 3704"
结论:Internet Connection Sharing (ICS) 服务占用了 UDP 53 端口。映像名称 PID 服务 svchost.exe 3704 SharedAccess
尝试了以下失败的解决方案
禁用 SharedAccess 服务
sc.exe config SharedAccess start= disabled net stop SharedAccess- 结果:服务停止后自动重启,端口仍被占用。
修改
.wslconfig[wsl2] networkingMode=NAT dnsTunneling=false autoProxy=false- 执行
wsl --shutdown后端口短暂释放,重启 WSL 后端口又被占用。
- 执行
重启
winnat并重置网络net stop winnat && net start winnat netsh winsock reset- 结果:无效。
尝试 TCP 53 代理
- 国内 DNS(如
223.5.5.5)的 TCP 53 端口被 RST(连接重置),无法使用。
- 国内 DNS(如
解决方案:DNS over HTTPS (DoH) 本地代理
原理
- 在 WSL 内启动本地 UDP 53 监听器。
- 将 DNS 请求封装为 DoH 请求,通过 HTTPS 443 端口发送至公共 DNS 服务器。
- 绕过宿主机被占用的 53 端口,直接获取解析结果。
实施步骤
创建 DoH 代理脚本
sudo tee /usr/local/bin/dns-doh-proxy.py << 'EOF' #!/usr/bin/env python3 import socket import struct import http.client import ssl UPSTREAM_IP = '223.5.5.5' # 阿里 DNS IP UPSTREAM_HOST = 'dns.alidns.com' # SNI 域名 UPSTREAM_PATH = '/dns-query' LISTEN = ('127.0.0.1', 53) def doh_query(data): try: raw_sock = socket.create_connection((UPSTREAM_IP, 443), timeout=5) ctx = ssl.create_default_context() ssl_sock = ctx.wrap_socket(raw_sock, server_hostname=UPSTREAM_HOST) conn = http.client.HTTPSConnection(UPSTREAM_HOST) conn.sock = ssl_sock conn.request( 'POST', UPSTREAM_PATH, body=data, headers={'Content-Type': 'application/dns-message'} ) resp = conn.getresponse() if resp.status == 200: return resp.read() except: pass return None sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(LISTEN) print(f"DoH proxy listening on {LISTEN}", flush=True) while True: data, addr = sock.recvfrom(512) resp = doh_query(data) if resp: sock.sendto(resp, addr) EOF sudo chmod +x /usr/local/bin/dns-doh-proxy.py本地 DNS 配置
sudo chattr -i /etc/resolv.conf 2>/dev/null sudo rm -f /etc/resolv.conf sudo tee /etc/resolv.conf << 'EOF' nameserver 127.0.0.1 EOF sudo chattr +i /etc/resolv.conf # 防止文件被修改启动代理
sudo nohup /usr/local/bin/dns-doh-proxy.py > /tmp/doh-proxy.log 2>&1 &验证
$ curl -I https://github.com HTTP/2 200 # 成功解析! $ ping www.baidu.com PING www.a.shifen.com (157.148.69.151) 56(84) bytes of data. 64 bytes from 157.148.69.151: icmp_seq=1 ttl=49 time=9.31 ms
开机自启配置
在~/.bashrc末尾添加:
pgrep -f dns-doh-proxy.py || sudo nohup /usr/local/bin/dns-doh-proxy.py > /tmp/doh-proxy.log 2>&1 &注意:需确保当前用户有
sudo免密权限,或启动时手动输入密码。
问题根源与总结
- 根源:Windows 的
SharedAccess服务强制绑定0.0.0.0:53,导致 WSL DNS 回包被丢弃。 - 方案:
- 通过 DoH 代理将 DNS 流量转移至 HTTPS 通道,绕过 53 端口占用。
若您遇到以下情况,可参考此方案:
- 能
ping通 IP 但域名解析失败。 - Windows 上
netstat显示 UDP 53 被占用。 - 常规网络重置、服务重启无效。