读 dig 的顺序
一句话总结
dig 的输出不是从上往下读,而是按 status → flags → 各个部分 的顺序读。遵守这个顺序,一次应答就能分辨出原因。
为什么需要这个
“DNS 不能用”的报告里至少混着五种不同的情况:名称根本不存在、只是没有该类型的记录、解析器无法生成答案、服务器拒绝应答,以及缓存陈旧。这五种情况的应对方式各不相同。而且一次 dig 输出就能确定是其中哪一种。
工作原理
先看应答码。
| status | ANSWER | 实际含义 | 常见原因 | 下一步 |
|---|---|---|---|---|
| NOERROR | 1 条以上 | 名称和类型都存在 | 正常 | 转向下一层 |
| NOERROR | 0 条 | 名称存在,但没有该类型 | 有 A 没有 AAAA;只有 CNAME,目标未创建 | 换类型再确认 |
| NXDOMAIN | — | 权威服务器确认该名称本身不存在 | 拼写错误、未创建、加上了 search 域的名称 | 直接询问权威服务器 |
| SERVFAIL | — | 解析器无法生成答案 | DNSSEC 验证失败、上游无响应、区域加载失败 | 解析器日志 |
| REFUSED | — | 服务器无意处理 | 不允许递归、ACL、不持有该区域 | 查询对象是否正确 |
最容易混淆的是 NOERROR 而 ANSWER: 0 的情况。名称存在,只是没有那种记录类型。只缺 IPv6,或者设置了 CNAME 却没有创建目标 A 记录,都属于这种情况。
接下来是 flags。
aa—— 权威应答。没有这个标志,答案就来自缓存。tc—— 被截断,需要用 TCP 重新查询。rd/ra—— 请求递归 / 支持递归ad/cd—— 通过 DNSSEC 验证 / 关闭验证查询
最好把按用途区分的组合练熟。
dig +short A example.com # values only
dig +noall +answer example.com # answer section only (with TTL and type)
dig +noall +authority +additional example.com
dig @1.1.1.1 example.com # ask one server directly
dig +norecurse @10.0.0.53 example.com # only check whether it is cached
dig -x 8.8.8.8 # reverse lookup
dig -t MX example.com
dig +tcp example.com
dig +time=2 +tries=1 example.com
dig +trace example.com # follow delegation from the root
+trace 有个陷阱。 +trace 从根开始直接查询每一级,因此会绕过你的解析器。 所以“+trace 正常,应用却失败”很常见,这时元凶不是权威服务器,而是解析器这一段。
TTL 与否定缓存
向解析器重复同一个查询,能看到 TTL 在减少。 而直接询问权威服务器,得到的总是原始设置值。这个差异是判断“是否来自缓存”的最简单方法。
不存在的名称,其结果也会被缓存。否定缓存时间取 SOA 的 MINIMUM 字段与 SOA 记录自身 TTL 中较小的那个。所以会出现新建了记录却仍持续一段时间 NXDOMAIN 的情况。“明明建好了为什么不行”,答案通常就是这个。
resolv.conf 中的数字
nameserver 10.0.0.2
search prod.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 timeout:2 attempts:3 rotate
nameserver最多只用 3 个。timeout默认 5 秒(最大 30),attempts默认 2 次(最大 5)。第一个名称服务器挂掉时,按默认值用户会实打实地感受到 5 秒。不缩短超时和尝试次数,冗余配置就形同虚设。ndots:n的规则是“点少于 n 个时先加上 search 域试试”。默认 1,最大 15。
Kubernetes 的 ndots:5 是有名的陷阱。api.stripe.com 只有 2 个点,少于 5,所以要先把 4 个 search 域全部加一遍,之后才询问原名称。按 A/AAAA 成对计算,10 个查询中有 8 个是为了收到 NXDOMAIN 而发出的。不过与常见建议不同,把 ndots 降到 1 会搞坏集群——payments.prod 这类跨命名空间调用会全部失败。安全的下限是 2。情况紧急时,在名称末尾加一个点(api.stripe.com.)明确它是 FQDN,就能跳过 search。
在现场遇到的样子
只开放 UDP 53 的防火墙。 平时没有任何问题,因为应答很小。可一旦记录增多或加上 DNSSEC 签名,应答超过 512 字节,就只有那个名称解析不了。“只有某一个域名不行”的报告,有时原因就在这里。用 dig +notcp +bufsize=512 复现,并查看 ;; MSG SIZE rcvd:。
不要整个清空缓存。 rndc flush 很痛快,但之后几分钟内上游查询会暴增。正确做法是只用 rndc flushname api.example.com 清除出问题的名称。
下一个实验要做的事
用 dig 查出 A/MX/NS/TXT,观察 TTL 减少,进行反向查询,并从 NXDOMAIN 应答中计算否定缓存时间。最后添加 hosts 条目,把 getent 与 dig 答案分歧的情况整理成表提交。