DNSSEC 基础故障排查

本文介绍的一部分排查技巧侧重于 BIND 9 DNS 服务器及其工具,但一般原则适用于所有实现中的 DNSSEC。

便于测试的正常域名与异常域名

准备已知能够通过或不能通过 DNSSEC 验证的域名,有助于测试不同工具,并确认失败不是由所有域名共有的问题引起的。不能保证以下域名永远保持这种状态,但它们可以作为起点。

  • 以下域名应无法通过 DNSSEC 验证:

  • 以下域名应能够通过 DNSSEC 验证:

日志

默认情况下,BIND 9 服务器会记录某些 DNSSEC 验证失败,因此应首先检查 journal 日志。

例如,向一个启用验证的解析器查询 www.dnssec-failed.org 的 IP 地址,查询会失败:

$
dig @127.0.0.1 -t A www.dnssec-failed.org

; <<>> DiG 9.20.11-Ubuntu <<>> @127.0.0.1 -t A www.dnssec-failed.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 26260
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 6339d7228b8587f401000000671bc2eb2fe25bdf099ef1af (good)
;; QUESTION SECTION:
;www.dnssec-failed.org.         IN      A

;; Query time: 460 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Fri Oct 25 16:10:19 UTC 2024
;; MSG SIZE  rcvd: 78

这个失败信息非常笼统:只有 SERVFAIL,并未给出 IP 地址,IN A 为空。BIND 9 日志则提供了更详细的信息:

$
journalctl -u named.service -f

(...)
named[286]: validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
named[286]: no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 68.87.85.132#53
named[286]: validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
named[286]: no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 68.87.68.244#53
named[286]: validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
named[286]: no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 68.87.76.228#53
named[286]: validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
named[286]: no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 68.87.72.244#53
named[286]: validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
named[286]: no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 69.252.250.103#53
named[286]: broken trust chain resolving 'www.dnssec-failed.org/A/IN': 68.87.72.244#53

客户端工具:dig

dig 是用途最广泛的 DNS 排查工具之一,通常用于询问 DNS 名称服务器、查找并显示域名信息。它的功能很丰富,可以直接控制查询中的大多数 DNS 标志,并显示详细响应供检查。

进行 DNSSEC 故障排查时,以下功能尤其有用:

  • +dnssec:设置 DNSSEC OK 位,要求服务器返回 RRSIG 记录。OPT 伪节中会显示 do 标志。

  • +cd:设置 checking disabled(禁用检查)标志,允许解析器返回未经验证的答案。

  • 响应中的 ad(authenticated data,已验证数据)标志,表示解析器已验证答案。

  • @<IP>:指定要向哪台服务器发送查询。

例如,向本机 systemd-resolved DNS 存根解析器(运行在 127.0.0.53)查询 isc.org 的 A 记录,并请求 DNSSEC 数据:

注意

如果需要,可以临时启用 DNSSEC,或将上游服务器改为 Cloudflare 的 1.1.1.1——例如当前上游无法正确处理 DNSSEC 时。测试结束后,使用 resolvectl revert eth0 恢复默认设置。

$
resolvectl dnssec eth0 true

$
resolvectl dns eth0 1.1.1.1

$
dig @127.0.0.53 -t A +dnssec +multiline isc.org

; <<>> DiG 9.20.11-Ubuntu <<>> @127.0.0.53 -t A +dnssec +multiline isc.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23376
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 65494
;; QUESTION SECTION:
;isc.org.		IN A

;; ANSWER SECTION:
isc.org.		299 IN A 151.101.2.217
isc.org.		299 IN A 151.101.66.217
isc.org.		299 IN A 151.101.130.217
isc.org.		299 IN A 151.101.194.217
isc.org.		299 IN RRSIG A 13 2 300 (
                20260130043603 20260116034316 27566 isc.org.
                kp+MQSlXw7xOqU072l4g3/Fq815ucOv5rN77kxizdxnL
                EMwYbgtcvI+AgDIwhm9qgLhc2GO6pUUF+puJCokxNA== )

;; Query time: 26 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Jan 22 13:56:58 UTC 2026
;; MSG SIZE  rcvd: 203

查看响应中的几个关键部分:

  • ad 标志表明答案已通过验证。

  • 状态为 NOERROR,答案部分包含 5 条记录。

  • RRSIG 记录随 A 资源记录一起返回,符合 +dnssec 参数的要求;OPT PSEUDOSECTION 中的 do 标志也确认了这一点。

再对已知无法通过 DNSSEC 验证的域名执行相同查询:

$
dig @127.0.0.53 -t A +dnssec +multiline dnssec-failed.org

; <<>> DiG 9.20.11-Ubuntu <<>> @127.0.0.53 -t A +dnssec +multiline dnssec-failed.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 2028
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 65494
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)
;; QUESTION SECTION:
;dnssec-failed.org.	IN A

;; Query time: 219 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Jan 22 13:57:33 UTC 2026
;; MSG SIZE  rcvd: 103

这次的结果不同:

  • 没有 ad 标志。

  • 状态为通用的 SERVFAIL,答案数量为 0。

  • journalctl 中记录了失败原因:

$
journalctl -u systemd-resolved.service -f

(...)
systemd-resolved[9203]: [🡕] DNSSEC validation failed for question dnssec-failed.org IN A: no-signature

可以使用 +cd,要求运行在 @127.0.0.53 的本地 systemd-resolved 存根解析器不执行 DNSSEC 验证。响应随之发生变化:

$
dig @127.0.0.53 -t A +dnssec +cd +multiline dnssec-failed.org

; <<>> DiG 9.20.11-Ubuntu <<>> @127.0.0.53 -t A +dnssec +cd +multiline dnssec-failed.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32064
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 65494
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)
;; QUESTION SECTION:
;dnssec-failed.org.	IN A

;; ANSWER SECTION:
dnssec-failed.org.	299 IN A 96.99.227.255
dnssec-failed.org.	299 IN RRSIG A 5 2 300 (
                20260204145120 20260118144620 44973 dnssec-failed.org.
                U8NkuyOJBdX6vA/f+o4DclA0x5YrCVOpMCGyCnXqaTTv
                8+QhDuwRGsAhXYtAZTx4k6q7B2NbqPFsavHKbbsEY46J
                SLpA1MIYydHTnUPHnu+foH4Dq/QctoXbUejMySdyZwPp
                MU5hm5IkwN8LgKjoE0YL89mr4ueu01DtESG6P+I= )

;; Query time: 119 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Jan 22 13:58:49 UTC 2026
;; MSG SIZE  rcvd: 296

这次虽然得到了一些答案,但要注意:

  • 没有 ad 标志,因此答案未经验证。

  • 状态为 NOERROR,答案部分包含 2 条记录。

  • cd 标志表明 checking disabled:解析器按照请求跳过了验证。

以上任何一种情况中,dig 本身都不执行 DNSSEC 验证,只展示解析器返回的结果;使用 +cd 时,甚至完全没有进行验证。如果需要自行验证,应使用其他工具。

客户端工具:delv

delv 与 dig 很相似,可以执行相同的 DNS 查询,但有一个关键区别:它也可以验证 DNSSEC。因此发生验证错误时,它可以报告更详细的原因,而不只是返回通用的 SERVFAIL 错误。

应使用 +cd,将验证工作交给 delv。否则,解析器可能直接返回 SERVFAIL,使 delv 无法取得需要验证的记录。

$
delv @127.0.0.53 -t A +dnssec +multiline dnssec-failed.org

;; resolution failed: SERVFAIL

加上 +cd 后,delv 自行验证,并报告具体的失败原因:

$
delv @127.0.0.53 -t A +dnssec +cd +multiline dnssec-failed.org

;; validating dnssec-failed.org/DNSKEY: no valid signature found (DS)
;; no valid RRSIG resolving 'dnssec-failed.org/DNSKEY/IN': 127.0.0.1#53
;; broken trust chain resolving 'dnssec-failed.org/A/IN': 127.0.0.1#53
;; resolution failed: broken trust chain

delv 的 -i 选项会禁用它自身的验证;+cd 则禁用解析器的验证。将两者结合使用时,得到的答案未经验证:

$
delv @127.0.0.53 -i -t A +dnssec +cd +multiline dnssec-failed.org

; answer not validated
dnssec-failed.org.      100 IN A 96.99.227.255

对于正常的域名,delv 会报告答案已通过验证:

$
delv @127.0.0.53 -t A +multiline +cd isc.org

; fully validated
isc.org.		299 IN A 151.101.2.217
isc.org.		299 IN A 151.101.66.217
isc.org.		299 IN A 151.101.130.217
isc.org.		299 IN A 151.101.194.217
isc.org.		299 IN RRSIG A 13 2 300 (
                20250908112301 20250825104017 27566 isc.org.
                9oclTno0Ub2NmUEXdyLv0zqwPBbbUVmT3RX4aP4BQQ+h
                4g839JXuCKHufXSPkWh/GJe/MveP83dDvJkrMmEIzg== )

由于这里使用了 +cd,验证由 delv 完成。如果解析器能够成功验证,不使用该选项也会得到相同结果。

客户端工具:resolvectl

resolvectl 可以与本机的 systemd-resolved 存根解析器交互,也可用于 DNSSEC 故障排查。为了得到可靠的测试结果,可以重置缓存及服务器功能状态。

注意

如果需要,可临时启用 DNSSEC,或将上游服务器改为 Cloudflare 的 1.1.1.1,例如当前上游无法正确处理 DNSSEC 时。测试完成后,用 resolvectl revert eth0 恢复默认设置。

清空缓存、重置服务器功能状态,然后确认已启用 DNSSEC:

$
sudo resolvectl flush-caches

$
sudo resolvectl reset-server-features

$
sudo resolvectl dnssec eth0 yes

$
sudo resolvectl dns eth0 1.1.1.1

$
resolvectl dnssec

Global: no
Link 44 (eth0): yes

查询支持 DNSSEC 的域名。通过 Data is authenticated 和 Data from 字段,确认数据已通过验证且来自网络:

$
resolvectl query --type=MX isc.org

isc.org IN MX 5 mx.pao1.isc.org                             -- link: eth0
isc.org IN MX 10 mx.ams1.isc.org                            -- link: eth0

-- Information acquired via protocol DNS in 3.0ms.
-- Data is authenticated: yes; Data was acquired via local or encrypted transport: no
-- Data from: network

系统时间不正确

与所有涉及密码学的机制一样,准确的时间至关重要。简而言之,数字签名和密钥都有失效时间。

例如,下面的 RRSIG 记录包含其有效时间范围:

noble.example.internal. 86400 IN RRSIG A 13 3 86400 (
                                20241106131533 20241023195023 48112 example.internal.
                                5fL4apIwCD9kt4XbzzlLxMXY3mj8Li1WZu3qzlcBpERp
                                lXPgLODbRrWyp7L81xEFnfhecKtEYv+6Y0Xa5iVRug== )

其中的有效期为:

  • 有效期截至:20241106131533(2024-11-06 13:15:33 UTC)。

  • 有效期始于:20241023195023(2024-10-23 19:50:23 UTC)。

如果系统时钟不在这个范围内,验证就会失败。例如,把时间设置在有效期之前,delv 会报告签名尚未生效:

$
date

Tue Oct 10 10:10:19 UTC 2000

$
delv @10.10.17.229 -a example.internal.key +root=example.internal +multiline noble.example.internal

;; validating example.internal/DNSKEY: verify failed due to bad signature (keyid=48112): RRSIG validity period has not begun
;; validating example.internal/DNSKEY: no valid signature found (DS)
;; no valid RRSIG resolving 'example.internal/DNSKEY/IN': 10.10.17.229#53
;; broken trust chain resolving 'noble.example.internal/A/IN': 10.10.17.229#53
;; resolution failed: broken trust chain

其他进行验证的解析器也会记录类似错误。

如果系统时钟不正确,BIND 9 会明显地记录根区的验证失败:

named[3593]: managed-keys-zone: DNSKEY set for zone '.' could not be verified with current keys
named[3593]:   validating ./DNSKEY: verify failed due to bad signature (keyid=20326): RRSIG validity period has not begun
named[3593]:   validating ./DNSKEY: no valid signature found (DS)
named[3593]: broken trust chain resolving './NS/IN': 199.7.83.42#53
named[3593]: resolver priming query complete: broken trust chain

第三方 Web 诊断工具

以下公开工具也能辅助诊断 DNSSEC:

  • DNSViz 以图形展示信任链,并标明发生中断的位置。

  • DNSSEC Debugger 以表格展示信任链,并标明发生中断的位置。

延伸阅读


来源:Ubuntu Server 官方文档 · Canonical。

著作权归原作者及来源机构所有。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容