DEV Community

kent-tokyo
kent-tokyo

Posted on

I Built a Next-Gen DNS Diagnostic CLI in Rust That Visualizes DNSSEC Trust Chains

If you've ever tried to debug a DNSSEC misconfiguration using dig, you know the pain. You're staring at a wall of raw text, manually cross-referencing DS records against DNSKEY records, tracing through TLD delegations one query at a time. It works — but it's exhausting.

I wanted something better. So I built shohei — a Rust-powered DNS diagnostic CLI that makes the invisible visible.

github.com/kent-tokyo/shohei


What Is shohei?

shohei is a next-generation DNS diagnostic tool that goes well beyond what dig or drill offer. It renders DNS resolution as color-coded terminal trees, walks you through DNSSEC trust chains step by step, and supports modern transports like DoH and DoT — all from a single command.

Think of it as dig if dig was designed for humans first.


The Three Hard Problems shohei Solves

Building a DNS diagnostic tool sounds straightforward until you try to make it actually useful. Here are the problems that motivated most of the design.

1. DNSSEC Trust Chains Are Invisible in Standard Tools

DNSSEC forms a cryptographic chain from the root zone down to individual records. The chain looks like this:

Root KSK (trust anchor, hardcoded in resolvers)
  └── Root ZSK (signs root zone records)
        └── DS record for .com  ← hash of .com's KSK
              └── .com KSK
                    └── .com ZSK (signs .com zone)
                          └── DS record for example.com
                                └── example.com KSK
                                      └── example.com ZSK
                                            └── RRSIG on A record ← what you care about
Enter fullscreen mode Exit fullscreen mode

When something breaks in this chain — a DS mismatch, an expired RRSIG, a missing DNSKEY — dig gives you raw records and leaves you to piece together the failure yourself. shohei walks the whole chain and tells you exactly where validation fails and why.

. (Root)
└── com.  [DS 30909 → DNSKEY 30909 ✓]
    └── example.com.  [DS 12345 → DNSKEY 12345 ✓]
        └── www.example.com.  A 93.184.216.34
            └── RRSIG (ZSK tag 12345) expires 2026-06-01 ✓
Enter fullscreen mode Exit fullscreen mode

A broken chain looks like:

. (Root)
└── com.  [DS 30909 → DNSKEY 30909 ✓]
    └── example.com.  [DS 99999 → DNSKEY ✗ NO MATCHING KEY FOUND]
        └── ⚠ Validation failed: DS/DNSKEY mismatch at example.com.
Enter fullscreen mode Exit fullscreen mode

2. Iterative Resolution Is a Black Box

Standard resolvers are recursive — they do the work for you and return an answer. That's convenient, but useless when you're debugging a delegation problem, a glue record mismatch, or propagation that hasn't reached a specific nameserver yet.

shohei's --trace mode sends queries the way a resolver actually would — manually, hop by hop:

[1] Query root servers for example.com. A
    → a.root-servers.net. (198.41.0.4)  4ms
    ← REFERRAL: com. NS [a.gtld-servers.net., ...]

[2] Query TLD servers for example.com. A
    → a.gtld-servers.net. (192.5.6.30)  11ms
    ← REFERRAL: example.com. NS [ns1.example.com., ns2.example.com.]
       GLUE: ns1.example.com. A 205.251.196.1

[3] Query authoritative servers for example.com. A
    → ns1.example.com. (205.251.196.1)  8ms
    ← ANSWER: www.example.com. A 93.184.216.34  TTL 3600
Enter fullscreen mode Exit fullscreen mode

Each hop shows which server was queried, its IP, round-trip time, and exactly what was returned. Delegation loops, missing glue records, and lame delegations all become immediately visible.

3. Resolver Disagreements Are Hard to Diagnose

Split-horizon DNS, stale caches, and regional differences mean two resolvers can return completely different answers for the same query. Figuring out why usually involves running dig @8.8.8.8 and dig @1.1.1.1 separately, then comparing the output by hand.

shohei's --compare mode queries both resolvers concurrently and shows a unified diff:

Comparing 8.8.8.8 vs 1.1.1.1 for example.com A

  ANSWER
  8.8.8.8:   93.184.216.34  TTL 3521
  1.1.1.1:   93.184.216.34  TTL 120

  AUTHORITY
+ 8.8.8.8:   example.com. NS ns1.example.com.  TTL 172800
- 1.1.1.1:   (none)

  FLAGS
  8.8.8.8:   QR AA TC RD RA AD  ← AD set (DNSSEC validated)
  1.1.1.1:   QR AA TC RD RA     ← AD not set
Enter fullscreen mode Exit fullscreen mode

The TTL difference here tells you 1.1.1.1 has a nearly-fresh cache entry while 8.8.8.8 is serving a stale one. The missing AD flag on 1.1.1.1 is immediately visible.


Feature Overview

DNSSEC Chain Visualization

Full trust chain from root to record, color-coded by validation status. Green for valid, red for failures, yellow for warnings (e.g., signature expiring within 7 days).

Iterative Resolution Tracing (--trace)

Manual hop-by-hop resolution with timing, referral details, and glue record display. Shows exactly what a recursive resolver would do.

DoH and DoT Support

Modern DNS transports with no external dependencies:

shohei example.com --doh https://cloudflare-dns.com/dns-query
shohei example.com --dot 1.1.1.1
Enter fullscreen mode Exit fullscreen mode

Useful for testing whether a domain resolves correctly over encrypted transports, or for bypassing a local resolver that might be interfering.

Resolver Comparison (--compare)

Side-by-side diff of two resolvers. Flags TTL differences, missing records, DNSSEC validation status mismatches, and flag differences:

shohei example.com --compare 8.8.8.8 1.1.1.1
Enter fullscreen mode Exit fullscreen mode

Multi-Type Queries

Query multiple record types in a single command instead of running dig four times:

shohei example.com A AAAA MX TXT SOA
Enter fullscreen mode Exit fullscreen mode

Output is grouped by type with consistent formatting.

Watch Mode (--watch)

Auto-refresh at a set interval. Useful for monitoring TTL countdown, propagation in real time, or catching flapping records:

shohei example.com --watch 5  # refresh every 5 seconds
Enter fullscreen mode Exit fullscreen mode

The display updates in-place, so changes are immediately visible without scrolling.

Interactive TUI (--tui)

Built with ratatui, the TUI gives you three navigable panels in a single terminal window:

  • Records panel — all RRsets for the queried domain, sorted by type
  • DNSSEC panel — the full trust chain with validation status
  • Trace panel — iterative resolution hops with timing

Switch between panels with Tab, scroll with arrow keys, and exit with q. Useful when you need to explore a domain's DNS health interactively rather than in a single pass.

Reverse DNS (--ptr)

PTR lookups for IPv4 and IPv6, with automatic in-addr.arpa / ip6.arpa formatting:

shohei --ptr 8.8.8.8
shohei --ptr 2001:4860:4860::8888
Enter fullscreen mode Exit fullscreen mode

Batch Mode & Script-Friendly Output

Pipe a list of domains for bulk querying, with JSON output for downstream processing:

cat domains.txt | shohei --batch --json | jq '.[] | select(.dnssec_valid == false)'
Enter fullscreen mode Exit fullscreen mode

The --minimal flag strips color and tree formatting for plain-text pipelines.


Why Rust?

Three reasons:

Performance. DNS diagnostics involve parallel resolution paths — querying multiple nameservers concurrently, running resolver comparisons simultaneously, tracing iterative hops while fetching DNSSEC records in parallel. Rust's async ecosystem via tokio handles this efficiently without GC pauses that would skew timing measurements.

Correctness. DNSSEC validation is stateful and involves cryptographic operations across multiple record types. Getting it wrong silently is worse than getting it wrong loudly. Rust's type system lets you encode validation state as types — a validated chain is a different type than an unvalidated one, and the compiler enforces that distinction.

hickory-dns. The hickory-dns crate (formerly trust-dns) is a mature pure-Rust DNS implementation with first-class DNSSEC, DoH, and DoT support. It handles wire-format parsing, cryptographic validation, and transport negotiation — the parts that are easy to get subtly wrong — so I could focus on the UX layer.


Core Dependencies

Crate Purpose
hickory-dns DNS resolution, DNSSEC validation, DoH/DoT transport
clap CLI argument parsing with derive macros
ratatui Interactive TUI framework
owo-colors Terminal colorization without ANSI escape string building
comfy-table Table rendering with Unicode box-drawing
tokio Async runtime for concurrent resolver queries
serde_json JSON output serialization

Installation

cargo install shohei
Enter fullscreen mode Exit fullscreen mode

Or build from source:

git clone https://github.com/kent-tokyo/shohei
cd shohei
cargo build --release
./target/release/shohei example.com
Enter fullscreen mode Exit fullscreen mode

The TUI is included by default. If you want a smaller binary without ratatui, build with --no-default-features.


Quick Reference

# Basic query — records + DNSSEC chain
shohei example.com

# Multiple record types in one shot
shohei example.com A AAAA MX TXT SOA

# Iterative resolution trace (hop by hop)
shohei example.com --trace

# DNSSEC chain only
shohei example.com --dnssec

# Compare two resolvers
shohei example.com --compare 8.8.8.8 1.1.1.1

# Query over DoH
shohei example.com --doh https://cloudflare-dns.com/dns-query

# Query over DoT
shohei example.com --dot 1.1.1.1

# Watch mode (refresh every 5s)
shohei example.com --watch 5

# Reverse DNS
shohei --ptr 8.8.8.8

# Interactive TUI
shohei example.com --tui

# Batch mode with JSON output
cat domains.txt | shohei --batch --json

# Minimal output for scripting
shohei example.com --minimal
Enter fullscreen mode Exit fullscreen mode

What's Next

  • DANE/TLSA validation — cross-reference TLS certificate fingerprints against DNS to verify DANE configurations
  • NSEC/NSEC3 zone walking — for security research and CTF scenarios
  • HTML report export — a shareable snapshot of a domain's full DNS health, including DNSSEC chain and trace output
  • CAA record checking — verify Certification Authority Authorization records alongside DNSSEC

Feedback Welcome

shohei is MIT licensed and open to contributions. If you work with DNS professionally — or just find yourself reaching for dig more than you'd like — I'd love to hear what features would be most useful.

github.com/kent-tokyo/shohei


Built with Rust, a healthy obsession with DNSSEC, and too many late nights staring at zone files.

Top comments (1)

Collapse
 
sm4rt-lab profile image
Kostiantyn Chertov

Really interesting approach to making DNSSEC debugging more human-readable.

Most DNS diagnostic tools still feel designed for protocol engineers rather than for people who actually need to troubleshoot infrastructure under pressure.

The trace visualization idea looks especially useful.