- 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
+34
-10
@@ -7,17 +7,20 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// ResponseClassification categorises a DNS response at a high level,
|
||||
// independent of the raw RCODE.
|
||||
type ResponseClassification int
|
||||
|
||||
// Classification constants, in order from most to least specific.
|
||||
const (
|
||||
ResponseAnswer ResponseClassification = iota
|
||||
ResponseReferral
|
||||
ResponseNODATA
|
||||
ResponseNXDOMAIN
|
||||
ResponseSERVFAIL
|
||||
ResponseREFUSED
|
||||
ResponseNOTIMPL
|
||||
ResponseOther
|
||||
ResponseAnswer ResponseClassification = iota // answer section contains records
|
||||
ResponseReferral // non-authoritative NS referral
|
||||
ResponseNODATA // NOERROR with empty answer section
|
||||
ResponseNXDOMAIN // name does not exist (RCODE 3)
|
||||
ResponseSERVFAIL // server failure (RCODE 2)
|
||||
ResponseREFUSED // query refused (RCODE 5)
|
||||
ResponseNOTIMPL // not implemented (RCODE 4)
|
||||
ResponseOther // any other RCODE
|
||||
)
|
||||
|
||||
func (rc ResponseClassification) String() string {
|
||||
@@ -41,6 +44,7 @@ func (rc ResponseClassification) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// DecodedResponse holds the extracted, structured fields from a raw *dns.Msg.
|
||||
type DecodedResponse struct {
|
||||
Rcode int
|
||||
RcodeName string
|
||||
@@ -51,8 +55,10 @@ type DecodedResponse struct {
|
||||
Answers []dns.RR
|
||||
Authority []dns.RR
|
||||
Additional []dns.RR
|
||||
CNAMEChain []string
|
||||
DNAMEMappings []DNAMEMapping
|
||||
// CNAMEChain contains the ordered CNAME targets from the answer section.
|
||||
CNAMEChain []string
|
||||
// DNAMEMappings contains any DNAME records for redirect synthesis.
|
||||
DNAMEMappings []DNAMEMapping
|
||||
}
|
||||
|
||||
// DNAMEMapping holds a DNAME record's owner and target for redirect synthesis.
|
||||
@@ -61,6 +67,8 @@ type DNAMEMapping struct {
|
||||
Target string // e.g., "example.net."
|
||||
}
|
||||
|
||||
// DecodeResponse converts a raw *dns.Msg into a DecodedResponse.
|
||||
// Returns nil when msg is nil.
|
||||
func DecodeResponse(msg *dns.Msg) *DecodedResponse {
|
||||
if msg == nil {
|
||||
return nil
|
||||
@@ -171,10 +179,13 @@ func SynthesizeCNAMEFromDNAME(queryName, dnameOwner, dnameTarget string) string
|
||||
return prefix + target
|
||||
}
|
||||
|
||||
// IsTruncated reports whether msg has the TC (truncated) bit set.
|
||||
func IsTruncated(msg *dns.Msg) bool {
|
||||
return msg != nil && msg.Truncated
|
||||
}
|
||||
|
||||
// RcodeName returns the string representation of the RCODE in msg (e.g. "NOERROR").
|
||||
// Returns "UNKNOWN" when msg is nil.
|
||||
func RcodeName(msg *dns.Msg) string {
|
||||
if msg == nil {
|
||||
return "UNKNOWN"
|
||||
@@ -182,6 +193,7 @@ func RcodeName(msg *dns.Msg) string {
|
||||
return dns.RcodeToString[msg.Rcode]
|
||||
}
|
||||
|
||||
// ExtractAnswers returns the answer section of msg, or nil when msg is nil.
|
||||
func ExtractAnswers(msg *dns.Msg) []dns.RR {
|
||||
if msg == nil {
|
||||
return nil
|
||||
@@ -189,6 +201,7 @@ func ExtractAnswers(msg *dns.Msg) []dns.RR {
|
||||
return msg.Answer
|
||||
}
|
||||
|
||||
// ExtractAuthority returns the authority section of msg, or nil when msg is nil.
|
||||
func ExtractAuthority(msg *dns.Msg) []dns.RR {
|
||||
if msg == nil {
|
||||
return nil
|
||||
@@ -196,6 +209,8 @@ func ExtractAuthority(msg *dns.Msg) []dns.RR {
|
||||
return msg.Ns
|
||||
}
|
||||
|
||||
// ExtractCNAMEChain returns the ordered list of CNAME targets from the answer section.
|
||||
// Returns nil when msg is nil.
|
||||
func ExtractCNAMEChain(msg *dns.Msg) []string {
|
||||
if msg == nil {
|
||||
return nil
|
||||
@@ -203,6 +218,8 @@ func ExtractCNAMEChain(msg *dns.Msg) []string {
|
||||
return extractCNAMEChain(msg)
|
||||
}
|
||||
|
||||
// IsReferral reports whether msg is a non-authoritative NS referral
|
||||
// (NOERROR, empty answer section, NS records in authority, AA=false).
|
||||
func IsReferral(msg *dns.Msg) bool {
|
||||
if msg == nil || msg.Rcode != dns.RcodeSuccess || len(msg.Answer) > 0 {
|
||||
return false
|
||||
@@ -210,6 +227,8 @@ func IsReferral(msg *dns.Msg) bool {
|
||||
return hasNSRecords(msg.Ns) && !msg.Authoritative
|
||||
}
|
||||
|
||||
// IsNODATA reports whether msg is a NODATA response
|
||||
// (NOERROR with an empty answer section and no referral).
|
||||
func IsNODATA(msg *dns.Msg) bool {
|
||||
if msg == nil || msg.Rcode != dns.RcodeSuccess {
|
||||
return false
|
||||
@@ -223,6 +242,8 @@ func IsNODATA(msg *dns.Msg) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// HasCNAMEChain reports whether msg contains at least one CNAME record in its
|
||||
// answer section.
|
||||
func HasCNAMEChain(msg *dns.Msg) bool {
|
||||
if msg == nil {
|
||||
return false
|
||||
@@ -230,6 +251,9 @@ func HasCNAMEChain(msg *dns.Msg) bool {
|
||||
return len(extractCNAMEChain(msg)) > 0
|
||||
}
|
||||
|
||||
// FormatRecord returns a human-readable representation of a DNS resource record
|
||||
// in the form: NAME TTL CLASS TYPE RDATA.
|
||||
// Returns an empty string when rr is nil.
|
||||
func FormatRecord(rr dns.RR) string {
|
||||
if rr == nil {
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user