DNS污染和DNS劫持怎么区分:用 dig 和 nslookup 判断解析是否被篡改

博客 / 排障指南

DNS污染和DNS劫持怎么区分:用 dig 和 nslookup 判断解析是否被篡改

DNS污染和 DNS 劫持的结果都是“域名解析到了不该去的 IP”,区别在于篡改发生在哪里。污染发生在传输路上:查询包经过的某台设备抢在真正的解析服务器之前回了一个假应答。劫持发生在端点:你的 hosts 文件、路由器或运营商的解析服务器本身返回了改过的结果。判断方法是把同一个域名分别交给本地解析器、多个公共解析器和加密 DNS 去查,比较答案,再用 RDAP 查应答 IP 归属谁。下面先列差别,再给可以照做的命令。

DNS 污染和 DNS 劫持到底差在哪?

对比项DNS 污染DNS 劫持
篡改位置传输链路上的旁路设备本机 hosts、路由器、运营商解析器或被替换的 DNS 设置
工作方式监听到查询后抢先发出伪造应答,真实应答晚到被丢弃解析器直接返回改过的记录,或把你的 53 端口流量重定向到别的解析器
换一个明文公共 DNS往往仍然错,因为路过同一段链路如果只是本地解析器被改,换了通常就对了;透明重定向的情况除外
用 TCP 或加密 DNS 查加密 DNS 一般能拿到正确结果加密 DNS 绕开了被改的解析器,通常也正确
向不跑 DNS 的 IP 发查询可能仍然收到“应答”,这是污染的典型特征一般超时,除非存在透明重定向
影响范围经过该链路的所有用户,通常针对特定域名某台设备、某个家庭网络或某个运营商的用户
常见的应答特征应答返回得比到解析器的往返时间还快;同一查询收到两个应答把不存在的域名解析成广告页 IP;返回 0.0.0.0、127.0.0.1 或内网地址

两者也可能同时存在,所以下面的流程按段逐一排除。

开始之前:先确认问题真的出在 DNS

很多“打不开”其实和解析无关。先跑一次 cdnping 在线测速,它记录的“首次连接”包含 DNS 与 TLS 握手,“往返”是连接复用后 3 次请求的中位数。如果首次连接很慢、往返正常,问题可能在解析或握手;如果往返本身就慢,更像是链路问题,可以接着看 traceroute 和 mtr 结果怎么看。打不开某个 AI 服务时,也可以先按 ChatGPT 挂了吗?三步判断是服务故障还是自己的网络问题 排除服务端故障。

还要记住一点:解析结果不一致不等于被篡改。下面几种情况都是正常的:

  • 域名用了 CDN 或按地区调度(GeoDNS),不同解析器、不同城市拿到的 IP 本来就不同。
  • 解析器带上了客户端网段信息(ECS),返回离你近的节点。
  • 记录刚改过,各解析器缓存的 TTL 还没过期。DNS 服务商自身的同步延迟也会造成这种短时不一致。例如 cdnping 从 Cloudflare 官方状态页同步到的事件里,2026-10-15 15:33(UTC)有一条“DNS Update Delays”,等级 minor,持续约 165 分钟(来源:cdnping /status 对官方状态页的 15 分钟同步,窗口为 2026 年 9 月 17 日以来)。这段时间里新改的记录在不同解析器上看到的结果可能不一样,但这不是污染。

因此要看的是 IP 归属对不对、应答是谁发的,单看 IP 是否相同说明不了问题。

第一步:对比本地解析器和多个公共解析器

下文用 example.com 代表你要检查的域名,命令里的 IP 都是公开的解析服务地址。

macOS / Linux:

D=example.com
# 系统默认解析器(路由器或运营商下发的那个)
dig +short $D A
# 几个公共解析器,走明文 UDP 53
for s in 223.5.5.5 119.29.29.29 1.1.1.1 8.8.8.8; do
  echo "== $s"; dig +short +time=3 +tries=1 @$s $D A
done

Windows(PowerShell):

$D = "example.com"
Resolve-DnsName $D -Type A -DnsOnly
foreach ($s in "223.5.5.5","119.29.29.29","1.1.1.1","8.8.8.8") {
  "== $s"; Resolve-DnsName $D -Type A -Server $s -DnsOnly -QuickTimeout
}

只有 nslookup 时,写成 nslookup example.com 223.5.5.5,逐个替换最后的服务器地址即可。

先检查本机有没有被改。cat /etc/hosts(Windows 是 C:\Windows\System32\drivers\etc\hosts)里如果有这个域名,解析根本不会发出去,这属于本机层面的“劫持”,可能是你自己或某个软件写进去的。

怎么读结果:

  • 只有系统默认解析器的答案异常,公共解析器都一致:大概率是路由器或运营商解析器的问题,偏向劫持。
  • 所有明文查询都返回同一个可疑 IP:可能是链路上的污染,也可能是 53 端口被透明重定向,第二步区分。
  • 答案各不相同,但都属于同一家 CDN:通常正常,第四步用 RDAP 确认。

第二步:确认查询是不是真的到了你指定的解析器

dig @1.1.1.1 并不保证包真的到了 1.1.1.1。有些路由器或网络会把所有 UDP 53 流量重定向到自己的解析器。可以用解析服务提供的“自我介绍”记录来验证:

# Cloudflare 返回处理这次查询的机房代码;被重定向时通常拿不到或格式不对
dig +short @1.1.1.1 id.server CH TXT
# Google 返回替你向权威服务器发起查询的解析器出口 IP
dig +short @8.8.8.8 o-o.myaddr.l.google.com TXT
# 走默认解析器,看真正干活的是谁
dig +short whoami.akamai.net A

第三条返回的是“解析器的出口 IP”,不是你的出口 IP。把它拿去第四步查 RDAP,如果归属是你没设置过的运营商或陌生主体,说明默认解析链路和你以为的不一样。浏览器里也能看到类似信息:cdnping /ip 的 DNS 泄漏检测会列出实际替你查询的解析器 IP 和归属,原理见 DNS 泄漏与 WebRTC 泄漏。

再测一个必然不存在的域名:

dig +short nx-$(date +%s).example.com A

正常结果应该是空(状态 NXDOMAIN)。如果返回了一个 IP,说明默认解析器把“不存在”改写成了某个页面地址,这是解析器层面劫持的明确证据。完整状态可以去掉 +short,看 status: 那一行。

第三步:对比 UDP、TCP 和加密 DNS

链路上的抢答大多针对 UDP。同一个解析器分别用 UDP、TCP 和 DoH 查,三者对照:

D=example.com
dig +short @1.1.1.1 $D A          # UDP
dig +short +tcp @1.1.1.1 $D A     # TCP
curl -s -H 'accept: application/dns-json' \
  "https://cloudflare-dns.com/dns-query?name=$D&type=A"   # DoH,JSON 格式
curl -s "https://dns.alidns.com/resolve?name=$D&type=1"   # DoH,JSON 格式

Windows 上 TCP 查询用 Resolve-DnsName $D -Server 1.1.1.1 -TcpOnly,或 nslookup -vc example.com 1.1.1.1。

UDP 结果TCP 结果DoH 结果倾向的结论
可疑正常正常链路上有针对 UDP 的抢答,偏向污染
可疑可疑正常明文 53 端口整体被重定向或篡改
可疑可疑可疑先怀疑域名本身的记录或 CDN 调度,再查 RDAP
正常正常正常解析没问题,回到连接层排查

还有一个直接的污染检测:向一台你确认没有运行 DNS 服务的境外主机发查询,例如你自己的一台云主机,53 端口没有开放。

dig +time=3 +tries=1 @<你的主机IP> example.com A

正常情况下应该超时。如果收到了带 IP 的应答,那这个应答只能来自路上的设备。配合抓包能看得更清楚:

sudo tcpdump -n -i any udp port 53 and host 1.1.1.1

另开一个终端执行一次 dig @1.1.1.1 example.com。如果一次查询收到两个应答,先到的那个与 DoH 结果不一致,就是被抢答了。

第四步:用 RDAP 查应答 IP 归属谁,并看应答时间

拿到可疑 IP 以后,不要只看它“像不像”,要查它注册在谁名下。RDAP 是 WHOIS 的结构化替代,返回 JSON。下面用的 rdap.org 会把请求重定向到负责该网段的地区注册机构(RIR)的 RDAP 服务:

IP=203.0.113.10   # 示例地址,换成你拿到的 IP
curl -sL "https://rdap.org/ip/$IP" | jq '{handle, name, country, startAddress, endAddress}'

判断方式:

  • 应答 IP 的网段属于该网站或它公开使用的 CDN:结果可信,不同 IP 只是调度差异。
  • 网段属于与该网站无关的主体,或属于你的运营商:结果被改过的可能性高。
  • 应答是 0.0.0.0、127.0.0.1、10.0.0.0/8、192.168.0.0/16 这类地址:可能是链路上的抢答,也可能是本地或运营商的过滤策略,RDAP 查不到公网归属本身就是信号。

cdnping /ip 的出口 IP 情报也走 RDAP 展示网段注册信息,可以拿来对照命令行的结果。

应答时间也有参考价值。dig 输出末尾的 Query time 是这次查询的耗时。先 ping 1.1.1.1 记下往返时间,如果某次查询的 Query time 明显小于这个往返时间,说明应答不可能来自那台解析器,只能是路上的设备回的。这条规则只用于对比同一时刻的两个数,不需要记任何固定阈值。

一张可以照抄的检查表

  1. 检查 hosts 文件,排除本机写死的记录。
  2. 用系统默认解析器和 3 到 4 个公共解析器查同一域名,记下答案。
  3. 用 id.server、o-o.myaddr、whoami.akamai.net 确认查询真的到了目标解析器。
  4. 查一个随机不存在的子域名,看是否返回 NXDOMAIN。
  5. 同一解析器分别用 UDP、TCP、DoH 查询,对照表格。
  6. 向一台不运行 DNS 的主机发查询,看是否收到应答。
  7. 用 RDAP 查可疑 IP 的归属,结合 Query time 与 ping 往返时间判断。
  8. 把以上结果截图或保存文本,方便向运营商或网络管理员反馈。

确认之后怎么处理?

如果结论是劫持,处理对象很明确:hosts 里的条目删掉;路由器里的 DNS 设置改回你信任的解析器,顺便改掉路由器的默认管理密码;运营商解析器改写 NXDOMAIN 的,可以向运营商反馈,或改用可信的加密 DNS。具体设置步骤见 DNS over HTTPS 配置指南,改完后回到 /ip 看 DNS 泄漏检测里列出的解析器是否已经变成你设置的那个。

如果结论是链路上的污染,本文只讲到确认为止。它不在你的设备或路由器上,单靠改本机设置不一定能处理,具体怎么做请遵守所在地的法律法规和网络服务条款。对开发工作来说,更现实的做法是把这一步记进排障记录,然后继续检查其他层:开发工具连不上时,可以按 Claude Code 连接超时和报错怎么排查 的四层清单往下走,完整的自检顺序见 开发者网络自检清单(2026 版)。

相关文章

继续阅读