Documentation
¶
Index ¶
- Constants
- Variables
- func AreScansIdentical(a, b *scan.RunORM) bool
- func Completions() []display.Options
- func Detail(r *scan.Run, all []*scan.Run, opt DetailOpts) display.Detail
- func DisplayDetails() []display.Options
- func DisplayHeaders() []display.Options
- func HeadOf(all []*scan.Run, r *scan.Run) *scan.Run
- func IsInterrupted(r *scan.Run) bool
- func IsResumable(r *scan.Run) bool
- func IsRunning(r *scan.Run) bool
- func IsSuperseded(r *scan.Run) bool
- func MarkTargetsDone(targets []*scan.Target, h *host.Host) int
- func RemainingTargets(targets []*scan.Target) []*scan.Target
- func SeriesOf(all []*scan.Run, head *scan.Run) []*scan.Run
- func SortRuns(runs []*scan.Run)
- func TargetMatchesHost(t *scan.Target, h *host.Host) bool
- func TargetSpecs(targets []*scan.Target) []string
- func TargetsFromHosts(hosts ...*host.Host) []*scan.Target
- func VisibleRuns(runs []*scan.Run) []*scan.Run
- type CleanupPlan
- type DetailOpts
- type HostDelta
- type PortDelta
- type PortStability
- type Result
- type Run
- type RunDiff
- type SeriesHistory
- type Stability
- type Target
- type TimelineEntry
Constants ¶
const ( ScannerNmap = "nmap" ScannerMasscan = "masscan" ScannerZgrab2 = "zgrab2" // ScannerNuclei names nuclei (github.com/projectdiscovery/nuclei) — a JSON-emitting finding // scanner. It ties together the ingest.Ingestor (scan/ingest/nuclei.go, folding -jsonl findings // into severity-tagged NSE-style scripts via jsonscript.go's schemaless mapping), the // drive.Scanner (scan/drive/nuclei.go, streaming those findings live), the server driver dispatch // (server/scan/run.go scannerFor), and the CLI leaf + template/tag/severity/id completers // (cmd/scan/run_nuclei.go, cmd/completers/nuclei_templates.go). ScannerNuclei = "nuclei" )
Scanner identity keys.
A scanner's name is the single string that ties its pieces together across packages: the server-side driver dispatch (server/scan/run.go), the ingestor Name() + the Scanner value it stamps on a Run (scan/ingest), the provenance Tool, and the completion guards (cmd/scan). A spelling drift (e.g. "zgrab2" vs "zgrab") silently breaks the driver↔ingestor lookup, so the identity lives here once rather than as literals scattered across those call sites.
const ExitInterrupted = "interrupted"
ExitInterrupted is the Finished.Exit value a deliberately-stopped scan carries (server-side `Stop` cancels the job, and consume stamps this on the partial run). It marks a *terminal* interrupted state — distinct from a scanner's own error exit ("failed") and from a heartbeat-stale orphan — so a stopped scan reads as interrupted immediately and deterministically (not after the 30s stale window), and stays resumable. A process killed outright cannot stamp it and still falls back to the heartbeat-stale path below; both converge on stateInterrupted.
const TargetDone = "done"
TargetDone marks a target that produced a result and so was actually scanned. It is AIMS's own, scanner-uniform record of per-target completion: because the fold sees every result stream in, a target the scan reached is one AIMS matched a result back to — a signal that survives a SIGKILL (which would lose a scanner's native checkpoint) and needs no per-tool support. It is deliberately target-granular, not port-granular: a target is "done" once ANY result matches it, so an interrupted host is re-scanned whole on resume (the fold makes that idempotent), while a host that was never reached is the remaining work. A down host counts as done — it was scanned, and deriving completion from targets-minus-observed-hosts would wrongly re-scan it forever.
Variables ¶
var DisplayFields = map[string]func(r *scan.Run) string{ "ID": func(r *scan.Run) string { id := display.FormatSmallID(r.GetId()) switch stateOf(r) { case stateDone: return color.HiGreenString(id) case stateFailed: return color.HiRedString(id) case stateRunning: return color.HiYellowString(id) case stateInterrupted: return color.HiBlackString(id) default: return id } }, "Scanner": func(r *scan.Run) string { return r.GetScanner() }, "Name": func(r *scan.Run) string { return r.GetProfileName() }, "Status": func(r *scan.Run) string { return stateToken(r) }, "Info": func(r *scan.Run) string { return scanInfo(r) }, "Args": func(r *scan.Run) string { return fullCommand(r) }, "Series": func(r *scan.Run) string { if n := r.GetFormerRuns(); n > 0 { return color.HiBlackString("+%d", n) } return "" }, "When": func(r *scan.Run) string { return whenLabel(r) }, "Hosts": func(r *scan.Run) string { return hostsUpDown(r) }, "Targets": func(r *scan.Run) string { if label := targetsLabel(r); label != "" { return color.HiCyanString("%s", label) } return "" }, "Tasks": func(r *scan.Run) string { return tasksSummary(r) }, }
DisplayFields maps column names to per-run value generators — the single source of truth feeding the table and completions. Every accessor is nil-safe (a partially observed run must never panic the table), and state-dependent fields route through stateOf so the whole view agrees.
Functions ¶
func AreScansIdentical ¶
AreScansIdentical reports whether two runs are the same scan re-imported.
RawXML is the scanner's verbatim output and thus a definitive fingerprint: when both runs carry it, equality alone decides identity and inequality alone rules it out. Only when a run lacks raw output does it fall back to a field-weighted comparison over the runs' identity fields.
The fallback counts *evidence*, not absence: a field contributes only when both runs actually populated it — agreement is positive evidence, a disagreement on a populated field is disqualifying, and a field left empty on either side is neutral. Two dataless runs therefore score no evidence and are not "identical" (the earlier scoring treated two empty task-lists as a match, which made every empty run collide with every other). Runs match when they agree on every populated identity field, disagree on none, and carry at least one field of real evidence.
func Completions ¶
Completions returns the columns combined into completion candidates and their descriptions.
func Detail ¶
Detail assembles the full `show` view for a single run: the state banner, the side-by-side info panes, derived insights (including the cross-run host-sharing count, which needs the whole set `all` to compute), and any flag-selected trailing sections. It hands these to the shared display.Detail renderer, so a run's detail view is laid out identically to every other domain's.
func DisplayDetails ¶
DisplayDetails is retained only for the c2 agent/channel `show` placeholders, which reuse this weighted header set against their own DisplayFields map. Scan's own `show` uses the richer Detail renderer (banner + panes + insights + sections); prefer that. Deprecated: do not build on this for the scan domain.
func DisplayHeaders ¶
DisplayHeaders returns all weighted table headers for a table of scans. Weight-1 columns are the always-on signal (identity, scanner, live status, host outcome, recency); heavier columns shed first on narrow terminals.
func HeadOf ¶ added in v0.2.0
HeadOf resolves the surviving head for any run: the run itself if visible, else the run its SupersededBy points to (following one level). Returns the input when nothing better is found.
func IsInterrupted ¶ added in v0.3.0
IsInterrupted reports whether a run is in the interrupted state (deliberately stopped, or an orphan whose heartbeat went stale) as opposed to failed — used to sub-categorize resumable runs.
func IsResumable ¶ added in v0.3.0
IsResumable reports whether a run can be resumed: it reached a terminal state that left work undone — interrupted (stopped or orphaned) or failed. A clean done run has nothing to resume, and a still-running one must be stopped first. `scan resume` guards on this.
func IsRunning ¶
IsRunning reports whether the run is mid-flight — a non-final run with a fresh heartbeat. A killed scan goes stale and reads as interrupted (not running), so it no longer blocks destructive operations (`scan rm`) the way a perpetually-"running" orphan would.
func IsSuperseded ¶ added in v0.2.0
IsSuperseded reports whether a run has been tombstoned under a surviving head.
func MarkTargetsDone ¶ added in v0.3.0
MarkTargetsDone stamps TargetDone on every target the observed host satisfies, so a run's persisted Targets record which targets have been scanned. Returns the number newly marked (so a caller can persist only when the completion set actually advanced).
func RemainingTargets ¶ added in v0.3.0
RemainingTargets returns the targets a run has not yet completed — those not marked TargetDone. This is the reforged target set a resume re-scans: only the work an interrupted run never reached, uniform across scanners and independent of any native checkpoint.
func SeriesOf ¶ added in v0.2.0
SeriesOf returns a head run together with every run tombstoned under it (directly), ordered head-first then by recency — the browse set behind `scan history`.
func SortRuns ¶
SortRuns orders runs for listing: running scans first (most actionable), then interrupted (orphaned, likely need attention), then freshly-created, then the rest — each group by most-recent activity. Stable, so equal keys keep their read order.
func TargetMatchesHost ¶ added in v0.3.0
TargetMatchesHost reports whether an observed host is the result of scanning this target: the host carries the target's address among its addresses, or the target's domain among its hostnames. This is the same identity a resume uses to decide a target is finished.
func TargetSpecs ¶
TargetSpecs renders targets as the address/host tokens a scanner takes on its command line — Address preferred, else Domain — preserving order and dropping blanks, so the result can be appended straight onto a scanner's arguments.
func TargetsFromHosts ¶
TargetsFromHosts derives scan Targets from stored hosts. Each host contributes one Target per address (its identity anchor); a host with no address falls back to its hostnames as Domain targets. Duplicate endpoints (same address, or same domain) are collapsed so overlapping hosts never re-target the same thing. The result is deterministic in host/address order.
Types ¶
type CleanupPlan ¶ added in v0.2.0
type CleanupPlan struct {
Heads []*scan.Run // survivors whose FormerRuns was (re)computed
Tombstoned []*scan.Run // runs newly pointed at their head via SupersededBy
Prunable []*scan.Run // tombstoned runs whose output is byte-identical to the head (hard-deletable)
}
CleanupPlan is the set of field mutations a cleanup pass computes over the whole run set. The runs it references are mutated in place (SupersededBy / FormerRuns set) and ready to persist: Heads and Tombstoned via Upsert, Prunable via Delete. It carries no DB or RPC dependency.
func ComputeCleanup ¶ added in v0.2.0
func ComputeCleanup(all []*scan.Run) CleanupPlan
ComputeCleanup groups every run into its series-and-outcome-class and collapses each multi-run group onto a single head, mutating the affected runs in place and returning the plan. It is idempotent: a group already collapsed to one visible head yields no new tombstones, so re-running is a no-op.
Only currently-visible, coalescible runs are candidates to become or absorb a head (see coalesceClass): a live scan, an interrupted run, and a failure that found hosts are left untouched as their own rows; already-tombstoned runs are re-homed only if their head is itself absorbed (chains are flattened to one level). FormerRuns on each head is recomputed from the full set so it always equals the number of runs it supersedes.
func SupersedeFor ¶ added in v0.2.0
func SupersedeFor(all []*scan.Run, runID string) CleanupPlan
SupersedeFor computes a cleanup plan limited to the series containing runID — the auto-collapse a server runs when a new scan of the same definition finishes, so `scan list` self-collapses without a manual `scan cleanup`. It restricts the run set to that one series and reuses ComputeCleanup, so the collapse stays within outcome classes: a finished clean run heads the success line, a resultless failure coalesces with earlier resultless failures of the same definition (latest wins, with a count), and the two heads coexist. A still-running or interrupted sibling, and a failure that found hosts, are left alone. Returns an empty plan when the run is unknown or its series has nothing to collapse.
func (CleanupPlan) Empty ¶ added in v0.2.0
func (p CleanupPlan) Empty() bool
Empty reports whether the plan collapses nothing.
type DetailOpts ¶
type DetailOpts struct {
Tasks bool // the running/done task tables (the live view)
Targets bool // the full target list with per-target status/reason
Hosts bool // the scanned hosts rendered as a compact table
}
DetailOpts selects which trailing sections a detail view includes. They are flag-gated at the CLI because each is verbose (task streams, full target lists, the shared-host table) and off by default keeps `scan show` scannable.
type HostDelta ¶
type HostDelta struct {
Before *host.Host
After *host.Host
NewPorts []*host.Port // in b, not in a
GonePorts []*host.Port // in a, not in b
Changed []PortDelta // same (proto, number), but service or state differs
}
HostDelta captures how one host's surface changed between the two runs.
type PortStability ¶ added in v0.2.0
type PortStability struct {
Addr string
Proto string
Port uint32
Service string
Presence []bool // per run, oldest -> newest: was this port open in that run
Class Stability
}
PortStability is one port's presence across the series.
func (PortStability) Ratio ¶ added in v0.2.0
func (p PortStability) Ratio() string
Ratio is the "present / total" fraction shown next to the sparkline.
func (PortStability) Sparkline ¶ added in v0.2.0
func (p PortStability) Sparkline() string
Sparkline renders a presence vector as full/empty blocks, oldest -> newest.
type Result ¶
Result - A type containing various objects that are outputs of a scan. It has only one .Target, which theoretically means that we must have n Results for n Results. This type is to be created from and used by a scan.Run type, which has various methods to set up, populate, curate and save the data from a complete Scan, sometimes concurrently. A Result is not meant to be saved in a database: it is only used as a feeder type for the scan.Run.
type Run ¶
Run - Represents a scan before, after or while being run. This run can be the one of any scanner: fields are not mandatorily used by all scanners for all scans, but this type gives a common tree in which to store hosts, ports, services, statistics and various other information.
The type provides many convenience methods to process all the output of the scan, either at once or continuously, or even to refine the objects based on/ with those already in a database. Therefore, all the methods of this type are meant to be used server-side, and not in an implant.
For having similar functionality from within an implant, use the Protobuf scan.Run type, which itself has some convenience methods that do NOT need any database or its related libraries.
func NewRun ¶
NewRun - Create a new scan.Run based on a tool (scanner) name, and with an optional Options type holding various settings to be customized for your use.
func (*Run) AddHosts ¶
AddHosts folds one or more hosts into this Run, deduplicating and merging by natural key. It is the bulk entry point behind the import path: the Hosts of a freshly parsed scan.Run (e.g. from nmap.FromXML) are folded in one by one, so an import that overlaps hosts already in the Run enriches them instead of duplicating.
func (*Run) AddResult ¶
AddResult folds one feeder Result into the Run's host tree. The Result is the universal adapter output (one {Host, Address, Port, Service, Data} tuple emitted by any scanner); AddResult assembles it into a single-host subtree and merges that in via the non-destructive fold (see fold.go / DEDUP.md). Calling it twice with the same observation is idempotent — the second call merges into the row the first created and changes nothing.
If the Result carries Data (a custom scanner's opaque payload), it is preserved as a script observation on the port (or host) so nothing is lost; mapping structured payloads into the recursive NSE Script/Table/Element tree (jsonToScript, SCAN.md §D) is the richer, philosophy-true follow-on.
func (*Run) InitResult ¶
InitResult - Instantiate a new result that has the Run UUID in ref. The rest of the object can be populated by the user as he wishes.
type RunDiff ¶
type RunDiff struct {
NewHosts []*host.Host // present in b, absent in a
GoneHosts []*host.Host // present in a, absent in b
Changed []HostDelta // present in both, but ports/services differ
}
RunDiff is the delta from Run a (earlier) to Run b (later).
type SeriesHistory ¶ added in v0.2.0
type SeriesHistory struct {
Runs []*scan.Run // the series ordered oldest -> newest
Timeline []TimelineEntry // ordered newest -> oldest, unchanged runs collapsed
Surface []PortStability // one row per (addr, proto, port) ever seen open, sorted
Span int64 // seconds from first to last run
Cadence int64 // mean seconds between consecutive runs (0 if <2 runs)
}
SeriesHistory is the analysed evolution of one scan series.
func BuildHistory ¶ added in v0.2.0
func BuildHistory(runs []*scan.Run) SeriesHistory
BuildHistory analyses a series (any order) into its drift timeline and stability surface.
type Stability ¶ added in v0.2.0
type Stability int
Stability classifies a port's presence pattern across a series.
type Target ¶
Target - This type can be used as an Input object to a scan, in which case only the Input fields matter to you
Represents how the target was specified when passed to nmap, its status and the reason of its status. Example: <target specification="domain.does.not.exist" status="skipped" reason="invalid"/>.
type TimelineEntry ¶ added in v0.2.0
type TimelineEntry struct {
Run *scan.Run // the run this row represents (the newest of a collapsed stretch)
Delta *RunDiff // change vs the previous (older) run; nil for the baseline (oldest run)
Unchanged int // >1 means this row collapses that many consecutive no-change runs
Summary []string // short per-change lines ("+ 443/tcp https", "~ 22/tcp ssh 8.9 → 9.0")
}
TimelineEntry is one row of the drift timeline: either a run (with its delta vs the previous run) or a collapsed marker standing in for a stretch of runs that changed nothing.