- 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:
co-authored by
Copilot
multica-agent
parent
fe1afe2a97
commit
9aa85d8e5d
@@ -11,12 +11,14 @@ import (
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// ResolutionState tracks whether a Referral's nameserver addresses have been resolved.
|
||||
type ResolutionState int
|
||||
|
||||
// Resolution state constants.
|
||||
const (
|
||||
StateUnresolved ResolutionState = iota
|
||||
StateResolving
|
||||
StateResolved
|
||||
StateUnresolved ResolutionState = iota // nameserver addresses are not yet known
|
||||
StateResolving // address resolution is in progress
|
||||
StateResolved // addresses are available in Addresses
|
||||
)
|
||||
|
||||
func (s ResolutionState) String() string {
|
||||
@@ -32,19 +34,32 @@ func (s ResolutionState) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Referral represents a pending DNS query: a (name, qtype) pair delegated to a
|
||||
// set of nameserver addresses. Referrals form a linked-list chain through
|
||||
// Parent, enabling loop and depth detection.
|
||||
type Referral struct {
|
||||
Name string
|
||||
Qtype uint16
|
||||
Qclass uint16
|
||||
// Name is the fully-qualified domain name being queried.
|
||||
Name string
|
||||
// Qtype is the DNS record type being queried.
|
||||
Qtype uint16
|
||||
// Qclass is the DNS class (always ClassINET in practice).
|
||||
Qclass uint16
|
||||
// Bailiwick is the zone that delegated this referral.
|
||||
Bailiwick string
|
||||
|
||||
// Addresses holds the resolved IP addresses for this nameserver referral.
|
||||
Addresses []net.IP
|
||||
State ResolutionState
|
||||
// State tracks whether Addresses have been resolved.
|
||||
State ResolutionState
|
||||
|
||||
// NSName is the nameserver hostname (before IP resolution).
|
||||
NSName string
|
||||
// Parent is the Referral that triggered this one, or nil for the root.
|
||||
Parent *Referral
|
||||
Depth int
|
||||
Prob float64
|
||||
// Depth is the number of referral hops from the root.
|
||||
Depth int
|
||||
// Prob is the probability weight for this branch (product of 1/fanout at each step).
|
||||
Prob float64
|
||||
}
|
||||
|
||||
// idnaLookup is the IDN lookup profile used to convert internationalised domain
|
||||
@@ -70,6 +85,9 @@ func toASCII(name string) string {
|
||||
return ascii
|
||||
}
|
||||
|
||||
// NewReferral creates a Referral for (name, qtype) within bailiwick, at the
|
||||
// given depth and probability. The name and bailiwick are normalised to
|
||||
// lowercase FQDN, and internationalised labels are converted to punycode.
|
||||
func NewReferral(name string, qtype uint16, bailiwick string, depth int, prob float64, parent *Referral) *Referral {
|
||||
return &Referral{
|
||||
Name: miekgdns.Fqdn(strings.ToLower(toASCII(name))),
|
||||
@@ -83,6 +101,8 @@ func NewReferral(name string, qtype uint16, bailiwick string, depth int, prob fl
|
||||
}
|
||||
}
|
||||
|
||||
// InBailiwick reports whether name is within this referral's bailiwick zone.
|
||||
// A root bailiwick ("." or "") is treated as matching everything.
|
||||
func (r *Referral) InBailiwick(name string) bool {
|
||||
if r.Bailiwick == "" || r.Bailiwick == "." {
|
||||
return true
|
||||
@@ -91,10 +111,12 @@ func (r *Referral) InBailiwick(name string) bool {
|
||||
return miekgdns.IsSubDomain(r.Bailiwick, fqdn)
|
||||
}
|
||||
|
||||
// HasAddresses reports whether at least one nameserver IP address is known.
|
||||
func (r *Referral) HasAddresses() bool {
|
||||
return len(r.Addresses) > 0
|
||||
}
|
||||
|
||||
// SetAddresses stores addrs and updates State accordingly.
|
||||
func (r *Referral) SetAddresses(addrs []net.IP) {
|
||||
r.Addresses = addrs
|
||||
if len(addrs) > 0 {
|
||||
@@ -104,6 +126,8 @@ func (r *Referral) SetAddresses(addrs []net.IP) {
|
||||
}
|
||||
}
|
||||
|
||||
// CircularReferralError is returned when a referral chain revisits a nameserver,
|
||||
// indicating a circular delegation.
|
||||
type CircularReferralError struct {
|
||||
Name string
|
||||
Chain []string
|
||||
@@ -113,6 +137,8 @@ func (e *CircularReferralError) Error() string {
|
||||
return fmt.Sprintf("circular referral detected for %s: %v", e.Name, e.Chain)
|
||||
}
|
||||
|
||||
// UnresolvableNameserverError is returned when a nameserver hostname cannot be
|
||||
// resolved to any IP address.
|
||||
type UnresolvableNameserverError struct {
|
||||
Name string
|
||||
Reason string
|
||||
@@ -122,6 +148,9 @@ func (e *UnresolvableNameserverError) Error() string {
|
||||
return fmt.Sprintf("unresolvable nameserver %s: %s", e.Name, e.Reason)
|
||||
}
|
||||
|
||||
// Resolve attempts to resolve the nameserver addresses for this Referral by
|
||||
// performing a fresh iterative traversal. It stores the found addresses and
|
||||
// updates State. Returns an error when resolution fails.
|
||||
func (r *Referral) Resolve(ctx context.Context, traverser *Traverser, cache *InfoCache, visited map[string]bool, depth int) error {
|
||||
if r.HasAddresses() {
|
||||
r.State = StateResolved
|
||||
|
||||
Reference in New Issue
Block a user