给一个新域名配好解析,隔了十分钟,在终端里查:

1
2
dig +short example.com
198.18.15.123

不对。那不是我配的地址。

于是开始怀疑人生:DNS 没生效?配置写错了?服务商抽风?——挨个查了一遍,全都没问题。

问题出在发出这条查询的那台电脑身上。

198.18 是个什么地址

先说结论:198.18.0.0/15 这个网段,在公网上是不存在的。

它被 RFC 2544 保留用作网络设备的性能测试,不会被分配给任何真实服务。所以当你查一个域名,得到的是 198.18.x.x,那它一定不是真实答案。

这个网段被 Clash、sing-box 这类代理工具拿去做了一件事,叫 fake-IP。

fake-IP 在做什么

代理工具需要知道你要访问哪个域名才能做规则分流——“这个域名走直连,那个走代理”。但应用程序发起连接时,握在手里的是一个 IP,域名早在 DNS 那一步就被丢掉了。

fake-IP 的解法很巧妙:接管 DNS,对每个域名现编一个假 IP 返回给你,同时在内部记下「这个假 IP 对应哪个域名」。

等你的程序拿着这个假 IP 去建连接时,代理在网络层拦下来,一查表就知道你真正想访问的是谁,然后按规则决定怎么走。

域名信息因此被完整地保留到了最后一刻。设计上很漂亮。

副作用是:你的电脑从此失去了如实回答 DNS 问题的能力。

三个会骗到你的细节

一、指定权威服务器也没用。

1
2
dig @8.8.8.8 example.com     # 照样是假的
dig @ns1.provider.com example.com # 还是假的

因为拦截发生在网络层(TUN 模式),不是改了系统的 DNS 配置。你的查询包根本没离开这台机器。

二、TTL = 1 是个信号。

1
example.com.  1  IN  A  198.18.15.123

真实的 DNS 记录 TTL 通常是几百到几千秒。1 秒是假 IP 的典型特征——代理要保证映射随时可以改。看到这个数字就该警觉。

三、拿假 IP 去 curl,居然是通的。

这条最阴险。

1
2
curl -H "Host: example.com" http://198.18.15.123/
# 正常返回了页面

因为代理会把这个假 IP 映射回域名再帮你转发出去。于是你”验证”了一遍,结论是”解析正常”——而你验证的整个链路都在代理内部。

同理,curl 直接访问域名时加上 -w '%{remote_ip}',你会看到:

1
remote_ip = 127.0.0.1

它在提示你:这次连接的对端是本机的代理端口,不是远方的服务器。

那怎么查到真的

查 DNS:走 DoH。

DNS-over-HTTPS 是普通的 HTTPS 请求,走的是代理的转发通道而不是 DNS 拦截通道,拿回来的是货真价实的答案:

1
2
3
curl -s "https://dns.google/resolve?name=example.com&type=A"
curl -s -H "accept: application/dns-json" \
"https://1.1.1.1/dns-query?name=example.com&type=A"

返回的 JSON 里,"Status": 0 是正常,"Status": 3 是域名不存在。Answer 数组里才是真实记录。

查网站可达性:找一台别人的服务器帮你看。

本机已经没救了——就算加 --noproxy '*',TUN 模式照样在网络层拦截。所以要换个视角,让一台不在你网络里的机器去访问:

1
curl -s "https://r.jina.ai/https://example.com/" | head -c 200

它会从自己的服务器抓取页面并返回内容。你看到的就是外部用户看到的。

查域名状态:问注册局。

1
whois -h whois.verisign-grs.com example.com

注册商那一段的信息可能滞后,注册局(.com 是 Verisign)才是权威。

一句话

在开着代理的机器上,dig 和 curl 不是在告诉你外面的世界是什么样,而是在告诉你代理希望你看到什么样。

这不是 bug,是 fake-IP 的设计本意。只是当你正好在排查网络问题时,这份善意的谎言会把你带得很远。

所以判断一件事”到底成没成”,最好换一双不在你局域网里的眼睛。