config

package
v0.2.23 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package config persists ndscan's TUI state: last-used scan settings, named profiles, and previous scan results (for change detection). Everything lives under ~/.config/ndscan/ as plain JSON.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DeleteProfile

func DeleteProfile(name string) error

DeleteProfile removes a named profile if present.

func Diff

func Diff(prev []HostSnapshot, cur []HostSnapshot) map[string]HostDiff

Diff compares the current scan against the previous snapshot, keyed by IP. The returned map includes an entry for every changed host, including hosts that disappeared (Gone=true).

func Dir added in v0.2.7

func Dir() string

Dir is the directory ndscan keeps its state in.

Exported so sibling packages store their data alongside config and history rather than each re-deriving the location. Three copies of this resolution would drift the first time the override rules change, and the symptom would be state silently written somewhere nobody looks.

func HistoryModTime added in v0.2.15

func HistoryModTime(k ScanKey) (time.Time, bool)

HistoryModTime reports when the baseline for this scan signature was last written, without loading it.

History filenames are one-way hashes of the key, so the store cannot be enumerated back into keys. A caller that wants to point the user at history filed under a *neighbouring* key — ndscan diff, when the exact key it was asked for has no baseline — can therefore only probe candidate signatures, and this is the read-only primitive for that probe. LoadHistory would answer the same question, but at the cost of reading and parsing every candidate file when all the caller needs is "does this exist, and how old is it".

func Save

func Save(f File) error

Save writes config.json, creating the directory as needed.

func SaveEligible added in v0.2.4

func SaveEligible(cancelled bool, failed int, hosts int) bool

SaveEligible reports whether a finished scan may become the new baseline.

The three front ends each answered this question separately and gave three different answers — the web saved unconditionally, including on cancellation, which corrupted history for every later run. Centralising the rule is what keeps them from drifting apart again.

An empty result set is rejected even when the scan reported success: finding zero hosts almost always means the machine lost its network (VPN dropped, Wi-Fi roamed) rather than that the network emptied out, and treating it as truth discards a good baseline in favour of a useless one.

func SaveHistory

func SaveHistory(k ScanKey, snaps []HostSnapshot) error

SaveHistory stores the snapshot for this scan signature.

Callers must not reach here with the results of a cancelled, failed, or partial scan: an incomplete run looks exactly like a network where everything disappeared, and persisting it as the baseline makes the *next* scan report the whole network as new. Eligibility is the caller's decision because only it knows how the run terminated; SaveEligible states the rule in one place.

func SaveLast

func SaveLast(s Settings) error

SaveLast persists the most recently used settings.

func UpsertProfile

func UpsertProfile(name string, s Settings) error

UpsertProfile adds or replaces a named profile.

func WriteFileAtomic added in v0.2.7

func WriteFileAtomic(path string, data []byte, perm os.FileMode) error

WriteFileAtomic writes data to path via a temp file and a rename, skipping the write entirely when the contents already match.

Exported for sibling packages that persist state alongside config: the same-contents check is what keeps watch mode from rewriting files every interval, and the rename is what stops an interrupted write from leaving truncated JSON behind.

Types

type File

type File struct {
	Last     *Settings `json:"last,omitempty"`
	Profiles []Profile `json:"profiles,omitempty"`
}

File is the on-disk layout of config.json.

func Load

func Load() File

Load reads config.json; a missing or unreadable file yields an empty File.

type HostDiff

type HostDiff struct {
	New         bool     // host wasn't in the previous scan
	Gone        bool     // host was in the previous scan but not this one
	PortsOpened []string // port numbers newly open
	PortsClosed []string // port numbers no longer open
}

HostDiff describes how one host changed between two scans.

func (HostDiff) Changed

func (d HostDiff) Changed() bool

Changed reports whether anything about the host differs.

type HostSnapshot

type HostSnapshot struct {
	IP    string   `json:"ip"`
	Host  string   `json:"host,omitempty"`
	Up    bool     `json:"up"`
	Ports []string `json:"ports,omitempty"` // bare port labels, e.g. "22/tcp ssh"
}

HostSnapshot is the minimal per-host state we remember between scans.

Up is recorded explicitly because a host that stopped responding is a different event from a host whose ports all closed. Without it, a machine that went offline diffs as "every port closed" while the host itself appears to still be there — the opposite of what happened.

func LoadHistory

func LoadHistory(k ScanKey) []HostSnapshot

LoadHistory returns the previous snapshot for this scan signature, or nil.

type Profile

type Profile struct {
	Name     string   `json:"name"`
	Settings Settings `json:"settings"`
}

Profile is a named, saved Settings snapshot.

type ScanKey added in v0.2.4

type ScanKey struct {
	Targets []string
	Ports   string
	Preset  string
	// Fast records whether this was the native ARP+TCP sweep rather than an
	// nmap scan. The two probe different things and legitimately find different
	// hosts, so mixing them under one key manufactures phantom
	// appeared/disappeared events on every alternation.
	Fast bool
}

ScanKey identifies "the same scan" across runs. Two scans are comparable only when every field matches, because each one changes which hosts or ports the scan could possibly have found.

This is a struct rather than a positional argument list on purpose. It was previously three bare strings, and the front ends drifted: the web passed "" for Ports while the TUI passed the real value, so the two never shared a baseline and neither could see the other's history. A named field per input makes an omission visible at the call site instead of silent.

func (ScanKey) Scope added in v0.2.10

func (k ScanKey) Scope() string

Scope is a stable identifier for "the same scan", suitable for tagging records in other stores so they can be filtered back to the scan that produced them.

It is derived from the same canonical signature the history filename uses, so a second store cannot drift into its own interpretation of what makes two scans comparable — the timeline previously had no scope at all, and `ndscan diff` consequently reported changes from whichever network happened to be scanned last.

type Settings

type Settings struct {
	Targets     string `json:"targets"`
	Preset      string `json:"preset"`
	Ports       string `json:"ports"`
	ShowMac     bool   `json:"show_mac"`
	ShowVendors bool   `json:"show_vendors"`
	RootScan    bool   `json:"root_scan"`
	Concurrency string `json:"concurrency"`
	HostTimeout string `json:"host_timeout"`
}

Settings mirrors the TUI form fields.

Jump to

Keyboard shortcuts

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