# dns.squish.net / dnstraverse — Reference Behaviour Spec
Compiled 2026-07-07 for diffing ExploreDNS against the original. Source precedence used throughout: **archived/live site output > Ruby source (squish/dnstraverse @ 733cc0b, v0.1.13) > secondhand accounts**. Each claim is tagged [LIVE] (probed 2026-07-07), [WB] (Wayback capture, date given), [SRC] (Ruby source file), or [DOC] (author's own docs at www.squish.net/dnstraverse/). Raw artifacts referenced are preserved under `/private/tmp/claude-502/-Users-ghansen-src-ExploreDNS/8c18e9d7-a07d-43e8-a21b-b9aad8182912/scratchpad/` (subdirs `squish/`, `websweep/`, Ruby clone in `dnstraverse/`).
---
## 1. Availability
**The site is UP.** [LIVE] `https://dns.squish.net/` and `http://dns.squish.net/` both return HTTP 200 (Cloudflare edge; backend `X-Powered-By: Phusion Passenger 5.0.30`, Rails session cookie `_dnstraverseweb_session`). Footer: **"UI 2.0.1 / Engine 0.1.14"** — the engine is the Ruby `dnstraverse` gem; the Rails wrapper ("dnstraverseweb") is closed-source (not in any public repo of GitHub user `squish`). "Kindly hosted by the ISC"; author James Ponder.
Practical constraints on the live site:
- Anonymous submission requires solving a Google reCAPTCHA v2 (a captcha-less POST to `/traverses/create_anon` gets 302 → `/` with flash `Sorry, the captcha did not succeed, please try again.`). [LIVE]
- **Old traverse data is purged**: pre-2026 traverse IDs still return the page shell (Name/Type/Date), but `/fetch` replies only `setTimeout("poll()", 1000);` forever and `/detail/fetch` replies `count = 0; setTimeout("poll()", 1000);` — results are never re-rendered. [LIVE] So a fresh captcha-solved run in a browser is the only way to capture new complete output.
Best archival/primary sources, in order of authority:
1. **Wayback Machine** — ~4,076 archived `/traverses/<32-hex>` show pages and 114 `/detail/fetch` RJS streams (CDX API). Best complete artifacts: careerhosts.net/A show+detail+servers (2016-03), learningsuite.byu.edu/A (2015-03), dadzi.ir/A all-failure (2019-06), www.ilpd-afrique.com/A NXDOMAIN (2017-11), intellivida.ca/A mixed (2011-09), www.nike.com CNAME chain detail/fetch (2018-03), `/info?packet=N` popups (aruba.it, 2021-01). Site captured live as recently as 2026-06-20; page wording is essentially unchanged 2011→2026 (engine only moved 0.1.11→0.1.14), so any era is representative. [WB]
2. **Ruby engine source** — github.com/squish/dnstraverse master @ 733cc0b (2011-12-17, v0.1.13; rubygems shows 0.1.14 released 2012-04-30). Cloned locally; this is the exact engine behind the site.
3. **Author's engine docs** — `http://www.squish.net/dnstraverse/` (+ manual.html, switches.html), live. [DOC]
4. **Old v1 Perl service** — `http://www.squish.net/dnscheck/dnscheck.cgi` **still executes live queries with no captcha** (verified 2026-07-07; full www.example.com/A run captured). It is a different, cruder engine (author's FAQ: the new one "is more accurate than the Perl-based dnscheck service, including DNS bailiwick concepts, simulation of the resolver cache"; v1 source "is not available") — useful only for cross-checking aggregate percentage math, not wording.
---
## 2. Inputs
### 2.1 Web form (dns.squish.net, confirmed identical 2011→live 2026) [LIVE][WB]
Form `id=new_traverse`, POST `/traverses/create_anon`, submit button `name=commit value=Create`:
| Field | Details | Default |
|---|---|---|
| `traverse[domain_name]` | text, size 30, hint "e.g. www.example.com". Help: "This is the full DNS entry to check. For example: www.google.com, news.bbc.co.uk, or www.cnn.com" / "If your web site is http://www.example.com/ you should enter the www.example.com component only." | (empty) |
| `traverse[domain_type]` | select, options exactly in order: **A, NS, MX, PTR, TXT, AAAA, SOA, SPF**. Caption: "Leave as 'A' unless you know what you're doing." Help notes PTR format is `D.C.B.A.in-addr.arpa`. | **A** |
| Human Check | reCAPTCHA v2 (sitekey `6LdIf08UAAAAAJgYP1bvi7vmf-EXEHWXH_AqthF9`), required for anonymous; "Registration is optional, but means you don't need to enter a reCAPTCHA every time!" | — |
| `authenticity_token` | Rails CSRF, session-bound | — |
That is the **entire** web surface: no root-server, depth, retries, UDP size, fast-mode or IPv6 options ("Currently this is IPv4 only."). Success redirects to `/traverses/<32-hex-id>` (ID is random per submission, **not** md5(name/type) — tested [WB]; "Friendly URLs for emailing"). Other routes: `/traverses/ ` per aggregated outcome, percent as `%5.1f%%` (no colon on web):
```html
50.0%
Answered from ns1.virtualempire.com (38.71.66.4)
`; CSS renders the answer italic, offset under its line. Observed mixes: `93.3% answered with … / 6.7% resulted in an exception` [WB 2011 intellivida.ca]; `100% resulted in an error` (all-NXDOMAIN) [WB 2017]; `100% resulted in an exception` [WB 2019 dadzi.ir]; `100% resulted in a lame referral` [WB 2013 g-p.es].
**Results** (`div#results`, heading "Results"), one `careerhosts.net. 86400 IN A 38.71.67.100
`; failure lines have no ``). Verbatim failure catalogue from archived pages [WB]: - `No such domain (NXDOMAIN) at ns1.cctld.co (156.154.100.25)` - `Query timed out at ns2.twisted4life.com (194.152.92.62)` - `Server failure (SERVFAIL) at casper.ln1x.ablesky.com (173.255.217.216)` - `Refused at ns1.afdns.net (190.183.61.2)` - `NODATA (for this type) at ns1.iranfirewall.in (148.251.110.146)` - `Lame referral received from f.nic.es (130.206.1.2) to dns2.namecheaphosting.com (69.160.33.71)` — web adds "received"; CLI says `Lame referral from …` [SRC referral.rb:506] - `recvfrom failed from 185.208.174.92; No route to host - recvfrom(2) at ns1.dadzi.ir (185.208.174.92)` (exception text verbatim from Ruby) - Failures inside a resolve append `While querying ns1.twisted4life.com/IN/A` (CLI: `While querying #{qname}/#{qclass}/#{qtype}`). Then links: **"Traversal detail"** → `/detail`; **"Server location and version information"** → `/servers`; while running: "Please wait while your traversal is completed, or alternatively watch the traversal as it progresses." ### 4.2 Web detail page `/traverses//detail` [WB streams; shell confirmed LIVE] Adds table rows **Initial Root** (`f.root-servers.net, 192.5.5.241` + `(1 roots returned)`) and **Query Key** — one coloured dotted-border chip per query, text like `A careerhosts.net`; colours cycle `#fefecc, #ccfecc, #ccfefe, #ccccfe, #feccfe, #fee5cc`. Banner node: `Traversing for careerhosts.net type A starting at the root(s)`. Tree rows are `div.node_line` tables: indentation drawn with 32×23 px spacer images (`spacer_gap/line/tee/end.png`); node text is `#{server} (#{ip}) <#{bailiwick}>` (root renders `<>`; glueless renders `( )` with a placeholder span later filled, truncated by the UI, e.g. `95.130.252.149,Loop encounter...`). Node extras: progress spinner → status icon linking `info_url('/traverses/ /info?packet=N')` (`referral.png` / `success.png` / `warning.png`), `show resolve`/`hide resolve` toggle revealing the hidden `.0` resolve subtree, and italic `completed earlier` span for fast-mode hits. Colour lifecycle: inserted muted (`#ededdd`; resolve nodes `#ddeddd`) → active `border:1px solid black` + query-key colour → completed. Updates arrive as Prototype.js RJS from `/detail/fetch?count=N` (`Element.insert`, `visualEffect`, `setStyle`), each chunk ending `count = N; setTimeout("poll()", 1000);`. On completion: Results injected (same stats_line HTML as show page), then a **Fingerprinting** phase cycling every server name, then the "further" (servers) link appears. ### 4.3 Web packet popup `/info?packet=N` [WB 2021] ` What is arudns1.aruba.it type A?
` + `Answer from 192.12.192.5 (dns.nic.it)
` + `` dnsruby dump (`;; Answer received from 192.12.192.5 (189 bytes)`, `;; Security Level : UNCHECKED`, header/flags/sections, `OPT pseudo-record : payloadsize 4096, xrcode 0, version 0, flags 0`) + `Status: referral
` "A referral occured. This means that the resolver did not know the answer, but indicated that results can be found elsewhere." (or `Status: answered` / "The server was able to answer the question successfully.") + `The following records were considered worthy of caching:
` + `These servers were chosen in bailiwick 'aruba.it' for the referral:
` (`name (ip)` lines) + `Results after processing this node and all branches beneath:
` with subtree-scoped stats_lines. Fast-mode variant prepends blue `This was completed earlier (fast mode)`. ### 4.4 Web servers page `/traverses//servers` [WB 2016/2025; shell LIVE] Google map + `table#servers_table`, columns exactly: **Country | City | Area code | Postal code | Servers | Software guess |** (+Show on map). Servers cell: `38.71.66.4 (ns1.virtualempire.com)
…` grouped by geolocation; Software guess: ` ISC BIND 9.2.3rc1 -- 9.4.0a4 (9.6.1-P1)`, ` VeriSign ATLAS ` (2025 adds ` (ATLAS)` suffix), ` TIMEOUT`, ` No match found`. Fingerprint DB is fpdns-derived ("Portions Copyright (c) 2003,2004,2005 Roy Arends & Jakob Schlyter"). ### 4.5 CLI output [DOC home page sample + mcgill.org.za 2017 run + SRC] Header (unless -q): `# Using fast mode` / `# Limiting traverse to one root` / `# UDP size N (EDNS0 is on)` [always prints "on" due to source bug `options[:udpsize == 512]`] / `# Retries N, max depth N` / `# Allow TCP is true, always TCP is false`; then `Using E.ROOT-SERVERS.NET (192.203.230.10) as initial root` / `Running query www.google.com type a`. Progress, verbose (`refid [qname] server (ips)`) [DOC, verbatim]: ``` 1 [www.google.com] E.ROOT-SERVERS.NET (192.203.230.10) <> 1.1 [www.google.com] B.GTLD-SERVERS.NET (192.33.14.30) 1.1.1 [www.google.com] ns1.google.com (216.239.32.10) 1.1.1.1 [www.l.google.com] a.l.google.com (209.85.139.9) ``` Non-verbose omits `[qname]`/` ` [mcgill 2017, verbatim]: ``` 1.2.2 ns1.coza.net.za -- resolving 1.2.2 ns1.coza.net.za (66.135.62.20,Loop encountered resolving ns.coza.net.za) 1.3.1 ns4.iafrica.com (196.7.142.131) -- completed earlier (1.2.3) ``` `Results:` — blocks with `printf "%5.1f%%: "` then per status [SRC referral.rb:503-532]: `Answer from ( )` + RRs indented 12 spaces; `No glue at ( ) for `; `Lame referral from ( ) to ( )`; `Loop encountered at `; `CNAME loop encountered at `; ` at ( )`; `NODATA (for this type) at ( )`; ` at …`; fallback `Stopped at ( ))` [trailing `)` is a source bug]; plus `While querying / / ` when the failing query differs. [DOC, verbatim]: ``` 14.3%: Answer from e.l.google.com (209.85.137.9) www.l.google.com. 300 IN A 74.125.77.99 ``` `Summary Results:` — same wording set as web (Section 4.1), prefix two spaces, e.g. ` 99.8% answered with co.za. 3600 IN NS ns0.is.co.za.` … ` 0.2% resulted in a loop` [mcgill 2017]. RR whitespace collapsed to single spaces; continuation RRs aligned under text start. `--show-servers`: `The following servers were encountered:` then `printf "%#{w}s: %-15s%s"` rows sorted by lowercased reversed name [DOC, verbatim]: ``` ns1.google.com: 216.239.32.10 ISC BIND 9.2.3rc1 -- 9.4.0a0 (9.4.2-P1) a.gtld-servers.net: 192.5.6.30 VeriSign ATLAS ``` ### 4.6 Legacy v1 (Perl dnscheck) — different engine, different wording [LIVE run 2026-07-07] Nested-table HTML; sections: root-server workings and SOA-serial check, then `Traversal of DNS for .` with units `Asking a.gtld-servers.net (192.5.6.30) for www.example.com (type A)` / `Referral: example.com is at hera.ns.cloudflare.com (108.162.192.162)` / `Response is:` with per-branch `16.7% ( ) with `; dedupe `[see above for results]`; final `Results`: `16.1% of queries will be returned by 108.162.195.228 (elliott.ns.cloudflare.com)` + RRset, `3.5% of queries will end in failure at too many nested queries`, `0.0% of queries will end in failure at 192.5.6.30 (a.gtld-servers.net) - failed to resolve h.gtld-servers.net due to 192.5.6.30 - nameserver loop detected`. **Do not copy this wording into ExploreDNS comparisons against dns.squish.net** — only the aggregate math (probability multiplication/summation) transfers. --- ## 5. Confidence notes **Confirmed by primary sources (archived/live site output + Ruby source agree):** - Web form fields/defaults, routes, captcha behaviour, polling protocol (LIVE + WB, identical 2011–2026). - Single-initial-root default, equal-split probability model and exact aggregation formulas, bailiwick filtering, hierarchical per-branch cache, fast mode, refid scheme with `.0` resolve subtrees, CNAME restart-from-cache, depth 20 / retries 2 (SRC, corroborated by WB output and DOC). - Result/Summary wording and percent formatting for: answered, error (NXDOMAIN/SERVFAIL/Refused), exception (timeout/recvfrom), nodata, lame referral, "While querying" suffix (WB verbatim + SRC format strings, verified in the local clone: `summary_stats.rb:76-99,135-136`, `referral.rb:503-532`). - CLI output shapes (DOC's own annotated sample + one full independent 0.1.14 run from mcgill.org.za 2017 + SRC). **Confirmed by source only (never seen in captured output):** web wording for `noglue` ("found no glue" / "No glue at X (ip) for Y"), `loop` and `cname_loop` result/summary lines on the *web* (CLI loop lines are confirmed via mcgill); `Stopped at` fallback; `Formate error (FORMERR)` typo; fast-cache key details; lame-referral "strictly deeper zone" rule. These are near-certain — the site runs this gem — but flagged CONFIRMED-by-source, not by output. **Known divergences to be careful with when diffing:** web "Answered from␣␣" (double space) vs CLI "Answer from"; web "Lame referral received from" vs CLI without "received"; web EDNS payloadsize 4096 vs CLI default 2048 (archived output preferred for the web service); library-vs-CLI internal defaults (10/512/false vs 20/2048/true); source bugs worth deciding whether to replicate (`(9.4.2-P1)`-style CLI EDNS banner always "on", `Stopped at …)` stray paren, answered-merge prob discard in `stats_display`, "CNANE loop" typo in `DecodedQuery#to_s`). **Not recovered / open items:** - The Rails front-end (dnstraverseweb) source — closed; web-only wording is reconstructed from captures. - Exactly one engine version gap: site runs 0.1.14; the cloned source is 0.1.13 master (rubygems has 0.1.14; diff not fetched — format strings match 0.1.14 outputs observed, so risk is low). - No archived web sample of a *completed* SPF/TXT/SOA traversal, of the web progress-percent computation, or of web noglue/loop/cname_loop result lines. - A fresh end-to-end capture is achievable: the live site works behind one reCAPTCHA — solve it once in a browser and record `/traverses/ `, `/detail` (streaming XHRs to `/fetch` and `/detail/fetch`), and `/servers`. The author's test domains `yellowtealpurple.net` / `testcname.yellowtealpurple.net` (seen Aug 2025) are candidate CNAME test vectors. The v1 CGI remains captcha-free for aggregate-math cross-checks. Where sources conflicted, archived site output was used (traverse IDs random not md5 — WB tests; EDNS 4096 on web — WB packet dumps; web "received"/double-space wordings — WB HTML), with the Ruby source as tie-breaker for everything unobserved.