// CLASH

【技术分享】Clash Meta DNS 学习文档 DNS 分流

Clash Meta DNS 配置指南:你写的每一行都应该有理由

适用人群:在公司内网环境下使用 Clash Meta(mihomo)的研发同学

前置条件:了解基本的 DNS 概念(域名解析、DNS 服务器),有 Clash 基本使用经验

目标:读完之后能看懂自己的 DNS 配置,知道出问题时该改哪里


为什么要专门讲 DNS?

很多同学的 Clash 配置是从论坛、同事那里复制过来的。跑通了就用,出问题了不知道从哪里下手,改了一个地方又破坏了另一个地方。

DNS 是其中最容易被忽视、也最容易出问题的部分。它不是"选一个快的 DNS 服务器"这么简单——在 TUN 模式下,DNS 的配置直接决定了你写的路由规则能不能生效。

这篇文章的逻辑是:先讲清楚问题是什么,再说配置是怎么解决这个问题的。


一、TUN 模式下 DNS 为什么这么重要

正常情况下,DNS 很简单:应用问操作系统,操作系统问 DNS 服务器,返回 IP,建立连接。

但 Clash 的 TUN 模式把这个流程打破了。

TUN 会创建一个虚拟网卡,在网络层(IP 层)接管所有流量。问题在于,IP 层的数据包里只有目标 IP 地址,没有域名。等流量到达 TUN 的时候,域名已经消失了。

这就产生了一个矛盾:你的路由规则是按域名写的——

rules:
  - DOMAIN-SUFFIX,github.com,LB Connect
  - DOMAIN-SUFFIX,longbridge-inc.com,DIRECT

但 Clash 收到的只是 140.82.114.4:443 这样一个 IP 地址。它根本不知道这个 IP 属于哪个域名,规则匹配无从谈起。

Clash 的 DNS 模块就是为了解决这个问题——通过在应用发出 DNS 查询时就介入,把域名留在 Clash 的视野里,后续才能做正确的路由决策。


二、fake-ip:用"假"换"快"

Clash 的 DNS 有两种工作模式,通过 enhanced-mode 控制。

redir-host 模式是直接解析。Clash 拿到域名,去真实解析,拿到真实 IP,再建立连接。逻辑简单,但每次连接都要等 DNS 解析完才能开始,延迟高。

fake-ip 模式是另一种思路:Clash 收到 DNS 查询时,立刻从一个保留地址段(198.18.0.0/16)里随机分配一个"假 IP"返回给应用。应用立刻开始连接这个假 IP,Clash 在后台拦截这个连接,查表知道"哦,198.18.0.5 对应的是 github.com",然后按规则路由出去。

效果是连接感知上更快,因为不需要等 DNS 解析完成。

enhanced-mode: fake-ip
fake-ip-range: '198.18.0.1/16'

fake-ip 的副作用

fake-ip 的前提是 Clash 能拦截所有到这个假 IP 的连接。但有一类应用不走这套逻辑:

  • NTP 时间同步:客户端解析到 time.windows.com 的假 IP,直接去连接,期望对方是一个时间服务器——显然不是,时间同步静默失败
  • 局域网设备发现192.168.1.1 是你的路由器,198.18.x.x 不是,发现不了
  • Windows 网络检测:Windows 会定期 ping www.msftconnecttest.com,拿到假 IP 后认为网络不通,状态栏显示"无网络访问"

这些问题的共同特征是:应用拿到 IP 之后,需要 IP 本身有特定含义,而不只是一个占位符。

解决方法是 fake-ip-filter——对这些域名的 DNS 查询,跳过 fake-ip,直接返回真实 IP。

fake-ip-filter-mode: blacklist   # 默认所有域名走 fake-ip,以下例外
fake-ip-filter:
  - '*.lan'                      # 局域网主机名
  - '*.local'                    # mDNS 本地服务
  - '*.arpa'                     # 反向 DNS,本质是 IP 查询
  - 'time.*.com'                 # NTP 时间服务器
  - 'ntp.*.com'                  # NTP 时间服务器
  - '*.msftncsi.com'             # Windows 网络检测
  - 'www.msftconnecttest.com'    # Windows 网络检测
  - 'localhost.ptlogin2.qq.com'  # QQ 本地鉴权
实践建议:不需要一开始就把这个列表写得很全。碰到某个应用出现"连接看起来成功但功能不正常"的问题时,先怀疑是不是 fake-ip 干扰,确认后再加进来。

三、Sniffer:域名的第二次机会

fake-ip 解决了"快速返回"的问题,但还有另一个漏洞:不是所有流量都会经过 Clash 的 DNS 拦截

有些应用把 DNS 结果缓存起来,重启后直接用缓存的 IP 建立连接,不发新的 DNS 查询。还有些应用直接硬编码 IP。在这些情况下,Clash 的 DNS 模块根本没有机会介入,它只看到一个 198.18.x.x 或者某个陌生 IP,域名信息完全丢失。

更关键的是:fake-ip 模式下所有假 IP 都在 198.18.0.0/16 段,这个地址段没有归属国,GEOIP 规则对它完全无效。

Sniffer 是补丁。它不从 DNS 层恢复域名,而是直接从流量的应用层协议里提取:

  • TLS:握手阶段的 ClientHello 报文里有 SNI(Server Name Indication)字段,明文包含目标域名
  • HTTP:每个请求的 Host 头就是域名
  • QUIC:和 TLS 类似,握手阶段包含域名信息

Clash 读取这些信息,把域名"还给"这条连接,之后的路由规则匹配才能正常工作。

sniffer:
  enable: true
  force-dns-mapping: true    # 用 SNI 覆盖可能过时的 DNS 映射
  parse-pure-ip: true        # 对完全没有 DNS 记录的连接也尝试嗅探
  override-destination: true
  sniff:
    TLS:
      ports: [443, 8443]
    HTTP:
      ports: [80, 8080-8880]
    QUIC:
      ports: [443, 8443]
⚠️ 在 fake-ip + TUN 模式下,不开 Sniffer 等于你写的域名规则只对一部分流量有效。 这是最常见的"规则明明写了但不生效"的根源。

四、DNS 查询的处理顺序

理解了上面三个概念之后,来看 DNS 查询在 Clash 内部是怎么流转的。

Clash 的 DNS 处理是一条三层流水线,按优先级从高到低:

收到 DNS 查询
     │
     ▼
① nameserver-policy   ← 最高优先级,按域名匹配,命中则直接返回
     │
     │ 未命中
     ▼
② nameserver           ← 默认解析层,所有未被 policy 覆盖的查询
     │
     │ (如果配置了 fallback)
     ▼
③ fallback             ← 与 nameserver 并发,根据 fallback-filter 决定用哪个结果

关键点:

  • nameserver-policy 命中后,nameserverfallback 都不会被调用
  • fallback不是"nameserver 挂了的备用"——它是用来检测 DNS 污染的,两个并发,根据结果质量决定用哪个
  • 如果你把 nameserver-policy 配置正确,fallback 实际上没有用武之地

五、国内外域名分流:nameserver-policy

为什么需要分流

对国内域名用境外 DNS(比如 8.8.8.8):技术上能解析,但 CDN 会认为你在国外,返回海外节点的 IP,速度变慢。

对境外域名用国内 DNS(比如 223.5.5.5):国内公共 DNS 对被封锁的域名会返回错误结果(污染),用这些 IP 无法正常连接。

所以需要根据域名来源决定用哪个 DNS。nameserver-policy 就是干这个的。

nameserver-policy:
  'geosite:cn,private':
    - '223.5.5.5'                        # 阿里公共 DNS
    - '119.29.29.29'                     # DNSPod
    - 'https://doh.pub/dns-query'        # DNSPod DoH(加密,备用)
    - 'https://dns.alidns.com/dns-query' # 阿里 DoH(加密,备用)

geosite:cn,private 是两个规则集的合并:

  • geosite:cn:社区维护的中国域名列表,包含百度、微信、淘宝等主流中国互联网服务
  • geosite:private:私有/保留域名,包括 *.local*.lan、反向 DNS 等——这些绝不应该发送到公网 DNS

列表里配置多个 DNS 服务器时,Clash 并发查询,取最快返回的结果。


六、境外域名:让查询本身也走代理

未被 nameserver-policy 命中的域名落到 nameserver 处理,此时基本上全是境外域名。

对这些域名,有两个要求:

  1. 查询不能被污染:直接从国内网络问 8.8.8.8,ISP 可能对结果动手脚
  2. 查询不能泄露:DNS 查询明文包含你访问的每个域名,过 ISP 就等于全部暴露

解决方案是让 DNS 查询本身也走代理隧道。Clash 支持在 DNS 服务器地址后面加 # 来指定出口:

nameserver:
  - 'https://8.8.8.8/dns-query#RULES'   # 查询请求按路由规则走代理
  - 'https://1.1.1.1/dns-query#RULES'

#RULES 表示这个 DNS 查询本身也走 Clash 的路由规则。由于 8.8.8.81.1.1.1 是境外 IP,会命中代理规则,通过代理节点出去,到达 DNS 服务器时已经在墙外了,得到干净、真实的解析结果。


七、鸡生蛋问题:两个 Bootstrap 字段

这里有个循环依赖问题:

  • nameserver-policy 配置了 https://doh.pub/dns-query 这样的 DoH 服务器,但 DoH 是 HTTPS,建立连接之前需要先解析 doh.pub 的 IP——谁来解析?
  • 代理节点配置的是域名(比如 lb-vmess-sg-01.taowiki.com),连接代理之前要先解析这个域名——但 DNS 配置要求走代理,这不是死循环?

Clash 为这两个问题各提供了一个专用字段。

default-nameserver:用于解析 DNS 服务器本身的域名(DoH 的 hostname)。它在整个 DNS 管道启动之前运行,所以必须是纯 IP 地址,不能是域名。

default-nameserver:
  - '223.5.5.5'    # 纯 IP,不需要被解析就能访问
  - '119.29.29.29'

proxy-server-nameserver:专门用于解析代理节点的域名。独立于主 DNS 管道运行,打破循环依赖。

proxy-server-nameserver:
  - '223.5.5.5'
  - '119.29.29.29'

这两个字段存在的原因是一样的:有些 DNS 解析必须在主管道准备好之前完成,需要独立的出口。


八、直连流量的真实 IP 问题

fake-ip 模式下,应用拿到的 IP 是假的(198.18.x.x)。对于走代理的流量没问题——代理节点收到域名,自己去解析,返回结果。

但对于走 DIRECT 的流量,Clash 最终要建立一个真实的 TCP 连接,假 IP 没法用,必须重新解析一遍拿到真实 IP。

direct-nameserver 就是做这件事的:

direct-nameserver:
  - '223.5.5.5'
  - '119.29.29.29'

流程大致是这样:

应用查询 longbridge-inc.com
  → Clash 立刻返回假 IP 198.18.0.x
  → 应用开始连接
  → 路由规则匹配:DIRECT
  → Clash 需要真实 IP → 用 direct-nameserver 重新解析 longbridge-inc.com
  → 拿到真实 IP,建立直连

另外建议同时开启:

direct-nameserver-follow-policy: true

这样直连重解析也遵循 nameserver-policy 的规则,国内域名用国内 DNS,行为前后一致。


九、fallback 该不该用

fallback 的设计初衷是:nameserver 对某些境外域名返回了被污染的结果(国内 IP),fallback 提供一个"参照组",如果两边结果差异大,就用 fallback 的结果。

但问题是:如果你已经用 nameserver-policy 把国内和境外域名分开了,境外查询走代理通道,根本没有被污染的机会,fallback 就没有存在的必要了。

两套方案同时用,会造成规则之间的干扰,而且很难调试。

正确做法是把 fallback 彻底关掉:

fallback: []
fallback-filter:
  geoip: false

fallback: [] 让过滤器完全没有输入,geoip: false 则关掉 GeoIP 评估。两行同时写,确保 GUI 工具(比如 Clash Verge)不会偷偷把这些字段还原成有效值。


十、常见误区

误区一:配了代理就以为 DNS 也走代理了

很多同学以为配了代理节点,DNS 查询就自动走代理了。实际上,如果 nameserver 没有加 #RULES,DNS 查询还是从本地直接出去,会被污染。

误区二:不开 Sniffer,规则写了也白写

在 fake-ip + TUN 模式下,没有 Sniffer,所有流量到 Clash 眼里只是 198.18.x.x,域名规则根本无从匹配。DOMAIN-SUFFIX,github.com,LB Connect 这样的规则形同虚设。

误区三:fallback 和 nameserver-policy 混用

这两种方案都是为了解决"DNS 分流"问题,但实现思路完全不同。同时用反而让行为难以预测。选一个,用彻底。

误区四:IP-CIDR 规则没有加 no-resolve

fake-ip 模式下遇到 IP-CIDR 规则,如果没有 no-resolve,Clash 会尝试先做一次 DNS 解析再匹配。这是多余的,加上 no-resolve 跳过这步。

- 'IP-CIDR,192.168.0.0/16,DIRECT,no-resolve'
- 'GEOIP,CN,DIRECT,no-resolve'

十一、完整的 DNS 配置参考

# ── Sniffer ──────────────────────────────────────────────────────────────────
# 从 TLS/HTTP/QUIC 握手中恢复域名,fake-ip + TUN 模式的必要配置
sniffer:
  enable: true
  force-dns-mapping: true    # 用嗅探到的 SNI 覆盖可能过期的映射
  parse-pure-ip: true        # 对完全没有 DNS 记录的连接也嗅探
  override-destination: true
  sniff:
    TLS:
      ports: [443, 8443]
    HTTP:
      ports: [80, 8080-8880]
    QUIC:
      ports: [443, 8443]

# ── DNS ──────────────────────────────────────────────────────────────────────
dns:
  enable: true
  listen: ':53'

  # fake-ip:立刻返回假 IP,连接不等 DNS,速度快
  enhanced-mode: fake-ip
  fake-ip-range: '198.18.0.1/16'

  # 黑名单模式:以下域名不走 fake-ip,返回真实 IP
  fake-ip-filter-mode: blacklist
  fake-ip-filter:
    - '*.lan'
    - '*.local'
    - '*.arpa'
    - 'time.*.com'
    - 'ntp.*.com'
    - '+.market.xiaomi.com'
    - 'localhost.ptlogin2.qq.com'
    - '*.msftncsi.com'
    - 'www.msftconnecttest.com'

  # Bootstrap:用于解析 DoH 服务器的域名,必须是纯 IP
  default-nameserver:
    - '223.5.5.5'
    - '119.29.29.29'

  # 解析代理节点域名,独立于主 DNS 管道,避免循环依赖
  proxy-server-nameserver:
    - '223.5.5.5'
    - '119.29.29.29'

  # 最高优先级分流:国内 + 私有域名走国内 DNS
  nameserver-policy:
    'geosite:cn,private':
      - '223.5.5.5'
      - '119.29.29.29'
      - 'https://doh.pub/dns-query'
      - 'https://dns.alidns.com/dns-query'

  # 兜底:境外域名,查询本身也走代理(#RULES)
  nameserver:
    - 'https://8.8.8.8/dns-query#RULES'
    - 'https://1.1.1.1/dns-query#RULES'

  # 直连流量重解析:fake-ip → 真实 IP
  direct-nameserver:
    - '223.5.5.5'
    - '119.29.29.29'
  direct-nameserver-follow-policy: true  # 重解析也遵循 policy,行为一致

  # fallback 关闭:nameserver-policy 已在源头分流,fallback 多余
  fallback: []
  fallback-filter:
    geoip: false

  prefer-h3: false
  respect-rules: false
  use-hosts: false
  use-system-hosts: false
  ipv6: false

十二、配置决策速查

问题对应配置
路由规则对 TUN 流量不生效检查 sniffer 是否开启
连接快还是等 DNS?enhanced-mode: fake-ip
时间同步/局域网设备发现失败把对应域名加入 fake-ip-filter
国内域名走错 CDN,速度慢配置 nameserver-policy 指向国内 DNS
境外 DNS 被污染nameserver 加 #RULES,查询走代理
代理节点域名无法解析配置 proxy-server-nameserver
直连流量无法建立配置 direct-nameserver
fallback 和 nameserver-policy 冲突选其一,推荐 policy 方案,fallback: [] 关闭另一个
IP 规则触发不必要的 DNS 解析所有 IP-CIDR 和 GEOIP 规则加 no-resolve

还没有评论

欢迎留下你的观点,保持交流的清晰和友好。

写下评论