Documentation
¶
Index ¶
Constants ¶
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 ¶
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
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 ¶
Detect runs all registered detectors on a line Returns on first match (detectors are ordered by likelihood)
func (*Registry) DetectAll ¶
DetectAll runs all detectors and returns all matches Useful for hybrid mode where multiple signals may be present
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
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) 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
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
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
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