DNS 污染自测:三条命令,分清污染、劫持、节点故障和网站自己挂了

一个网站打不开,别的都正常

这篇处理的是一种很具体的故障:某一个站点访问不了,而你其他的网站、其他的应用都好好的。

这种情况下,浏览器给你的信息几乎为零——不管是解析被污染、运营商在骗你、代理节点挂了,还是那个网站自己出了问题,浏览器都只会转圈然后报一个含糊的错。

这四种原因的处理方式完全不同,猜错一次就是半小时。 所以这篇不解释原理,只给三条命令和一张判读表。

原理想补的话去这两页:《DNS 污染是什么》 讲投毒机制,《DNS 劫持是怎么回事,怎么防》 讲中间人欺骗。这一页假设你已经知道它们是什么,只想知道你现在遇到的是哪一个

先说结论

  1. 三条命令,按顺序跑,不要跳。 第一条判断「有没有人抢答」,第二条判断「正确答案是什么」,第三条判断「拿到正确答案之后还通不通」。
  2. 第一条是全篇最有价值的一条:向一个按规范不可能有 DNS 服务的地址发查询。收到回答,就证明路上有设备在抢答——不需要任何海外机器配合。
  3. 不要只看 IP 对不对,要看 dig 头部的 status:flags:,以及 Query time。一个异常快的回答本身就是信号。
  4. DoH 是第二条命令的工具,不是结论。它证明「正确答案长什么样」,不证明你连得上。
  5. 解析对了还是打不开,就别再碰 DNS 设置了,问题在连接层,见《Clash 报错对照表》的连接类一节。
  6. 开着代理测,结果会不一样,因为客户端接管了 DNS;fake-ip 模式下 ping198.18.x.x 是正常的。先用 DNS 泄露检测 确认现在到底是谁在回答你。

一句话原则:DNS 故障的判断不靠「结果对不对」,靠同一个问题问不同的人,比较他们的答案。三条命令就是三种问法。

准备:确认你手上有什么工具

系统dignslookupcurl
macOS自带自带自带
Linux多数发行版自带(或装 dnsutils / bind-utils自带自带
Windows不自带,需安装 BIND 工具包自带Windows 10 1803 起自带

Windows 用户如果不想装 BIND,第一条命令用 nslookup 也能做,写法在下面一并给出。

先做一件事:把浏览器关了。 浏览器有自己的 DNS 缓存和自己的 DoH 设置,它的行为和命令行不一定一致,会干扰你的判断。

第一条命令:有没有人在抢答

原理

DNS 的明文查询走 UDP,没有身份验证——谁先回答,客户端就信谁。所以路上的设备只要抢在真正的解析服务器之前回一个包,就能决定你去哪里。

利用这一点可以做一个非常干净的测试:向一个不可能运行 DNS 服务的地址提问。 如果还有人回答,那个回答必然是伪造的。

选哪个地址?用 RFC 5737 规定的文档专用段。规范原文:

The blocks 192.0.2.0/24 (TEST-NET-1), 198.51.100.0/24 (TEST-NET-2), and 203.0.113.0/24 (TEST-NET-3) are provided for use in documentation.

按定义,这些地址只用于文档示例,不会有任何真实服务跑在上面

命令

dig +timeout=3 +tries=1 @192.0.2.1 你要测的域名

参数依据 ISC 的 BIND 官方手册:@server 指定要查询的域名服务器;+timeout=T 是「sets the timeout for a query to T seconds」(把一次查询的超时设为 T 秒,默认 5 秒);+tries 设置重试次数。设成 3 秒 1 次,是为了让「超时」这个结果快点出来。

你可能在别处见到写成 +time=3 的版本,两种写法都对。 手册在「Query Options」一节写明「Keywords may be abbreviated, provided the abbreviation is unambiguous」(关键字可以缩写,只要缩写不产生歧义),+time 就是 +timeout 的一个不产生歧义的缩写;部分随系统附带的旧版 dig(例如 macOS 自带的 BIND 9.10)在自己的 dig -h 里直接把这个选项印成 +time=###。照手册写全名最保险。

Windows 用 nslookup 的等价写法:

nslookup 你要测的域名 192.0.2.1

怎么读结果

你看到的结论
;; connection timed out; no servers could be reached正常。没人抢答,这一层是干净的
几秒内返回了一个 ANSWER SECTION,里面有 IP有人在抢答。这个答案不可能来自 192.0.2.1
nslookup 下:返回了地址而不是 timed out同上

关于那条「正常」结果connection timed out; no servers could be reached 是这条命令符合规范时应有的输出——RFC 5737 把 192.0.2.0/24 留给文档使用,那里不该有任何东西回应你,所以「没人应答」正是对的,不是命令写错了。

但请不要直接相信这句话,先给自己立一个基准。 拿一个你确信没问题的网络(例如一台境外服务器,或手机热点换一条链路)跑一次这条命令:

  • 看到超时 → 说明命令写对了、这个测试在你手上是有效的,这就是你的基准;
  • 在这条「干净」链路上也立刻拿到了 IP → 先别下污染的结论,多半是你把地址或参数敲错了,或者这台机器上有本地解析软件在代答,把命令逐字核一遍再说。

有了基准,再回到出故障的那个网络跑第二次。两次结果不同,才是证据;只跑一次拿到的任何结果,都还不能区分「链路有问题」和「这条命令本来就跑不对」。

如果这一条就抓到了抢答,那你遇到的是路上的问题,换一个公共 DNS 地址没有用——因为抢答者不在乎你问的是谁。这种情况直接跳到第二条命令,用 DoH 拿正确答案。

顺手多看两眼头部

即使没抓到抢答,dig 的头部也值得读。一次正常查询的输出格式是这样(下面是 dig 的标准输出样式,用来说明该看哪几行;具体的 id、IP、耗时每次都不一样):

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24104
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; ANSWER SECTION:
example.com.		166	IN	A	172.66.147.243
;; Query time: 28 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)

要看的四处:

  • status: —— NOERROR 是成功;NXDOMAIN 表示这个域名不存在(这是域名本身的状态,不是网络问题);SERVFAIL 表示服务器处理失败。
  • flags: —— ra 表示对方支持递归。一个没有 ra 却给了你答案的响应值得怀疑。
  • Query time —— 和你平时查同一个 DNS 的耗时比。明显更快的回答往往来自更近的地方,而更近的地方不一定是你想问的那个人。
  • SERVER: —— 确认它真的问了你指定的那台,而不是回落到了系统默认。

第二条命令:正确答案到底是什么

原理

第一条只告诉你「有没有被动手脚」,不告诉你正确答案。要拿正确答案,得让查询在路上不可读——这就是 DoH(DNS over HTTPS)的作用:查询被包在 HTTPS 里,中间设备看不见内容,也就无从抢答。

命令

三家提供商,地址都取自它们自己的文档:

Cloudflare(官方文档给出的调用形式,原样照抄):

curl --header "accept: application/dns-json" \
  "https://cloudflare-dns.com/dns-query?name=你要测的域名&type=A"

Google(官方文档写明 Google Public DNS 提供两套 DoH 接口:dns.google/dns-query 走 RFC 8484,dns.google/resolve 是 JSON 接口、仅支持 GET):

curl "https://dns.google/resolve?name=你要测的域名&type=A"

阿里云公共 DNS(官网列出的 DoH/DoT 地址是 dns.alidns.com,IPv4 为 223.5.5.5、223.6.6.6):

curl "https://dns.alidns.com/resolve?name=你要测的域名&type=A"

为什么要同时跑境内和境外两家:它们的答案不一致,本身就是有用的信息——很多国际站点在国内有独立的 CDN 节点,答案不同不等于有人作恶。境内外都问一遍,才分得清「被污染」和「本来就该给你不同的 IP」。

不想敲命令的话,本站的 DNS 记录查询 就是基于 DoH 的,可以直接在浏览器里做这一步。

怎么读结果

返回的 JSON 里,Status 字段就是 DNS 响应码:0 是 NOERROR(成功),3 是 NXDOMAIN(域名不存在)。Answer 数组里的 data 就是解析出的地址,TTL 是它的剩余缓存时间。

对比结果结论
DoH 有答案,明文 dig 的答案不同明文那条被动过。用 DoH 的答案继续第三条
DoH 和明文答案一致DNS 这一层没问题,直接做第三条
DoH 的 Status3(NXDOMAIN)这个域名确实不存在——拼错了,或者它真的没了
境内外 DoH 答案不同,但两个都连得通正常的 CDN 就近解析,不是故障
DoH 请求本身连不上你到那个 DoH 服务的这条路不通,换一家再试

DoH 不是万能的,这一点《DoH 与 ECH》那一页说得更完整。 它只加密了「问」的这一段。拿到正确 IP 之后能不能连上,是完全独立的另一件事——也就是第三条命令。

第三条命令:拿到正确答案之后,还通不通

原理

前两条都成功,你现在手上有一个可信的 IP。但「知道地址」和「能连上」是两回事。第三条命令的作用是绕开本机的一切 DNS 解析,直接拿这个 IP 去建立连接。

curl--resolve 参数正是为此设计的:它把「域名 + 端口」硬绑到你指定的 IP,跳过解析步骤,同时保留域名用于 TLS 的 SNI 和 HTTP 的 Host 头——这一点很关键,因为直接 curl https://那个IP/ 会因为证书不匹配而失败,那属于你自己制造的错误。

命令

curl -v --max-time 10 \
  --resolve 你要测的域名:443:第二条命令拿到的IP \
  https://你要测的域名/

怎么读结果

你看到的结论下一步
TLS 握手成功,拿到 HTTP 响应DNS 是对的,连接也是通的问题在你本机:DNS 缓存旧了,或 hosts 文件里有条目
连上了但在 TLS 握手阶段被断开解析没问题,连接层被打断不要再改 DNS。见《Clash 报错对照表》
连接超时,压根没握上手到这个 IP 的路不通可能是节点问题,也可能是这个 IP 本身不可达
证书错误,提示域名不匹配你连到的那台机器不是这个站点回到第二条,换一家 DoH 再取一次

第一行那个结论最常被忽略:如果直连 IP 一切正常,浏览器却打不开,那就是本机缓存问题,清一次 DNS 缓存就好——改 DNS 服务器、换节点、重装客户端全都是白费力气。

判读表:三条结果合起来看

把三条命令的结果按下表对号入座:

① 抢答测试② DoH 答案③ 直连那个 IP你的病是按什么顺序处理
超时(正常)与明文一致本机缓存或 hosts清 DNS 缓存 → 检查 hosts → 重启浏览器
超时(正常)与明文一致不通连接层问题,与 DNS 无关换节点 → 查客户端日志 → 别碰 DNS 设置
超时(正常)与明文不一致你问的那台解析服务器在给你别的答案换公共 DNS → 改用 DoH → 复测
有人抢答与明文不一致路上有设备抢答换 DNS 没用;改用 DoH/加密通道
超时(正常)Status: 3域名不存在检查拼写;确认这个站还在不在
超时(正常)取不到到 DoH 服务的路也不通换一家 DoH;这往往说明问题更靠上游

第三行和第四行的区别,就是「劫持」和「污染」的区别,也是这张表最值得记住的一格:

  • 换一个 DNS 服务器就好了 → 问题在你原来问的那一方。
  • 换谁问都一样,连不存在的地址都会抢答 → 问题在路上,换谁问都没用。

开着代理的时候,测的是谁

这是最容易得出错误结论的场景。代理客户端会接管 DNS,所以你在本机跑的明文 dig,问到的很可能是客户端的内部 DNS 模块,而不是外面的任何一台服务器。

两个必须知道的现象:

  1. fake-ip 模式下,ping 域名得到 198.18.x.x 是正常的。 mihomo 官方文档的示例里 fake-ip-range 默认就是 198.18.0.1/16——它给每个域名发一个假的内网地址,真正的解析推迟到连接建立时才做。这不是劫持。
  2. 客户端的 DNS 配置本身可能就是故障源。 订阅提供的配置文件包含完整的 DNS 设置和分流规则,这些全部由配置提供方决定。

所以在代理开启的情况下,正确的第一步不是跑 dig,而是先搞清楚现在是谁在回答你

最后:这三条命令查不到的东西

诚实地划一下边界。下面这些情况,三条命令都会显示「一切正常」:

  • 网站自己挂了,或者对你所在的地区做了限制——解析正常、连接正常,只是内容不给你。
  • 你的账号被限制了,和网络无关。
  • 证书链、时间不同步这类本机问题——表现是握手失败,但根因不在 DNS。
  • 只有某个 App 不行,浏览器正常——那多半是那个程序没走代理,见《代理开着却还是超时》

三条命令的价值不是解决问题,是把问题缩小到一层。 缩小之后,剩下的排查才有方向——否则你会在 DNS 设置里改上半小时,而故障压根不在那里。

参考资料

以下文档均于 2026 年 9 月 20—21 日核对;三个 DoH 接口的调用形式(端点、请求头、返回字段)均按各家自己文档的写法照录,你可以在自己机器上用上面的命令逐条复现。

命令与参数

  • ISC BIND 9 官方手册(dig 查询选项)@server+timeout=T(「sets the timeout for a query to T seconds」,默认 5 秒)、+tries+short+tcp+trace+recurse / +norecurse 的定义原文,以及「Keywords may be abbreviated, provided the abbreviation is unambiguous」这一条(+time 能用的依据)
  • Microsoft — nslookup 命令参考 — Windows 自带工具的用法

地址与规范

DoH 服务(均取自提供商自己的文档)

代理客户端侧

将本指南加入收藏夹

跨境网络环境瞬息万变。建议按下 Ctrl+D (Windows) 或 Cmd+D (Mac) 收藏本页,以便在连接波动时快速查阅解决方案。

加入 5,000+ 跨境从业者,第一时间获取最新的 GFW 封锁动态与协议升级提醒。

* 我们绝不发送垃圾邮件,您可以随时取消订阅。

← Kill Switch 实操:在 Windows 和 macOS 上把「隧道一断就断网」做出来,并验证它真的生效