# 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](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 - **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](https://gitea.hansenits.com.au/hits/ExploreDNS/releases). ### Build from source Requires Go 1.21 or later. ```sh 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 ```sh go install github.com/hits/ExploreDNS/cmd/exploredns@latest go install github.com/hits/ExploreDNS/cmd/server@latest ``` --- ## Quick Start ```sh # 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] Query Options: --type Record type to query (default: A) Supported: A, AAAA, NS, CNAME, MX, TXT, SOA, PTR, ANY --root-server 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 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 Per-server retry count, 0–10 (default: 2) Traversal Options: --max-depth 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 ```sh # 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: ```sh 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): ```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`): ```json { "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`. ```json { "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](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) 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 ```sh 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: ```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 MIT — see [LICENSE](LICENSE).