docs: comprehensive documentation for ExploreDNS
CI / test (pull_request) Failing after 2m13s

- Rewrite README.md with overview, features, installation (go install +
  build from source), quick start, full CLI flag reference table,
  output section descriptions, project structure, and development guide

- Add package-level doc comments to all five internal packages:
  config, dns, fingerprint, output, traverse (via doc.go or existing
  package-declaration files)

- Add GoDoc comments on every exported type, constant, function, and
  method across all packages:
  - internal/config: Config struct fields, all Parse*/Default/Validate
  - internal/dns: QueryConfig, Resolver, BasicResolver, CachingResolver,
    ExchangeFunc, RootServer, RootDiscoveryConfig, DecodedResponse,
    ResponseClassification, all exported helpers
  - internal/fingerprint: Fingerprinter, New, NewWithTimeout, Query,
    FingerprintAll
  - internal/traverse: Traverser, TraverserConfig, TraversalResult,
    Referral, ResolutionState, Response, ResponseType, InfoCache,
    Stack, TraverserHooks, EventStage, TraversalEvent, EventHandler,
    CircularReferralError, UnresolvableNameserverError
  - internal/output: Format, Config, Formatter, SummaryStats,
    NewFormatter, AttachHooks, RunTraversal, DefaultConfig,
    ComputeSummary

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:01:51 +10:00
co-authored by Copilot multica-agent
parent fe1afe2a97
commit 9aa85d8e5d
21 changed files with 675 additions and 91 deletions
+38 -15
View File
@@ -7,19 +7,21 @@ import (
miekgdns "github.com/miekg/dns"
)
// ResponseType classifies the outcome of querying a single Referral.
type ResponseType int
// Response type constants used to drive traversal logic.
const (
RespReferral ResponseType = iota
RespAnswer
RespCNAMEFollow
RespNODATA
RespNXDOMAIN
RespSERVFAIL
RespREFUSED
RespNOTIMPL
RespCNAMELoop
RespError
RespReferral ResponseType = iota // server returned an NS referral
RespAnswer // server returned a final answer
RespCNAMEFollow // answer contains a CNAME requiring further traversal
RespNODATA // NOERROR with no matching records
RespNXDOMAIN // name does not exist
RespSERVFAIL // server failure
RespREFUSED // query refused
RespNOTIMPL // query type not implemented
RespCNAMELoop // CNAME chain revisits a name already in the chain
RespError // transport or decoding error
)
func (rt ResponseType) String() string {
@@ -49,15 +51,25 @@ func (rt ResponseType) String() string {
}
}
// Response is the result of querying a single Referral against a specific
// nameserver. It contains the decoded DNS message, the classified ResponseType,
// and any error message for display.
type Response struct {
Referral *Referral
Server net.IP
Cache *InfoCache
Decoded *dns.DecodedResponse
Type ResponseType
// Referral is the query this response corresponds to.
Referral *Referral
// Server is the nameserver IP that was queried.
Server net.IP
// Cache is the InfoCache used during processing (for glue resolution).
Cache *InfoCache
// Decoded holds the structured DNS response fields.
Decoded *dns.DecodedResponse
// Type is the high-level classification of this response.
Type ResponseType
// ErrorMessage is a human-readable description when Type is RespError or RespCNAMELoop.
ErrorMessage string
}
// NewResponse creates a Response for the given Referral and server.
func NewResponse(ref *Referral, server net.IP, cache *InfoCache) *Response {
return &Response{
Referral: ref,
@@ -66,6 +78,9 @@ func NewResponse(ref *Referral, server net.IP, cache *InfoCache) *Response {
}
}
// Process decodes msg, classifies it, and populates r.Type and r.Decoded.
// Synthesises CNAME records from DNAME mappings when no explicit CNAME is present.
// Returns r for chaining.
func (r *Response) Process(msg *miekgdns.Msg) *Response {
if msg == nil {
r.Type = RespError
@@ -133,6 +148,10 @@ func (r *Response) hasFinalAnswer() bool {
return false
}
// ChildReferrals returns the set of child Referrals implied by a referral
// response. It extracts nameservers from the authority section, resolves
// any glue from the additional section, and sets Prob proportionally.
// Returns nil when Type != RespReferral.
func (r *Response) ChildReferrals() []*Referral {
if r.Type != RespReferral {
return nil
@@ -177,6 +196,8 @@ func (r *Response) ChildReferrals() []*Referral {
return children
}
// CNAMEFollowReferral constructs a follow-up Referral targeting the last CNAME
// in the chain. Returns nil when Type != RespCNAMEFollow.
func (r *Response) CNAMEFollowReferral() *Referral {
if r.Type != RespCNAMEFollow || len(r.Decoded.CNAMEChain) == 0 {
return nil
@@ -229,6 +250,8 @@ func (r *Response) resolveGlue(child *Referral) {
r.Cache.StoreGlue(nsName, child.Addresses)
}
// IsTerminal reports whether this response ends a traversal branch (no further
// referrals or CNAME follows are expected).
func (r *Response) IsTerminal() bool {
switch r.Type {
case RespAnswer, RespNODATA, RespNXDOMAIN, RespSERVFAIL, RespREFUSED, RespNOTIMPL, RespCNAMELoop, RespError: