TT Lab
博客 开始
学习 学习路径 课程

Linux 网络诊断

读 dig 的顺序

在 TT Lab 中继续学习

一句话总结

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。

最好把按用途区分的组合练熟。

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

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 答案分歧的情况整理成表提交。