851203e8f6 fix: merge main into PR branch, resolve CI and go.mod conflicts
- Keep go-version-file: 'go.mod' from PR (reads Go version from go.mod)
- Keep gitea.hansenits.com.au module path in coverage check
- Pick up .gitignore bin/* entry from main
- go.mod: keep go 1.24.0 directive from main (GOTOOLCHAIN=local)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-06-17 22:05:16 +10:00
…

ExploreDNS

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.

Inspired by the classic 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
  • Web interface — browser-based UI backed by an HTTP API server with real-time Server-Sent Events progress streaming

Installation

Pre-built binary

Download the latest release binary for your platform from the Releases page.

Build from source

Requires Go 1.21 or later.

git clone https://gitea.hansenits.com.au/hits/ExploreDNS.git
cd ExploreDNS
make build          # produces bin/exploredns
make build-server   # produces bin/exploredns-server
make build-all      # produces both binaries

go install

go install gitea.hansenits.com.au/hits/ExploreDNS/cmd/exploredns@latest
go install gitea.hansenits.com.au/hits/ExploreDNS/cmd/server@latest

Quick Start

# 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

CLI Reference

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

Web Interface

ExploreDNS ships a second binary — exploredns-server — that exposes a browser-based UI and a JSON REST API backed by the same traversal engine as the CLI.

Starting the server

# Default: listen on :8080
./bin/exploredns-server

# Custom address
./bin/exploredns-server --addr :9090
./bin/exploredns-server --addr 127.0.0.1:8080

Or via Make:

make build-server
./bin/exploredns-server

Open http://localhost:8080 in your browser. The SPA lets you enter a domain, choose a record type, and watch the traversal progress in real time. When the traversal completes the full result tree is displayed in the browser.

API endpoints

Method Path Description
POST /api/traverse Start an asynchronous traversal
GET /api/traverse/{id} Poll traversal status and results
GET /api/traverse/{id}/stream Server-Sent Events live progress stream
GET /api/health Health check — returns {"status":"ok"}

POST /api/traverse

Request body (JSON):

{
  "domain":    "www.example.com",
  "type":      "A",
  "all_roots": false
}

type defaults to "A" if omitted. all_roots queries all 13 root server sets in parallel (equivalent to --all-root-servers in the CLI).

Response (202 Accepted):

{
  "id":     "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status": "running"
}

GET /api/traverse/{id}

Returns a snapshot of the job including the full result list once complete. status is one of running, complete, or error.

{
  "id":         "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status":     "complete",
  "domain":     "www.example.com",
  "query_type": "A",
  "started_at": "2024-01-01T12:00:00Z",
  "done_at":    "2024-01-01T12:00:02Z",
  "results": [
    {
      "depth":         2,
      "probability":   1.0,
      "response_type": "Answer",
      "server":        "192.0.2.53:53",
      "answers":       ["www.example.com. 3600 IN A 93.184.216.34"]
    }
  ]
}

GET /api/traverse/{id}/stream

An SSE stream of ProgressEvent objects, one per data: message. Past events recorded before the client connected are replayed immediately, then live events follow. The stream ends with event: done.

data: {"stage":"start","depth":1,"name":"www.example.com","qtype":"A","bailiwick":"com"}

data: {"stage":"complete","depth":1,"name":"www.example.com","qtype":"A","server":"192.0.2.53:53","bailiwick":"com"}

event: done
data: {}

Completed jobs are kept in memory for one hour before being purged.


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

cmd/exploredns/        CLI entry point and flag parsing
cmd/server/            HTTP API server entry point
internal/config/       Configuration types, validation, and usage text
internal/dns/          DNS query layer, root discovery, transport
internal/traverse/     Core traversal engine, referral resolution, caching
internal/fingerprint/  DNS server version fingerprinting (version.bind CHAOS)
internal/output/       Result formatting — text tree and JSON renderers
internal/integration/  End-to-end integration tests
web/api/               HTTP handler, job store, SSE streaming, static assets

Development

make build          # compile CLI binary to bin/exploredns
make build-server   # compile server binary to bin/exploredns-server
make build-all      # compile both binaries
make test           # run all unit and integration tests
make lint           # run go vet
make clean          # remove build artefacts

Run a single package's tests:

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

MIT — see LICENSE.

S
Description
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.
https://exploredns.hansenits.com
Readme GPL-3.0
14 MiB
2026-07-07 15:16:11 +00:00
Languages
Go 84.3%
HTML 14%
Shell 1.5%
Makefile 0.2%