先分清 DNS 解析、规则分流与流量接管

Clash 的 DNS 配置负责把域名转换为地址,或在 Fake-IP 模式下建立域名与虚拟地址的映射。规则决定连接走哪个策略;系统代理与 TUN 决定哪些连接能进入内核。这三层互相关联,但不能互相代替:填入公共 DNS 地址,不等于浏览器请求已经走代理;开启 TUN,也不等于所有加密 DNS 都会被接管。

本文以 Clash Meta 后续发展的 mihomo 内核为主要说明对象。传统 Clash 与不同客户端所支持的字段并不完全一致,尤其是 tun、proxy-server-nameserver 等配置。排查前先在客户端的「关于」或内核信息页面记录实际内核名称和版本,不要只看客户端产品名称。

  • DNS 请求入口:应用、系统解析器或 TUN 接管的 53 端口流量。
  • DNS 上游:nameserver、fallback 等列表中配置的解析服务。
  • 业务连接出口:由 rules 与代理策略决定,不由 DNS 服务器所在地区直接决定。

dns 配置块:从可验证的最小示例开始

调试时建议先使用 redir-host 观察真实地址,确认上游可达后再按需要切换 Fake-IP。以下示例在本机 127.0.0.1:1053 提供 DNS 服务;1053 是示例监听端口,不是要求所有客户端统一修改的默认值。

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: redir-host
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
  fallback:
    - https://1.1.1.1/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4
字段示例含义排查重点
enable启用内核 DNS 模块启动日志中是否出现 DNS 初始化错误
listen在回环地址的 1053 端口监听是否被占用,测试请求是否指定正确端口
ipv6本例不返回 AAAA 地址这不等于关闭操作系统的 IPv6 网络
enhanced-mode使用真实地址解析模式Fake-IP 模式下返回虚拟地址是正常现象
default-nameserver引导解析上游 DNS 的主机名引导解析器本身是否可达

listen: 127.0.0.1:1053 只接受本机访问,适合桌面调试。改成 0.0.0.0:1053 会扩大监听范围;如果确实需要给局域网设备提供服务,还必须限制防火墙访问来源,避免把解析服务暴露给不受信任的网络。

default-nameserver 不是常规查询的“第三组备用服务器”。当上游写成 https://dns.alidns.com/dns-query 时,内核首先需要知道这个主机名对应的 IP。示例用数字地址完成引导,避免解析器依赖自身才能启动。普通 UDP 引导查询不具备 DoH 的传输加密属性,应结合所在网络的隐私与可达性要求选择。

nameserver 与 fallback:候选结果,不是简单主备

nameserver 提供常规解析结果

nameserver 是常规上游列表。没有单独配置域名策略时,普通查询由这组服务器处理。配置多个地址不表示按第一项、第二项严格依次尝试;内核可能并发向多个上游查询并选用可用结果,因此不要依靠排列顺序实现域名分流。

fallback 提供另一组候选结果

启用 fallback 后,不能把它理解成“只有 nameserver 超时才查询”。在典型的 nameserver/fallback 机制下,两组解析可以并行进行,最终结合 fallback-filter 决定采用哪组结果。这样可以减少需要换用另一组结果时的等待,但也意味着另一组服务可能收到查询。

是否走代理是另一回事。把 https://1.1.1.1/dns-query 写进 fallback,不会自动让这个 DoH 连接经过代理节点;实际出站受内核版本、DNS 上游指定方式及相关路由配置影响。如果当前网络无法连接该服务,应先解决可达性,而不是反复更换过滤条件。

  • 只想验证基础解析:先保留一组可达的 nameserver,暂时移除 fallback 及其过滤器。
  • 确实需要两组结果选择:再加入 fallback,并明确配置过滤条件。
  • 特定域名必须交给指定解析器:使用 nameserver-policy,不要靠列表顺序推测。

fallback-filter:geoip、ipcidr 与 domain 的判定

fallback-filter 判断的是何时应采用 fallback 结果。它不是防火墙规则,也不是给业务流量指定代理的规则。配置了 geoip-code: CN,并不代表中国大陆网站一定直连,更不代表其他地区的网站一定代理。

geoip:检查 nameserver 返回地址的归属

当 geoip: true、geoip-code: CN 时,通常保留归属为 CN 的 nameserver 结果;不符合该归属条件时,倾向采用 fallback 结果。判断依赖内核使用的 GeoIP 数据,而不是 DNS 服务商的地理位置。数据缺失、过旧或 CDN 地址归属变化,都可能影响结果。

ipcidr:为特定地址范围切换结果来源

示例中的 240.0.0.0/4 用于把命中该范围的 nameserver 结果交给 fallback 处理。这只是可疑地址范围示例,不能覆盖所有错误解析。不要直接把 192.168.0.0/16 等私网范围全部加入过滤器:企业内网、路由器后台和本地域名可能本来就应该返回私网地址。

domain:按域名强制使用 fallback

域名过滤条件与 IP 条件不同,它可以在域名层面指定采用 fallback。下面采用独立示例,关闭 GeoIP 判断,仅对保留示例域 example.com 及其子域应用该选择逻辑;实际部署时应填入确实需要此行为的域名。

dns:
  fallback-filter:
    geoip: false
    domain:
      - '+.example.com'

domain、ipcidr 与启用的 GeoIP 判断各自都可能触发 fallback,并不是要求三个条件同时成立。如果希望“只有这些域名使用另一组上游”,就应显式关闭不需要的 GeoIP 条件,并核对完整配置中是否还保留其他过滤项。

nameserver-policy 与节点域名:避免解析链路绕圈

局域网域名通常不适合发往公共解析服务。在 mihomo 中可以用 nameserver-policy 为特定域名指定上游。以下地址 192.168.1.1 仅适用于该地址确实是本地 DNS 服务的网络,不能在网关为 192.168.50.1 的环境中直接照用。

dns:
  nameserver-policy:
    '+.home.arpa':
      - 192.168.1.1
  proxy-server-nameserver:
    - 223.5.5.5
    - 119.29.29.29

home.arpa 是家庭网络使用的特殊域名空间。单独指定策略可以让它交给本地解析器,而不是依赖公共 fallback 猜测局域网记录。命中 policy 后会走相应的专用解析路径,因此不要再假设该域名仍然完全遵循通用 nameserver/fallback 的选择流程。

proxy-server-nameserver 用于解析代理节点服务器自身的域名。它与“通过哪个节点查询目标网站”不是同一个问题:如果 DoH 必须依赖代理连接,而代理节点的域名又只能依赖这个 DoH 解析,就会形成启动依赖环。为节点域名准备可达的独立解析路径,能够减少这种循环风险;具体字段支持情况应以实际 mihomo 版本为准。

切勿为了修复一个解析环而同时加入多组路由选项。先确认节点域名可以解析、节点出口可以建立,再决定是否让普通 DNS 遵循业务规则。修改后应查看客户端最终生成的运行配置,确认订阅覆写没有把新字段删除。

TUN 下 dns-hijack 的正确层级与协议写法

dns-hijack 属于顶层 tun 配置块,不属于 dns。它把符合条件、且已经进入 TUN 的 DNS 流量转给内核 DNS 模块。下面是 mihomo 的常见写法;启用前应确认客户端具备创建虚拟网卡与修改路由所需的权限。

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - 'any:53'
    - 'tcp://any:53'
  • any:53:匹配进入 TUN 的 UDP 53 端口 DNS 请求。
  • tcp://any:53:补充 TCP 53 端口,覆盖 TCP 查询及部分截断响应后的重试。
  • auto-route:自动配置相应路由;它不保证所有平台上的本地网络流量都进入 TUN。
  • auto-detect-interface:尝试识别出口接口;多网卡、其他 VPN 或复杂路由环境仍需检查实际出口。

dns-hijack 不是把系统 DNS 地址改成 127.0.0.1:1053,也不是要求把劫持目标改写成 1053。前者匹配原本发往 53 端口的请求;dns.listen 则是独立的 DNS 服务监听入口。两者作用不同,可以配合使用。

为什么开启劫持仍然看到其他 DNS 连接?

DoH 通常使用 HTTPS 443 端口,DoT 常用 TCP 853 端口,DoQ 常用 UDP 853 端口。这些不属于普通 53 端口 DNS,不能通过上述两条配置直接截获并解密。浏览器启用“安全 DNS”、Android 启用“私人 DNS”,或者应用内置解析器时,查询可能仍作为加密业务连接存在。

此外,发往同网段路由器的流量可能经物理接口直达,而未进入 TUN。需要结合平台路由和系统 DNS 地址确认接管路径,不能只凭开关亮起判断。若为了排查暂时关闭应用加密 DNS,应记录原设置,完成验证后按实际需求恢复。

用命令验证:先监听,再上游,最后检查接管

以下命令用于复现测试步骤,不代表某个网络环境的实测结果。先保留示例中的 redir-host,避免 Fake-IP 虚拟地址干扰对真实解析结果的判断。每次只调整一组字段,再重新加载配置。

第一步:直接请求内核 DNS 监听端口

在具备 dig 的 macOS 或 Linux 终端中,分别测试 UDP 与 TCP。Windows 可在安装了相应工具的环境中使用同样命令;系统自带 nslookup 也可以进入交互模式后设置端口。

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp
nslookup
server 127.0.0.1
set port=1053
set type=A
example.com
exit

若收到 NOERROR 且 ANSWER 中有 A 记录,说明该次查询完成了地址解析;SERVFAIL 表示解析链路处理失败,超时则还要检查监听、上游与防火墙。仅看到 NOERROR 但没有 A 记录,不能直接认定失败,域名也可能没有对应记录。

第二步:分离上游与过滤器问题

  1. 暂时移除 fallback,只保留一组 nameserver,重新查询同一域名。
  2. 将待测 fallback 服务临时作为唯一 nameserver,确认它自身能够完成解析。
  3. 恢复两组上游,再逐项启用 GeoIP、IP 范围或域名条件,观察变化。
  4. 结合日志中的上游连接错误、超时与配置加载错误定位,不要把所有异常都归为 DNS 污染。

第三步:验证 TUN,而不是再次验证监听端口

直接查询 127.0.0.1:1053 只能证明监听入口可用,不能证明 TUN 劫持成功。接管测试需要让系统或应用向普通 DNS 地址的 53 端口发起请求,同时观察内核日志与连接信息;有抓包条件时,再核对物理出口是否仍发出了原始查询。测试应排除浏览器 DoH,并注意本地缓存可能让查询根本不发生。

Windows 可用 ipconfig /flushdns 清理系统 DNS 缓存;macOS 可用 sudo dscacheutil -flushcache 与 sudo killall -HUP mDNSResponder。Linux 的缓存服务因发行版不同而异,使用 systemd-resolved 时可执行 resolvectl flush-caches。这些命令不会清除所有浏览器缓存,也不能代替客户端内部 DNS 缓存刷新。

常见现象与配置收尾

现象优先检查下一步操作
1053 端口查询超时DNS 模块未启用、端口冲突或上游不可达核对运行配置和启动日志,单独测试一组上游
返回 198.18 开头地址实际配置启用了 Fake-IP确认虚拟地址池与 TUN 路由,不要直接判为解析错误
局域网主机解析失败查询发往公共 DNS,或私网地址被过滤为内部域名设置本地解析策略,检查过滤列表
节点启用后所有域名超时节点域名与 DNS 出站形成依赖环单独验证节点域名解析和节点连接
TUN 已开但浏览器仍用其他解析器浏览器安全 DNS 或流量未进入 TUN分别核对加密 DNS、系统 DNS 与路由

配置收尾时,保留有明确用途的字段即可:nameserver 提供常规解析;fallback 配合过滤器选择另一组结果;nameserver-policy 处理特定域名;dns-hijack 接管已经进入 TUN 的传统 DNS 请求。最后检查订阅更新后的运行配置,并恢复调试过程中临时修改的浏览器、系统 DNS 与日志级别设置。能逐层验证的短配置,比不断叠加公共 DNS 地址更容易维护。