docs: comprehensive documentation for HAN-387
CI / test (pull_request) Failing after 1m19s

- README.md: full project overview, installation, quick start, CLI reference,
  output format descriptions, architecture overview, and dnstraverse comparison
- GoDoc: package-level documentation for traverse, dns, config, output, and
  fingerprint packages
- GoDoc: TraverserConfig and TraversalResult type comments in traverser.go

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Gary Hansen
2026-06-08 04:05:15 +10:00
co-authored by Copilot multica-agent
parent e6e07941a5
commit ee20ed51f6
7 changed files with 283 additions and 19 deletions
+221 -19
View File
@@ -1,44 +1,246 @@
# ExploreDNS # ExploreDNS
DNS reconnaissance and exploration tool. ExploreDNS is a comprehensive DNS traversal tool that explores every possible
resolution path for a domain — from the root servers all the way down — just
like a real iterative resolver, but without stopping at the first answer. It
follows every referral exhaustively, collates all results, and presents them in
a structured, human-readable (or JSON) report.
## Build Inspired by the classic [dnstraverse](https://github.com/squish/dnstraverse)
Ruby tool, ExploreDNS is a modern Go rewrite that produces a self-contained
binary with no runtime dependencies.
---
## Features
- **Full iterative traversal** — queries root servers and follows every referral
branch, mirroring real resolver behaviour
- **All root servers** — optionally query all 13 root server sets in parallel
- **No-glue resolution** — automatically resolves nameserver addresses when
referrals lack glue records
- **DNS server fingerprinting** — identifies server software via `version.bind`
CHAOS queries
- **Multiple output formats** — coloured text tree and machine-readable JSON
- **Configurable transport** — UDP/TCP, EDNS0 buffer size, retries, timeouts
- **Fast mode** — shares glue across branches for speed; disable for independent
paths
- **CNAME tracking** — follows CNAME chains and detects loops
---
## Installation
### Pre-built binary
Download the latest release binary for your platform from the
[Releases page](https://gitea.hansenits.com.au/hits/ExploreDNS/releases).
### Build from source
Requires Go 1.21 or later.
```sh ```sh
go build -o bin/exploredns ./cmd/exploredns git clone https://gitea.hansenits.com.au/hits/ExploreDNS.git
cd ExploreDNS
make build # produces bin/exploredns
``` ```
Or use the Makefile: ### go install
```sh ```sh
make build go install github.com/hits/ExploreDNS/cmd/exploredns@latest
``` ```
## Usage ---
## Quick Start
```sh ```sh
./bin/exploredns <domain> # Basic A record traversal
exploredns www.example.com
# MX records for a domain
exploredns --type MX example.com
# Use all 13 root server sets
exploredns --all-root-servers www.example.com
# JSON output
exploredns --json www.example.com
# Quiet (results only)
exploredns --quiet www.example.com
# Debug mode
exploredns --debug www.example.com
# Library-level debug (very verbose)
exploredns --dd www.example.com
# Force TCP
exploredns --allow-tcp --always-tcp www.example.com
# Disable fast mode (independent paths per branch)
exploredns --fast=false www.example.com
# Increase traversal depth limit
exploredns --max-depth 30 www.example.com
``` ```
## Development ---
## CLI Reference
```sh
make test # run tests
make lint # run go vet
make clean # remove build artifacts
``` ```
Usage:
exploredns [flags] <domain>
Query Options:
--type <TYPE> Record type to query (default: A)
Supported: A, AAAA, NS, CNAME, MX, TXT, SOA, PTR, ANY
--root-server <IP> Override the root server IP address
--all-root-servers Query all 13 root server sets (default: false)
--root-aaaa Include IPv6 addresses for root servers (default: false)
--follow-aaaa Only follow AAAA addresses for referrals (default: false)
Transport Options:
--udp-size <N> EDNS0 UDP buffer size, 512–4096 (default: 2048)
--allow-tcp Fall back to TCP on truncation (default: true)
--always-tcp Always use TCP (requires --allow-tcp)
--retries <N> Per-server retry count, 0–10 (default: 2)
Traversal Options:
--max-depth <N> Maximum referral depth, 1–100 (default: 20)
--fast / --fast=false Share glue cache across branches (default: true)
Output Options:
--json Emit results as JSON instead of text
--verbose, -v Show extra detail in text output
--debug, -d Enable application debug messages (stderr)
--dd Enable library-level debug messages (very verbose)
--quiet, -q Suppress header and supplementary information
--show-progress Show live traversal progress (default: true)
--no-show-progress Hide traversal progress
--show-resolves Show glue-resolution steps (default: true)
--no-show-resolves Hide glue-resolution steps
--show-servers Show which servers were queried (default: true)
--no-show-servers Hide server list
--show-versions Show DNS server software versions (default: true)
--no-show-versions Hide server versions
--show-all-stats Show query statistics (default: true)
--no-show-all-stats Hide statistics
--show-results Show per-branch query results (default: true)
--no-show-results Hide per-branch results
--show-summary-results Show deduplicated summary section (default: true)
--no-show-summary-results Hide summary section
```
---
## Output Formats
### Text (default)
Coloured, hierarchical tree output showing each traversal branch, the servers
queried, referrals followed, and final answers. Disable colour by setting the
`NO_COLOR` environment variable.
### JSON (`--json`)
Structured JSON array of traversal results. Suitable for piping into `jq` or
ingesting into other tools. Each element contains the referral metadata, the
responding server, the response type, and the decoded DNS records.
---
## Comparison with dnstraverse
| Feature | dnstraverse (Ruby) | ExploreDNS (Go) |
|---|---|---|
| Language | Ruby | Go |
| Self-contained binary | No | Yes |
| All root servers | Yes | Yes |
| No-glue resolution | Yes | Yes |
| JSON output | No | Yes |
| Server fingerprinting | Yes | Yes |
| CNAME loop detection | Partial | Yes |
| Active development | Dormant | Active |
---
## Project Structure ## Project Structure
``` ```
cmd/exploredns/ CLI entry point cmd/exploredns/ CLI entry point and flag parsing
internal/dns/ DNS query operations internal/config/ Configuration types, validation, and usage text
internal/traverse/ DNS tree traversal internal/dns/ DNS query layer, root discovery, transport
internal/fingerprint/ DNS server fingerprinting internal/traverse/ Core traversal engine, referral resolution, caching
internal/output/ Result formatting and output internal/fingerprint/ DNS server version fingerprinting (version.bind CHAOS)
internal/config/ Configuration management internal/output/ Result formatting — text tree and JSON renderers
internal/integration/ End-to-end integration tests
``` ```
---
## Development
```sh
make build # compile binary to bin/exploredns
make test # run all unit and integration tests
make lint # run go vet
make clean # remove build artefacts
```
Run a single package's tests:
```sh
go test ./internal/traverse/...
```
---
## Architecture Overview
```
main → config.Parse → traverse.NewTraverser → traverse.Traverse
│
┌─────────▼──────────┐
│ Stack (BFS/DFS) │
│ Referral queue │
└─────────┬──────────┘
│ per referral
┌─────────▼──────────┐
│ processReferral │
│ ├─ resolveGlue │ (no-glue NS resolution)
│ └─ queryServer │ (dns.Query)
└─────────┬──────────┘
│
┌─────────────▼──────────────┐
│ Response classifier │
│ Answer / Referral / │
│ CNAME / NXDOMAIN / │
│ SERVFAIL / Error │
└─────────────┬──────────────┘
│
┌─────────▼──────────┐
│ output.Formatter │
│ (text | JSON) │
└────────────────────┘
```
The traversal engine (`internal/traverse`) maintains a work stack of
`Referral` objects. Each referral represents a single query to a single set
of nameservers. When a response contains further referrals, child `Referral`
objects are pushed onto the stack and processed in turn.
The `InfoCache` is used to store glue records discovered during traversal. In
fast mode (default), a single root cache is shared across all branches so that
glue discovered early is reused. In non-fast mode, each branch gets its own
independent cache.
---
## License ## License
MIT MIT — see [LICENSE](LICENSE).
+2
View File
@@ -1,3 +1,5 @@
// Package config defines the configuration types and defaults for ExploreDNS,
// along with validation helpers and the CLI usage text.
package config package config
import ( import (
+6
View File
@@ -1,3 +1,9 @@
// Package dns provides the low-level DNS query primitives used by ExploreDNS.
//
// It wraps the github.com/miekg/dns library to provide retrying, TCP fallback,
// EDNS0 buffer size negotiation, and root server discovery. The package is
// intentionally narrow: it sends iterative (non-recursive) queries and returns
// the raw responses for the traversal engine to interpret.
package dns package dns
import ( import (
+7
View File
@@ -1,3 +1,10 @@
// Package fingerprint identifies DNS server software by querying the
// version.bind name in the CHAOS class. Many authoritative and recursive DNS
// servers respond with a version string (e.g. "BIND 9.18.1-1") that can be
// used to identify the software and version in use.
//
// Queries are cached per server IP so that repeated lookups within a single
// traversal run do not incur extra network round-trips.
package fingerprint package fingerprint
import ( import (
+10
View File
@@ -1,3 +1,13 @@
// Package output renders ExploreDNS traversal results for human consumption or
// machine processing.
//
// Two formats are supported:
//
// - FormatText — a coloured hierarchical tree (default)
// - FormatJSON — a JSON array of traversal results
//
// Create a Formatter via NewFormatter and call RunTraversal to drive the
// traversal engine and stream output incrementally.
package output package output
import ( import (
+26
View File
@@ -1 +1,27 @@
// Package traverse implements the core DNS traversal engine for ExploreDNS.
//
// The traversal engine starts from the DNS root servers and iteratively
// follows every referral it receives, building a complete picture of the
// delegation path for a domain. Unlike a standard recursive resolver, which
// stops at the first authoritative answer, the traversal engine explores every
// branch so that delegation mismatches, lame delegations, or split authorities
// are all visible in the output.
//
// # Architecture
//
// A Traverser maintains a stack of Referral objects. Each Referral
// represents a pending query to a specific set of nameservers for a specific
// name and record type. The engine pops referrals one at a time, sends the
// query, classifies the response, and pushes any child referrals back onto the
// stack.
//
// When a referral contains nameserver names but no glue records (IP addresses),
// the engine resolves them via a secondary traversal before continuing.
//
// # Caching
//
// An InfoCache stores discovered glue records. In fast mode (default) a
// single root cache is shared across all branches so that glue discovered in
// one branch is immediately available to sibling branches. Disable fast mode
// (TraverserConfig.Fast = false) for fully independent branch resolution.
package traverse package traverse
+11
View File
@@ -11,12 +11,20 @@ import (
miekgdns "github.com/miekg/dns" miekgdns "github.com/miekg/dns"
) )
// TraverserConfig configures the behaviour of a Traverser.
type TraverserConfig struct { type TraverserConfig struct {
// MaxDepth is the maximum referral depth before the traversal gives up.
MaxDepth int MaxDepth int
// QueryType is the DNS record type to query (e.g. dns.TypeA).
QueryType uint16 QueryType uint16
// RootConfig controls how root servers are discovered.
RootConfig *dns.RootDiscoveryConfig RootConfig *dns.RootDiscoveryConfig
// QueryConfig controls per-query transport parameters.
QueryConfig *dns.QueryConfig QueryConfig *dns.QueryConfig
// RootAddrs is an optional pre-seeded list of root server IP addresses.
// When non-empty, root discovery via RootConfig is skipped.
RootAddrs []net.IP RootAddrs []net.IP
// Hooks provides optional callbacks for traversal events.
Hooks *TraverserHooks Hooks *TraverserHooks
// Fast controls cache sharing across branches. When true (default), child // Fast controls cache sharing across branches. When true (default), child
// branches inherit glue discovered by earlier branches via the shared root // branches inherit glue discovered by earlier branches via the shared root
@@ -37,11 +45,14 @@ func DefaultTraverserConfig() *TraverserConfig {
} }
} }
// TraversalResult pairs a Referral with the Response received when it was processed.
type TraversalResult struct { type TraversalResult struct {
Referral *Referral Referral *Referral
Response *Response Response *Response
} }
// Traverser performs an exhaustive iterative DNS traversal starting from the
// root servers. Create one via NewTraverser and call Traverse to start a run.
type Traverser struct { type Traverser struct {
config *TraverserConfig config *TraverserConfig
exchange dns.ExchangeFunc exchange dns.ExchangeFunc