is it dns? / wiki ← back to the live monitor

🔬 DNSViz: the DNSSEC chain, visualized

DNSViz is the tool you reach for when dig +dnssec and delv say "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.

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)#

ShapeMeaning
EllipseA 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 rectangleA signed RRset (the data being signed)
Rectangle with compartmentsThe 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 styleMeaning
Solid blueValid: secure delegation, valid RRSIG, or a DS digest that matches the DNSKEY
Solid blackInsecure delegation: no DNSSEC at this link
Solid redBroken: invalid signature or DS digest mismatch
Dashed redBogus delegation; also a DS or RRSIG whose use is invalid, such as one pointing at a revoked key
Dashed grayRRSIG or DS with no matching DNSKEY (the missing key draws with a dashed gray border)
Dashed yellowLame or incomplete delegation
Solid yellowUnknown or unsupported algorithm (a DS digest type or RRSIG algorithm the tool cannot check)
Solid purpleRRSIG 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#

SituationUse DNSViz for
EDE 6 (DNSSEC Bogus) (RFC 8914) and you don't know whyThe graph shows which edge is red
Planning a KSK rolloverSnapshot before + during + after; verify the parent DS lines up
Migrating between DNS providersSnapshot 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 DNSSECThe 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:

https://dnsviz.net/d/cloudflare.com/dnssec/

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.com has 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 +short
2371 13 2 2DF8E1D4E0855DF60F2A8B51C914F2F2866ED1E3344F74F9682DAC4D 42D18802

The 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_43 without 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 +short
256 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_48 with 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-DnsName does 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: SERVFAIL

Both 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.json

Probes 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.json

Analyzes the JSON and prints a structured report of every object in the chain and its status.

dnsviz probe cloudflare.com | dnsviz graph -Tsvg > chain.svg

Renders 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 error

One-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:

ToolGives you
dig +dnssecThe raw answer; SERVFAIL confirms the chain is broken
curl DoHThe AD bit and EDE code, without resolver interference
delvOne definitive "validates / doesn't validate" verdict
DNSVizThe picture of why
dnstap streamWhat 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 min

Resolvers 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#