先区分三条路径:接管、解析与连接

“启用了 DNS”并不等于“所有应用都使用了这份 DNS 配置”。mihomo 的 DNS 排障需要拆成三步:应用的查询是否进入内核,内核向哪个上游查询,以及解析后的连接由哪条代理规则处理。这三步分别出错,都可能表现为网页打不开,但修改同一个开关通常治不好三种问题。

  • 接管入口:dns.listen 提供 DNS 监听;TUN 下的 dns-hijack 将匹配的 DNS 流量转入内置解析器。
  • 上游选择:nameserver、nameserver-policy、fallback 等字段决定解析路径与结果选择。
  • 连接分流:rules 决定网站连接走直连还是代理;启用 respect-rules 后,DNS 上游连接也会按路由规则处理。

本文面向使用 mihomo 内核的客户端。原版 Clash、Premium 与不同年代的 Meta 内核并不支持完全相同的字段。先在客户端内核信息或启动日志中确认实际内核,再编辑当前生效配置;图形客户端自身的版本号不能代替内核版本。

default-nameserver:先解析 DNS 服务器自己的域名

当上游写成 https://dns.alidns.com/dns-query 时,内核需要先知道 dns.alidns.com 的 IP,才能建立 HTTPS 连接。default-nameserver 主要承担这一步引导解析,而不是“所有网站默认使用的 DNS”。两者只差几个字,排障方向却完全不同。

DNS 引导解析片段
dns:
  enable: true
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query

上面的两个 IP 用于引导解析。普通 IP 地址形式的 DNS 通常使用 UDP 53;它不会因为后面的上游是 DoH,就自动变成加密请求。若网络要求连引导查询也加密,需要选择当前内核支持、且不依赖另一次域名解析的 IP 形式加密端点,并确认该服务的证书与访问方式兼容。

nameserver 与 fallback:不是主服务器超时后才切备用

nameserver 提供常规解析结果

nameserver 是未被更具体 DNS 策略覆盖时使用的主要上游集合。配置多个地址可以提高容错,但不要将列表顺序理解成严格的“第一个失败才查第二个”。内核可能并发查询,DNS 缓存也会让本次请求根本不访问上游。

DoH 的 HTTPS 连接通常使用 TCP 443,DoT 通常使用 TCP 853;加密协议解决的是查询链路保护,不直接决定连接走哪个代理节点。一个 DoH 地址能在浏览器里打开,也不能证明 mihomo 在当前路由、证书与代理配置下能访问它。

fallback 配合结果筛选工作

fallback 不宜理解为仅在网络超时后启用的传统备用服务器。配置它之后,内核会结合 fallback-filter 对结果进行选择,相关查询可能并行进行。排障时看到两个上游都收到了查询,并不表示配置被读取了两遍。

字段主要职责不应误认为
default-nameserver引导解析 DNS 上游的主机名全部网站的默认上游
nameserver常规域名解析严格顺序执行的列表
fallback提供供筛选使用的另一组结果仅超时才查询的备机
fallback-filter控制何时选用 fallback 结果代理规则或防火墙规则
dns-hijack在 TUN 路径内接管匹配的 DNS 流量解密应用私有 DoH 的开关

fallback-filter:按地域、地址和域名筛选

下面采用国内上游与另一组公共 DoH 的组合演示筛选逻辑。它适合解释字段,不代表每个网络都能直连所有端点。若备用上游不可达,先解决它的连通性或路由,再讨论返回结果是否可信。

合并到现有 dns 段
dns:
  enable: true
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  fallback:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
  fallback-filter:
    geoip: true
    geoip-code: CN
    ipcidr:
      - 240.0.0.0/4
    domain:
      - '+.google.com'
  • geoip: true 与 geoip-code: CN:通常可理解为主要上游返回的地址若不属于指定地域,则倾向采用 fallback 结果;该判断依赖内核所用的 GeoIP 数据。
  • ipcidr:主要上游返回的地址若命中所列网段,触发 fallback 结果选择。示例中的 240.0.0.0/4 是保留地址范围,不是完整的异常地址清单。
  • domain:命中的域名直接使用 fallback 路径。示例的 +.google.com 覆盖该域及子域,写成带引号的字符串可减少 YAML 解析歧义。

地域筛选是一种策略,不是污染检测的数学证明。海外域名也可能使用境内 CDN,境内业务也可能返回境外地址;GeoIP 数据过旧还会导致误判。若目标只是为几个已知域名指定解析器,使用 nameserver-policy 往往比堆叠复杂的地域条件更直接。命中该类策略后,也不要再假定它必然经过这里的通用 fallback 流程。

如果不需要地域判断,可以显式设置 geoip: false,再只保留确有依据的域名与地址条件。不要为了消除一条超时日志,随意加入大段私网地址过滤;内网站点返回私网 IP 本来就是正确结果。

respect-rules:让 DNS 上游连接按规则走

respect-rules: true 处理的是“内核连接 DNS 上游时如何选路”,不是“是否启用域名规则”。开启前应准备 proxy-server-nameserver,用来解析代理节点自身的域名,避免出现“解析节点需要代理,建立代理又需要解析节点”的循环依赖。

在现有 dns 映射中追加或修改
dns:
  respect-rules: true
  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query

这段是增量片段,不要用它替换整个 DNS 配置。保留前面用于引导的 default-nameserver、常规上游与其他设置,并确保节点域名解析所用的上游本身可以在启动阶段连通。给节点配置解析器,不等于给所有业务域名配置了解析器。

  1. 先确认代理节点可连接,规则引用的策略组名称确实存在。
  2. 检查 DNS 服务域名或目标 IP 命中了什么规则。规则若将该上游送到不可达路径,开启此项只会让失败更稳定。
  3. 观察日志中上游连接的出站选择,再测试网站连接;不要仅凭节点延迟图标判断 DNS 已经正常。

TUN 下的 dns-hijack:接住进入虚拟网卡的 53 端口流量

仅设置 dns.enable: true 不会替操作系统修改全部解析路径。TUN 模式中,可用 dns-hijack 将进入 TUN、且符合目标条件的 DNS 流量交给内核。下面是一份可合并到现有 mihomo 配置的基础片段;原有节点、策略组与规则仍需保留。

TUN 与 fake-ip 基础片段
dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53
    - tcp://any:53

any:53 用于 UDP DNS,tcp://any:53 补充 TCP DNS。目标端口不必先改成本机的 1053;接管动作会将符合条件的流量送入内置 DNS。listen 则是可供显式查询的独立监听入口,保留环回地址可避免无意对局域网开放解析服务。

198.18.0.1/16 在这里用于 fake-ip 映射。查询返回该范围中的合成地址属于预期行为,不代表上游真的返回了这个地址。内核借助映射还原域名并进行后续连接处理;若某个应用必须拿到真实 IP,需要按应用场景考虑 fake-ip-filter,而不是把整个保留地址段当成 DNS 故障。

  • 桌面端:TUN 通常需要管理员权限、服务模式或相应网络权限,具体取决于客户端和系统。
  • Android:VPN 授权与其他 VPN 应用可能冲突,系统“私人 DNS”也可能改变解析路径。
  • 浏览器:自带安全 DNS 通过 HTTPS 发往 443,不能指望 53 端口接管自动覆盖。
  • 局域网与 IPv6:未进入 TUN 的流量、被路由排除的地址以及其他接口路径,都需要单独确认。

示例的 dns.ipv6: false 控制 DNS 对 AAAA 查询的处理,不等于关闭操作系统 IPv6,更不是完整的 IPv6 防绕行方案。Linux 的本地解析服务、macOS 的局域网解析路径,以及 Android 的 VPN 实现还可能有各自限制;判断接管是否生效,必须观察实际请求。

用命令拆分验证:先监听,再接管,最后看上游

第一步:检查配置和本机监听

编辑前备份现有配置。独立运行内核时,可以先用以下命令检查配置;图形客户端则使用它实际调用的内核与工作目录,避免检测了另一份同名文件。

终端:配置检查与显式 DNS 查询
mihomo -t -f config.yaml

dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com A +tcp

前两条查询分别验证 1053 监听的 UDP 与 TCP 路径。没有 dig 的 Windows 环境可运行 nslookup -port=1053 example.com 127.0.0.1。返回 fake-ip 只能证明请求进入了解析器并得到映射,不能单独证明指定 DoH 已成功返回真实 IP。

第二步:验证 53 端口是否被 TUN 接管

终端:对比 UDP 与 TCP 接管
dig @8.8.8.8 example.com A
dig @8.8.8.8 example.com A +tcp

这里显式指定的 8.8.8.8 是测试目标;若请求被 TUN 接管,它不一定是实际收到查询的上游。结合内核日志与 fake-ip 返回结果判断,不能只看 dig 输出中的 SERVER 行,那一行可能仍显示程序原本指定的目标。

第三步:确认真实解析和网站连接

  1. 临时提高日志级别至 debug,保留一次问题请求的域名、错误信息和上游地址;分享日志前隐藏订阅地址与节点凭据。
  2. 清理客户端 DNS 缓存,或重启内核后测试尚未查询的域名。Windows 系统缓存可用 ipconfig /flushdns 清理,但这不会同时清空浏览器及内核缓存。
  3. 需要观察真实回答时,可在受控测试中临时使用 enhanced-mode: redir-host,重启后再次查询;测试结束恢复原配置,避免应用残留的旧 fake-ip 映射干扰判断。
  4. 最后访问网站并检查连接规则。DNS 返回成功而 HTTPS 超时,应继续查代理出口、连接路由、TLS 与 MTU,不要反复更换解析器。

本文命令是复现与定位步骤,不包含针对某个网络的延迟实测。比较性能时,应在同一网络分别记录冷缓存与热缓存结果;只拿第二次查询的耗时作比较,测到的往往是缓存有多勤快。

常见故障对照与回退顺序

现象优先检查处理方向
本机 1053 查询超时配置加载、端口占用、内核日志先恢复监听,再查上游
1053 正常,应用仍用系统 DNSTUN 授权、路由、浏览器安全 DNS验证请求是否进入接管范围
开启 respect-rules 后全部超时节点域名解析与 DNS 上游的出站规则补齐独立的节点解析路径
只有部分域名异常策略命中、fallback 条件、缓存逐个域名验证,不同时改整段配置
订阅更新后故障复发最终生效配置与覆写合并结果将修改放入可保留的覆写入口

回退时先恢复到“一个可达上游、关闭复杂筛选”的状态,确认常规解析;再开启 TUN 接管,最后增加 fallback 和按规则选路。每一步都保留一次配置与查询结果。字段越多不代表解析越稳,能解释每条请求为何走到某个上游,才算配置真正可维护。