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-ip | redir-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 入口作出了回答,不能单独证明远端网页可访问。还要检查对应连接是否进入同一个内核,以及节点是否能建立连接。
第二步:区分上游不可达和入口未接管
- 指定 1053 查询也超时:先检查监听是否成功,再看上游连接错误。必要时临时只保留一个已确认可达的 nameserver,缩小变量。
- 指定 1053 有回答,应用仍使用其他 DNS:检查 TUN 是否启用、路由是否生效,以及浏览器安全 DNS是否另走通道。
- 域名能解析,网页仍打不开:检查连接日志里的规则命中、策略组选择和节点错误,不要继续盲目更换 DNS。
- 只有局域网名称失败:确认路由器 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 配置说明。排障的关键是每次只改变一层:先确认请求进入内核,再确认上游回答,最后检查连接规则。这样才能判断修改究竟解决了哪个问题。