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.
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
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 ✓
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.
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
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
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
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
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
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
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
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)'
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
Or build from source:
git clone https://github.com/kent-tokyo/shohei
cd shohei
cargo build --release
./target/release/shohei example.com
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
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.
Built with Rust, a healthy obsession with DNSSEC, and too many late nights staring at zone files.
Top comments (1)
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.