把问题拆成一条链路:应用发起 DNS 查询,Mihomo 接住 53 端口或系统 DNS,请求进入内置 DNS,enhanced-mode: fake-ip 返回虚拟地址,连接再用映射表还原域名,最后进入规则匹配。网页打不开、内网服务失效、规则组命中反常,通常是这 5 段里断了一段。
这篇只讨论 Mihomo / Clash Meta 内核的 fake-ip DNS 排错,不讨论订阅格式、客户端 UI 按钮,也不把所有现象都归到“网络不通”。测试基线按官方文档里的字段写:tun.dns-hijack、dns.enhanced-mode、fake-ip-filter、profile.store-fake-ip、log-level: debug。
判断断在哪一段
先不要同时改 nameserver、规则集、TUN、系统 DNS。把现象归到下面一类,排查会快很多。
| 现象 | 更可能断点 | 看哪个字段 | 验证信号 |
|---|---|---|---|
| 浏览器打不开,命令行工具正常 | 浏览器 DoH 没走系统 DNS | Chrome / Firefox 安全 DNS 设置 | Mihomo 日志没有对应域名的 DNS 查询 |
| 所有域名都返回 198.18 段,但连接失败 | fake-ip 映射没有被连接阶段还原 | dns.enhanced-mode、profile.store-fake-ip | debug 日志有 DNS 分配,没有 connection rule match |
| 内网域名、NAS、打印机后台打不开 | 该域名被分配了 fake-ip | fake-ip-filter、fake-ip-filter-mode | *.lan、*.local 被返回真实内网地址 |
| 规则命中和预期不一致 | 连接只剩 IP,域名上下文丢了 | DNS 接管入口、sniffer 设置 | 日志能看到 rule match 用域名规则命中 |
| 重启后同一域名表现变了 | fake-ip 映射缓存丢失 | profile.store-fake-ip | 重启前后同域名映射变化被记录 |
官方 DNS 文档写明 enhanced-mode 可选 fake-ip 和 redir-host,默认是 redir-host。所以排查 fake-ip 时,第一件事是确认配置最终生效后的值,而不是只看模板里有没有写过。
fake-ip 映射到底怎么工作?
fake-ip 不是把域名解析成真实服务器地址。它会先从 fake-ip-range 里分配一个虚拟 IPv4,常见是 198.18.0.0/16 这类测试网段;应用随后连接这个虚拟地址,Mihomo 再通过映射表找回原始域名。
这一层映射解释了两个常见误判:
ping example.com看到 198.18 段不代表解析坏了,反而可能说明 fake-ip 已经生效。- 连接阶段如果没有进入 Mihomo,系统只会拿着 198.18 段直连,结果就是超时。
最小配置先长这样,排错时不要急着加入十几条上游 DNS:
profile:
store-fake-ip: true
log-level: info
tun:
enable: true
dns-hijack:
- any:53
- tcp://any:53
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://doh.pub/dns-query
- https://dns.alidns.com/dns-query
fake-ip-filter:
- +.lan
- +.local
- +.home.arpa
profile.store-fake-ip: true 的作用是把 fake-ip 映射表保存下来,下一次启动继续复用。排查“重启就坏”时,这个字段比反复换 DNS 更值得先看。
dns-hijack 没接住时会出现什么?
Mihomo TUN 文档里的 dns-hijack 示例是 any:53 和 tcp://any:53。没有写协议时默认按 UDP 处理,所以很多配置会同时写 UDP 和 TCP 53。
它的作用是把命中的 DNS 连接导入 Mihomo 内置 DNS。换句话说,dns.enhanced-mode: fake-ip 写得再正确,请求没有进来,也不会产生 fake-ip 映射。
| 场景 | dns-hijack 能否接住 | 排查动作 |
|---|---|---|
| 系统普通 UDP 53 查询 | 通常可以 | 看日志里是否出现域名查询 |
| TCP 53 查询 | 需要写 tcp://any:53 | 少写时补上 TCP 入口 |
| 浏览器内置 DoH | 通常接不住 | 关闭浏览器安全 DNS,或让浏览器使用系统 DNS |
| Android Private DNS | 文档提示会影响自动接管 | 关闭 Private DNS 后再测同一域名 |
| macOS / Windows 局域网 DNS | 文档提示不会自动捕获所有 LAN 查询 | 单独检查系统 DNS 和客户端接管方式 |
如果你在公司网络、公共 Wi-Fi 或多设备环境里维护同一份 Mihomo 配置,DNS 接管是否完整比“换一个规则组”更关键。订阅本身还要能给 Clash / Mihomo / sing-box 这类客户端导出兼容格式;不想手工改多份客户端配置时,可以把 兼容 Clash / Singbox / V2Ray 的订阅 作为同一配置链路的上游来源之一,再用本文的日志方法验收。
浏览器 DoH 为什么会让 Mihomo 看不见域名?
Chrome、Firefox、Edge 都可能启用浏览器级安全 DNS。它们直接向 DoH 服务器发 HTTPS 请求时,Mihomo 的 dns-hijack: any:53 看不到传统 DNS 包,也就没有机会返回 fake-ip。
判断方法很简单:同一个域名,用系统工具查,再用浏览器打开。
| 工具 | 期待看到什么 | 如果不符合 |
|---|---|---|
nslookup example.com 127.0.0.1 | 返回 fake-ip 或被过滤后的真实地址 | Mihomo DNS listen / 系统 DNS 没接上 |
浏览器访问 example.com | Mihomo 日志出现同域名 DNS 查询 | 浏览器可能启用了 DoH |
curl -v https://example.com | 日志有 DNS 和连接两段 | 如果 curl 正常、浏览器异常,优先查浏览器 DNS |
浏览器 DoH 排查不要只看页面错误码。更可靠的证据是:Mihomo debug 日志里有没有同一时间、同一域名的 DNS 查询记录。
fake-ip-filter 该放什么,不该放什么?
fake-ip-filter 的目标不是“越多越安全”,而是让不适合虚拟地址的域名返回真实地址。官方 DNS 文档还提供了 fake-ip-filter-mode:blacklist、whitelist、rule,默认是 blacklist。
常见过滤对象如下:
| 域名类型 | 建议 | 原因 |
|---|---|---|
+.lan、+.local、+.home.arpa | 放入 fake-ip-filter | 局域网发现和设备后台通常需要真实内网地址 |
| 路由器、NAS、打印机自定义域名 | 放入 fake-ip-filter | 避免后台被分配 198.18 段后无法连接 |
| 代理上游主机名 | 结合配置决定,异常时优先放入 | GitHub issue 2740 讨论过 fake-ip 与 sniffing 组合下的回环风险 |
| 普通网站域名 | 不建议大面积放入 | 过滤太宽会让规则分流失去域名接管优势 |
| 广告或遥测域名 | 交给规则处理 | 不要用 DNS 过滤代替规则集维护 |
如果你启用了 sniffer.override-destination: true,还要额外注意上游主机名。2026 年 4 月的 MetaCubeX/mihomo issue 2740 讨论过一种坑:代理上游主机名没有排除在 fake-ip 外,嗅探改写目标后又被解析成 fake-ip,可能造成连接回环。这个 issue 不是官方确认的通用故障,但足够作为排障提醒。
规则匹配为什么会被 DNS 影响?
规则模式依赖连接阶段拿到足够上下文。fake-ip 模式下,Mihomo通过映射表把 198.18.x.x 还原成原始域名,然后域名规则、GEOSITE、RuleSet 才有机会命中。
如果映射丢了,连接阶段只看到一个虚拟 IP,表现会变成:
- 域名规则没有命中,落到
MATCH。 DOMAIN-SUFFIX明明写了,日志却只显示 IP 规则。- 重启或热重载后,短时间内大量连接超时。
排查规则命中时,临时把日志拉到 debug:
log-level: debug
复现 30 到 60 秒就够了。debug 日志量很大,拿到证据后改回 info,否则桌面客户端和软路由都容易被日志刷屏。
cache 丢失时怎么确认?
fake-ip 的关键不是“某个域名永远对应同一个虚拟 IP”,而是连接发生时映射表还在。下面几类操作会让你误以为规则坏了:
| 操作 | 可能影响 | 记录什么 |
|---|---|---|
| 重启 Mihomo | 映射表重新加载或重建 | 重启前后同域名返回值 |
关闭 store-fake-ip | 历史映射不再持久化 | 配置变更时间和表现变化 |
| 热更新配置 | DNS 模块可能重载 | 更新前后 60 秒日志 |
| 清理客户端缓存 | 旧连接和新连接混杂 | 关闭浏览器全部进程后重测 |
保守做法是:先启用 profile.store-fake-ip: true,再做一次完整复现。若重启前后同域名的 fake-ip 不同,只要连接阶段仍能还原域名,规则命中就不该受影响;真正的问题是“连接阶段找不到映射”。
用哪些日志确认已经修好?
排查 fake-ip DNS,不要只看“网页能打开”。至少留 4 类证据。
level=debug msg="[DNS] query example.com A from 127.0.0.1"
level=debug msg="[DNS] example.com --> 198.18.0.23"
level=debug msg="[TCP] 198.18.0.23:443 --> example.com:443"
level=info msg="[Rule] DOMAIN-SUFFIX,example.com matched, proxy_group"
不同 Mihomo 前端的日志格式会略有差异,不要逐字匹配上面的示例。你要找的是四个信号:DNS 查询进来了、fake-ip 分配了、连接被还原成域名了、规则命中了。
| 只看到哪一段 | 说明什么 | 下一步 |
|---|---|---|
| 没有 DNS query | 请求没进 Mihomo | 查系统 DNS、浏览器 DoH、dns-hijack |
| 有 DNS query,没有 fake-ip | enhanced-mode 或 filter 生效方向不对 | 查 enhanced-mode、fake-ip-filter-mode |
| 有 fake-ip,没有连接还原 | 连接没进 Mihomo 或映射丢失 | 查 TUN、系统代理、store-fake-ip |
| 有连接还原,没有规则命中 | 规则写法或规则集加载问题 | 查 RuleSet、GEOSITE、MATCH 顺序 |
最后把 log-level 改回 info,保留出问题前后的 30 到 60 秒日志、配置片段和测试命令。下一次再遇到同类问题,不必从头猜。
还可以对照哪些排查文?
- Mihomo 日志级别排障取样:用于决定什么时候开
debug,以及日志该截取多少。 - OpenWrt DNSMasq Mihomo 顺序:用于排除旁路由上 DNS 链路接成环的问题。
- Mihomo DNS nameserver 和 fallback-filter:用于区分上游解析、备用解析和污染筛选。
- Fake-IP 和 Redir-Host 在规则模式里怎么选:用于判断这台设备是否适合继续用 fake-ip。