部署 WireGuard 后出现 ping IP 通但 ping 域名不通的问题,根因是 wg-quick 脚本自动将全局 DNS 路由域 ~. 绑定到 wg0 网卡,导致 DNS 请求被劫持到不通的链路。本文从问题现象、排查过程、底层原理到预防方案做完整复盘。
实际 WireGuard 配置
出问题的 wg0.conf 如下:
1 | [Interface] |
注意关键点:AllowedIPs = 10.7.0.0/24,说明该 WG 隧道仅用于访问 10.7.0.0/24 内网段,并非全局代理。但配置了 DNS = 223.5.5.5, 223.6.6.6,这直接导致了后续的 DNS 劫持问题。
问题现象
WireGuard 启用后:
ping 223.5.5.5正常ping www.baidu.com失败
结论:网络层连通,DNS 解析链路异常。
排查过程
查看系统 DNS 状态
1 | resolvectl status |
输出关键信息:
1 | Global |
关键发现:Link 4 (wg0) 中的 DNS Domain: ~. 表示所有 DNS 查询都通过 wg0 接口走(全局作用域),而 enp3s0 的 DNS 被降级为非全局。
定位根因
WireGuard 安装启用后,wg-quick 脚本检测到配置文件中的 DNS = 223.5.5.5, 223.6.6.6,为防止 DNS 泄漏,自动执行:
1 | resolvectl dns wg0 223.5.5.5 223.6.6.6 |
但 wg0 隧道的 AllowedIPs = 10.7.0.0/24 并未包含 223.5.5.5,DNS 请求包无法被正确路由,对端也不会转发公共 DNS 请求,导致解析失败。
临时修复
1 | # 移除 wg0 的全局接管 |
底层原理
Linux DNS 解析机制的演进
传统模式下直接修改 /etc/resolv.conf 写入 nameserver 8.8.8.8,但全局配置无法应对多网卡、多 VPN 场景——VPN 连接时覆盖文件,断开时忘记恢复,导致断网。
现代 Linux 发行版引入 systemd-resolved 服务来解决此问题:
- 系统级 DNS 缓存和 DNS 路由服务
- 允许为每个网卡(Link)独立配置 DNS 服务器和域名规则
- 应用程序发起 DNS 查询时发给
127.0.0.53(systemd-resolved),由它决定使用哪个网卡的 DNS 去解析
resolvectl 核心命令
resolvectl 是 systemd-resolved 的命令行管理工具:
| 命令 | 用途 |
|---|---|
resolvectl status |
查看各网卡 DNS 配置 |
resolvectl query <域名> |
测试 DNS 解析路径及耗时 |
resolvectl dns <网卡> <IP> |
动态修改网卡 DNS 服务器 |
resolvectl domain <网卡> <域名> |
动态修改网卡域名路由规则 |
resolvectl revert <网卡> |
还原网卡 DNS 配置 |
stub 模式
输出中 resolv.conf mode: stub 表示 /etc/resolv.conf 内容为 nameserver 127.0.0.53,传统应用把 DNS 请求发给本地 systemd-resolved,再由它按路由规则转发。此时直接修改 /etc/resolv.conf 无效,重启会被覆盖。
路由域 ~. (核心难点)
systemd-resolved 中 Domain 分两种:
- 搜索域(无
~前缀):如example.com,仅做后缀补全,ping host会尝试解析host.example.com - 路由域(带
~前缀):如~example.com,告诉系统”只有匹配该域的 DNS 请求才通过此网卡解析”
~. 的特殊含义:. 是 DNS 根域,~. 匹配所有域名。当 wg0 配置了 DNS Domain: ~. 时,它宣告自己是全局默认 DNS 出口,所有 DNS 请求都必须交由 wg0 处理。
为什么 WireGuard 会导致 DNS 失败
结合本次实际配置分析:AllowedIPs = 10.7.0.0/24 仅允许内网流量走 WG 隧道,但 DNS = 223.5.5.5, 223.6.6.6 让 wg-quick 将全局 DNS 劫持到 wg0,而 DNS 服务器的 IP 不在 AllowedIPs 范围内,导致 DNS 请求无处可去。
更一般地,解析失败通常因为:
- 路由不匹配:
AllowedIPs没有包含 DNS 服务器 IP,导致 DNS UDP 包没有进入 WG 隧道 - 对端限制:WG 对端服务器屏蔽了对外部公共 DNS 53 端口的访问
- 物理网卡被降级:
wg0抢走~.后,物理网卡 DNS 变为非全局,wg0DNS 不通时systemd-resolved不会及时回退
DNS 排查 SOP
遇到 “Ping IP 通,Ping 域名不通” 时:
Step 1:确认 DNS 路由状态
1 | resolvectl status |
查看哪个网卡拥有 ~.。
Step 2:测试具体域名解析路径
1 | resolvectl query www.baidu.com |
Step 3:绕过系统直接测试 DNS 服务器
1 | dig @223.5.5.5 www.baidu.com |
若 resolvectl query 失败但 dig 成功,说明是 systemd-resolved 路由问题;若 dig 也失败,说明是网络层/防火墙拦截了 53 端口。
Step 4:抓包确认(终极手段)
1 | sudo tcpdump -i enp3s0 port 53 -n |
最终解决方案
本次场景为仅通过 WG 访问 10.7.0.0/24 内网段,不需要 WG 处理 DNS,因此直接删除配置文件中的 DNS 字段即可一劳永逸:
1 | [Interface] |
重启服务后恢复:
1 | sudo systemctl restart wg-quick@wg0 |
没有 DNS 字段,wg-quick 就不会调用 resolvectl 接管全局 DNS,物理网卡继续掌管 DNS 解析,问题彻底解决。
其他预防方案(不同场景参考)
场景一:仅内网互通(本文场景)
只需通过 WG 访问特定内网 IP,日常 DNS 走物理网卡。直接删除配置文件中的 DNS 字段(即上文最终方案),wg-quick 不会触碰 systemd-resolved,物理网卡继续掌管 DNS。
场景二:按域名分流(Split DNS)
访问 *.company.local 用 WG 隧道内 DNS,其他用本地 DNS。使用 PostUp / PostDown 精确控制:
1 | [Interface] |
%i 是 wg-quick 内置变量,代表当前网卡名。只有 company.local 后缀的域名才走 wg0 的 DNS。
场景三:全局代理但 DNS 不通
所有流量走 WG,但配置 DNS = 8.8.8.8 后无法解析。确保 DNS 服务器 IP 被 AllowedIPs 包含:
1 | [Interface] |
若对端 WG 服务器不转发公网 DNS 请求,需显式放行:AllowedIPs = 0.0.0.0/0, ::/0, 8.8.8.8/32。
场景四:使用 NetworkManager(推荐)
弃用 wg-quick,改用 NetworkManager 管理 WireGuard,它不会粗暴添加 ~.:
1 | # 导入配置 |
防坑 Checklist
- 需要全局代理吗? 否 → 删掉
DNS = ...(本文场景);是 → 保留并检查对端是否允许 DNS 请求通过 - 需要解析内网域名吗? 是 → 删掉
DNS = ...,改用PostUp+resolvectl domain %i '~域名' - 受够了手动修复 DNS? 是 → 弃用
wg-quick,投入NetworkManager的怀抱