core

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultTimeout = 5 * time.Second

DefaultTimeout is used when Target.Timeout is zero.

Variables

This section is empty.

Functions

This section is empty.

Types

type Confidence

type Confidence float64

Confidence represents a detection certainty score between 0.0 and 1.0. Using a named type prevents accidental misuse and makes domain logic explicit.

func (Confidence) IsHigh

func (c Confidence) IsHigh(threshold float64) bool

IsHigh reports whether c meets or exceeds the given threshold.

func (Confidence) Valid

func (c Confidence) Valid() bool

Valid reports whether c is within the allowed range [0.0, 1.0].

type ConnectionError

type ConnectionError struct {
	Protocol Protocol
	Addr     string
	Err      error
}

ConnectionError indicates a transport-level failure (refused, unreachable, etc.).

func (*ConnectionError) Error

func (e *ConnectionError) Error() string

func (*ConnectionError) Unwrap

func (e *ConnectionError) Unwrap() error

type DetectError

type DetectError struct {
	Protocol Protocol
	Op       string // short operation name, e.g. "dial", "send", "receive"
	Err      error
}

DetectError wraps an error that occurred during protocol detection. Callers can inspect Protocol and Op for structured logging and metrics.

func (*DetectError) Error

func (e *DetectError) Error() string

func (*DetectError) Unwrap

func (e *DetectError) Unwrap() error

type Engine

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

Engine orchestrates protocol detection using registered fingerprinters.

func NewEngine

func NewEngine(registry *Registry, config EngineConfig) *Engine

NewEngine creates a new detection engine with the given registry and config.

func (*Engine) Detect

func (e *Engine) Detect(ctx context.Context, target Target) Result

Detect runs all fingerprinters and returns the best match. If no protocol is detected, it returns a Result with Protocol=ProtocolUnknown.

func (*Engine) DetectAll

func (e *Engine) DetectAll(ctx context.Context, target Target) []Result

DetectAll runs all registered fingerprinters against the target and returns all results sorted by confidence (highest first).

func (*Engine) DetectProtocol

func (e *Engine) DetectProtocol(ctx context.Context, target Target, protocol Protocol) (Result, error)

DetectProtocol runs a specific named fingerprinter against the target.

func (*Engine) Scan

func (e *Engine) Scan(ctx context.Context, target Target) ScanReport

Scan runs a full detection sweep and returns a structured ScanReport.

type EngineConfig

type EngineConfig struct {
	// Parallel enables parallel protocol detection.
	// When false, protocols are tested sequentially.
	Parallel bool

	// EarlyStop causes the engine to stop after the first high-confidence match
	// (Confidence >= HighConfidenceThreshold).
	EarlyStop bool

	// HighConfidenceThreshold is the minimum confidence to trigger early stop.
	// Default: 0.9
	HighConfidenceThreshold Confidence

	// MaxConcurrency limits the number of in-flight goroutines when Parallel
	// is true. Zero or negative means unbounded.
	MaxConcurrency int

	// MinInterval enforces a minimum delay between sequential protocol
	// attempts (or between goroutine launches in parallel mode).
	// In ICS environments, burst scanning may trigger IDS alerts.
	// Zero means no delay.
	MinInterval time.Duration

	// Observer receives callbacks during detection for metrics, tracing,
	// or audit logging. Nil disables observation.
	Observer Observer
}

EngineConfig configures the detection engine behavior.

func DefaultEngineConfig

func DefaultEngineConfig() EngineConfig

DefaultEngineConfig returns sensible default engine configuration. Parallel is disabled by default because protocol detection always targets a single endpoint, and many industrial devices cannot handle concurrent TCP connections reliably — leading to non-deterministic results.

func SafeEngineConfig

func SafeEngineConfig() EngineConfig

SafeEngineConfig returns a conservative configuration suitable for production OT environments where minimising network impact is critical.

type Exchange

type Exchange struct {
	// Label describes this exchange phase (e.g. "phase1", "probe").
	Label string `json:"label"`
	// Probe is the raw bytes sent to the target.
	Probe []byte `json:"probe"`
	// Response is the raw bytes received from the target.
	Response []byte `json:"response"`
}

Exchange records the raw bytes of a single probe/response round-trip. Populated when debug tracing is desired; nil otherwise.

type Fingerprint

type Fingerprint struct {
	// ID is a dot-separated identifier, e.g. "modbus.fc43".
	ID string `json:"id"`

	// Signature is a compact machine-parseable string of key observations.
	Signature string `json:"signature"`

	// Metadata holds protocol-specific key-value pairs.
	Metadata map[string]string `json:"metadata,omitempty"`
}

Fingerprint holds structured identification data from a detection. It provides machine-readable fields suitable for SIEM integration, asset fingerprint databases, and security product embedding.

func (*Fingerprint) String

func (f *Fingerprint) String() string

String returns a compact representation of the fingerprint.

type Fingerprinter

type Fingerprinter interface {
	// Name returns the protocol identifier this fingerprinter detects.
	Name() Protocol

	// Priority returns the detection order priority (lower = tested first).
	// Priorities are conventionally spaced in increments of 10 to allow
	// insertion without renumbering.
	Priority() int

	// Detect attempts to identify the protocol on the given target.
	// It must respect context cancellation and target timeout.
	// It must never panic, even on malformed or unexpected responses.
	Detect(ctx context.Context, target Target) (Result, error)
}

Fingerprinter is the interface that each protocol detector must implement. Implementations must be safe for concurrent use.

type InvalidResponseError

type InvalidResponseError struct {
	Protocol Protocol
	Reason   string
}

InvalidResponseError indicates the target responded, but the response was malformed or did not conform to the expected protocol framing. Useful for distinguishing "wrong protocol" from "broken implementation".

func (*InvalidResponseError) Error

func (e *InvalidResponseError) Error() string

type Observer

type Observer interface {
	// OnStart is called before each protocol detection attempt begins.
	OnStart(protocol Protocol, target Target)
	// OnResult is called after each detection attempt completes.
	OnResult(result Result)
}

Observer receives callbacks during protocol detection for instrumentation. Implementations must be safe for concurrent use when Parallel is true. All methods must be non-blocking.

type Protocol

type Protocol uint8

Protocol represents a named OT protocol identifier as an efficient integer type. String representations are maintained via a lookup table. Protocol values are stable across versions and must not be reordered.

const (
	ProtocolUnknown  Protocol = 0
	ProtocolModbus   Protocol = 1
	ProtocolMMS      Protocol = 2
	ProtocolS7       Protocol = 3
	ProtocolOPCUA    Protocol = 4
	ProtocolBACnet   Protocol = 5
	ProtocolCAN      Protocol = 6
	ProtocolPROFINET Protocol = 7
	ProtocolDNP3     Protocol = 8
	ProtocolIEC104   Protocol = 9
	ProtocolENIP     Protocol = 10
)

Known protocol identifiers.

func AllProtocols

func AllProtocols() []Protocol

AllProtocols returns every known protocol in recommended detection order. The order prioritises ISO-based protocols, then progressively moves to lighter-weight probes and niche gateways.

func ParseProtocol

func ParseProtocol(s string) (Protocol, error)

ParseProtocol converts a protocol name string to its typed constant. Returns an error if the name does not match any known protocol.

func (Protocol) IsValid

func (p Protocol) IsValid() bool

IsValid reports whether p is a known, non-Unknown protocol.

func (Protocol) String

func (p Protocol) String() string

String returns the human-readable protocol name.

type ProtocolNotFoundError

type ProtocolNotFoundError struct {
	Protocol Protocol
}

ProtocolNotFoundError is returned when a requested protocol is not registered.

func (*ProtocolNotFoundError) Error

func (e *ProtocolNotFoundError) Error() string

type Registry

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

Registry holds registered protocol fingerprinters. It is safe for concurrent use.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty Registry.

func (*Registry) All

func (r *Registry) All() []Fingerprinter

All returns all registered fingerprinters sorted by priority (lowest first).

func (*Registry) Get

func (r *Registry) Get(protocol Protocol) Fingerprinter

Get returns the fingerprinter for the given protocol, or nil if not found.

func (*Registry) Names

func (r *Registry) Names() []Protocol

Names returns the protocol identifiers of all registered fingerprinters.

func (*Registry) Register

func (r *Registry) Register(fp Fingerprinter) error

Register adds a fingerprinter to the registry. Returns an error if a fingerprinter with the same name is already registered.

type Result

type Result struct {
	// Protocol identifies the protocol this result relates to.
	Protocol Protocol

	// Matched is true if the protocol was positively identified.
	Matched bool

	// Confidence is a score between 0.0 and 1.0 indicating detection certainty.
	Confidence Confidence

	// Details provides additional human-readable information about the detection.
	Details string

	// Error records the underlying error when detection fails.
	// A non-nil Error with Matched==false allows callers to distinguish
	// "no match" from "could not reach host".
	Error error

	// Fingerprint holds structured identification data.
	// Nil when no fingerprint is available.
	Fingerprint *Fingerprint

	// DetectionID is a unique identifier for this detection attempt,
	// useful for correlating log entries and audit trails.
	DetectionID string

	// Timestamp records when this result was created.
	Timestamp time.Time

	// Exchanges records raw probe/response byte pairs for debug tracing.
	// Nil when tracing is not enabled.
	Exchanges []Exchange `json:"exchanges,omitempty"`
}

Result holds the outcome of a fingerprint detection attempt.

Detection semantics:

Scenario            Matched   Error             Confidence
Positive match      true      nil               > 0
No match            false     nil               0
Timeout             false     *TimeoutError      0
Connection refused  false     *ConnectionError   0
Invalid response    false     *InvalidRespError  0

func ErrorResult

func ErrorResult(protocol Protocol, err error) Result

ErrorResult returns a Result recording a detection error. Matched is false and the error is preserved for inspection.

func Match

func Match(protocol Protocol, confidence Confidence, details string) Result

Match returns a Result indicating a successful protocol detection.

func NoMatch

func NoMatch(protocol Protocol) Result

NoMatch returns a Result indicating no protocol was detected.

func (Result) String

func (r Result) String() string

String returns a human-readable summary of the result.

func (Result) WithExchange

func (r Result) WithExchange(label string, probe, response []byte) Result

WithExchange appends a probe/response exchange to the result for debug tracing.

func (Result) WithFingerprint

func (r Result) WithFingerprint(fp *Fingerprint) Result

WithFingerprint returns a copy of r with the given fingerprint set.

type ScanReport

type ScanReport struct {
	// Target is the endpoint that was scanned.
	Target Target

	// StartedAt records when the scan began.
	StartedAt time.Time

	// FinishedAt records when the scan completed.
	FinishedAt time.Time

	// Duration is the wall-clock time of the scan.
	Duration time.Duration

	// Results holds all individual detection outcomes, sorted by
	// confidence descending.
	Results []Result

	// BestMatch is the highest-confidence matched result, or a
	// ProtocolUnknown result if nothing matched.
	BestMatch Result
}

ScanReport is a structured summary of a complete detection run.

type Target

type Target struct {
	// IP is the target IP address.
	IP string
	// Port is the target TCP port.
	Port int
	// Timeout is the maximum duration for the fingerprint operation.
	// If zero, a default timeout of 5 seconds is used.
	Timeout time.Duration
}

Target represents a network endpoint to fingerprint.

func (Target) Addr

func (t Target) Addr() string

Addr returns the target address in "host:port" format.

func (Target) EffectiveTimeout

func (t Target) EffectiveTimeout() time.Duration

EffectiveTimeout returns the configured timeout or DefaultTimeout if zero.

func (Target) Validate

func (t Target) Validate() error

Validate checks that the target fields are well-formed. It returns an error describing the first invalid field found:

  • IP must be a parseable IPv4 or IPv6 address
  • Port must be in range [1, 65535]
  • Timeout must not be negative

type TimeoutError

type TimeoutError struct {
	Protocol Protocol
	Addr     string
	Err      error
}

TimeoutError indicates a detection attempt exceeded its deadline.

func (*TimeoutError) Error

func (e *TimeoutError) Error() string

func (*TimeoutError) Unwrap

func (e *TimeoutError) Unwrap() error

Jump to

Keyboard shortcuts

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