先区分三条路径:接管、解析与连接
“启用了 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:
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:
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:
respect-rules: true
proxy-server-nameserver:
- https://dns.alidns.com/dns-query
这段是增量片段,不要用它替换整个 DNS 配置。保留前面用于引导的 default-nameserver、常规上游与其他设置,并确保节点域名解析所用的上游本身可以在启动阶段连通。给节点配置解析器,不等于给所有业务域名配置了解析器。
- 先确认代理节点可连接,规则引用的策略组名称确实存在。
- 检查 DNS 服务域名或目标 IP 命中了什么规则。规则若将该上游送到不可达路径,开启此项只会让失败更稳定。
- 观察日志中上游连接的出站选择,再测试网站连接;不要仅凭节点延迟图标判断 DNS 已经正常。
TUN 下的 dns-hijack:接住进入虚拟网卡的 53 端口流量
仅设置 dns.enable: true 不会替操作系统修改全部解析路径。TUN 模式中,可用 dns-hijack 将进入 TUN、且符合目标条件的 DNS 流量交给内核。下面是一份可合并到现有 mihomo 配置的基础片段;原有节点、策略组与规则仍需保留。
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 实现还可能有各自限制;判断接管是否生效,必须观察实际请求。
用命令拆分验证:先监听,再接管,最后看上游
第一步:检查配置和本机监听
编辑前备份现有配置。独立运行内核时,可以先用以下命令检查配置;图形客户端则使用它实际调用的内核与工作目录,避免检测了另一份同名文件。
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 接管
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 行,那一行可能仍显示程序原本指定的目标。
第三步:确认真实解析和网站连接
- 临时提高日志级别至
debug,保留一次问题请求的域名、错误信息和上游地址;分享日志前隐藏订阅地址与节点凭据。 - 清理客户端 DNS 缓存,或重启内核后测试尚未查询的域名。Windows 系统缓存可用
ipconfig /flushdns清理,但这不会同时清空浏览器及内核缓存。 - 需要观察真实回答时,可在受控测试中临时使用
enhanced-mode: redir-host,重启后再次查询;测试结束恢复原配置,避免应用残留的旧 fake-ip 映射干扰判断。 - 最后访问网站并检查连接规则。DNS 返回成功而 HTTPS 超时,应继续查代理出口、连接路由、TLS 与 MTU,不要反复更换解析器。
本文命令是复现与定位步骤,不包含针对某个网络的延迟实测。比较性能时,应在同一网络分别记录冷缓存与热缓存结果;只拿第二次查询的耗时作比较,测到的往往是缓存有多勤快。
常见故障对照与回退顺序
| 现象 | 优先检查 | 处理方向 |
|---|---|---|
| 本机 1053 查询超时 | 配置加载、端口占用、内核日志 | 先恢复监听,再查上游 |
| 1053 正常,应用仍用系统 DNS | TUN 授权、路由、浏览器安全 DNS | 验证请求是否进入接管范围 |
| 开启 respect-rules 后全部超时 | 节点域名解析与 DNS 上游的出站规则 | 补齐独立的节点解析路径 |
| 只有部分域名异常 | 策略命中、fallback 条件、缓存 | 逐个域名验证,不同时改整段配置 |
| 订阅更新后故障复发 | 最终生效配置与覆写合并结果 | 将修改放入可保留的覆写入口 |
回退时先恢复到“一个可达上游、关闭复杂筛选”的状态,确认常规解析;再开启 TUN 接管,最后增加 fallback 和按规则选路。每一步都保留一次配置与查询结果。字段越多不代表解析越稳,能解释每条请求为何走到某个上游,才算配置真正可维护。