detector

package
v1.2.2 Latest Latest
Warning

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

Go to latest
Published: Jan 17, 2026 License: MPL-2.0 Imports: 5 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ReasonSSHFailedPassword  uint16 = 1001
	ReasonSSHInvalidUser     uint16 = 1002
	ReasonSSHPreauth         uint16 = 1003
	ReasonSSHTooManyFailures uint16 = 1004
	ReasonSSHRootAttempt     uint16 = 1005
	ReasonDovecotAuthFail    uint16 = 2001
	ReasonPostfixSASL        uint16 = 2002
	ReasonEximAuthFail       uint16 = 2003
	ReasonFTPAuthFail        uint16 = 3001
	ReasonDirectAdminLogin   uint16 = 4001
	ReasonCPanelLogin        uint16 = 4002
	ReasonWordPressXMLRPC    uint16 = 5001
	ReasonWordPressWPLogin   uint16 = 5002
	ReasonPleskLogin         uint16 = 4003
	ReasonGenericAuthFail    uint16 = 9001
)

Reason codes for different detection types (stable enum values)

Variables

View Source
var ReasonName = map[uint16]string{
	ReasonSSHFailedPassword:  "ssh_failed_password",
	ReasonSSHInvalidUser:     "ssh_invalid_user",
	ReasonSSHPreauth:         "ssh_preauth_disconnect",
	ReasonSSHTooManyFailures: "ssh_too_many_failures",
	ReasonSSHRootAttempt:     "ssh_root_attempt",
	ReasonDovecotAuthFail:    "dovecot_auth_fail",
	ReasonPostfixSASL:        "postfix_sasl_fail",
	ReasonEximAuthFail:       "exim_auth_fail",
	ReasonFTPAuthFail:        "ftp_auth_fail",
	ReasonDirectAdminLogin:   "directadmin_login_fail",
	ReasonCPanelLogin:        "cpanel_login_fail",
	ReasonWordPressXMLRPC:    "wordpress_xmlrpc",
	ReasonWordPressWPLogin:   "wordpress_wp_login",
	ReasonPleskLogin:         "plesk_login_fail",
	ReasonGenericAuthFail:    "generic_auth_fail",
}

ReasonName maps reason codes to human-readable names

Functions

This section is empty.

Types

type BanAction added in v1.0.31

type BanAction struct {
	IP       netip.Addr
	Duration time.Duration
	Reason   string
	Score    int32
	Service  string
	IsNew    bool // true if this is a new ban, false if escalation
}

BanAction represents a ban decision

type Detector

type Detector interface {
	// Name returns the detector identifier
	Name() string

	// Detect checks if a log line matches this detector's patterns
	// Returns (verdict, true) if matched, (zero, false) if not
	// The line is passed as []byte to enable zero-copy processing
	Detect(line []byte) (Verdict, bool)
}

Detector is the interface for all login failure detectors Each detector implements signal-based detection: 1. Cheap prefilter (bytes.Contains) to skip non-matching lines 2. Precise extraction only on matching lines

type FTPDetector

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

FTPDetector detects FTP authentication failures

func NewFTPDetector

func NewFTPDetector() *FTPDetector

NewFTPDetector creates a new FTP detector

func (*FTPDetector) Detect

func (d *FTPDetector) Detect(line []byte) (Verdict, bool)

Detect checks if a log line is an FTP authentication failure

func (*FTPDetector) Name

func (d *FTPDetector) Name() string

Name returns the detector identifier

type IPState added in v1.0.31

type IPState struct {
	Score       int32     // Current score (scaled by 100)
	Detections  int32     // Total detection count
	BanCount    int32     // Number of times banned
	LastSeen    time.Time // Last detection time
	LastBan     time.Time // Last ban time
	FirstSeen   time.Time // First detection time
	LastService string    // Last service that detected this IP
	LastReason  uint16    // Last reason code
}

IPState tracks state for a single IP

type MailDetector

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

MailDetector detects mail authentication failures (Dovecot, Postfix, Exim)

func NewMailDetector

func NewMailDetector() *MailDetector

NewMailDetector creates a new mail detector

func (*MailDetector) Detect

func (d *MailDetector) Detect(line []byte) (Verdict, bool)

Detect checks if a log line is a mail authentication failure

func (*MailDetector) Name

func (d *MailDetector) Name() string

Name returns the detector identifier

type PanelDetector

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

PanelDetector detects control panel authentication failures

func NewPanelDetector

func NewPanelDetector() *PanelDetector

NewPanelDetector creates a new panel detector

func (*PanelDetector) Detect

func (d *PanelDetector) Detect(line []byte) (Verdict, bool)

Detect checks if a log line is a panel authentication failure

func (*PanelDetector) Name

func (d *PanelDetector) Name() string

Name returns the detector identifier

type Registry

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

Registry holds all registered detectors

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a new detector registry with default detectors

func (*Registry) Detect

func (r *Registry) Detect(line []byte) (Verdict, bool)

Detect runs all registered detectors on a line Returns on first match (detectors are ordered by likelihood)

func (*Registry) DetectAll

func (r *Registry) DetectAll(line []byte) []Verdict

DetectAll runs all detectors and returns all matches Useful for hybrid mode where multiple signals may be present

func (*Registry) Detectors

func (r *Registry) Detectors() []string

Detectors returns the list of registered detector names

func (*Registry) Register

func (r *Registry) Register(d Detector)

Register adds a detector to the registry

type SSHDetector

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

SSHDetector detects SSH authentication failures

func NewSSHDetector

func NewSSHDetector() *SSHDetector

NewSSHDetector creates a new SSH detector with precomputed signals

func (*SSHDetector) Detect

func (d *SSHDetector) Detect(line []byte) (Verdict, bool)

Detect checks if a log line is an SSH authentication failure

func (*SSHDetector) Name

func (d *SSHDetector) Name() string

Name returns the detector identifier

type Scorer added in v1.0.31

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

Scorer tracks IP scores and triggers bans

func NewScorer added in v1.0.31

func NewScorer(config ScorerConfig) *Scorer

NewScorer creates a new scoring engine

func NewScorerDefault added in v1.0.31

func NewScorerDefault() *Scorer

NewScorerDefault creates a scorer with default config

func (*Scorer) Cleanup added in v1.0.31

func (s *Scorer) Cleanup() int

Cleanup removes old IP entries

func (*Scorer) DecayScores added in v1.0.31

func (s *Scorer) DecayScores()

DecayScores reduces all IP scores (call periodically)

func (*Scorer) GetIPState added in v1.0.31

func (s *Scorer) GetIPState(ip netip.Addr) (IPState, bool)

GetIPState returns the current state for an IP (thread-safe copy)

func (*Scorer) GetStats added in v1.0.31

func (s *Scorer) GetStats() StatsSnapshot

GetStats returns current statistics snapshot

func (*Scorer) RecordVerdict added in v1.0.31

func (s *Scorer) RecordVerdict(v Verdict) *BanAction

RecordVerdict records a detection verdict and returns ban action if threshold reached

func (*Scorer) Reset added in v1.0.31

func (s *Scorer) Reset()

Reset clears all state (for testing)

func (*Scorer) TrackedIPs added in v1.0.31

func (s *Scorer) TrackedIPs() int

TrackedIPs returns the number of currently tracked IPs

type ScorerConfig added in v1.0.31

type ScorerConfig struct {
	// Thresholds (score * 100 for precision)
	ThresholdTempBan   int32 // Score to trigger temp ban (default: 45 = 0.45)
	ThresholdEscalate  int32 // Score to escalate ban (default: 65 = 0.65)
	ThresholdPermanent int32 // Score for permanent ban (default: 100 = 1.00)

	// Ban durations
	TempBanDuration   time.Duration   // Initial temp ban (default: 15m)
	EscalateDurations []time.Duration // Escalation ladder (2h, 4h, 12h, 24h)

	// Decay
	ScoreDecayInterval time.Duration // How often to decay scores (default: 5m)
	ScoreDecayAmount   int32         // Points to decay per interval (default: 5)

	// Cleanup
	IPRetentionDuration time.Duration // How long to keep IP data (default: 24h)
}

ScorerConfig holds scoring thresholds

func DefaultScorerConfig added in v1.0.31

func DefaultScorerConfig() ScorerConfig

DefaultScorerConfig returns production defaults

type Stats added in v1.0.31

type Stats struct {
	TotalDetections  atomic.Int64
	TotalBans        atomic.Int64
	TotalEscalations atomic.Int64
	TotalPermanent   atomic.Int64
	UniqueIPs        atomic.Int64

	// IPv4/IPv6 tracking
	DetectionsIPv4 atomic.Int64
	DetectionsIPv6 atomic.Int64
	BansIPv4       atomic.Int64
	BansIPv6       atomic.Int64
	UniqueIPv4     atomic.Int64
	UniqueIPv6     atomic.Int64

	// Per-service detection counts
	DetectionsByService sync.Map // map[string]*atomic.Int64

	// Per-service ban counts
	BansByService sync.Map // map[string]*atomic.Int64

	// Per-reason detection counts
	DetectionsByReason sync.Map // map[uint16]*atomic.Int64

	// Per-reason ban counts
	BansByReason sync.Map // map[uint16]*atomic.Int64
}

Stats holds global statistics

type StatsSnapshot added in v1.0.31

type StatsSnapshot struct {
	TotalDetections  int64
	TotalBans        int64
	TotalEscalations int64
	TotalPermanent   int64
	UniqueIPs        int64

	// IPv4/IPv6 breakdown
	DetectionsIPv4 int64
	DetectionsIPv6 int64
	BansIPv4       int64
	BansIPv6       int64
	UniqueIPv4     int64
	UniqueIPv6     int64

	// By service
	DetectionsByService map[string]int64
	BansByService       map[string]int64

	// By reason
	DetectionsByReason map[string]int64
	BansByReason       map[string]int64
}

StatsSnapshot is a point-in-time copy of statistics

type Verdict

type Verdict struct {
	IP         netip.Addr // Parsed IP address (IPv4 or IPv6)
	Reason     uint16     // Stable enum code for the detection reason
	ScoreDelta int16      // Points to add to the IP's risk score (scaled by 100)
	User       string     // Optional: username involved (empty if not extracted)
	Service    string     // Service name (ssh, dovecot, etc.)
}

Verdict represents the result of a detection match

Directories

Path Synopsis
cmd
test-detector command

Jump to

Keyboard shortcuts

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