进阶配置 预计阅读 12 分钟

Mihomo DNS 配置详解:nameserver、fallback 与 DNS 劫持的写法

逐项拆解 dns 段的 nameserver、fallback、fallback-filter 与 dns-hijack,说明 fake-ip 与 redir-host 的取舍,并给出可直接改用的 YAML 示例。

DNS 配置的三层关系:入口、解析与连接

排查 Clash Meta(mihomo)的 DNS 问题,先把三个动作分开:应用把查询交给谁,内核向哪个上游查询,以及取得结果后连接走哪条规则。网页打不开,可能出在其中任意一层。只更换 nameserver,不能修复系统没有把 DNS 请求交给内核的问题。

  • 入口:dns.listen 开放内核 DNS 监听端口;TUN 下的 dns-hijack 接管符合条件的 DNS 流量。
  • 解析:nameserver、fallback 和 nameserver-policy 决定查询上游与结果选择。
  • 连接:应用得到地址后发起连接,内核再按照代理模式、规则与策略组处理流量。

系统 HTTP 代理通常不会自动接管所有应用的 DNS。浏览器自己的安全 DNS、Android 私人 DNS、应用内置的 DoH,也可能走独立通道。因此,“系统代理已打开”和“所有解析都经过 Mihomo”不是同一个判断。

nameserver 与 default-nameserver:上游和引导解析

nameserver 是常规域名查询使用的上游列表。裸 IP 地址通常表示普通 DNS;https:// 表示 DoH,tls:// 表示 DoT。普通 DNS 常用端口是 53,DoT 默认使用 853,DoH 一般使用 HTTPS 的 443 端口。

当上游写成 https://dns.alidns.com/dns-query 时,内核需要先知道 dns.alidns.com 的地址。default-nameserver 用于解析 DNS 服务器自身的域名,属于引导解析,不是“所有查询优先使用的默认服务器”。用 IP 地址填写这一项,可以避免在起点再次依赖一个尚未解析的域名。

字段用途常见误解
listen设置本机 DNS 监听地址与端口写入后系统就会自动使用它
default-nameserver解析 DNS 上游的域名它是所有域名的首选解析器
nameserver处理常规解析请求多个地址一定按列表顺序逐个尝试
proxy-server-nameserver专门解析代理节点的域名它负责所有经代理访问的网站
nameserver-policy为匹配的域名指定解析上游它直接决定网站连接走哪个节点

代理节点本身如果使用域名,也有解析依赖。可以通过 proxy-server-nameserver 单独提供可达上游,减少“必须先连接代理才能解析代理地址”的循环。它与网站连接的规则分流是两件事,不能互相替代。

fallback 与 fallback-filter:并行查询后的结果选择

fallback 不宜理解成传统的“主 DNS 超时后才启动的备用地址”。在需要结合 fallback 进行结果选择的常规解析路径中,内核会向相关上游并发查询,再依据过滤条件判断是否采用 fallback 的结果。因此,加入 fallback 可能让同一次域名查询到达两组解析服务。

三个常用过滤条件

  • geoip:启用基于地址所属地区的判断;配合 geoip-code 指定地区代码。例如设为 CN 时,常规结果不符合该地区条件会触发 fallback 选择。该判断依赖 GeoIP 数据。
  • ipcidr:常规结果落入列出的地址段时,改用 fallback。它针对地址范围,不是域名匹配规则。
  • domain:匹配的域名直接使用 fallback 结果。示例中的 +.github.com 表示根域名及其子域名。

下面的完整 DNS 片段显式设置 geoip: false,只演示地址段与域名条件,避免把 GeoIP 数据更新问题混入首次配置。0.0.0.0/8 与 240.0.0.0/4 用作异常结果过滤示例,不构成完整的污染地址清单,也不能识别所有错误解析。

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-mode: blacklist
  fake-ip-filter:
    - localhost
    - "+.lan"
    - "+.local"

  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29

  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query

  nameserver:
    - https://dns.alidns.com/dns-query

  fallback:
    - https://cloudflare-dns.com/dns-query

  fallback-filter:
    geoip: false
    ipcidr:
      - 0.0.0.0/8
      - 240.0.0.0/4
    domain:
      - "+.github.com"

这个例子要求所列上游在当前网络与路由条件下可达。DoH 使用加密传输,但加密不等于自动经代理;上游连接实际走向仍由相关配置决定。若网络无法连接某个上游,先换成已确认可达的服务,不要一次叠加多组未知地址。

fake-ip 与 redir-host:返回给应用的地址不同

enhanced-mode: fake-ip 会为适用的 DNS 查询返回映射地址。应用向该地址连接时,内核利用映射找回域名,再进行规则处理。上例的 198.18.0.1/16 位于用于基准测试的地址范围中;看到该范围的回答,不应立即认定 DNS 被污染。

redir-host 则向应用返回真实解析地址,再通过域名与地址的关联辅助处理连接。它更接近传统 DNS 行为,但在共享 IP、多域名指向同一地址或应用使用缓存的场景中,域名关联可能不如 fake-ip 直接。

项目fake-ipredir-host
应用看到的地址通常为映射地址,过滤项除外上游返回的真实地址
适合优先验证的场景TUN 接管与基于域名的规则分流应用必须取得真实地址的兼容场景
重点检查连接是否也回到持有映射的内核DNS 与连接是否保持可关联

过滤列表只改变地址返回方式

示例中的 fake-ip-filter-mode: blacklist 表示列表匹配项不返回 fake-ip。给局域网后缀添加过滤,可以避免向这些名称返回映射地址,但不保证名称一定能解析。.local 通常涉及 mDNS;局域网设备也可能只登记在路由器 DNS 中,公共 DNS 并不知道它们。

因此,NAS 名称仍解析失败时,应先确认它依赖 mDNS 还是路由器 DNS,再决定是否增加局域网解析策略。不要把所有域名加入过滤来回避问题。切换两种模式后,还应清理旧 DNS 缓存并重建连接,避免应用继续使用上一次得到的地址。

TUN 的 dns-hijack:接管 53 端口查询

dns-hijack 位于顶层 tun 段中,不在 dns 段内。下面片段用于桌面端支持相应 TUN 配置的客户端。它需要 TUN 创建权限;客户端界面也可能通过服务模式或权限辅助程序管理这些设置。

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 的普通 DNS 查询。
  • auto-route 用于自动设置相关路由,但能否覆盖某个应用仍受系统路由与客户端实现影响。
  • auto-detect-interface 用于自动检测出口接口,多网卡或特殊路由环境需要额外核对实际出口。

这里的“any”不代表可以截获网络上的全部 DNS。只有进入接管路径的流量才有机会被处理;它也不会把浏览器通过 HTTPS 443 端口发送的 DoH 自动转换成普通 DNS。DoT 的 853 端口同样不在以上两个匹配项内。

上例 DNS 监听在 127.0.0.1:1053,适合本机测试。普通系统 DNS 设置界面往往只接受地址、不接受自定义端口,直接填写 127.0.0.1 会查询 53 端口,而不是 1053。TUN 内部 DNS 劫持与手工设置系统 DNS 是两条入口,不要混为一谈。

按顺序验证:监听、上游、接管与规则

第一步:确认最终配置和监听端口

重新载入配置后,先查看客户端日志是否有 YAML 解析失败、字段不支持或端口绑定失败。重点核对最终配置中的 dns.enable、listen 与 enhanced-mode。不同客户端的菜单名称不同,应寻找实际的运行配置或配置预览,而不是仅查看订阅原文。

macOS、Linux 或安装了 dig 的环境,可直接向 1053 端口发起查询。第一条测试 UDP,第二条测试 TCP;这是验证命令,不是预设的实测结果。

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

在 fake-ip 模式下,未被过滤的 A 查询通常返回映射范围内的地址。它只能说明当前 DNS 入口作出了回答,不能单独证明远端网页可访问。还要检查对应连接是否进入同一个内核,以及节点是否能建立连接。

第二步:区分上游不可达和入口未接管

  1. 指定 1053 查询也超时:先检查监听是否成功,再看上游连接错误。必要时临时只保留一个已确认可达的 nameserver,缩小变量。
  2. 指定 1053 有回答,应用仍使用其他 DNS:检查 TUN 是否启用、路由是否生效,以及浏览器安全 DNS是否另走通道。
  3. 域名能解析,网页仍打不开:检查连接日志里的规则命中、策略组选择和节点错误,不要继续盲目更换 DNS。
  4. 只有局域网名称失败:确认路由器 DNS 或 mDNS 的解析路径,检查是否需要局域网专用策略。

第三步:清理缓存后复测

Windows 可在终端执行 ipconfig /flushdns。macOS 可依次执行下面两条命令,第二条需要管理员授权。浏览器和应用可能还有自己的缓存,系统刷新后应关闭旧连接,再重新发起访问。

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

测试是否仍向非预期服务器发出 DNS 查询时,应同时观察系统、浏览器和内核的实际行为。仅看到 DoH 地址,或仅访问一次 DNS 检测网页,都不足以解释所有进程的解析路径。fallback 并发查询、浏览器独立 DoH 和系统后台请求,需要分开判断。

配置合并与后续调整

同一个 YAML 文件不要重复写两个顶层 dns: 或两个 tun:。重复键可能被解析器拒绝,也可能导致某一段覆盖另一段。应将示例字段合入现有段,并确认客户端的覆写顺序;订阅更新后再检查一次运行配置是否保留。

  • 先建立可用基线:确认单一上游可达、本机 1053 查询正常,再添加 fallback 和 TUN 接管。
  • 再处理特定域名:确定需要域名定向解析时,使用 nameserver-policy;需要连接分流时,修改 rules,两者分别验证。
  • 最后处理 IPv6:示例的 dns.ipv6: false 用于关闭 DNS 的 AAAA 回答,不等于关闭操作系统全部 IPv6,也不会阻止应用使用已有的 IPv6 地址。
  • 保留回退步骤:出现全局断网时,先关闭 TUN、恢复原有系统 DNS与代理设置,再加载备份,而不是继续叠加未知配置。

需要进一步核对规则和 TUN 的配置关系,可查阅DNS 配置手册与TUN 配置说明。排障的关键是每次只改变一层:先确认请求进入内核,再确认上游回答,最后检查连接规则。这样才能判断修改究竟解决了哪个问题。

下载Clash