output

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: GPL-3.0 Imports: 18 Imported by: 0

Documentation

Overview

Package output renders scan results (text, JSON, JSONL, CSV) to stdout and the -o file, and serializes progress and diagnostics on stderr.

Index

Constants

View Source
const SummarySchema = 1

SummarySchema versions the Summary object. Fields may be added without a bump; renaming or removing one, or changing its meaning, bumps it (#70).

Variables

This section is empty.

Functions

func WriteSARIF added in v0.9.0

func WriteSARIF(path, version string, results []Result) error

WriteSARIF writes the takeover candidates among results to path as a SARIF 2.1.0 log, atomically. version is the tool version.

func WriteSummaryFile added in v0.9.0

func WriteSummaryFile(path string, s Summary) error

WriteSummaryFile writes s as indented JSON to path, atomically.

Types

type DiffSummary added in v0.9.0

type DiffSummary struct {
	Previous       string `json:"previous"`
	Added          int    `json:"added"`
	Removed        int    `json:"removed"`
	StillResolving int    `json:"still_resolving,omitempty"`
	Unverified     int    `json:"unverified,omitempty"`
}

DiffSummary is the -diff part of a Summary (#84). Removed stays 0 when the run was not complete, because missing names may only be failed lookups. A previous name this run did not find is looked up again: only NXDOMAIN counts as removed; StillResolving names were not among this run's candidates, and Unverified ones could not be looked up (#110).

type File added in v0.9.0

type File struct {
	*bufio.Writer
	// contains filtered or unexported fields
}

File is an -o results file that is replaced atomically. Output goes to a temporary file in the target's directory and Close(true) renames it over the target, so a run that fails before any scan finishes (preflight, wildcard abort, Ctrl+C during preflight) leaves an existing results file unchanged (#52). A target that exists but is not a regular file, such as /dev/stdout or a named pipe, is written directly.

func CreateFile added in v0.9.0

func CreateFile(path string) (*File, error)

CreateFile opens path for writing results. An existing regular file keeps its permissions; a new one gets 0666 less the process umask, as os.Create would, so a umask of 077 keeps results private (#119). A path that is a symlink is followed: the file it points at is replaced and the link kept.

func (*File) Close added in v0.9.0

func (f *File) Close(commit bool) error

Close flushes and closes the file. With commit set, the temporary file replaces the target; otherwise it is discarded and the target is left as it was. A failed flush or close also discards it rather than replacing a good file with a truncated one. Close returns the first error and is safe to call more than once.

type Format added in v0.6.0

type Format int

Format selects how resolved results are rendered on stdout and in the output file.

const (
	// FormatText is the default human-friendly streaming output.
	FormatText Format = iota
	// FormatJSON buffers results and emits a single JSON array at completion.
	FormatJSON
	// FormatCSV streams "subdomain,type,value" rows with a header.
	FormatCSV
	// FormatJSONL streams one JSON object per resolved subdomain, one per line.
	// Unlike FormatJSON it needs no Finish to be complete, so it pipes live.
	FormatJSONL
)

func ParseFormat added in v0.6.0

func ParseFormat(s string) (Format, error)

ParseFormat converts a flag string into a Format.

type Outcomes added in v0.9.0

type Outcomes struct {
	Resolved         int64 `json:"resolved"`
	NXDomain         int64 `json:"nxdomain"`
	Timeout          int64 `json:"timeout"`
	Refused          int64 `json:"refused"`
	Other            int64 `json:"other"`
	WildcardFiltered int64 `json:"wildcard_filtered"`
	Excluded         int64 `json:"excluded"` // out of scope (-exclude); never queried
}

Outcomes counts how each lookup ended. SERVFAIL and other errors Go's resolver does not distinguish are counted under Other.

type PermutationSummary added in v0.9.0

type PermutationSummary struct {
	Seeds      int    `json:"seeds"`
	Candidates int    `json:"candidates"`
	Found      int    `json:"found"`
	Verdict    string `json:"verdict,omitempty"`
}

PermutationSummary counts a target's -permute pass.

type Result added in v0.6.0

type Result struct {
	Subdomain string       `json:"subdomain"`
	Records   []dns.Record `json:"records"`
	Simulated bool         `json:"simulated,omitempty"`
	// Takeover is a DNS-only subdomain-takeover hint ("dangling",
	// "provider:<name>" or "dangling:<name>"); verify it by hand (#71).
	Takeover string `json:"takeover_candidate,omitempty"`
	// Change is "added" or "removed" in -diff mode (#84).
	Change string `json:"change,omitempty"`
	// Permutation marks a name found by the -permute pass (#72).
	Permutation bool `json:"permutation,omitempty"`
}

Result is one resolved subdomain and its records, used for structured output. Simulated is set on every result of a -simulate run, so invented names can never pass for real recon output once saved or piped (#53).

type Summary added in v0.9.0

type Summary struct {
	Type        string          `json:"type"` // always "summary"
	Schema      int             `json:"schema"`
	Tool        string          `json:"tool"`
	Version     string          `json:"version"`
	Started     time.Time       `json:"started"`
	DurationMs  int64           `json:"duration_ms"`
	Simulated   bool            `json:"simulated"`
	Seed        uint64          `json:"seed,omitempty"`
	Resolver    string          `json:"resolver,omitempty"`
	Zone        string          `json:"zone,omitempty"`      // -simulate-zone scenario; Resolver is then its local server (#76)
	Transport   string          `json:"transport,omitempty"` // udp, tls or https (#86)
	RateLimit   int             `json:"rate_limit"`
	QueriesSent int64           `json:"queries_sent"`
	AchievedQPS float64         `json:"achieved_qps"`
	Verdict     string          `json:"verdict"`
	Reason      string          `json:"reason"`
	Targets     []TargetSummary `json:"targets"`
	// Resolvers is the -r pool's per-resolver accounting; Resolver is then
	// the trusted resolver every pool hit was re-validated against.
	Resolvers []dns.ResolverStats `json:"resolvers,omitempty"`
	// Diff counts the -diff changes against the previous results file.
	Diff *DiffSummary `json:"diff,omitempty"`
}

Summary is the machine-readable run-quality report: what was scanned, how many queries were sent, how every lookup ended, and a verdict on how far the results can be trusted. It is written by -stats and, in jsonl format, as the last line of the output.

type TargetSummary added in v0.9.0

type TargetSummary struct {
	Domain      string   `json:"domain"`
	Status      string   `json:"status"` // ok, failed, skipped, interrupted, not_run
	Error       string   `json:"error,omitempty"`
	Processed   int64    `json:"processed"`
	Total       int64    `json:"total"`
	Found       int64    `json:"found"`
	Outcomes    Outcomes `json:"outcomes"`
	QueriesSent int64    `json:"queries_sent"`
	SkippedCap  int64    `json:"skipped_by_cap"`
	Takeover    int64    `json:"takeover_candidates,omitempty"` // results with a takeover hint
	// Permutation is the -permute pass, when one ran (#72).
	Permutation *PermutationSummary `json:"permutation,omitempty"`
	// CTNames counts the Certificate Transparency names -ct added as
	// candidates and seeds; CTError says why the lookup failed (#130).
	CTNames     int          `json:"ct_names,omitempty"`
	CTError     string       `json:"ct_error,omitempty"`
	PoolHits    int64        `json:"pool_hits,omitempty"`   // -r: names a pool resolver said exist
	Confirmed   int64        `json:"confirmed,omitempty"`   // pool hits the trusted resolver confirmed
	Unconfirmed int64        `json:"unconfirmed,omitempty"` // pool hits the trusted resolver denied
	Wildcard    bool         `json:"wildcard"`
	Fingerprint []dns.Record `json:"wildcard_fingerprint,omitempty"`
	Verdict     string       `json:"verdict"`
	Reason      string       `json:"reason"`
}

TargetSummary is one scanned domain's part of a Summary.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer synchronises all output. Results go to stdout (and optionally a file); everything else (progress, verbose, errors) goes to stderr.

Individual writes ignore their errors on purpose: outWriter is a bufio.Writer, whose errors are sticky and are returned by Finish and by the output file's Close, and a failed diagnostic write to stderr has nowhere better to be reported.

func New

func New(outWriter *bufio.Writer, simulate bool, format Format) *Writer

New returns a Writer that streams results to stdout. If outWriter is non-nil, resolved domains are also written there. Set simulate to true to tag text result lines as simulated.

func NewFile added in v0.7.0

func NewFile(outWriter *bufio.Writer, simulate bool, format Format) *Writer

NewFile returns a Writer that writes only to outWriter, never to stdout. The TUI uses this so structured results land in the chosen file while the alt-screen viewport keeps full ownership of the terminal.

func (*Writer) Emit added in v0.9.0

func (w *Writer) Emit(res Result)

Emit writes one result in the configured format. Simulated is set from the writer; Change marks a -diff result.

func (*Writer) Error

func (w *Writer) Error(format string, a ...any)

Error writes an error line to stderr, serialized like Info.

func (*Writer) Finish added in v0.6.0

func (w *Writer) Finish() error

Finish flushes any buffered or streamed structured output. It must be called once after the scan completes (before the output file is flushed and closed). It returns the first error writing to the output file, so callers can report an incomplete results file instead of exiting successfully. Errors writing to stdout (for example a closed pipe) are not reported here.

func (*Writer) Info

func (w *Writer) Info(format string, a ...any)

Info writes an informational line to stderr. It is serialized with the progress line, so concurrent verbose logging cannot splice into it (#36).

func (*Writer) Notice added in v0.9.0

func (w *Writer) Notice(format string, a ...any)

Notice writes a line to stderr like Info, even under SetQuiet: for what a user must not miss, such as results being simulated.

func (*Writer) Progress

func (w *Writer) Progress(pct float64, processed, total, found int64)

Progress writes a progress line to stderr using carriage-return overwrite, or as a complete line when SetProgressLines is on.

func (*Writer) ProgressDone

func (w *Writer) ProgressDone()

ProgressDone ends the progress line with a newline on stderr.

func (*Writer) Result

func (w *Writer) Result(domain string, records []dns.Record)

Result records a resolved domain. In text mode it prints immediately; in JSON mode it is buffered for Finish; in CSV and JSONL mode it is streamed.

func (*Writer) ResultWithHint added in v0.9.0

func (w *Writer) ResultWithHint(domain string, records []dns.Record, takeover string)

ResultWithHint is Result with a subdomain-takeover hint attached.

func (*Writer) SetDiff added in v0.9.0

func (w *Writer) SetDiff(on bool)

SetDiff switches to -diff output (#84): text lines get a "+ " or "- " prefix and CSV gains a change column. JSON and JSONL carry Change as is.

func (*Writer) SetPlain added in v0.8.0

func (w *Writer) SetPlain(plain bool)

SetPlain makes text-mode stdout print bare subdomain names, one per line, without the "Found:" banner, so output pipes straight into other tools. The CLI enables it when stdout is not a terminal.

func (*Writer) SetProgressLines added in v0.9.0

func (w *Writer) SetProgressLines(lines bool)

SetProgressLines makes Progress print complete newline-terminated lines instead of redrawing one line with carriage returns. The CLI enables it when stderr is not a terminal, so logs that merge stdout and stderr never get a result glued onto a progress line (#78).

func (*Writer) SetQuiet added in v0.9.0

func (w *Writer) SetQuiet(quiet bool)

SetQuiet makes Info and Progress print nothing, for -silent pipelines (#128). Error and Notice still print.

func (*Writer) SetSeed added in v0.9.0

func (w *Writer) SetSeed(seed uint64)

SetSeed records the simulation seed for the simulated-results file header.

func (*Writer) SetShowRecords added in v0.8.0

func (w *Writer) SetShowRecords(show bool)

SetShowRecords makes text-mode output (stdout and file) append each result's records as TYPE=value pairs.

func (*Writer) SetTakeoverColumn added in v0.9.0

func (w *Writer) SetTakeoverColumn(on bool)

SetTakeoverColumn adds a takeover_candidate column to CSV output. The CLI sets it when CNAME records are requested, the only case that yields hints.

func (*Writer) Summary added in v0.9.0

func (w *Writer) Summary(s Summary)

Summary writes s as the final line of jsonl output (stdout and the -o file). Other formats ignore it; use -stats for those.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL