技术指南
DNS 解析故障:从权威服务器查到本机缓存
用 dig 分层定位委派、权威数据、递归缓存、DNSSEC、本机解析与 Cloudflare 代理问题。
DNS 故障常被笼统地归因于“传播慢”,但一次查询实际经过注册局委派、权威服务器、递归解析器和本机解析栈,浏览器还可能使用独立的加密 DNS。先固定域名、记录类型、查询时间和观察位置,再逐层对比;不要一开始就清缓存或改多处配置。
先固定一次故障样本
| 字段 | 需要记录的值 | 为什么重要 |
|---|---|---|
| 查询对象 | 完整域名与 A、AAAA、CNAME 等类型 | 不同类型可以同时呈现不同状态 |
| 观察位置 | 网络、设备、递归解析器地址 | 办公室、移动网络和浏览器可能走不同路径 |
| 时间与期望 | UTC 时间、预期值、实际值 | TTL 和缓存剩余时间会持续变化 |
| 最近变更 | 委派、记录、DNSSEC、代理或证书 | 把排查范围收敛到真正发生变化的层 |
先准备变量并确认工具版本。`ZONE` 是权威区域,`NAME` 是发生问题的完整名称,两者不一定相同。后续命令默认使用 BIND 的 `dig`;输出中的 `status`、flags、ANSWER、AUTHORITY 和剩余 TTL 都应保留。
ZONE=example.com
NAME=www.example.com
TYPE=A
dig -v
dig "$NAME" "$TYPE" +noall +answer +authority +comments先按响应类别分流
| 响应 | 含义 | 下一步 |
|---|---|---|
| NOERROR 且有答案 | 查询成功;值仍可能不是预期 | 比较权威与多个递归解析器 |
| NOERROR 但无目标答案 | 通常是 NODATA:名称存在,但该类型不存在 | 查看 AUTHORITY 中的 SOA 和其他记录类型 |
| NXDOMAIN | 解析器判断名称不存在 | 核对委派、拼写和负缓存 TTL |
| SERVFAIL | 解析过程失败,常见于 DNSSEC 或上游不可达 | 比较验证与关闭验证的诊断结果 |
| 超时或 REFUSED | 网络、ACL、服务或查询策略阻止响应 | 检查 UDP/TCP 53、服务状态与访问规则 |
从父区委派走到权威服务器
`+trace` 从根开始迭代查询,适合确认父区给出的 NS 和 glue 是否能一路到达当前权威服务器。它不是普通用户请求的完整复现,因为它绕过了日常递归缓存;它的作用是定位委派链,而不是证明所有解析器都已更新。
dig +trace "$ZONE" NS
AUTH_NS=$(dig +short NS "$ZONE" | sort | sed -n '1p')
printf 'authoritative server: %s\n' "$AUTH_NS"
dig @"$AUTH_NS" "$NAME" "$TYPE" +norecurse +noall +answer +authority +comments若父区仍委派给旧服务器,应在注册商处修正 nameserver;若委派正确但权威答案错误,应在实际权威 DNS 提供商处改记录。只改另一套未被委派的控制台不会影响公网结果。多台权威服务器答案不一致时,应先停止继续发布并检查区域同步。
比较递归缓存,不把它叫作玄学传播
for RESOLVER in 1.1.1.1 8.8.8.8; do
printf '\n== %s ==\n' "$RESOLVER"
dig @"$RESOLVER" "$NAME" "$TYPE" +noall +answer +authority +comments
done权威答案已经正确而递归结果仍旧,通常应等待旧 TTL 到期,并用变更前记录的 TTL 估算窗口。不要反复降低 TTL 来修正已经缓存的旧值;降低 TTL 只影响随后取得的新答案。对一个确认不存在且没有 wildcard 命中的测试名称查询,可观察 NXDOMAIN 或 NODATA 以及 AUTHORITY 中用于负缓存的 SOA。
MISSING=known-absent.example.com
dig @1.1.1.1 "$MISSING" A +noall +answer +authority +comments把 CNAME、IPv4 和 IPv6 分开核对
for QUERY_TYPE in CNAME A AAAA; do
printf '\n== %s ==\n' "$QUERY_TYPE"
dig "$NAME" "$QUERY_TYPE" +noall +answer +authority +comments
doneRFC 1034 要求存在 CNAME 的节点不能再承载其他数据。若同名 A、AAAA 或 CNAME 冲突,应回到权威配置修正;区域 apex 通常还必须承载 SOA 和 NS,因此普通 CNAME 不适用,供应商的 flattening 或 ALIAS 属于各自实现。AAAA 存在只表示发布了 IPv6 地址,不证明客户端有可用 IPv6 路由。
Cloudflare 代理下不要拿源站地址作预期
Cloudflare 官方说明,被代理的 A、AAAA 或 CNAME 查询会返回 Cloudflare anycast 地址而不是源站地址;这是预期行为。不要为了“看见真实 IP”随手切到 DNS only:这样会公开源站,并移除代理层的缓存、防护和证书终止。先在控制台核对代理状态,再从 HTTP 层验证。
ORIGIN_IP=192.0.2.10
curl --resolve "${NAME}:443:${ORIGIN_IP}" \
--connect-timeout 5 --head "https://${NAME}/"用验证差异定位 DNSSEC
dig @1.1.1.1 "$NAME" "$TYPE" +dnssec
dig @1.1.1.1 "$NAME" "$TYPE" +dnssec +cdflag
dig +trace "$ZONE" DS若正常验证返回 SERVFAIL,而 `+cdflag` 能取得未验证答案,DNSSEC 链很可能存在问题。`+cdflag` 只是诊断手段,不是修复,也不应让应用长期绕过验证。核对注册商父区中的 DS 与当前权威提供商发布的 DNSKEY;迁移 DNS 时尤其要按提供商顺序更新或移除旧 DS。
最后检查本机解析路径
getent ahosts "$NAME"
if systemctl is-active --quiet systemd-resolved; then
resolvectl status
resolvectl query --type="$TYPE" "$NAME"
else
printf '%s\n' 'systemd-resolved is not active; inspect the resolver used by this host'
fi只有在确认 `systemd-resolved` 正在使用且需要重试本机缓存时,才执行 `sudo resolvectl flush-caches`。它不会清除公共递归解析器或浏览器自己的缓存。浏览器的 Secure DNS / DoH 还可能绕过操作系统配置,因此应分别记录浏览器和命令行结果。
解析正确后转向传输与应用
curl -4 --head --connect-timeout 5 "https://${NAME}/"
curl -6 --head --connect-timeout 5 "https://${NAME}/"| 证据组合 | 更可能的故障层 |
|---|---|
| 权威错误,递归一致错误 | 权威记录或区域发布 |
| 权威正确,部分递归仍旧 | 正缓存或负缓存尚未到期 |
| 验证 SERVFAIL,+cdflag 有答案 | DNSSEC DS/DNSKEY/签名链 |
| dig 正确,getent 或浏览器不同 | 本机解析、VPN、DoH 或 hosts |
| A/AAAA 正确,curl 连接或 TLS 失败 | 路由、防火墙、证书、代理或应用 |
用可复现结果结束排查
- 父区委派和每台权威服务器对目标类型返回一致结果。
- 至少两个递归解析器在预期 TTL 窗口后返回正确状态和答案。
- 启用验证的解析器不再 SERVFAIL,DS 与 DNSKEY 属于当前提供商。
- 系统解析、浏览器解析、IPv4、IPv6 和 Cloudflare 代理路径分别有明确结论。
- 变更项、旧值、新值、时间、回滚方法和原始命令输出进入事件记录。