跳到主要内容

在 Linux 上,VPN 的 DNS 泄漏是一个很常见的现象:隧道看上去完全正常,ip addr 里能看到 VPN 接口,公网 IP 也变了,但咖啡馆的路由器、酒店网关或者运营商仍然在回答你的 DNS 查询,也就知道你访问了哪些网站。原因在于 Linux 并没有一个统一的地方来“做 DNS”,而是由多个组件协作完成,其中任何一个都可能继续使用旧的解析器。

本文是一份面向桌面和服务器用户的实操指南:怎样找出是哪一层在应答,怎样用抓包证明,以及在三种最常见的环境里怎样修复,分别是 systemd-resolved、NetworkManager 和普通的 /etc/resolv.conf。如果你想先了解概念,可以阅读 什么是 DNS 泄漏 和 DNS 是如何工作的。

为什么 Linux 上特别容易配错

Windows 和 macOS 基本只有一个主要的解析服务,而 Linux 的情况取决于发行版和网络的配置方式。一台典型的桌面机器大致有下面几层叠在一起。

  • 应用程序与 C 库:程序调用 C 库,C 库先参考 /etc/nsswitch.conf,再读取 /etc/resolv.conf。
  • 存根解析器:在 Ubuntu、Fedora 等系统上,/etc/resolv.conf 指向 127.0.0.53,这是 systemd-resolved 的本地监听地址。有些系统用的是 dnsmasq 或其他本地缓存。
  • 网络管理器:NetworkManager、systemd-networkd 或 ifupdown 负责决定哪个接口用哪些 DNS 服务器,并通知解析器。
  • 浏览器:Firefox 和 Chromium 系浏览器可以绕过系统解析器,直接向 DNS-over-HTTPS 服务器发问。
  • 容器与虚拟机:Docker、Podman 和虚拟机往往带着自己的解析器设置。

VPN 客户端通常只动其中一层,有时一层都不动。用裸 ip link add 建立的隧道,或者没有 DNS = 这一行的最简 WireGuard 配置,只会改变路由,而解析器保持原样。这就是典型的泄漏:网页流量进了隧道,DNS 请求却仍然发给路由器。

第一步:查出谁在应答 DNS

动手修改之前,先在 VPN 已连接的状态下取得基线。

  1. 运行 resolvectl status。它会列出每个接口(称为 link)的 DNS 服务器、搜索域,以及一行 Default Route。如果物理接口例如 wlp3s0 显示 Default Route: yes,而 VPN 接口显示 no,说明普通请求正从物理接口发出。
  2. 运行 resolvectl query example.com。最后几行会说明由哪个 link 应答,例如 link: wlp3s0 或 link: wg0。你希望看到的是 VPN 接口。
  3. 运行 cat /etc/resolv.conf。如果里面是 nameserver 127.0.0.53,说明 systemd-resolved 在管理;如果是 192.168.1.1 这样的私有地址,说明系统在直接和路由器对话。
  4. 运行 ip route get 1.1.1.1。输出会给出内核访问该目标时选用的接口。如果显示的是物理接口,说明连普通流量都还没有进隧道,你面对的是路由问题,而不仅仅是 DNS 问题。

如果你没有使用 systemd-resolved,resolvectl 会提示服务未运行,请直接跳到下面关于 NetworkManager 和 resolv.conf 的部分。

第二步:在网线上取证

配置只能告诉你“应该发生什么”,抓包才能告诉你“实际发生了什么”。打开两个终端。

第一个终端运行:

sudo tcpdump -ni any 'udp port 53 or tcp port 53'

第二个终端请求几个最近没访问过的域名:

resolvectl flush-caches
getent hosts example.org
dig +short example.net

留意抓包结果里的接口名称列。出现在 wg0 或 tun0 上的请求已在隧道内,在物理接口上只会表现为加密流量。出现在 wlp3s0 或 eth0 上、目的地是路由器或公共解析器的请求,则是通过普通网络发出的,这些就是泄漏。

有两个细节可避免误判。第一,存根地址 127.0.0.53 永远出现在 lo 接口上,它只是本机内部通信,无害。第二,隧道里的 DNS 由隧道加密,所以一切正常时你在物理接口上根本看不到 53 端口,只会看到加密的 VPN 数据包。最后可以再用浏览器里的在线泄漏检测交叉验证,其余检查可参考 如何测试 VPN。

如何解读结果

你看到的现象 含义 下一步
请求只出现在 VPN 接口 这条路径没有泄漏 继续测试 IPv6 和浏览器
请求在物理接口上发往路由器 解析器仍跟随旧接口 按接口设置 DNS,并让 VPN 接口成为默认路由
请求在物理接口上发往公共解析器 浏览器 DoH 或硬编码的服务器 检查浏览器与应用配置
请求在两个接口上交替出现 存在多个默认路由接口 从物理接口移除 DNS,或使用路由域
修复后什么都没有 解析可能已失效 确认 VPN 的 DNS 地址能通过隧道访问

修复方案一:systemd-resolved 按接口设置 DNS

这是最干净的做法,因为 systemd-resolved 本来就是为多接口设计的。思路是给 VPN 接口配置专属的 DNS 服务器,并让它负责所有域名。

  1. 在 VPN 接口上设置服务器:sudo resolvectl dns wg0 10.0.0.1。请使用你的 VPN 配置所提供的解析器地址。
  2. 用通配路由域让它负责所有名称:sudo resolvectl domain wg0 '~.'。波浪号表示把这个域的查询路由到这里,而不把它加入搜索列表。
  3. 关闭物理接口的默认路由,让它只回答自己的本地名称:sudo resolvectl default-route wlp3s0 no。
  4. 再次用 resolvectl status 和 resolvectl query example.com 检查。

这些设置只在接口存在期间有效。要让 WireGuard 的设置长期生效,可以在配置文件里写 DNS = 10.0.0.1,接口启动时 wg-quick 会把它交给解析器工具。在 resolvconf 由 systemd 提供的系统上,这个调用最终会变成上面的命令。每次重启后请用 resolvectl status 实际验证,不要凭想象。

修复方案二:NetworkManager

由 NetworkManager 管理连接时,应在连接配置文件上修改 DNS,这样重新连接后设置仍然有效。

  • 给 VPN 配置文件一个负优先级:nmcli connection modify "my-vpn" ipv4.dns-priority -50 ipv4.ignore-auto-dns yes。负值会让 NetworkManager 只使用该配置文件里的服务器。
  • 对 Wi-Fi 或以太网配置文件,告诉它在 VPN 期间不要使用路由器的 DNS:nmcli connection modify "Home Wi-Fi" ipv4.ignore-auto-dns yes,然后重新连接。
  • 如果网络通告了 IPv6 解析器,也要加上 ipv6.ignore-auto-dns yes。
  • 对修改过的配置文件执行 nmcli connection down 再 up。

代价是断开 VPN 之后,物理连接的配置文件如果没有自己的 DNS 就无法解析。很多人会为同一个 Wi-Fi 保留两份配置文件,或者在退出 VPN 时临时手动改一下。

修复方案三:普通 resolv.conf 与其他解析器

在精简的服务器或较旧的发行版上,/etc/resolv.conf 可能只是一个普通文件。你可以把 VPN 的解析器写进去,但任何会重写该文件的程序(例如 DHCP 客户端)都会抹掉你的修改。更稳妥的做法有两种:

  • 交给 VPN 脚本管理。resolvconf、openresolv 这类工具会保存多个来源的列表并按优先级合并,隧道启动期间 VPN 的条目会取代路由器的条目,隧道关闭后又会自动撤销。
  • 如果非要固定文件,请把它当作有意识的决定并留下记录。用 chattr +i 冻结文件,也会冻结此后所有正当的变更,下次开机或换网络时常常导致断网。笔记本电脑上不建议这样做。

如果你运行了 dnsmasq 或 unbound 这样的本地缓存解析器,应修改它的上游服务器而不是那个文件,并在隧道启停时重启它。

IPv6 与浏览器的 DNS-over-HTTPS

有两种泄漏即便是谨慎的用户也容易忽略。第一种是 IPv6。如果路由器通告了 IPv6 的 DNS 服务器,而 VPN 只覆盖 IPv4,请求可能从 IPv6 路径泄出。请在 resolvectl status 中检查物理接口下是否有 IPv6 地址,然后让 IPv6 也走隧道,或在测试期间用 NetworkManager 的 ipv6.method disabled 关闭该连接的 IPv6。IPv6 泄漏 一文有更深入的说明。

第二种是浏览器。Firefox 可以使用自带的提供商列表进行 DNS-over-HTTPS,Chromium 系浏览器则可能跟随系统设置,也可能使用自己的设置。这些请求封装在访问 443 端口的 HTTPS 连接里,因此不会出现在你对 53 端口的抓包中,也不理会你刚刚修好的解析器。请有意识地做决定:要么让浏览器使用系统解析器,要么在知情的前提下选定某个 DoH 服务器。DNS over HTTPS 与 VPN 的比较 解释了两者的关系。

用防火墙规则堵住漏网的请求

设置正确之后,再加一道保险,让将来的配置失误以“关闭”的方式失败,而不是泄漏。下面这张小小的 nftables 表会丢弃试图从隧道和回环以外的接口发出的明文 DNS:

table inet dnsguard {
  chain output {
    type filter hook output priority 0; policy accept;
    oifname != "wg0" oifname != "lo" udp dport 53 drop
    oifname != "wg0" oifname != "lo" tcp dport 53 drop
  }
}

用 sudo nft -f dnsguard.nft 加载,用 sudo nft delete table inet dnsguard 删除。有两点要注意。第一,规则生效且隧道断开时,DNS 会完全失效,这正是目的,却常让人意外。建议把加载和删除绑定到接口的启停上,例如使用 PostUp 与 PostDown。第二,VPN 客户端仍需要解析服务器的名称,所以请把 endpoint 写成确切的 IP 地址,或者只在首次连接成功后再加载规则。这一思路的整体介绍见 VPN 断线保护(Kill Switch)是什么。

常见错误

  • 只用网站上的泄漏检测,从不看抓包结果。
  • 修改了 /etc/resolv.conf,却不明白为什么休眠唤醒后又恢复原样。
  • 在 VPN 配置里写了 DNS =,但系统没有 resolvconf 或相应的解析器集成,这一行被悄悄忽略。
  • 忘记容器,它们保留自己的解析器,可能绕过主机的设置。
  • 只修了 IPv4,路由器仍在通告 IPv6。
  • 以为公网 IP 变了就等于修好了。地址和解析器是两个独立的问题。

总结

Linux 上的 DNS 泄漏几乎从来不是隧道本身的问题,而是解析器栈、网络管理器、浏览器或 IPv6 仍然沿用旧路径。先用 resolvectl 找到应答的那一层,用 tcpdump 取证,再通过按接口设置 DNS 或调整连接优先级来修复,最后加上防火墙规则让失误以关闭方式收场。每次重启和更换网络后都要重新测试一遍。

如果你使用免费的 VPNclient 应用连接,Linux 设置指南 介绍了安装方法,准备好之后也可以到 价格页面 了解选项。

常见问题

隧道明明正常,为什么 Linux 上的 VPN 还会发生 DNS 泄漏?

隧道只负责承载被路由表送进去的数据包。DNS 请求由另一层解析器产生,如果这一层仍然指向路由器的地址,请求就会走普通网络,即使你的网页流量已经走了 VPN。

哪条命令能看出我的 DNS 请求去了哪里?

使用 systemd-resolved 的系统可以运行 resolvectl status 查看各接口的 DNS 服务器,再用 resolvectl query example.com 查看由哪个 link 应答。想在网线上取证,可以在浏览时运行 sudo tcpdump -ni any port 53。

手动修改 /etc/resolv.conf 是个好办法吗?

通常不是。多数现代发行版的这个文件由 systemd-resolved 或 NetworkManager 生成,网络一变化你的修改就会被覆盖。应当在连接配置或接口上设置 DNS。

DNS 泄漏还需要考虑 IPv6 吗?

需要。如果网络下发了 IPv6 解析器,而 VPN 只覆盖 IPv4,请求可能从 IPv6 路径泄出。用 resolvectl status 检查有没有 IPv6 服务器,然后让 IPv6 也走隧道,或在该连接上关闭 IPv6。

关于作者

Bob Kanokphon Thongdee,XPASS VPN 创始人

Bob Kanokphon Thongdee

  • XPASS VPN 创始人
  • eSIMonline.asia 联合创始人
  • 7 年以上网络营销经验
  • Cojourney Visa 与 Cojourney Travel 创始人

短途出行或忙碌的一个月,需要 VPN?

XPASS 提供按天数计算的预付通行证。一次付款,不会自动续费。

查看通行证

继续阅读

VPN 安全

什么是 DNS 泄漏?

DNS 泄漏是指设备在 VPN 隧道之外查询网站地址。本文说明它为什么发生、如何检测,以及该怎么处理。

阅读约 10 分钟

VPN 基础

DNS 是如何工作的:从域名到 IP 地址

DNS 是把网站名称转换成设备实际连接的 IP 地址的查询系统。本文逐步讲解一次查询的过程,以及它为什么与隐私有关。

阅读约 9 分钟

VPN 安全

VPN 的 Split DNS(分流 DNS)是什么

Split DNS 让设备按域名选择不同的解析器:内部名称走 VPN,其他名称走平时的解析器。本文介绍原理、使用场景和检查方法。

阅读约 9 分钟

设备指南

如何修复 Windows 上的 VPN DNS 泄漏

为什么 Windows 会把 DNS 查询发到 VPN 之外,如何用系统自带工具确认泄漏,以及对大多数电脑有效的修复顺序。

阅读约 10 分钟

VPN 安全

如何自己评测 VPN:一份测试清单

许多 VPN 评测是为赚取佣金而写的。这份清单教你自己测试任何 VPN:哪些能验证,哪些不能,以及如何给结果打分。

阅读约 9 分钟