From 8e7beacc223188ee0eacae4e62404ce10d18e46b Mon Sep 17 00:00:00 2001 From: Gary Hansen Date: Mon, 8 Jun 2026 02:32:58 +1000 Subject: [PATCH] fix: address code review issues on PR #9 - gofmt main.go to fix tab indentation in main() body - stats.go ComputeSummary: return nil when Answers and ByType are empty - dns/types.go: remove duplicate ParseQueryType (dead code) - formatter.go: log hook errors to stderr when Debug > 0; add Debug to Config - text.go referralID: remove redundant depth==0 branch - text.go writeServers: remove version lookup placeholder string Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: multica-agent --- cmd/exploredns/main.go | 373 ++++++++++++++-------------- internal/config/config.go | 16 +- internal/dns/decode_test.go | 10 +- internal/dns/query_test.go | 1 - internal/dns/types.go | 29 --- internal/output/formatter.go | 13 +- internal/output/json.go | 4 +- internal/output/stats.go | 3 + internal/output/text.go | 9 +- internal/traverse/cache.go | 8 +- internal/traverse/referral.go | 18 +- internal/traverse/response.go | 2 +- internal/traverse/stack.go | 4 +- internal/traverse/traverser_test.go | 72 +++--- 14 files changed, 268 insertions(+), 294 deletions(-) diff --git a/cmd/exploredns/main.go b/cmd/exploredns/main.go index 01a59e7..6bcdf43 100644 --- a/cmd/exploredns/main.go +++ b/cmd/exploredns/main.go @@ -1,219 +1,220 @@ package main import ( -"context" -"flag" -"fmt" -"os" -"time" + "context" + "flag" + "fmt" + "os" + "time" -"github.com/hits/ExploreDNS/internal/config" -"github.com/hits/ExploreDNS/internal/dns" -"github.com/hits/ExploreDNS/internal/output" -"github.com/hits/ExploreDNS/internal/traverse" + "github.com/hits/ExploreDNS/internal/config" + "github.com/hits/ExploreDNS/internal/dns" + "github.com/hits/ExploreDNS/internal/output" + "github.com/hits/ExploreDNS/internal/traverse" ) func main() { -cfg := config.DefaultConfig() + cfg := config.DefaultConfig() -queryType := flag.String("type", cfg.QueryType, "Record type (A, AAAA, NS, CNAME, MX, TXT, SOA, PTR, ANY)") -rootServer := flag.String("root-server", cfg.RootServer, "Override root server") -allRootServers := flag.Bool("all-root-servers", cfg.AllRootServers, "Use all 13 root servers") -rootAAAA := flag.Bool("root-aaaa", cfg.RootAAAA, "Include IPv6 root addresses") -followAAAA := flag.Bool("follow-aaaa", cfg.FollowAAAA, "Only follow AAAA for referrals") -udpSize := flag.Int("udp-size", cfg.UDPSize, "EDNS0 buffer size (512-4096)") -allowTCP := flag.Bool("allow-tcp", cfg.AllowTCP, "TCP fallback on truncation") -alwaysTCP := flag.Bool("always-tcp", cfg.AlwaysTCP, "Always use TCP") -maxDepth := flag.Int("max-depth", cfg.MaxDepth, "Max traversal depth (1-100)") -retries := flag.Int("retries", cfg.Retries, "Retry count (0-10)") -fast := flag.Bool("fast", cfg.Fast, "Fast mode: reuse earlier branch cache") -jsonOutput := flag.Bool("json", false, "Output results as JSON") + queryType := flag.String("type", cfg.QueryType, "Record type (A, AAAA, NS, CNAME, MX, TXT, SOA, PTR, ANY)") + rootServer := flag.String("root-server", cfg.RootServer, "Override root server") + allRootServers := flag.Bool("all-root-servers", cfg.AllRootServers, "Use all 13 root servers") + rootAAAA := flag.Bool("root-aaaa", cfg.RootAAAA, "Include IPv6 root addresses") + followAAAA := flag.Bool("follow-aaaa", cfg.FollowAAAA, "Only follow AAAA for referrals") + udpSize := flag.Int("udp-size", cfg.UDPSize, "EDNS0 buffer size (512-4096)") + allowTCP := flag.Bool("allow-tcp", cfg.AllowTCP, "TCP fallback on truncation") + alwaysTCP := flag.Bool("always-tcp", cfg.AlwaysTCP, "Always use TCP") + maxDepth := flag.Int("max-depth", cfg.MaxDepth, "Max traversal depth (1-100)") + retries := flag.Int("retries", cfg.Retries, "Retry count (0-10)") + fast := flag.Bool("fast", cfg.Fast, "Fast mode: reuse earlier branch cache") + jsonOutput := flag.Bool("json", false, "Output results as JSON") -// Verbose: long and short form share the same variable. -var verboseVal bool -flag.BoolVar(&verboseVal, "verbose", cfg.Verbose, "Verbose output") -flag.BoolVar(&verboseVal, "v", cfg.Verbose, "Verbose output (shorthand)") + // Verbose: long and short form share the same variable. + var verboseVal bool + flag.BoolVar(&verboseVal, "verbose", cfg.Verbose, "Verbose output") + flag.BoolVar(&verboseVal, "v", cfg.Verbose, "Verbose output (shorthand)") -// Debug: -d sets level 1, -dd sets level 2 (library debug). -var dFlag, ddFlag bool -flag.BoolVar(&dFlag, "d", false, "Debug mode (stackable: -dd for library debug)") -flag.BoolVar(&dFlag, "debug", false, "Debug mode") -flag.BoolVar(&ddFlag, "dd", false, "Library debug mode (equivalent to -d -d)") + // Debug: -d sets level 1, -dd sets level 2 (library debug). + var dFlag, ddFlag bool + flag.BoolVar(&dFlag, "d", false, "Debug mode (stackable: -dd for library debug)") + flag.BoolVar(&dFlag, "debug", false, "Debug mode") + flag.BoolVar(&ddFlag, "dd", false, "Library debug mode (equivalent to -d -d)") -// Quiet: long and short form share the same variable. -var quietVal bool -flag.BoolVar(&quietVal, "quiet", cfg.Quiet, "Suppress supplementary info") -flag.BoolVar(&quietVal, "q", cfg.Quiet, "Suppress supplementary info (shorthand)") + // Quiet: long and short form share the same variable. + var quietVal bool + flag.BoolVar(&quietVal, "quiet", cfg.Quiet, "Suppress supplementary info") + flag.BoolVar(&quietVal, "q", cfg.Quiet, "Suppress supplementary info (shorthand)") -showProgress := flag.Bool("show-progress", cfg.ShowProgress, "Show traversal progress") -noShowProgress := flag.Bool("no-show-progress", false, "Hide traversal progress") -showResolves := flag.Bool("show-resolves", cfg.ShowResolves, "Show glue resolution details") -noShowResolves := flag.Bool("no-show-resolves", false, "Hide glue resolution details") -showServers := flag.Bool("show-servers", cfg.ShowServers, "Show servers queried") -noShowServers := flag.Bool("no-show-servers", false, "Hide servers queried") -showVersions := flag.Bool("show-versions", cfg.ShowVersions, "Show server versions") -noShowVersions := flag.Bool("no-show-versions", false, "Hide server versions") -showAllStats := flag.Bool("show-all-stats", cfg.ShowAllStats, "Show all statistics") -noShowAllStats := flag.Bool("no-show-all-stats", false, "Hide all statistics") -showResults := flag.Bool("show-results", cfg.ShowResults, "Show query results") -noShowResults := flag.Bool("no-show-results", false, "Hide query results") -showSummaryResults := flag.Bool("show-summary-results", cfg.ShowSummaryResults, "Show summary of results") -noShowSummaryResults := flag.Bool("no-show-summary-results", false, "Hide summary of results") + showProgress := flag.Bool("show-progress", cfg.ShowProgress, "Show traversal progress") + noShowProgress := flag.Bool("no-show-progress", false, "Hide traversal progress") + showResolves := flag.Bool("show-resolves", cfg.ShowResolves, "Show glue resolution details") + noShowResolves := flag.Bool("no-show-resolves", false, "Hide glue resolution details") + showServers := flag.Bool("show-servers", cfg.ShowServers, "Show servers queried") + noShowServers := flag.Bool("no-show-servers", false, "Hide servers queried") + showVersions := flag.Bool("show-versions", cfg.ShowVersions, "Show server versions") + noShowVersions := flag.Bool("no-show-versions", false, "Hide server versions") + showAllStats := flag.Bool("show-all-stats", cfg.ShowAllStats, "Show all statistics") + noShowAllStats := flag.Bool("no-show-all-stats", false, "Hide all statistics") + showResults := flag.Bool("show-results", cfg.ShowResults, "Show query results") + noShowResults := flag.Bool("no-show-results", false, "Hide query results") + showSummaryResults := flag.Bool("show-summary-results", cfg.ShowSummaryResults, "Show summary of results") + noShowSummaryResults := flag.Bool("no-show-summary-results", false, "Hide summary of results") -flag.Usage = config.PrintUsage + flag.Usage = config.PrintUsage -flag.Parse() + flag.Parse() -args := flag.Args() + args := flag.Args() -cfg.QueryType = *queryType -cfg.RootServer = *rootServer -cfg.AllRootServers = *allRootServers -cfg.RootAAAA = *rootAAAA -cfg.FollowAAAA = *followAAAA -cfg.UDPSize = *udpSize -cfg.AllowTCP = *allowTCP -cfg.AlwaysTCP = *alwaysTCP -cfg.MaxDepth = *maxDepth -cfg.Retries = *retries -cfg.Fast = *fast -cfg.Verbose = verboseVal -cfg.Debug = config.ParseDebugLevel(dFlag, ddFlag) -cfg.Quiet = quietVal + cfg.QueryType = *queryType + cfg.RootServer = *rootServer + cfg.AllRootServers = *allRootServers + cfg.RootAAAA = *rootAAAA + cfg.FollowAAAA = *followAAAA + cfg.UDPSize = *udpSize + cfg.AllowTCP = *allowTCP + cfg.AlwaysTCP = *alwaysTCP + cfg.MaxDepth = *maxDepth + cfg.Retries = *retries + cfg.Fast = *fast + cfg.Verbose = verboseVal + cfg.Debug = config.ParseDebugLevel(dFlag, ddFlag) + cfg.Quiet = quietVal -if *noShowProgress { -cfg.ShowProgress = false -} else if *showProgress { -cfg.ShowProgress = true -} -if *noShowResolves { -cfg.ShowResolves = false -} else if *showResolves { -cfg.ShowResolves = true -} -if *noShowServers { -cfg.ShowServers = false -} else if *showServers { -cfg.ShowServers = true -} -if *noShowVersions { -cfg.ShowVersions = false -} else if *showVersions { -cfg.ShowVersions = true -} -if *noShowAllStats { -cfg.ShowAllStats = false -} else if *showAllStats { -cfg.ShowAllStats = true -} -if *noShowResults { -cfg.ShowResults = false -} else if *showResults { -cfg.ShowResults = true -} -if *noShowSummaryResults { -cfg.ShowSummaryResults = false -} else if *showSummaryResults { -cfg.ShowSummaryResults = true -} + if *noShowProgress { + cfg.ShowProgress = false + } else if *showProgress { + cfg.ShowProgress = true + } + if *noShowResolves { + cfg.ShowResolves = false + } else if *showResolves { + cfg.ShowResolves = true + } + if *noShowServers { + cfg.ShowServers = false + } else if *showServers { + cfg.ShowServers = true + } + if *noShowVersions { + cfg.ShowVersions = false + } else if *showVersions { + cfg.ShowVersions = true + } + if *noShowAllStats { + cfg.ShowAllStats = false + } else if *showAllStats { + cfg.ShowAllStats = true + } + if *noShowResults { + cfg.ShowResults = false + } else if *showResults { + cfg.ShowResults = true + } + if *noShowSummaryResults { + cfg.ShowSummaryResults = false + } else if *showSummaryResults { + cfg.ShowSummaryResults = true + } -if err := cfg.Validate(); err != nil { -fmt.Fprintf(os.Stderr, "Error: %v\n", err) -os.Exit(1) -} + if err := cfg.Validate(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } -domain, err := cfg.GetDomain(args) -if err != nil { -fmt.Fprintf(os.Stderr, "Error: %v\n", err) -os.Exit(1) -} + domain, err := cfg.GetDomain(args) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } -rootIP, err := cfg.ParseRootServer() -if err != nil { -fmt.Fprintf(os.Stderr, "Error: invalid root server: %v\n", err) -os.Exit(1) -} + rootIP, err := cfg.ParseRootServer() + if err != nil { + fmt.Fprintf(os.Stderr, "Error: invalid root server: %v\n", err) + os.Exit(1) + } -queryTypeValue, err := config.ParseQueryType(cfg.QueryType) -if err != nil { -fmt.Fprintf(os.Stderr, "Error: %v\n", err) -os.Exit(1) -} + queryTypeValue, err := config.ParseQueryType(cfg.QueryType) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } -var rootServerAddr string -if rootIP != nil { -rootServerAddr = rootIP.String() -} + var rootServerAddr string + if rootIP != nil { + rootServerAddr = rootIP.String() + } -queryConfig := &dns.QueryConfig{ -UDPSize: cfg.UDPSize, -Timeout: 5 * time.Second, -Retries: cfg.Retries, -UseTCP: cfg.AlwaysTCP, -AllowTCP: cfg.AllowTCP, -} + queryConfig := &dns.QueryConfig{ + UDPSize: cfg.UDPSize, + Timeout: 5 * time.Second, + Retries: cfg.Retries, + UseTCP: cfg.AlwaysTCP, + AllowTCP: cfg.AllowTCP, + } -rootConfig := &dns.RootDiscoveryConfig{ -IncludeAAAA: cfg.RootAAAA, -Server: rootServerAddr, -AllRoots: cfg.AllRootServers, -} + rootConfig := &dns.RootDiscoveryConfig{ + IncludeAAAA: cfg.RootAAAA, + Server: rootServerAddr, + AllRoots: cfg.AllRootServers, + } -traverserConfig := &traverse.TraverserConfig{ -MaxDepth: cfg.MaxDepth, -QueryType: queryTypeValue, -RootConfig: rootConfig, -QueryConfig: queryConfig, -} + traverserConfig := &traverse.TraverserConfig{ + MaxDepth: cfg.MaxDepth, + QueryType: queryTypeValue, + RootConfig: rootConfig, + QueryConfig: queryConfig, + } -traverser := traverse.NewTraverser(traverserConfig) + traverser := traverse.NewTraverser(traverserConfig) -if cfg.Debug > 0 { -fmt.Fprintf(os.Stderr, "Debug: Config loaded\n") -fmt.Fprintf(os.Stderr, " Domain: %s\n", domain) -fmt.Fprintf(os.Stderr, " Query Type: %s\n", cfg.QueryType) -fmt.Fprintf(os.Stderr, " Max Depth: %d\n", cfg.MaxDepth) -fmt.Fprintf(os.Stderr, " UDP Size: %d\n", cfg.UDPSize) -fmt.Fprintf(os.Stderr, " Retries: %d\n", cfg.Retries) -fmt.Fprintf(os.Stderr, " Allow TCP: %v\n", cfg.AllowTCP) -fmt.Fprintf(os.Stderr, " Always TCP: %v\n", cfg.AlwaysTCP) -fmt.Fprintf(os.Stderr, " Fast Mode: %v\n", cfg.Fast) -} + if cfg.Debug > 0 { + fmt.Fprintf(os.Stderr, "Debug: Config loaded\n") + fmt.Fprintf(os.Stderr, " Domain: %s\n", domain) + fmt.Fprintf(os.Stderr, " Query Type: %s\n", cfg.QueryType) + fmt.Fprintf(os.Stderr, " Max Depth: %d\n", cfg.MaxDepth) + fmt.Fprintf(os.Stderr, " UDP Size: %d\n", cfg.UDPSize) + fmt.Fprintf(os.Stderr, " Retries: %d\n", cfg.Retries) + fmt.Fprintf(os.Stderr, " Allow TCP: %v\n", cfg.AllowTCP) + fmt.Fprintf(os.Stderr, " Always TCP: %v\n", cfg.AlwaysTCP) + fmt.Fprintf(os.Stderr, " Fast Mode: %v\n", cfg.Fast) + } -if !cfg.Quiet && !*jsonOutput { -fmt.Printf("ExploreDNS - exploring: %s (type: %s)\n", domain, cfg.QueryType) -} + if !cfg.Quiet && !*jsonOutput { + fmt.Printf("ExploreDNS - exploring: %s (type: %s)\n", domain, cfg.QueryType) + } -outFmt := output.FormatText -if *jsonOutput { -outFmt = output.FormatJSON -} + outFmt := output.FormatText + if *jsonOutput { + outFmt = output.FormatJSON + } -outCfg := &output.Config{ -Format: outFmt, -Domain: domain, -QueryType: cfg.QueryType, -ShowProgress: cfg.ShowProgress, -ShowResolves: cfg.ShowResolves, -ShowServers: cfg.ShowServers, -ShowVersions: cfg.ShowVersions, -ShowAllStats: cfg.ShowAllStats, -ShowResults: cfg.ShowResults, -ShowSummaryResults: cfg.ShowSummaryResults, -Verbose: cfg.Verbose, -Quiet: cfg.Quiet, -Color: os.Getenv("NO_COLOR") == "", -} + outCfg := &output.Config{ + Format: outFmt, + Domain: domain, + QueryType: cfg.QueryType, + ShowProgress: cfg.ShowProgress, + ShowResolves: cfg.ShowResolves, + ShowServers: cfg.ShowServers, + ShowVersions: cfg.ShowVersions, + ShowAllStats: cfg.ShowAllStats, + ShowResults: cfg.ShowResults, + ShowSummaryResults: cfg.ShowSummaryResults, + Verbose: cfg.Verbose, + Quiet: cfg.Quiet, + Color: os.Getenv("NO_COLOR") == "", + Debug: cfg.Debug, + } -ctx := context.Background() -formatter := output.NewFormatter(outCfg, os.Stdout) -_, err = output.RunTraversal(ctx, traverser, outCfg, formatter, domain) -if err != nil { -fmt.Fprintf(os.Stderr, "Error: traversal failed: %v\n", err) -os.Exit(1) -} + ctx := context.Background() + formatter := output.NewFormatter(outCfg, os.Stdout) + _, err = output.RunTraversal(ctx, traverser, outCfg, formatter, domain) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: traversal failed: %v\n", err) + os.Exit(1) + } -if cfg.Debug > 0 { -fmt.Fprintf(os.Stderr, "Debug: Traversal completed\n") -} + if cfg.Debug > 0 { + fmt.Fprintf(os.Stderr, "Debug: Traversal completed\n") + } } diff --git a/internal/config/config.go b/internal/config/config.go index e46a464..5f7dd1d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -36,13 +36,13 @@ type Config struct { Debug int Quiet bool - ShowProgress bool - ShowResolves bool - ShowServers bool - ShowVersions bool - ShowAllStats bool - ShowResults bool - ShowSummaryResults bool + ShowProgress bool + ShowResolves bool + ShowServers bool + ShowVersions bool + ShowAllStats bool + ShowResults bool + ShowSummaryResults bool } func ParseQueryType(s string) (uint16, error) { @@ -235,4 +235,4 @@ func DefaultConfig() *Config { ShowResults: true, ShowSummaryResults: true, } -} \ No newline at end of file +} diff --git a/internal/dns/decode_test.go b/internal/dns/decode_test.go index 121f817..7985652 100644 --- a/internal/dns/decode_test.go +++ b/internal/dns/decode_test.go @@ -314,8 +314,8 @@ func TestCNAMEChain(t *testing.T) { func TestResponseClassificationString(t *testing.T) { tests := []struct { - rc ResponseClassification - want string + rc ResponseClassification + want string }{ {ResponseAnswer, "answer"}, {ResponseReferral, "referral"}, @@ -344,10 +344,10 @@ func TestFormatRecord(t *testing.T) { t.Run("A record", func(t *testing.T) { rr := &dns.A{ Hdr: dns.RR_Header{ - Name: "example.com.", + Name: "example.com.", Rrtype: dns.TypeA, - Class: dns.ClassINET, - Ttl: 300, + Class: dns.ClassINET, + Ttl: 300, }, A: MustParseIP("93.184.216.34"), } diff --git a/internal/dns/query_test.go b/internal/dns/query_test.go index 6fa840f..c4c5737 100644 --- a/internal/dns/query_test.go +++ b/internal/dns/query_test.go @@ -328,4 +328,3 @@ func TestQueryNoTCPFallbackWhenDisabled(t *testing.T) { t.Error("expected truncated response to be returned as-is") } } - diff --git a/internal/dns/types.go b/internal/dns/types.go index f082ecb..3a2353d 100644 --- a/internal/dns/types.go +++ b/internal/dns/types.go @@ -1,9 +1,6 @@ package dns import ( - "fmt" - "strings" - "github.com/miekg/dns" ) @@ -40,32 +37,6 @@ func QNameType(qtype uint16) string { return dns.TypeToString[qtype] } -func ParseQueryType(s string) (uint16, error) { - s = strings.ToUpper(strings.TrimSpace(s)) - switch s { - case "A": - return TypeA, nil - case "AAAA": - return TypeAAAA, nil - case "NS": - return TypeNS, nil - case "CNAME": - return TypeCNAME, nil - case "MX": - return TypeMX, nil - case "TXT": - return TypeTXT, nil - case "SOA": - return TypeSOA, nil - case "PTR": - return TypePTR, nil - case "ANY": - return TypeANY, nil - default: - return 0, fmt.Errorf("invalid query type: %s", s) - } -} - func DefaultEDNS0UDPSize() int { return 2048 } diff --git a/internal/output/formatter.go b/internal/output/formatter.go index 62266f2..446eac2 100644 --- a/internal/output/formatter.go +++ b/internal/output/formatter.go @@ -1,6 +1,7 @@ package output import ( + "fmt" "io" "os" @@ -28,6 +29,7 @@ type Config struct { Verbose bool Quiet bool Color bool + Debug int } func DefaultConfig() *Config { @@ -69,16 +71,21 @@ func AttachHooks(cfg *Config, formatter Formatter) *traverse.TraverserHooks { if cfg == nil || formatter == nil { return nil } + logErr := func(context string, err error) { + if err != nil && cfg.Debug > 0 { + fmt.Fprintf(os.Stderr, "Debug: formatter %s: %v\n", context, err) + } + } return &traverse.TraverserHooks{ OnEvent: func(event traverse.TraversalEvent) { switch { case event.IsResolve && cfg.ShowResolves: - _ = formatter.WriteResolve(event) + logErr("WriteResolve", formatter.WriteResolve(event)) case !event.IsResolve && cfg.ShowProgress: - _ = formatter.WriteProgress(event) + logErr("WriteProgress", formatter.WriteProgress(event)) } if event.Stage == traverse.EventComplete && cfg.ShowAllStats { - _ = formatter.WriteResult(event.Result) + logErr("WriteResult", formatter.WriteResult(event.Result)) } }, } diff --git a/internal/output/json.go b/internal/output/json.go index e1d8ba3..ea96959 100644 --- a/internal/output/json.go +++ b/internal/output/json.go @@ -54,8 +54,8 @@ type jsonSummary struct { } type jsonAnswerStat struct { - RData string `json:"rdata"` - Probability float64 `json:"probability"` + RData string `json:"rdata"` + Probability float64 `json:"probability"` Records []string `json:"records,omitempty"` } diff --git a/internal/output/stats.go b/internal/output/stats.go index 50fb188..a7df3d2 100644 --- a/internal/output/stats.go +++ b/internal/output/stats.go @@ -73,6 +73,9 @@ func ComputeSummary(results []traverse.TraversalResult) *SummaryStats { return stats.Answers[i].RData < stats.Answers[j].RData }) + if len(stats.Answers) == 0 && len(stats.ByType) == 0 { + return nil + } return stats } diff --git a/internal/output/text.go b/internal/output/text.go index ae6183d..48d3bf9 100644 --- a/internal/output/text.go +++ b/internal/output/text.go @@ -99,11 +99,7 @@ func (f *textFormatter) writeServers(results []traverse.TraversalResult) error { for _, name := range names { for _, ip := range servers[name] { - version := "" - if f.cfg.ShowVersions { - version = " (version lookup pending)" - } - if _, err := fmt.Fprintf(f.w, "%*s: %-15s%s\n", width, name, ip, version); err != nil { + if _, err := fmt.Fprintf(f.w, "%*s: %-15s\n", width, name, ip); err != nil { return err } } @@ -234,9 +230,6 @@ func referralID(ref *traverse.Referral) string { if ref == nil { return "" } - if ref.Depth == 0 { - return "1" - } return fmt.Sprintf("%d", ref.Depth+1) } diff --git a/internal/traverse/cache.go b/internal/traverse/cache.go index e4422ae..9894324 100644 --- a/internal/traverse/cache.go +++ b/internal/traverse/cache.go @@ -9,10 +9,10 @@ import ( ) type InfoCache struct { - parent *InfoCache - mu sync.RWMutex - ns map[string][]string - glue map[string][]net.IP + parent *InfoCache + mu sync.RWMutex + ns map[string][]string + glue map[string][]net.IP } func NewInfoCache(parent *InfoCache) *InfoCache { diff --git a/internal/traverse/referral.go b/internal/traverse/referral.go index 04be8d1..3bdfe8a 100644 --- a/internal/traverse/referral.go +++ b/internal/traverse/referral.go @@ -32,18 +32,18 @@ func (s ResolutionState) String() string { } type Referral struct { - Name string - Qtype uint16 - Qclass uint16 + Name string + Qtype uint16 + Qclass uint16 Bailiwick string Addresses []net.IP State ResolutionState - NSName string - Parent *Referral - Depth int - Prob float64 + NSName string + Parent *Referral + Depth int + Prob float64 } func NewReferral(name string, qtype uint16, bailiwick string, depth int, prob float64, parent *Referral) *Referral { @@ -81,7 +81,7 @@ func (r *Referral) SetAddresses(addrs []net.IP) { } type CircularReferralError struct { - Name string + Name string Chain []string } @@ -90,7 +90,7 @@ func (e *CircularReferralError) Error() string { } type UnresolvableNameserverError struct { - Name string + Name string Reason string } diff --git a/internal/traverse/response.go b/internal/traverse/response.go index 2176a0a..0cbc6d6 100644 --- a/internal/traverse/response.go +++ b/internal/traverse/response.go @@ -10,7 +10,7 @@ import ( type ResponseType int const ( - RespReferral ResponseType = iota + RespReferral ResponseType = iota RespAnswer RespCNAMEFollow RespNODATA diff --git a/internal/traverse/stack.go b/internal/traverse/stack.go index ecb7a36..7e09cd3 100644 --- a/internal/traverse/stack.go +++ b/internal/traverse/stack.go @@ -3,7 +3,7 @@ package traverse const DefaultMaxDepth = 20 type Stack struct { - items []*Referral + items []*Referral maxDepth int } @@ -12,7 +12,7 @@ func NewStack(maxDepth int) *Stack { maxDepth = DefaultMaxDepth } return &Stack{ - items: make([]*Referral, 0), + items: make([]*Referral, 0), maxDepth: maxDepth, } } diff --git a/internal/traverse/traverser_test.go b/internal/traverse/traverser_test.go index cd41625..e422624 100644 --- a/internal/traverse/traverser_test.go +++ b/internal/traverse/traverser_test.go @@ -44,9 +44,9 @@ func TestTraverserSimpleTraversal(t *testing.T) { }() tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return answerResp.Copy(), nil @@ -94,9 +94,9 @@ func TestTraverserReferralTraversal(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { q := msg.Question[0] @@ -124,9 +124,9 @@ func TestTraverserReferralTraversal(t *testing.T) { func TestTraverserMaxDepth(t *testing.T) { callCount := 0 tr := NewTraverser(&TraverserConfig{ - MaxDepth: 2, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 2, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { callCount++ @@ -170,9 +170,9 @@ func TestTraverserMaxDepth(t *testing.T) { func TestTraverserContextCancellation(t *testing.T) { tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { m := new(dns.Msg) @@ -203,9 +203,9 @@ func TestTraverserNXDOMAIN(t *testing.T) { nxdResp.Rcode = dns.RcodeNameError tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return nxdResp.Copy(), nil @@ -229,9 +229,9 @@ func TestTraverserSERVFAIL(t *testing.T) { sfResp.Rcode = dns.RcodeServerFailure tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return sfResp.Copy(), nil @@ -268,9 +268,9 @@ func TestTraverserCNAMEFollow(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { q := msg.Question[0] @@ -328,9 +328,9 @@ func TestTraverserProbabilityCalculation(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("1.2.3.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("1.2.3.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { q := msg.Question[0] @@ -364,9 +364,9 @@ func TestTraverserNODATA(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return nodataResp.Copy(), nil @@ -394,9 +394,9 @@ func TestTraverserMultipleRoots(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4"), net.ParseIP("199.9.14.201")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4"), net.ParseIP("199.9.14.201")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return answerResp.Copy(), nil @@ -414,9 +414,9 @@ func TestTraverserMultipleRoots(t *testing.T) { func TestTraverserNilExchangeResponse(t *testing.T) { tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { return nil, nil @@ -451,9 +451,9 @@ func TestTraverserCacheChaining(t *testing.T) { }) tr := NewTraverser(&TraverserConfig{ - MaxDepth: 5, - QueryType: dnsTypeA, - RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, + MaxDepth: 5, + QueryType: dnsTypeA, + RootAddrs: []net.IP{net.ParseIP("198.41.0.4")}, }) tr.SetExchange(func(ctx context.Context, server string, msg *dns.Msg, useTCP bool) (*dns.Msg, error) { q := msg.Question[0]