validator

package
v1.100.4 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: MPL-2.0 Imports: 8 Imported by: 0

Documentation

Overview

============================================================================= NFTBan v1.78 - Validator CLI Helpers ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="validator-cli" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-05" meta:description="CLI output helpers for the validator" meta:inventory.files="internal/validator/cli.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none" =============================================================================

============================================================================= NFTBan v1.82 - Consistency Axis Evaluator ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="consistency" meta:type="lib" meta:version="1.82.0" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:description="Cross-source consistency verification per M81-4 health derivation" meta:inventory.files="internal/validator/consistency.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none"

The consistency axis detects disagreements between truth sources:

config vs kernel (enabled but missing = DEGRADED)
kernel vs validator (structural truth agreement)

Per vocabulary Rule 8: DISABLED + PRESENT = valid residual, NOT a mismatch. Per vocabulary Rule 1: zero counters/sets = NEUTRAL, NOT evidence of failure. =============================================================================

============================================================================= NFTBan v1.81 - Health Output Mapper ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="health_mapper" meta:type="lib" meta:version="1.81.0" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:description="Maps internal ValidationResult to frozen HealthOutput JSON schema" meta:inventory.files="internal/validator/health_mapper.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none"

This mapper is the ONLY path from internal state to JSON output. It enforces: - vocabulary-approved values only - omission rules (disabled modules, kernel-only modules) - no nulls - schema contract compliance

It MUST NOT contain derivation logic. It projects. =============================================================================

============================================================================= NFTBan v1.81 - Health JSON Output (M81-6 Schema Contract) ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="health_output" meta:type="lib" meta:version="1.81.0" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:description="JSON output schema types and mapper per JSON_SCHEMA_SPEC_v1.81.md" meta:inventory.files="internal/validator/health_output.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none"

This file defines the JSON OUTPUT contract. It is a PROJECTION layer only. It MUST NOT contain derivation logic — that belongs in module_health.go. It MUST NOT contain evaluation logic — that belongs in validator.go.

All field values are vocabulary-approved terms from NFTBAN_VOCABULARY_REFERENCE_v1.81.md. Schema frozen per JSON_SCHEMA_SPEC_v1.81.md. =============================================================================

============================================================================= NFTBan v1.84 - Bounded Journal Evidence Reader ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="journal-evidence" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-15" meta:description="Bounded journal query for daemon runtime evidence" meta:inventory.files="internal/validator/journal.go" meta:inventory.binaries="journalctl" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="root"

A1-1: Bounded journal evidence reader, consumed by BotGuard (A1-2) and LoginMon (A1-3) module evaluators for runtime evidence beyond systemctl is-active.

Design contract: - Bounded: time window (-15m) + line count (-n 200), no full scan - Deterministic: same input → same output, newest-first (-r) - Fail-safe: command failure returns structured error, never panics - Silent: no impact on validator status, findings, or exit code

Command shape:

journalctl -u nftband --since "-15m" --no-pager -o cat -r -n 200

Pattern matching is done in Go (substring), not journalctl --grep. This avoids repeated subprocess cost and keeps matching deterministic. =============================================================================

============================================================================= NFTBan v1.81 - Module Health Evaluator ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="module_health" meta:type="lib" meta:version="1.81.0" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:description="Per-module 4-axis health evaluation per M81-4 HEALTH_METRIC_DERIVATION_v1.81.md" meta:inventory.files="internal/validator/module_health.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="conf.d/botguard/main.conf,conf.d/ddos/main.conf,conf.d/portscan/main.conf,conf.d/login_alert.conf" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="root"

This evaluator implements the truth tables from HEALTH_METRIC_DERIVATION_v1.81.md. It MUST NOT invent derivation logic outside that specification. All state values are vocabulary-approved terms from NFTBAN_VOCABULARY_REFERENCE_v1.81.md. =============================================================================

============================================================================= NFTBan v1.78 - nft JSON Output Parsing ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="validator-nftjson" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-05" meta:description="Parse nft -j list ruleset JSON output" meta:inventory.files="internal/validator/nftjson.go" meta:inventory.binaries="nft" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="root" =============================================================================

============================================================================= NFTBan v1.78 - Kernel Truth Validator Types ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="validator-types" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-05" meta:description="Type definitions for kernel state validation" meta:inventory.files="internal/validator/types.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none" =============================================================================

============================================================================= NFTBan v1.78 - Kernel Truth Validator ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="validator" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-05" meta:description="Validates live nftables kernel state against NFTBan requirements" meta:inventory.files="internal/validator/validator.go" meta:inventory.binaries="nft" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="root"

CRITICAL: This validator is ZERO-SIDE-EFFECT. It MUST NEVER write files, modify nft, or call mutating shell scripts. =============================================================================

Index

Constants

View Source
const (
	// Table findings
	CodeTableMissing     = "VAL-TABLE-001"
	CodeTableBothMissing = "VAL-TABLE-002"

	// Chain findings
	CodeChainMissing       = "VAL-CHAIN-001"
	CodeHelperChainMissing = "VAL-CHAIN-002"
	CodeChainCountDrop     = "VAL-CHAIN-003"
	CodeChainEmpty         = "VAL-CHAIN-004" // B80-3: chain exists but has no rules

	// Anchor findings
	CodeAnchorMissing  = "VAL-ANCHOR-001"
	CodeAnchorOrder    = "VAL-ANCHOR-002"
	CodeAnchorFinal    = "VAL-ANCHOR-003" // FINAL GUARD
	CodeAnchorTruncate = "VAL-ANCHOR-004"

	// Set findings
	CodeSetMissing = "VAL-SET-001"

	// Module findings
	CodeModuleDegraded = "VAL-MODULE-001"

	// Service findings (B80-4)
	CodeServiceDown = "VAL-SERVICE-001" // required service not active
	CodeTimerNone   = "VAL-TIMER-001"   // v1.83: no nftban timers active
	CodeTimerError  = "VAL-TIMER-002"   // v1.83: timer query failed

	// Module-specific findings (M81-4)
	CodeGeobanDBMissing    = "VAL-GEOBAN-001"   // geoip database missing/empty
	CodeBotGuardNoEvidence = "VAL-BOTGUARD-001" // v1.84: no recent BotGuard runtime evidence
	CodeLoginMonNoEvidence = "VAL-LOGINMON-001" // v1.84: no recent LoginMon runtime evidence

	// Consistency findings (v1.82)
	CodeConsistencyMismatch = "VAL-CONS-001" // config/kernel disagreement

	// System findings
	CodeNftFailed   = "VAL-SYSTEM-001"
	CodeNftNoOutput = "VAL-SYSTEM-002"
	CodeParseError  = "VAL-SYSTEM-003"
)

Finding codes (stable for automation).

View Source
const SchemaVersionCurrent = "1.83.0"

SchemaVersionCurrent is the frozen schema version per M81-6. v1.83: bumped for timer_count addition to service_state.

Variables

View Source
var AllHelperChains = GeneratedAllHelperChains

AllHelperChains lists all known helper chains for module-truth derivation and informational reporting. Not used for base structural validation.

View Source
var ConfigDir = "/etc/nftban"

ConfigDir is the base config directory. Overridable for testing.

View Source
var GeneratedAllHelperChains = []string{
	"ddos_penalty",
	"ddos_prefix",
	"ddos_protection",
	"ddos_sanity",
	"http_bot_guard",
	"portscan_detection",
}

GeneratedAllHelperChains — all known helper chains (shell-declared + DDoS fragment sub-chains). Module-scoped: only required when their module is enabled.

View Source
var GeneratedAllSetsIPv4 = []string{
	"blacklist_ipv4",
	"blacklist_manual_ipv4",
	"http_bot_allow",
	"http_bot_ban",
	"http_bot_emergency",
	"http_bot_grey",
	"http_bot_pending",
	"http_bot_suspect",
	"port_allow_tcp_ipv4",
	"port_allow_udp_ipv4",
	"tcp_ports_in",
	"tcp_ports_out",
	"udp_ports_in",
	"udp_ports_out",
	"whitelist_ipv4",
}

GeneratedAllSetsIPv4 — all known IPv4 set names from canonical schema (including optional module sets).

View Source
var GeneratedAllSetsIPv6 = []string{
	"blacklist_ipv6",
	"blacklist_manual_ipv6",
	"http_bot_allow6",
	"http_bot_ban6",
	"http_bot_emergency6",
	"http_bot_grey6",
	"http_bot_pending6",
	"http_bot_suspect6",
	"port_allow_tcp_ipv6",
	"port_allow_udp_ipv6",
	"tcp_ports_in",
	"tcp_ports_out",
	"udp_ports_in",
	"udp_ports_out",
	"whitelist_ipv6",
}

GeneratedAllSetsIPv6 — all known IPv6 set names from canonical schema (including optional module sets).

View Source
var GeneratedRequiredBaseChains = []string{
	"forward",
	"input",
	"output",
}

GeneratedRequiredBaseChains from NFTBAN_IPV4_CHAINS keys.

View Source
var GeneratedRequiredHelperChains = []string{}

GeneratedRequiredHelperChains — helper chains universally required for base PROTECTED. Currently empty: all helper chains are module-scoped.

View Source
var GeneratedRequiredSetsIPv4 = []string{
	"blacklist_ipv4",
	"blacklist_manual_ipv4",
	"tcp_ports_in",
	"udp_ports_in",
	"whitelist_ipv4",
}

GeneratedRequiredSetsIPv4 — core sets required for base protection.

View Source
var GeneratedRequiredSetsIPv6 = []string{
	"blacklist_ipv6",
	"blacklist_manual_ipv6",
	"tcp_ports_in",
	"udp_ports_in",
	"whitelist_ipv6",
}

GeneratedRequiredSetsIPv6 — core sets required for base protection.

View Source
var ModuleClassification = map[string]ModuleClass{

	"ddos":     ModuleCoreModule,
	"botguard": ModuleCoreModule,
	"portscan": ModuleCoreModule,
	"loginmon": ModuleCoreModule,
	"geoban":   ModuleCoreModule,

	"botscan": ModuleCoreInfra,
	"geoip":   ModuleCoreInfra,
	"panels":  ModuleCoreInfra,

	"tunnel": ModuleAdvisory,

	"rbl": ModuleMonitor,

	"suricata": ModuleExternal,
}

ModuleClassification maps every config-present module to its class. This is the completeness contract: if a module has a config directory, it MUST appear here. CI gate G8-2 enforces this.

CORE_MODULE entries MUST have: evaluator + ModuleHealthMap field + JSON + tests. CORE_INFRA entries are served by a parent module's evaluator. ADVISORY/MONITOR/EXTERNAL entries MUST NOT appear in evaluator or JSON.

View Source
var RequiredAnchors = []string{
	"ANCHOR_HYGIENE",
	"ANCHOR_TRUSTED",
	"ANCHOR_BAN",
	"ANCHOR_ESTABLISHED",
	"ANCHOR_DETECT",
	"ANCHOR_SERVICE",
	"ANCHOR_FINAL",
}

Required anchors in strict order. AUTHORITY NOTE (B80-5): Anchors are a validator-defined invariant, NOT derived from the shell schema. They represent the required rule-comment sequence in the input chain. The canonical authority for chains/sets is nft_schema.sh via schema_generated.go. The canonical authority for anchor ordering is this list, maintained manually in this file.

View Source
var RequiredBaseChains = GeneratedRequiredBaseChains

Required base chains per family. B80-5/6: sourced from schema_generated.go (canonical: cli/lib/nftban/lib/nft_schema.sh).

View Source
var RequiredHelperChains = GeneratedRequiredHelperChains

Required helper chains per family. Currently EMPTY — all helper chains are module-scoped (only exist when their module is enabled). Base PROTECTED does not require any helper chains. Module-level chain validation is handled by per-module evaluators in module_health.go.

View Source
var RequiredSetsIPv4 = GeneratedRequiredSetsIPv4

Required sets for IPv4. B80-5/6: sourced from schema_generated.go (core required sets only).

View Source
var RequiredSetsIPv6 = GeneratedRequiredSetsIPv6

Required sets for IPv6. B80-5/6: sourced from schema_generated.go (core required sets only).

Functions

func CompareChainCounts

func CompareChainCounts(pre, post ChainCounts, tolerance int) (bool, string)

CompareChainCounts compares pre and post chain counts for rebuild safety. Returns (degraded bool, message string).

func SetJournalReader added in v1.84.0

func SetJournalReader(r JournalReader)

SetJournalReader replaces the journal reader (for testing only).

func SetServiceChecker added in v1.80.0

func SetServiceChecker(sc ServiceChecker)

SetServiceChecker replaces the service checker (for testing only).

func SetTimerChecker added in v1.83.0

func SetTimerChecker(tc TimerChecker)

SetTimerChecker replaces the timer checker (for testing only).

Types

type AnchorCheck

type AnchorCheck struct {
	RequiredCount int      `json:"required_count"`
	FoundCount    int      `json:"found_count"`
	Ordered       bool     `json:"ordered"`
	AnchorsFound  []string `json:"anchors_found"`
	Missing       []string `json:"missing"`
	OrderExpected []string `json:"order_expected"`
	OrderActual   []string `json:"order_actual"`
	FinalPresent  bool     `json:"final_present"` // FINAL GUARD invariant
}

AnchorCheck holds anchor validation results.

type BlacklistHealth added in v1.81.0

type BlacklistHealth struct {
	Manual BlacklistSubHealth `json:"manual"`
	Feeds  BlacklistSubHealth `json:"feeds"`
	Geoban BlacklistSubHealth `json:"geoban"`
}

BlacklistHealth holds the split blacklist state per M81-3 contract.

type BlacklistJSON added in v1.81.0

type BlacklistJSON struct {
	Manual BlacklistSubJSON `json:"manual"`
	Feeds  BlacklistSubJSON `json:"feeds"`
	Geoban BlacklistSubJSON `json:"geoban"`
}

BlacklistJSON is the composite blacklist module output. Does NOT follow the 4-axis model — blacklist is source-split.

type BlacklistSubHealth added in v1.81.0

type BlacklistSubHealth struct {
	State   string `json:"state"`             // enforcing|primed|idle|loaded|stale|disabled
	Entries int    `json:"entries,omitempty"` // element count (manual/feeds)
	Drops   int64  `json:"drops,omitempty"`   // counter value (manual only — attributable)
}

BlacklistSubHealth represents a blacklist sub-source state.

type BlacklistSubJSON added in v1.81.0

type BlacklistSubJSON struct {
	State   string `json:"state"`             // enforcing|primed|idle|loaded|stale|degraded|disabled
	Entries int    `json:"entries,omitempty"` // element count (omitted if 0 or not applicable)
	Drops   int64  `json:"drops,omitempty"`   // counter value (omitted if 0 or not attributable)
}

BlacklistSubJSON represents one blacklist source.

type ChainCheck

type ChainCheck struct {
	Required []string `json:"required"`
	Found    []string `json:"found"`
	Missing  []string `json:"missing"`
	AllFound bool     `json:"all_found"`
}

ChainCheck holds chain validation results.

type ChainCounts

type ChainCounts struct {
	IPv4Total   int `json:"ipv4_total"`
	IPv4Base    int `json:"ipv4_base"`
	IPv4Helper  int `json:"ipv4_helper"`
	IPv6Total   int `json:"ipv6_total"`
	IPv6Base    int `json:"ipv6_base"`
	IPv6Helper  int `json:"ipv6_helper"`
	TotalChains int `json:"total_chains"`
}

ChainCounts for relative comparison (rebuild safety).

type ConfigState added in v1.81.0

type ConfigState string

ConfigState represents operator intent from config files.

const (
	ConfigEnabled  ConfigState = "enabled"
	ConfigDisabled ConfigState = "disabled"
)

type ConsistencyCheck added in v1.82.0

type ConsistencyCheck struct {
	Module string `json:"module"`
	Check  string `json:"check"`  // what was compared
	Result string `json:"result"` // "ok" | "mismatch"
	Detail string `json:"detail,omitempty"`
}

ConsistencyCheck represents one cross-source comparison.

type ConsistencyJSON added in v1.81.0

type ConsistencyJSON struct {
	KernelVsValidator string `json:"kernel_vs_validator"` // ok|mismatch
}

ConsistencyJSON holds cross-source agreement status. Stub for v1.81.0 — expanded in v1.82.

type ConsistencyResult added in v1.82.0

type ConsistencyResult struct {
	Overall  string             `json:"overall"` // "ok" | "mismatch"
	Checks   []ConsistencyCheck `json:"checks"`
	Findings []Finding          `json:"-"` // collected, appended to main result
}

ConsistencyResult holds the outcome of cross-source verification.

type EffectiveState added in v1.81.0

type EffectiveState string

EffectiveState represents the module's activity level based on evidence.

const (
	EffectiveEnforcing EffectiveState = "enforcing"
	EffectiveObserving EffectiveState = "observing"
	EffectiveIdle      EffectiveState = "idle"
	EffectivePrimed    EffectiveState = "primed"
)

type ErrKind added in v1.84.0

type ErrKind string

ErrKind classifies journal query failures.

const (
	ErrNone    ErrKind = ""        // success (may still have Found=false)
	ErrTimeout ErrKind = "timeout" // context deadline exceeded
	ErrExec    ErrKind = "exec"    // binary not found / permission denied
	ErrNonZero ErrKind = "nonzero" // journalctl exited non-zero (not "no matches")
	ErrEmpty   ErrKind = "empty"   // command succeeded but zero output
)

type FamilyResult

type FamilyResult struct {
	Family       string      `json:"family"` // "ip" or "ip6"
	Status       Status      `json:"status"`
	TablePresent bool        `json:"table_present"`
	ChainCount   int         `json:"chain_count"`
	SetCount     int         `json:"set_count"`
	BaseChains   ChainCheck  `json:"base_chains"`
	HelperChains ChainCheck  `json:"helper_chains"`
	Anchors      AnchorCheck `json:"anchors"`
	Sets         SetCheck    `json:"sets"`
}

FamilyResult holds validation results for a single address family (ip/ip6).

type Finding

type Finding struct {
	Code        string   `json:"code"`
	Severity    Severity `json:"severity"`
	Component   string   `json:"component"`
	Family      string   `json:"family,omitempty"`
	Message     string   `json:"message"`
	Remediation string   `json:"remediation,omitempty"`
}

Finding represents a single validation finding.

type FindingJSON added in v1.81.0

type FindingJSON struct {
	Code        string `json:"code"`
	Severity    string `json:"severity"` // info|warn|error|critical
	Component   string `json:"component"`
	Family      string `json:"family,omitempty"`
	Message     string `json:"message"`
	Remediation string `json:"remediation,omitempty"`
}

FindingJSON is a single validation finding in the output.

type HealthOutput added in v1.81.0

type HealthOutput struct {
	SchemaVersion string           `json:"schema_version"`
	Status        string           `json:"status"`
	Timestamp     string           `json:"timestamp"`
	ServiceState  ServiceStateJSON `json:"service_state"`
	Modules       ModulesJSON      `json:"modules"`
	Consistency   ConsistencyJSON  `json:"consistency"`
	Findings      []FindingJSON    `json:"findings"`
	ChainCounts   ChainCounts      `json:"chain_counts"`
	Summary       SummaryCounts    `json:"summary"`
}

HealthOutput is the top-level JSON output structure for nftban-validate --json. This is the canonical M81-6 schema. Fields MUST NOT be added without a schema version bump. See JSON_SCHEMA_SPEC_v1.81.md Section 8.

func MapToHealthOutput added in v1.81.0

func MapToHealthOutput(r *ValidationResult) HealthOutput

MapToHealthOutput converts a ValidationResult to the frozen HealthOutput schema. This is the single mapping point — all JSON output goes through here.

type JournalEvidence added in v1.84.0

type JournalEvidence struct {
	Found        bool    // true if at least one pattern matched
	MatchedLine  string  // first matching line (newest-first order)
	MatchedIndex int     // index of matched line in output (0-based)
	LinesRead    int     // total lines read from journal
	Truncated    bool    // true if journalctl hit -n limit
	ErrKind      ErrKind // failure classification
	Err          error   // underlying error (nil on success)
}

JournalEvidence holds the result of a bounded journal query.

type JournalQuery added in v1.84.0

type JournalQuery struct {
	Unit     string        // systemd unit to filter (e.g. "nftband")
	Patterns []string      // substring patterns to match (first match wins)
	Since    time.Duration // how far back to look (default 15m)
	MaxLines int           // max lines from journalctl -n (default 200)
	Timeout  time.Duration // exec timeout (default 2s)
}

JournalQuery defines a bounded journal search.

type JournalReader added in v1.84.0

type JournalReader interface {
	Query(ctx context.Context, q JournalQuery) JournalEvidence
}

JournalReader abstracts journal queries for testability.

type ModuleClass added in v1.85.0

type ModuleClass string

ModuleClass defines a module's role in the system.

const (
	ModuleCoreModule ModuleClass = "core_module" // Protection module: evaluator + JSON + tests required
	ModuleCoreInfra  ModuleClass = "core_infra"  // Internal support: served by parent evaluator
	ModuleAdvisory   ModuleClass = "advisory"    // Non-blocking, no kernel enforcement
	ModuleMonitor    ModuleClass = "monitor"     // Observes but does not enforce
	ModuleExternal   ModuleClass = "external"    // Third-party integration, deferred
)

type ModuleHealth added in v1.81.0

type ModuleHealth struct {
	Config     ConfigState     `json:"config"`
	Structural StructuralState `json:"structural,omitempty"`
	Runtime    RuntimeState    `json:"runtime,omitempty"`
	Effective  EffectiveState  `json:"effective,omitempty"`
}

ModuleHealth holds the 4-axis health evaluation for one module.

type ModuleHealthMap added in v1.81.0

type ModuleHealthMap struct {
	BotGuard  *ModuleHealth    `json:"botguard,omitempty"`
	DDoS      *ModuleHealth    `json:"ddos,omitempty"`
	Portscan  *ModuleHealth    `json:"portscan,omitempty"`
	LoginMon  *ModuleHealth    `json:"loginmon,omitempty"`
	Blacklist *BlacklistHealth `json:"blacklist,omitempty"`
}

ModuleHealthMap holds all per-module health evaluations.

type ModuleJSON added in v1.81.0

type ModuleJSON struct {
	Config     string `json:"config"`               // enabled|disabled (always present)
	Structural string `json:"structural,omitempty"` // present|missing (omitted if disabled)
	Runtime    string `json:"runtime,omitempty"`    // running|stopped (omitted if not daemon-dependent)
	Effective  string `json:"effective,omitempty"`  // enforcing|observing|idle (omitted if disabled)
}

ModuleJSON is the standard 4-axis module output. Fields are omitted when not applicable (e.g. runtime for kernel-only modules).

type ModulesJSON added in v1.81.0

type ModulesJSON struct {
	BotGuard  *ModuleJSON    `json:"botguard,omitempty"`
	DDoS      *ModuleJSON    `json:"ddos,omitempty"`
	Portscan  *ModuleJSON    `json:"portscan,omitempty"`
	LoginMon  *ModuleJSON    `json:"loginmon,omitempty"`
	Blacklist *BlacklistJSON `json:"blacklist,omitempty"`
}

ModulesJSON holds all per-module health in JSON output form. Disabled modules emit config only (no other fields). No nulls. Omitted fields = not applicable.

type NftChain

type NftChain struct {
	Family   string `json:"family"`
	Table    string `json:"table"`
	Name     string `json:"name"`
	Type     string `json:"type,omitempty"`
	Hook     string `json:"hook,omitempty"`
	Priority int    `json:"prio,omitempty"`
	Policy   string `json:"policy,omitempty"`
	Handle   int    `json:"handle,omitempty"`
}

NftChain represents an nftables chain.

type NftCounter

type NftCounter struct {
	Family  string `json:"family"`
	Table   string `json:"table"`
	Name    string `json:"name"`
	Handle  int    `json:"handle,omitempty"`
	Packets int64  `json:"packets,omitempty"`
	Bytes   int64  `json:"bytes,omitempty"`
}

NftCounter represents a named counter.

type NftMetainfo

type NftMetainfo struct {
	Version           string `json:"version"`
	ReleaseName       string `json:"release_name"`
	JsonSchemaVersion int    `json:"json_schema_version"`
}

NftMetainfo holds nft version info.

type NftObject

type NftObject struct {
	Metainfo *NftMetainfo `json:"metainfo,omitempty"`
	Table    *NftTable    `json:"table,omitempty"`
	Chain    *NftChain    `json:"chain,omitempty"`
	Set      *NftSet      `json:"set,omitempty"`
	Rule     *NftRule     `json:"rule,omitempty"`
	Counter  *NftCounter  `json:"counter,omitempty"`
}

NftObject is a wrapper for any nft object (table, chain, set, rule, etc.). Only one field will be populated per object.

type NftRule

type NftRule struct {
	Family  string        `json:"family"`
	Table   string        `json:"table"`
	Chain   string        `json:"chain"`
	Handle  int           `json:"handle,omitempty"`
	Comment string        `json:"comment,omitempty"`
	Expr    []interface{} `json:"expr,omitempty"`
}

NftRule represents an nftables rule.

type NftRuleset

type NftRuleset struct {
	Nftables []NftObject `json:"nftables"`
}

NftRuleset represents the top-level nft -j list ruleset output. The JSON structure is: { "nftables": [ {...}, {...}, ... ] }

func LoadRulesetJSON

func LoadRulesetJSON(ctx context.Context) (*NftRuleset, error)

LoadRulesetJSON executes nft -j list ruleset and parses the output. This is a PURE function - it only reads kernel state, never modifies.

type NftSet

type NftSet struct {
	Family  string     `json:"family"`
	Table   string     `json:"table"`
	Name    string     `json:"name"`
	Type    NftSetType `json:"type,omitempty"`
	Flags   []string   `json:"flags,omitempty"`
	Timeout int        `json:"timeout,omitempty"`
	Handle  int        `json:"handle,omitempty"`
}

NftSet represents an nftables set.

type NftSetType

type NftSetType struct {
	Types []string
}

NftSetType handles nft set type which can be string or []string (for concatenations).

func (*NftSetType) UnmarshalJSON

func (t *NftSetType) UnmarshalJSON(data []byte) error

UnmarshalJSON handles both string and []string for nft set type field.

type NftTable

type NftTable struct {
	Family string `json:"family"`
	Name   string `json:"name"`
	Handle int    `json:"handle,omitempty"`
}

NftTable represents an nftables table.

type RulesetDocument

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

RulesetDocument provides structured access to the parsed ruleset.

func ParseRuleset

func ParseRuleset(raw *NftRuleset) *RulesetDocument

ParseRuleset converts raw NftRuleset into a structured document.

func (*RulesetDocument) ChainExists

func (d *RulesetDocument) ChainExists(family, table, chain string) bool

ChainExists checks if a chain exists.

func (*RulesetDocument) CountChains

func (d *RulesetDocument) CountChains(family string) int

CountChains returns total chain count for a family's nftban table.

func (*RulesetDocument) CountRulesInChain added in v1.80.0

func (d *RulesetDocument) CountRulesInChain(family, table, chain string) int

CountRulesInChain returns the number of rules in a specific chain. Returns 0 if the chain has no rules or does not exist.

func (*RulesetDocument) CountSets

func (d *RulesetDocument) CountSets(family string) int

CountSets returns total set count for a family's nftban table.

func (*RulesetDocument) ExtractAnchorsFromChain

func (d *RulesetDocument) ExtractAnchorsFromChain(family, table, chain string) []string

ExtractAnchorsFromChain extracts anchor names from rule comments in a chain. Anchors are identified by comments containing "NFTBAN_ANCHOR:ANCHOR_*".

func (*RulesetDocument) GetAllCounters added in v1.89.0

func (d *RulesetDocument) GetAllCounters(family, table string) map[string]*NftCounter

GetAllCounters returns all named counters for a family and table. Keys are counter names (without family/table prefix). v1.89: Added for evidence layer extraction (INV-M-002).

func (*RulesetDocument) GetChains

func (d *RulesetDocument) GetChains(family, table string) []string

GetChains returns all chain names for a table.

func (*RulesetDocument) GetCounter added in v1.81.0

func (d *RulesetDocument) GetCounter(family, table, name string) int64

GetCounter returns a named counter's packet count, or 0 if not found.

func (*RulesetDocument) GetCounterFull added in v1.89.0

func (d *RulesetDocument) GetCounterFull(family, table, name string) *NftCounter

GetCounterFull returns a named counter with both packets and bytes. Returns nil if the counter does not exist. v1.89: Added for evidence layer extraction (INV-M-002).

func (*RulesetDocument) GetRules

func (d *RulesetDocument) GetRules(family, table, chain string) []*NftRule

GetRules returns all rules for a chain.

func (*RulesetDocument) GetSets

func (d *RulesetDocument) GetSets(family, table string) []string

GetSets returns all set names for a table.

func (*RulesetDocument) SetExists

func (d *RulesetDocument) SetExists(family, table, set string) bool

SetExists checks if a set exists.

func (*RulesetDocument) TableExists

func (d *RulesetDocument) TableExists(family, name string) bool

TableExists checks if a table exists.

type RuntimeState added in v1.80.0

type RuntimeState string

RuntimeState represents a three-state service status. Aligns with the v1.82 health model direction (RUNNING / STOPPED / ERROR).

const (
	RuntimeRunning RuntimeState = "RUNNING"
	RuntimeStopped RuntimeState = "STOPPED"
	RuntimeError   RuntimeState = "ERROR" // systemctl query itself failed
)

type ServiceChecker added in v1.80.0

type ServiceChecker interface {
	// CheckUnit returns (RuntimeState, detail string).
	// RuntimeState: RUNNING / STOPPED / ERROR.
	// detail: the raw systemctl output (e.g. "active", "inactive", "failed").
	CheckUnit(unit string) (RuntimeState, string)
}

ServiceChecker abstracts service-state queries so unit tests can mock systemd without requiring a real init system. The default implementation calls `systemctl is-active <unit>`.

type ServiceState added in v1.80.0

type ServiceState struct {
	Nftband       RuntimeState `json:"nftband"`
	NftbandDetail string       `json:"nftband_detail,omitempty"`
	TimerCount    int          `json:"timer_count"` // v1.83: active nftban-* timer count
}

ServiceState holds the live status of required system services. B80-4: the validator MUST check these before declaring PROTECTED. A system with correct kernel structure but a dead daemon is not protected.

type ServiceStateJSON added in v1.81.0

type ServiceStateJSON struct {
	Nftband       string `json:"nftband"`                  // RUNNING|STOPPED|ERROR
	NftbandDetail string `json:"nftband_detail,omitempty"` // raw systemctl output
	TimerCount    int    `json:"timer_count"`              // v1.83: active nftban-* timer count
}

ServiceStateJSON is the JSON representation of daemon and timer state.

type SetCheck

type SetCheck struct {
	Required []string `json:"required"`
	Found    []string `json:"found"`
	Missing  []string `json:"missing"`
	AllFound bool     `json:"all_found"`
}

SetCheck holds set validation results.

type Severity

type Severity string

Severity for findings.

const (
	SeverityInfo     Severity = "info"
	SeverityWarn     Severity = "warn"
	SeverityError    Severity = "error"
	SeverityCritical Severity = "critical"
)

type Status

type Status string

Status represents the overall protection state.

const (
	// StatusProtected means all validation checks passed and at least one module active.
	StatusProtected Status = "protected"
	// StatusIdle means all axes pass but no relevant traffic observed. Exit 0.
	StatusIdle Status = "idle"
	// StatusDegraded means partial protection - some checks failed.
	StatusDegraded Status = "degraded"
	// StatusDown means no viable nftban protection detected.
	StatusDown Status = "down"
)

type StructuralState added in v1.81.0

type StructuralState string

StructuralState represents kernel object presence.

const (
	StructuralPresent StructuralState = "present"
	StructuralMissing StructuralState = "missing"
)

type SummaryCounts

type SummaryCounts struct {
	TotalFindings    int `json:"total_findings"`
	CriticalFindings int `json:"critical_findings"`
	ErrorFindings    int `json:"error_findings"`
	WarnFindings     int `json:"warn_findings"`
	CheckedFamilies  int `json:"checked_families"`
	ProtectedFams    int `json:"protected_families"`
	DegradedFams     int `json:"degraded_families"`
}

SummaryCounts provides quick stats.

type SystemdChecker added in v1.80.0

type SystemdChecker struct{}

SystemdChecker is the default production ServiceChecker.

func (SystemdChecker) CheckUnit added in v1.80.0

func (SystemdChecker) CheckUnit(unit string) (RuntimeState, string)

CheckUnit queries systemd for the unit's active state. This is a read-only query — zero side effects.

type SystemdJournalReader added in v1.84.0

type SystemdJournalReader struct{}

SystemdJournalReader is the production implementation using journalctl.

func (SystemdJournalReader) Query added in v1.84.0

Query executes a bounded journalctl query and matches patterns in Go.

Strategy: fetch bounded output once with -o cat -r -n N, then scan lines for substring matches. No --grep, no shell pipes, no repeated subprocess calls.

type SystemdTimerChecker added in v1.83.0

type SystemdTimerChecker struct{}

SystemdTimerChecker is the default production TimerChecker.

func (SystemdTimerChecker) CountActiveTimers added in v1.83.0

func (SystemdTimerChecker) CountActiveTimers() (int, error)

CountActiveTimers queries systemd for active nftban-* timers. Read-only — zero side effects.

type TimerChecker added in v1.83.0

type TimerChecker interface {
	// CountActiveTimers returns the number of active nftban-* timers.
	// On query error it returns (0, error).
	CountActiveTimers() (int, error)
}

TimerChecker abstracts timer-count queries so unit tests can mock systemd without requiring a real init system.

type ValidationResult

type ValidationResult struct {
	SchemaVersion      string          `json:"schema_version"`
	Status             Status          `json:"status"`
	Timestamp          time.Time       `json:"timestamp"`
	Families           []FamilyResult  `json:"families"`
	Findings           []Finding       `json:"findings"`
	Summary            SummaryCounts   `json:"summary"`
	ChainCount         ChainCounts     `json:"chain_counts"`
	ServiceState       ServiceState    `json:"service_state"`
	Modules            ModuleHealthMap `json:"modules"`             // M81-4
	ConsistencyOverall string          `json:"consistency_overall"` // v1.82: "ok" | "mismatch"

	// v1.89 INV-M-001/002: Expose kernel state for evidence layer.
	// These fields are internal — not serialized to the frozen JSON schema.
	Doc              *RulesetDocument `json:"-"` // parsed kernel ruleset (counters, chains, sets)
	SetElementCounts map[string]int   `json:"-"` // "family:set" → element count
}

ValidationResult is the complete output of kernel validation.

func RunValidation

func RunValidation(ctx context.Context) (*ValidationResult, error)

RunValidation is a convenience function that runs validation and returns the result. Returns (result, nil) even if status is DOWN - that's a valid result.

func ValidateKernel

func ValidateKernel(ctx context.Context) (*ValidationResult, error)

ValidateKernel performs complete kernel state validation. This is the main entrypoint for the validator.

CRITICAL: This function is PURE - it only reads, never modifies.

func (*ValidationResult) ExitCode

func (r *ValidationResult) ExitCode() int

ExitCode returns the appropriate exit code for the status. 0 = PROTECTED or IDLE, 1 = DEGRADED, 2 = DOWN Per M81-4: IDLE is exit 0 (not an error).

func (*ValidationResult) PrintSummary

func (r *ValidationResult) PrintSummary()

PrintSummary prints a human-readable summary to stdout.

func (*ValidationResult) StatusString

func (r *ValidationResult) StatusString() string

StatusString returns a human-readable status.

func (*ValidationResult) ToJSON

func (r *ValidationResult) ToJSON() ([]byte, error)

ToJSON converts the validation result to the frozen M81-6 JSON schema. Uses MapToHealthOutput to enforce the schema contract — never serializes the internal ValidationResult directly.

func (*ValidationResult) ToJSONLegacy added in v1.81.0

func (r *ValidationResult) ToJSONLegacy() ([]byte, error)

ToJSONLegacy serializes the raw ValidationResult for backward compat. Used by rebuild safety checks that parse the old schema. TODO(v1.82): migrate consumers to frozen schema then remove this.

Jump to

Keyboard shortcuts

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