🔬 DNSViz: the DNSSEC chain, visualized
DNSViz is the tool you reach for when
dig +dnssecanddelvsay "it's bogus" but you can't see where. Paste a domain in, get back a complete graph of every DNSKEY, DS, RRSIG, NSEC, and the relationships between them, with broken edges highlighted in red. There is no better way to understand a DNSSEC chain.
- Web UI: https://dnsviz.net/
- CLI: https://github.com/dnsviz/dnsviz: full validation locally; same output
Why it's a wiki page on its own#
DNSSEC is a tree of relationships. A bogus zone is almost never bogus for one reason: there's usually a primary cause and a downstream symptom. Reading EDE codes one-at-a-time misses the structure. DNSViz draws the structure. Once you see the graph, the failure jumps out.
A healthy chain in DNSViz looks like a clean ladder: root → TLD → zone → record set, every arrow blue, every box solid. A broken chain has a red edge, a dashed box, or a missing node: and the eye finds it instantly.
Reading a DNSViz graph#
The graph clusters nodes by zone, one box per zone in the chain, and carries the information in three layers:
The boxes (nodes)#
| Shape | Meaning |
|---|---|
| Ellipse | A DNSKEY (signing key); gray fill marks the SEP bit, a double border marks a trust anchor, a thick border marks the revoke bit |
| Ellipse (at the parent, labeled DS) | A DS record (delegation hash at the parent); DS RRs sharing an algorithm and key tag draw as one node |
| Rounded rectangle | A signed RRset (the data being signed) |
| Rectangle with compartments | The NSEC or NSEC3 records proving a negative response; each top compartment is one record (one to three of them), the bottom compartment carries the NSEC or NSEC3 label |
Shapes per the official legend: dnsviz.net/doc/dnssec.
The arrows (edges)#
| Arrow style | Meaning |
|---|---|
| Solid blue | Valid: secure delegation, valid RRSIG, or a DS digest that matches the DNSKEY |
| Solid black | Insecure delegation: no DNSSEC at this link |
| Solid red | Broken: invalid signature or DS digest mismatch |
| Dashed red | Bogus delegation; also a DS or RRSIG whose use is invalid, such as one pointing at a revoked key |
| Dashed gray | RRSIG or DS with no matching DNSKEY (the missing key draws with a dashed gray border) |
| Dashed yellow | Lame or incomplete delegation |
| Solid yellow | Unknown or unsupported algorithm (a DS digest type or RRSIG algorithm the tool cannot check) |
| Solid purple | RRSIG outside its validity window (expired or not yet valid) |
The colors (status)#
Node outlines carry the validation status: blue means secure (an unbroken chain of trust from an anchor), red means bogus (the chain broke somewhere), black means insecure (no chain exists at all). DNSViz does not color by algorithm; the algorithm and key tag are printed as text inside each DNSKEY node (for example alg=13, id=2371), which is how you spot old and new algorithms side by side during a rollover.
When to reach for it#
| Situation | Use DNSViz for |
|---|---|
EDE 6 (DNSSEC Bogus) (RFC 8914) and you don't know why | The graph shows which edge is red |
| Planning a KSK rollover | Snapshot before + during + after; verify the parent DS lines up |
| Migrating between DNS providers | Snapshot the source zone; do not start migration until the chain is clean |
| Algorithm rollover (RSA → ECDSA) | See both algorithms present during the transition |
| Auditing a customer / partner zone before integration | "Is your DNSSEC actually working?" in one URL |
| Teaching DNSSEC | The visual makes the concept stick in a way RFC 4033 never will |
Quick run#
Pick a signed zone you know works. cloudflare.com is reliable:
Expected: an unbroken blue chain from the root through .com to cloudflare.com, with DNSKEY records carrying flags 257 (KSK) and 256 (ZSK), and a matching DS at the .com parent. The exact algorithm depends on what the zone is using; Cloudflare-managed zones show algorithm 13 (ECDSAP256SHA256).
If a zone's chain is not clean, look for:
- A red edge between the parent's DS and the zone's DNSKEY → the DS at the parent doesn't match.
- A red edge on an RRset → signatures expired, missing, or covered by a key not in the active DNSKEY set.
- A dashed edge → rollover in progress; verify both algorithms are intended.
Worth comparing against an unsigned zone too, to see what "no chain" looks like.
neverssl.comhas no DNSKEY and no DS record: https://dnsviz.net/d/neverssl.com/dnssec/ shows no DNSKEY boxes at all. That is what a non-DNSSEC zone looks like, not a broken one. A broken chain (like a zone with DNSKEY records but a missing or mismatched DS at the parent) will still show DNSKEY boxes, but with a red or missing edge connecting them to the parent.
Verifying the chain yourself#
Before DNSViz, confirm you are looking at a real validation failure. These commands run against a live zone and give you something to compare against the graph.
Step 1: does the zone have a DS record at the parent?
dig @1.1.1.1 isitdns.net DS +short2371 13 2 2DF8E1D4E0855DF60F2A8B51C914F2F2866ED1E3344F74F9682DAC4D 42D18802The DS record lives at the parent TLD (.net in this case) and contains a hash of the zone's KSK. If this record is missing or mismatched, the chain is broken right at the delegation. See dnssec for what each field means: key tag 2371, algorithm 13 (ECDSAP256SHA256), digest type 2 (SHA-256), then the hash.
nslookup can show DS but renders it as
rdata_43without field labels, which is not useful for diagnosis. Use dig.
Step 2: does the zone publish a DNSKEY?
dig @1.1.1.1 isitdns.net DNSKEY +short256 3 13 oJMRESz5E4gYzS/q6XDrvU1qMPYIjCWzJaOau8XNEZeqCYKD5ar0IRd8 KqXXFJkqmVfRvMGPmM1x8fGAa2XhSA==
257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+ KkxLbxILfDLUT0rAK9iUzy1L53eKGQ==(dig splits the base64 key material with a space and prints records in response order, which can vary.)
Flag 257 is the KSK (the key the DS record hashes). Flag 256 is the ZSK (the key that signs RRsets). Both must be present for a healthy zone. Algorithm 13 is ECDSAP256SHA256.
nslookup renders DNSKEY as
rdata_48with no field labels, which is not useful for diagnosis. Use dig.
Step 3: confirm a validating resolver accepts the chain (AD bit)
The AD (Authenticated Data) bit in a DNS response means a validating resolver checked the full chain to the root and found it valid (RFC 4035 §3.2.3). dig shows it as ad in the flags line, but only when the resolver you asked actually validates, and middleboxes on the path to a port-53 resolver can strip or inject it. The cleanest check is curl against a public DNS-over-HTTPS endpoint, which takes the local path out of the picture:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=isitdns.net&type=A'{"Status":0,"TC":false,"RD":true,"RA":true,"AD":true,"CD":false,
"Question":[{"name":"isitdns.net","type":1}],
"Answer":[{"name":"isitdns.net","type":1,"TTL":300,"data":"104.21.56.211"},
{"name":"isitdns.net","type":1,"TTL":300,"data":"172.67.155.242"}]}"AD":true confirms Cloudflare's validating resolver accepted the chain. "Status":0 is NOERROR. (The TTL counts down while the answer sits in cache, so you may see less than 300.)
nslookup can't show the AD bit. On Windows,
Resolve-DnsNamedoes not expose it either.
Step 4: confirm a broken zone returns SERVFAIL
dnssec-failed.org is a deliberately broken DNSSEC zone kept live for testing:
dig @1.1.1.1 dnssec-failed.org A;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31540
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)nslookup dnssec-failed.org 1.1.1.1** server can't find dnssec-failed.org: SERVFAILBoth tools surface SERVFAIL. A modern dig also prints the EDE: line in the OPT pseudosection, which names the failure class; nslookup gives you nothing more. But neither draws the chain. That is where DNSViz earns its place: paste dnssec-failed.org into https://dnsviz.net/ and the broken edge from the DS to the DNSKEY is immediately visible.
If your dig is too old to print EDE, the same extended error code is visible via DoH:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=dnssec-failed.org&type=A'{"Status":2,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,
"Question":[{"name":"dnssec-failed.org","type":1}],
"Comment":["EDE(9): DNSKEY Missing no SEP matching the DS found for dnssec-failed.org."]}"Status":2 is SERVFAIL. The EDE (Extended DNS Error, RFC 8914) code 9 means "DNSKEY Missing": a DS exists at the parent, but no matching DNSKEY could be found in the child. DNSViz shows this as a dashed gray edge from the parent's DS ellipse to a DNSKEY drawn with a dashed border, the key the DS references but the zone is not publishing.
nslookup can't show the EDE code. Use curl DoH or a dig recent enough to print the
EDE:line shown above (EDNS carries it as an OPT option).
CLI variant#
If you want to script DNSSEC checks (for example in a probe runner), use the dnsviz CLI:
dnsviz probe cloudflare.com > probe.jsonProbes the zone and its full delegation chain from the root (the default behavior) and writes a JSON snapshot. Add -A to query the authoritative servers directly instead of a recursive resolver. Note that -d sets the debug log level (0 to 3), not delegation depth; see the dnsviz-probe man page.
dnsviz grok < probe.jsonAnalyzes the JSON and prints a structured report of every object in the chain and its status.
dnsviz probe cloudflare.com | dnsviz graph -Tsvg > chain.svgRenders the same graph the web UI shows, as an SVG, without a network round-trip to dnsviz.net.
dnsviz probe cloudflare.com | dnsviz grok -l errorOne-shot problem check: -l error limits the report to error-level findings, so a clean chain prints an essentially empty result. For a CI pass/fail signal, test whether the output contains errors; per the dnsviz-grok man page, the exit code only reflects program errors (bad usage, missing dependencies, I/O), not DNSSEC status. (-t is for a trusted-keys file, not filtering.)
Pairing with the other tools#
DNSViz is the structure view. Pair it with:
| Tool | Gives you |
|---|---|
dig +dnssec | The raw answer; SERVFAIL confirms the chain is broken |
curl DoH | The AD bit and EDE code, without resolver interference |
delv | One definitive "validates / doesn't validate" verdict |
| DNSViz | The picture of why |
dnstap stream | What your resolver is doing in real time |
See nslookup-and-dig for the dig/nslookup primer, dig-flags for the full flag reference, and dnssec-troubleshooting for what to do once you have found the broken link.
The flow chart for a DNSSEC fire-drill:
dig @1.1.1.1 ZONE A SERVFAIL = chain is broken
|
curl DoH EDE code tells you what kind of break
|
DNSViz shows you which link is red
|
fix the red link re-sign, update DS, fix clock, etc.
|
DNSViz again confirm the chain is clean
|
wait for SERVFAIL cache resolvers re-fetch; up to ~5 minResolvers cache the failure for a bounded time: RFC 9520 caps resolution-failure caching at 5 minutes (§3.2), and DNSSEC validation failures are explicitly in scope (§3.4). So a re-signing fix propagates within about that long. One caveat: if the fix was a changed DS at the parent, resolvers that cached the old DS keep validating against it until that record's TTL runs out (86400 seconds, a full day, at .net), so DS changes settle much more slowly than re-signing fixes.
When to reach for DNSViz#
- Before any DNSSEC-relevant change to a zone you own, key rollover, algorithm change, provider migration. Run it before and after; compare the graphs.
- Teaching artifact, the canonical first thing to show someone learning DNSSEC. "Here's a healthy zone. Here's a broken zone. See the difference?"
- External auditing of zones you depend on but don't control, your registrar's, your CDN's, your mail provider's. If any of them goes bogus, your service breaks downstream.
See also#
- DNSSEC, signed and validated, the foundational concepts including DNSKEY, DS, RRSIG, and NSEC
- DNSSEC troubleshooting, what to do after you have found the broken link
digflag reference, the CLI counterpart- nslookup and dig, the two tools side by side
- CAA records, another piece of the cert/zone hardening story
- Anatomy of a DNS query, what is actually flowing when DNSViz draws those arrows
- DoT / DoH / DoQ, encrypting the transport so nobody on the wire can read or rewrite your queries