一、先分清 DNS 出口、网页出口与规则预期
网页显示代理出口 IP,并不代表域名解析也经过代理。一次访问至少涉及两条路径:应用先解析域名,再向目标地址建立连接。系统代理通常只接管愿意遵守代理设置的应用,系统解析器、应用自带 DNS 和浏览器安全 DNS 可能走不同路径。
本文把“DNS 泄漏”限定为:本应经由指定解析路径处理的查询,实际交给了预期之外的解析器,或经由本地网络直接发出。如果规则本来要求本地域名直连并使用本地解析,检测到本地解析器不一定是故障;如果目标是所有普通查询经代理转发,那么相同结果就值得排查。
| 观察项 | 能说明什么 | 不能直接证明什么 |
|---|---|---|
| 网页公网 IP | 该网页请求的出口 | 其他应用或 DNS 也走相同出口 |
| 检测站列出的 DNS IP | 参与递归解析的服务器出口 | 设备到解析器之间是否经过代理 |
| 返回 198.18.x.x | 这次查询拿到了常见 fake-ip 地址段内的映射 | 全部系统查询都已被接管 |
| 出现本地运营商解析器 | 存在需要核对的本地解析路径 | 所有连接都绕过代理 |
二、检测站要做三组对照,不只看国家名称
先记录固定条件
可以使用 dnsleaktest.com 的 Standard test、Extended test,以及 browserleaks.com/dns 交叉观察。它们通过触发测试域名解析,记录查询到达权威服务器时的递归解析出口;不是在浏览器里直接读取操作系统 DNS 设置。
- 记录当前网络,例如家庭 Wi-Fi;记录客户端模式、所选节点、TUN 开关与浏览器安全 DNS 状态。
- 关闭代理,运行一次测试作为基线。记下公网 IP、DNS 服务商及解析器地址,不必公开完整截图。
- 开启代理并保持节点不变,再运行一次。系统代理模式与 TUN 模式分别记录,避免同时修改多个条件。
- 临时关闭浏览器安全 DNS,重启浏览器后再测一次。若结果变化,优先检查浏览器自己的 DoH 路径。
这些是建议的操作步骤,不是本站提供的实测数据。对照时重点看“开关前后是否变化”和“是否符合配置策略”,不要把某个国家标签当成唯一判据。公共 DNS 使用任播网络,地理数据库也可能滞后,解析器登记位置与实际服务节点位置未必相同。
按结果缩小范围
- 网页 IP 变化,DNS 仍是家庭宽带运营商:先查系统 DNS 是否进入内核,以及浏览器是否另有解析设置。
- 只有某个浏览器出现不同 DNS:优先查该浏览器的安全 DNS、扩展和独立代理设置。
- 出现两家公共 DNS:可能配置了多个上游或回退解析,不能只凭数量判定泄漏。
- TUN 开启后结果才符合预期:说明系统代理未覆盖原先的解析路径,继续验证应用范围与 IPv6。
三、用 fake-ip 建立域名映射,再核对解析上游
fake-ip 的作用是向应用返回虚拟地址,并由内核保存域名映射。当后续连接抵达内核时,可以据此使用域名规则进行匹配。它并不是一种加密协议,也不会自动接管操作系统 DNS。配置开关打开、系统却继续询问路由器,仍然可能绕过这条路径。
下面是一段合并到现有配置的 DNS 片段,不是完整订阅。保留现有节点、代理组和规则,将已有的顶层 dns: 段整体检查后再修改,不要在同一文件里再追加第二个同名段。
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- '+.lan'
- '+.local'
respect-rules: true
default-nameserver:
- 223.5.5.5
proxy-server-nameserver:
- 223.5.5.5
nameserver:
- https://cloudflare-dns.com/dns-query
listen是内核 DNS 监听地址。示例的1053适合先做定向测试,不会自动让系统改用这个端口。default-nameserver用于解析 DNS 服务器自身的域名,是启动解析链的一环,不是普通查询的常规上游列表。proxy-server-nameserver用于解析代理节点域名,避免“解析节点要先连代理,连代理又要先解析节点”的循环依赖。nameserver中的 DoH 地址用于常规上游解析。HTTPS 加密的是到解析服务的传输,并不等于这条传输必定走代理。fake-ip-filter中的域名不使用 fake-ip 映射;该列表不等于直连规则,也不代表这些域名不再发起 DNS 查询。
四、respect-rules 决定上游连接怎么走,不负责接管系统
respect-rules: true 让相关 DNS 上游连接遵循路由规则。它解决的是“内核向上游发请求时选哪条出口”,不是“系统的请求有没有进入内核”。这两件事分开验证,排障会少绕一圈。
核对最终命中的规则
- 确认当前使用规则模式,即
mode: rule。全局模式与直连模式下的行为不能拿来代替规则模式验证。 - 检查 DNS 服务域名是否被前置规则或规则集匹配到
DIRECT。如果命中直连,开启respect-rules也不会把它变成代理。 - 通过客户端连接面板及日志核对上游连接的规则与出口;必要时短时间提高日志级别,排查后恢复,避免持续记录过多域名。
- 若需要为 DNS 服务域名单独指定出口,使用现有代理组的准确名称,并放在会提前命中的宽泛规则之前。不要复制一个配置中根本不存在的组名。
原配置若含有 nameserver-policy、direct-nameserver 或 fallback,也要一并检查。只修改 nameserver,可能根本没有改变某些域名实际使用的解析器。首次定位时宜减少变量,确认最小配置正常后,再逐项恢复策略。
fallback 也不是一个简单的“主 DNS 超时才启动”开关。回退结果的选用与 fallback-filter 等条件有关;为了修复泄漏而随手堆上多个解析器,通常只是把观察结果变得更热闹。
五、系统 DNS 接管:TUN 与 53 端口各管什么
多数桌面系统的网络设置只能填写 DNS 服务器地址,不能填写 1053 这样的自定义端口。因此,把系统 DNS 写成 127.0.0.1,却让内核只监听 127.0.0.1:1053,会造成端口不匹配。使用系统直连本地 DNS 的方案时,需要监听 53 端口,并处理权限与占用;不要盲目把监听地址改为对整个局域网开放。
另一条常用路径是 TUN 接管网络流量,并把进入 TUN 的普通 DNS 请求交给内核处理。以下仍是合并片段,应先确认当前客户端没有通过界面生成另一份 TUN 配置。
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53与tcp://any:53分别覆盖进入 TUN 的 UDP、TCP 53 端口 DNS 请求。auto-route负责自动配置相关路由;启动失败时,应先检查服务权限、路由冲突和其他 VPN,而非反复切换 DNS 地址。- 发往本地链路或被路由排除的 DNS 请求,未必会进入 TUN。路由器 DNS、其他虚拟网卡和本地回环解析器都需要单独验证。
- DoH 通常使用 HTTPS 的 443 端口,DoT 通常使用 853 端口。53 端口劫持不会自动把它们转换成内核 DNS 查询。
六、Windows、macOS、Linux 与 Android 逐个平台复测
Windows:区分内核监听测试与系统路径测试
以管理员权限启动客户端所需的服务或 TUN 后,先用下面两条命令检查。第一条明确查询本地 1053 端口,第二条使用系统默认 DNS,二者验证的不是同一条路径。
nslookup -port=1053 example.com 127.0.0.1
nslookup example.com
ipconfig /all
ipconfig /flushdns
第一条在域名不属于过滤列表时,通常应返回配置地址池中的 fake-ip。第二条即使命中 TUN 劫持,界面仍可能显示原先配置的 DNS 服务器名称,不能只看那一行就判定失败。结合结果地址、日志和检测站交叉确认。清理缓存后重新访问测试域名,避免旧答案干扰。
macOS:看系统解析器列表,不只看 Wi-Fi 页面
scutil --dns
dig @127.0.0.1 -p 1053 example.com A
dscacheutil -q host -a name example.com
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
scutil --dns 可以查看包含按接口或域名划分的解析器配置。dig 的定向查询用于检查内核监听;dscacheutil 更适合补充观察系统解析路径。启用 TUN 所需的授权后,再复测浏览器;不要因为 dig 成功就省略系统层检查。
Linux:注意 systemd-resolved 与回环地址
resolvectl status
resolvectl query example.com
dig @127.0.0.1 -p 1053 example.com A
sudo resolvectl flush-caches
/etc/resolv.conf 中出现 127.0.0.53,通常表示应用先访问本地解析存根,不代表最终上游就是本机。继续查看 resolvectl status 的每接口 DNS。未使用 systemd-resolved 的发行版,应检查 NetworkManager 或实际 DNS 管理服务,不要直接覆盖由服务自动生成的文件。
Android:私人 DNS 与浏览器安全 DNS 分开排查
在原生 Android 常见路径“设置”→“网络和互联网”→“私人 DNS”中,临时关闭指定的私人 DNS,再重跑同一组测试;不同厂商菜单名称可能不同。确认客户端已获得 VPN 授权,且分应用代理没有排除测试浏览器。Android 通常只能同时运行一个普通 VPN 服务,另一个 VPN 或本地过滤工具可能占用这条路径。
Chrome 桌面版常见路径为“设置”→“隐私和安全”→“安全”→“使用安全 DNS”。关闭它只是用于定位变量,测试结束后可以恢复,再核对该 DoH 连接的实际出口。保留浏览器 DoH 不一定构成泄漏,关键是它是否符合你的解析与路由策略。
七、fake-ip 已生效,仍有异常时检查这四项
- IPv6 走了另一条路:
dns.ipv6: false控制内核 DNS 对 AAAA 查询的处理,不等于关闭系统 IPv6。应用缓存、自带解析器或已有 IPv6 地址仍可能建立连接,应核对 IPv6 路由与 TUN 覆盖范围。 - 订阅更新覆盖了手工修改:重新加载后检查运行中的有效配置,而不只是编辑器里的文件。需要长期保留的字段应通过客户端支持的覆写、合并或持久化配置机制管理。
- 过滤列表过大:把大量公共域名加入
fake-ip-filter会让它们返回真实地址,但不会自动修正解析出口。只为确实存在兼容问题的域名添加例外,每次添加后复测。 - 缓存与旧连接残留:系统缓存、浏览器缓存、内核映射和已建立连接各有生命周期。重载后先关闭测试标签页,必要时重启浏览器,再执行新的检测,不要拿旧连接给新配置打分。
最后用一张验收清单收口
- 定向查询
127.0.0.1:1053有响应,普通测试域名能得到预期的 fake-ip 映射。 - 系统默认解析与实际浏览器测试均已检查,不只是测试过内核端口。
- DNS 上游的出口与规则一致,节点域名和启动解析的例外已明确记录。
- 分别检查普通 DNS、浏览器 DoH、IPv6 与分应用排除项,没有把 53 端口劫持当成全协议接管。
- 订阅更新、客户端重启以及 Wi-Fi 切换后重新测试,结果仍符合既定策略。
排查顺序可以压缩成三句话:先证明查询进入内核,再证明上游连接走对出口,最后证明常用应用没有另走一条路。fake-ip 解决域名映射,respect-rules 解决上游选路,系统 DNS 接管解决入口覆盖;三者分工明确,日志才不会变成猜谜游戏。