package output import ( "context" "fmt" "net" "gitea.hansenits.com.au/hits/ExploreDNS/internal/fingerprint" "gitea.hansenits.com.au/hits/ExploreDNS/internal/traverse" ) func RunTraversal(ctx context.Context, traverser *traverse.Traverser, cfg *Config, formatter Formatter, domain string) ([]traverse.TraversalResult, error) { if traverser == nil { return nil, fmt.Errorf("traverser is required") } if cfg == nil { cfg = DefaultConfig() } if formatter == nil { formatter = NewFormatter(cfg, nil) } traverser.SetHooks(AttachHooks(cfg, formatter)) results, err := traverser.Traverse(ctx, domain) if err != nil { return results, err } // Fingerprint servers when both ShowVersions and ShowServers are enabled. // Gating on ShowServers avoids unnecessary network calls when versions // would not be displayed anyway. if cfg.ShowVersions && cfg.ShowServers { cfg.Fingerprints = fingerprint.New().FingerprintAll(ctx, collectUniqueServerIPs(results)) } if err := formatter.WriteSummary(results); err != nil { return results, err } if err := formatter.Flush(); err != nil { return results, err } return results, nil } // collectUniqueServerIPs returns the set of unique server IPs seen in results. func collectUniqueServerIPs(results []traverse.TraversalResult) []net.IP { seen := make(map[string]bool) var ips []net.IP for _, r := range results { if r.Response == nil || r.Response.Server == nil { continue } key := r.Response.Server.String() if !seen[key] { seen[key] = true ips = append(ips, r.Response.Server) } } return ips }