DNS 泄漏的判断边界
DNS 泄漏指域名查询没有遵循预期的解析路径。例如,浏览器访问通过代理出口建立连接,但域名查询仍发给本地网络运营商的递归解析器。网页能打开、出口 IP 已改变,都不能单独证明 DNS 请求也经过代理。
排查时需要分开看三个环节:应用把查询交给谁,Clash 内核选择哪个上游,以及连接上游的流量走哪条线路。fake-ip 主要改变内核返回给应用的地址;nameserver-policy 选择解析器;respect-rules 决定解析器连接是否遵循路由规则。它们解决的是不同问题。
| 看到的现象 | 能说明什么 | 不能直接推断什么 |
|---|---|---|
| 网页出口 IP 是代理服务器 | 这次网页连接使用了代理 | 系统 DNS、其他应用也都走代理 |
| 查询返回 198.18.0.0/16 内的地址 | 该次查询可能由 Fake-IP 映射处理 | 上游 DNS 连接一定经过代理 |
| 测试页列出某公共 DNS 服务商 | 测试域名由该服务商的解析基础设施处理 | 本机到解析器之间一定加密或一定走代理 |
| 日志显示 DNS 上游连接命中代理策略 | 该条上游连接按指定策略路由 | 浏览器自带 DoH 也经过内核 DNS 模块 |
检测顺序:系统查询、内核查询与浏览器查询
第一步:记录当前状态
先记录当前网络、客户端模式、是否启用系统代理、是否启用 TUN,以及浏览器是否开启安全 DNS。测试期间固定一个代理节点,暂时避免自动策略组切换,否则两次结果可能来自不同出口。不要把公司 VPN、其他代理客户端与本次测试同时运行。
- Windows:在 PowerShell 执行
Get-DnsClientServerAddress,记录正在使用的网卡与 DNS 地址。 - macOS:执行
scutil --dns,查看默认与按域名划分的解析器;系统可能同时存在多组 resolver。 - 使用 systemd-resolved 的 Linux:执行
resolvectl status,检查每条链路的 DNS,而不只查看/etc/resolv.conf。
网卡显示路由器地址并不必然代表发生泄漏。启用 TUN 后,发往该地址的 53 端口查询可能被内核接管;反过来,网卡显示公共 DNS 地址,也不代表查询已加密。需要继续确认实际连接。
第二步:直接询问内核监听端口
下文示例将内核 DNS 监听在 127.0.0.1:1053。应用配置成功后,执行以下命令。第一条适用于提供 nslookup 的系统,第二条适用于已经安装 dig 的环境。
nslookup -port=1053 example.com 127.0.0.1
dig @127.0.0.1 -p 1053 example.com A
在未命中 Fake-IP 过滤规则的情况下,A 查询预期获得所设地址池内的映射地址。这是预期判读,不是本文声称完成的实测结果。若出现超时,优先确认 DNS 模块已启用、配置已加载,以及 1053 端口没有被占用。不要立刻改动全部分流规则。
随后执行 nslookup example.com,比较系统默认查询与直接询问内核的结果。只开启系统代理时,两者不同很常见,因为命令行解析器通常不使用 HTTP 系统代理。启用 TUN 后再测试,才能判断系统查询是否被接管。
第三步:检查浏览器独立解析
Chrome 可在「设置」→「隐私和安全」→「安全」→「使用安全 DNS」检查 DoH 设置。菜单文字可能随版本略有调整。首次排查可暂时关闭该功能,让浏览器走系统解析;完成基线测试后再恢复,并单独检查浏览器 DoH 连接的路由。
DNS 泄漏测试页通常通过随机子域名观察递归解析器。比较启用代理前后出现的解析服务商,并结合内核连接记录判断。解析器的地理位置不必与代理出口一致,公共 DNS 的 Anycast 与递归出口也可能分处不同位置;单看国家或城市容易误判。
Fake-IP 与 DNS 上游的配置示例
下面是可合并到 mihomo 配置的 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"
- "localhost"
respect-rules: true
default-nameserver:
- 223.5.5.5
- 119.29.29.29
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
nameserver:
- https://cloudflare-dns.com/dns-query
nameserver-policy:
"+.qq.com":
- https://dns.alidns.com/dns-query#DIRECT
"+.weixin.qq.com":
- https://dns.alidns.com/dns-query#DIRECT
字段作用与边界
listen仅绑定本机回环地址。这里的 1053 是示例监听端口,不会自动把操作系统 DNS 改为这个端口,也不适合直接提供给局域网设备。enhanced-mode: fake-ip为域名分配映射地址,便于后续连接保留域名信息并匹配规则。它本身不加密上游查询。fake-ip-filter中的域名不按通常的 Fake-IP 映射方式返回结果。过滤条目不是直连路由规则,不能用它代替rules。ipv6: false用于缩小本次 DNS 排查范围,不代表关闭系统 IPv6,也不能阻止应用访问已有的 IPv6 地址。proxy-server-nameserver专门解析代理节点的域名,避免解析节点地址时又依赖该节点建立连接。节点解析属于需要单独审视的引导路径。
这里保留明确的引导路径,是为了让首次加载更容易定位故障。若所在网络无法访问所选解析服务,应换成实际可达的上游,并重新验证路由。DoH 只能保护本机到解析服务之间的 DNS 传输内容;直连 DoH 仍会向网络暴露目标解析器地址。
nameserver-policy 与 respect-rules 的配合
先选解析器,再确定连接出口
nameserver-policy 按查询域名选择上游,而不是决定网站连接走哪个节点。示例将 qq.com 及其子域名交给指定的国内解析器,并通过 #DIRECT 明确该解析器连接使用直连。weixin.qq.com 条目在这里属于重复覆盖,保留它是为了展示细分域名写法;没有不同需求时可以删除。
其余查询交给 cloudflare-dns.com。开启 respect-rules 后,上游 DNS 连接遵循路由规则,但“遵循规则”不等于“自动走代理”:如果对应域名最终命中 DIRECT,DoH 仍会直连。
假设现有配置中已经有名为「代理」的策略组,并且该组当前选择了可用代理节点,可把下面两条规则放在较宽泛的直连规则与最终 MATCH 之前。配置中的组名必须与实际名称一致;若现有组叫「节点选择」,请同步修改引用。
rules:
- DOMAIN,dns.alidns.com,DIRECT
- DOMAIN,cloudflare-dns.com,代理
# 其后保留现有分流规则和最终 MATCH 规则
这段只展示应合并的位置,不是完整的 rules 替换内容。不要为了复制两条规则而删除订阅中的其余规则。代理组若允许选择 DIRECT,也要核对当前选中项,否则规则名称看似正确,实际出口仍可能是直连。
避免解析依赖循环
常见循环是:解析 DoH 服务域名需要代理,而代理服务器域名又需要同一个尚未建立的 DoH 连接。症状通常是启动后大量解析超时,节点连接也无法建立。示例把节点域名交给 proxy-server-nameserver,并让其上游连接直连,以分开这两条依赖。
- 节点使用域名时,先确认节点域名能通过独立解析路径得到地址。
- 节点使用 IP 时,不需要解析节点主机名,但 DoH 服务的引导解析仍可能存在。
- 不要把所有引导解析器也强制指向尚未可用的代理链,再期待自动恢复。
- 每次只修改一种依赖,保存后检查配置加载结果,再检查连接日志。
TUN 模式接管系统 DNS
系统代理主要影响遵循系统代理设置的应用,并不自动接管操作系统发出的 UDP DNS 查询。需要让更多应用的普通 DNS 请求进入内核时,可启用客户端的 TUN 功能。桌面系统通常需要相应权限、服务或虚拟网卡支持;应优先使用客户端提供的开关,避免界面设置与文件配置互相覆盖。
以下为 mihomo 的 TUN 合并示例。若客户端已经生成 tun 段,先查看最终生效配置,再决定是否修改。
tun:
enable: true
stack: system
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
any:53 用于接管进入 TUN 的 UDP 53 查询,第二项覆盖 TCP 53。关键限制是“进入 TUN”:路由排除、其他 VPN、虚拟机网络与平台限制,都可能使部分流量绕开这条路径。对于局域网 DNS 地址,尤其要用实际查询验证接管情况。
DoH 通常使用 HTTPS 的 443 端口,DoT 通常使用 853 端口,它们不会因为配置了 53 端口劫持就自动进入内核 DNS 模块。TUN 可以按路由接管这些网络连接,但无法仅凭端口 53 设置替换其内部查询。Android 的「私人 DNS」与浏览器安全 DNS也应分别核对。
修改后的验收与故障回滚
按相同条件复测
- 确认配置加载成功。若提示未知字段或策略组不存在,先修复配置,不要继续浏览器测试。
- 固定节点,直接查询
127.0.0.1:1053,确认 DNS 模块有响应。 - 启用 TUN 后查询系统默认 DNS,同时观察内核 DNS 日志与连接记录。
- 访问新的域名,确认
cloudflare-dns.com的上游连接命中预期代理组,而不是只看网页连接。 - 重新运行浏览器 DNS 测试,最后恢复安全 DNS 等原有设置,再测试一次,记录差异。
Windows 可用 ipconfig /flushdns 清理系统 DNS 缓存;使用 systemd-resolved 的 Linux 可用 resolvectl flush-caches。浏览器与内核可能还有各自的缓存,必要时重启浏览器并重新加载配置。Fake-IP 映射可能持久化,出现旧地址不能单独作为配置未生效的证据。
| 故障 | 优先检查 | 处理顺序 |
|---|---|---|
| 内核 DNS 查询超时 | 1053 监听、配置加载、端口冲突 | 先恢复本机 DNS 响应,再检查上游 |
| Fake-IP 正常但网页打不开 | 代理节点、映射连接是否回到内核、TUN 路由 | 确认连接接管,再检查代理可达性 |
| 测试页仍出现本地解析器 | 浏览器 DoH、系统旁路查询、其他网卡 | 区分应用来源,再检查对应路径 |
| 启用 respect-rules 后节点全超时 | 节点域名解析与 DoH 路由依赖 | 恢复独立节点解析,再逐条启用规则 |
| 局域网设备名称失效 | 本地域名后缀、mDNS、局域网解析器 | 为实际本地域名设计解析策略,不泛化直连全部域名 |
回滚时先恢复保存的 DNS 与规则配置,再关闭本次新增的 TUN 设置,最后核对操作系统代理和网卡 DNS 是否仍为测试值。不要直接删除整个客户端数据目录;这会同时丢失订阅、自定义规则与日志,反而减少可用于定位问题的信息。
常见问题
启用 Fake-IP 后,为什么测试页仍显示运营商 DNS?
可能是浏览器使用独立解析器,也可能是内核上游仍按直连规则发送查询。Fake-IP 只证明地址映射机制参与了某次解析,不能证明全部 DNS 流量都走代理。分别检查浏览器设置、上游连接和引导解析。
把 nameserver 全部换成 DoH 就够了吗?
不够。DoH 解决查询传输加密问题,代理出口由路由决定;系统或应用还可能完全绕过内核。需要同时验证请求接管、上游选择、路由规则与节点解析依赖。
保留国内域名直连解析,是否一定算泄漏?
应按预先定义的目标判断。若策略明确允许这些域名通过指定的直连解析器查询,这属于有意分流;若目标要求所有查询均经代理,这种配置就不符合目标。先写清允许的例外,再用日志验证,比追求测试页中只出现一个地址更可靠。
订阅更新后设置消失,应该修改哪里?
不要长期直接编辑会被远程订阅覆盖的原始文件。使用客户端支持的本地覆写、合并配置或脚本机制,具体入口随客户端版本而异。更新订阅后检查最终生效的 DNS、TUN 与规则顺序,而不是只查看覆写文件是否保存。