返回博客

DNS 改了没生效?其实是 Clash fake-ip 在骗你

部署新子域名,改完 A 记录,习惯性跑一句 dig 验证,结果回来的是:

$ dig +short sub.example.com A
198.18.0.202

198.18.0.202——既不是我的服务器 IP,也不是 Cloudflare,完全陌生。第一反应:DNS 没有传播完?注册商出问题了?记录填错了?追了半小时,全是红鲱鱼。真相只有一句话:这个地址是假的,是本地代理伪造的。

现象

  • dig +short <域名> / nslookup / ping 解析出 198.18.x.x198.19.x.x(RFC 2544 基准测试保留段),有时也是 240.x.x.x
  • dig @1.1.1.1 <域名> 直接超时,没有响应
  • 但浏览器里访问该域名完全正常,页面加载无误
  • 实际业务流量没有任何异常

根因

这是 Clash / ClashX / Mihomo / Surge / Stash 等代理客户端 fake-ip 模式的正常工作机制,不是 Bug。

在 fake-ip 模式下,代理接管了 OS 的 DNS 解析器(通常是 127.0.0.1:53)。每当应用发起 DNS 查询,代理不等真实响应,立刻返回一个 198.18.0.0/15 段里的占位地址,同时在内部维护一张映射表:198.18.0.202 → sub.example.com。当 TCP 连接发往这个假 IP 时,代理拦截、查表、替换为真实目标,再通过隧道转发出去。

这套机制的好处是减少 DNS 查询延迟(不等 RTT 就能建连);代价是本机的解析结果完全是假的。dig @1.1.1.1 超时,是因为代理同时劫持了出站 :53 UDP,Cloudflare 的 53 端口根本收不到包。

坑:本机 dig 返回 198.18.x,不等于 DNS 没更新

只要本地跑着 Clash/Surge 等代理且启用了 fake-ip(绝大多数用户的默认配置),dig / nslookup / ping 的解析结果对"域名指向哪个真实 IP"这件事毫无参考价值198.18.0.0/15 是代理分配的会话级占位符,每次重启代理都会变。

正解

绕过本地解析器,直接查公共 DNS,或者在没有代理的机器上查:

方法一:指定公共解析器(推荐)

# 国内首选 AliDNS,在代理环境下通常不被拦截
dig @223.5.5.5 +short sub.example.com A
 
# Google DNS(代理可能劫持 :53,若超时换 AliDNS)
dig @8.8.8.8 +short sub.example.com A

方法二:在目标服务器上解析(最权威)

服务器没有本地代理,解析结果就是全球真实传播状态:

ssh root@your-server 'getent hosts sub.example.com'
# 输出示例:203.0.113.10   sub.example.com

方法三:在线工具

dnschecker.org 会从全球多个节点同时查询,一眼看清传播进度。

正解:跳过本地解析器,用 @223.5.5.5 或服务器端验证

dig @223.5.5.5 +short <域名>ssh server 'getent hosts <域名>' 返回相同的真实 IP,而裸 dig <域名> 还在返回 198.18.x,这个差异本身就证明 fake-ip 是根因,DNS 配置没有问题。

诊断速查

| 命令 | 返回 198.18.x | 返回真实 IP | |------|:---:|:---:| | dig +short <域名> | fake-ip 中 | 未开启 fake-ip | | dig @1.1.1.1 +short <域名> | 代理拦截 :53 | 代理放行 :53 | | dig @223.5.5.5 +short <域名> | — | 这个才是真相 | | 服务器 getent hosts <域名> | — | 这个才是真相 |

只要公共解析器和服务器端结果一致且指向目标 IP,你的 DNS 就是正确的,不需要任何修改。

一句话外卖

开着 Clash fake-ip 时,本机的 DNS 解析结果是代理伪造的占位地址,验证域名解析只能用 dig @223.5.5.5 或在无代理的服务器上执行。