loginmon

package
v1.135.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	ModuleName    = "loginmon"
	ModuleVersion = "1.0.30"

	// Suricata paths (NFTBan alert-only output)
	DefaultEVEPath        = "/var/log/nftban/suricata/eve-alerts.json"
	DefaultSuricataBin    = "/usr/bin/suricata"
	EVEFreshnessThreshold = 60 // seconds

	// Detection intervals
	DefaultCheckInterval = constants.LoginmonCheckInterval
)

Variables

This section is empty.

Functions

func Descriptor

func Descriptor() module.Descriptor

Descriptor returns the module descriptor

Types

type Action

type Action struct {
	Type     string        // Action type: "allow", "alert_only", "block_short", "block_long", "block_permanent"
	IP       string        // IP to act on
	Duration time.Duration // Ban duration (0 = permanent)
	Reason   string        // Why this action was taken
	Risk     float64       // Risk score that triggered this action
	Event    *LoginEvent   // The login event that caused this action
}

Action represents a decision made by the login monitor

type Config

type Config struct {
	// Module control
	Enabled bool // Whether the module is enabled (default: true)

	// v1.80 Phase B: Go pipeline feature flag.
	// When true, the Go pipeline runs DirectAdmin parser IN ADDITION to the
	// legacy tail -F watcher. Both paths produce events; dedup prevents
	// double-counting. When false (default), only the legacy path runs.
	// Set via PIPELINE_ENABLED=true in main.conf.local.
	PipelineEnabled bool

	// Ban thresholds - score needed to trigger ban (scale: 0-100)
	// Example: ThresholdTempBan=45 means ban when score >= 45
	ThresholdTempBan   int32 // Score to trigger temp ban (default: 45)
	ThresholdEscalate  int32 // Score to escalate ban (default: 65)
	ThresholdPermanent int32 // Score for permanent ban (default: 100)

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

	// Score decay (reduces score over time if no new failures)
	ScoreDecayInterval time.Duration // How often to decay scores (default: 5m)
	ScoreDecayAmount   int32         // Points to decay per interval (default: 5)

	// IP retention (how long to remember an IP after last activity)
	IPRetentionDuration time.Duration // How long to keep IP data (default: 24h)

	// SSH scores
	SSHFailedPassword int16 // Score for "Failed password" (default: 10)
	SSHInvalidUser    int16 // Score for invalid user attempt (default: 15)
	SSHPreauth        int16 // Score for preauth disconnect (default: 20)
	SSHTooMany        int16 // Score for "too many failures" (default: 30)
	SSHRootAttempt    int16 // Bonus score for root attempts (default: 10)

	// Mail scores
	DovecotAuthFail int16 // Score for Dovecot native auth failure (default: 15)
	DovecotPamFail  int16 // Score for Dovecot PAM auth failure (default: 15)
	PostfixSASL     int16 // Score for Postfix SASL failure (default: 15)
	EximAuthFail    int16 // Score for Exim auth failure (default: 15)

	// FTP scores
	FTPAuthFail int16 // Score for FTP auth failure (default: 15)

	// Panel scores
	DirectAdminLogin int16 // Score for DirectAdmin login failure (default: 20)
	CPanelLogin      int16 // Score for cPanel login failure (default: 20)
	PleskLogin       int16 // Score for Plesk login failure (default: 20)

	// WordPress scores
	WordPressXMLRPC  int16 // Score for WordPress xmlrpc attack (default: 25)
	WordPressWPLogin int16 // Score for wp-login brute force (default: 20)

	// Risk thresholds
	BlockHighRisk   float64 // Block if risk >= this (default: 0.8)
	BlockMediumRisk float64 // Block if risk >= this (default: 0.6)
	AlertRisk       float64 // Alert if risk >= this (default: 0.4)

	// Ban durations (risk-based)
	HighRiskDuration   time.Duration // Ban duration for high risk (default: 24h)
	MediumRiskDuration time.Duration // Ban duration for medium risk (default: 1h)
	LowRiskDuration    time.Duration // Ban duration for low risk (default: 10m)

	// Behavioral analysis weights
	NewIPWeight         float64 // Risk weight for new IP (default: 0.3)
	NewCountryWeight    float64 // Risk weight for new country (default: 0.3)
	BadReputationWeight float64 // Risk weight for bad reputation (default: 0.4)
	MultipleUsersWeight float64 // Risk weight for multiple users from same IP (default: 0.2)

	// Time windows
	FailureWindow    time.Duration // Window to count failed attempts (default: 10m)
	ProfileRetention time.Duration // How long to keep user profiles (default: 30d)

	// Thresholds
	MaxFailedAttempts int // Max failed attempts before blocking (default: 5)
	MaxUsersPerIP     int // Max different users from same IP before suspicious (default: 3)

	SubnetAggEnabled      bool          // Master toggle (default: false; explicit opt-in)
	SubnetAggMode         string        // "observe" or "enforce" (default: "observe")
	SubnetWindow          time.Duration // Rolling-window duration (default: 5m)
	SubnetUniqueIPsMin    int           // Min distinct IPs in window to trigger (default: 5)
	SubnetMinTotalEvents  int           // Min total events in window to trigger (default: 10)
	SubnetIPv4Prefix      int           // IPv4 aggregation prefix bits (default: 24)
	SubnetIPv6Prefix      int           // IPv6 aggregation prefix bits (default: 64)
	SubnetAction          string        // "ban_cidr" only ships v1.113 (default: "ban_cidr")
	SubnetCIDRBanDuration time.Duration // Duration of subnet bans (default: 24h)
}

Config contains configuration for the login monitor

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns default configuration

type EVEEvent

type EVEEvent struct {
	Timestamp string `json:"timestamp"`
	EventType string `json:"event_type"`
	SrcIP     string `json:"src_ip"`
	DestIP    string `json:"dest_ip"`
	SrcPort   int    `json:"src_port"`
	DestPort  int    `json:"dest_port"`
	Alert     *struct {
		Action      string `json:"action"`
		Category    string `json:"category"`
		Signature   string `json:"signature"`
		SignatureID int    `json:"signature_id"`
	} `json:"alert,omitempty"`
	SSH *struct {
		Client string `json:"client"`
		Server string `json:"server"`
	} `json:"ssh,omitempty"`
}

EVEEvent represents a Suricata EVE JSON event

type GeoInfo

type GeoInfo struct {
	Country     string // ISO country code (e.g., "US", "CN", "RU")
	CountryName string // Human-readable country name
	City        string // City name (optional)
	ASN         string // Autonomous System Number (ISP identifier)
	ASNOrg      string // Organization name for the ASN
	IsProxy     bool   // Known proxy/VPN/Tor exit node
	IsTor       bool   // Known Tor exit node
	IsHosting   bool   // Hosting provider (often used for bots)
}

GeoInfo contains geographic/network information for an IP

type IPProfile

type IPProfile struct {
	IP           string               // IP address
	Users        map[string]time.Time // All users that logged in from this IP (user -> last seen)
	FailedLogins int                  // Count of recent failed attempts from this IP
	TotalLogins  int                  // Total successful logins from this IP
	LastCountry  string               // Last known country for this IP
	LastASN      string               // Last known ASN for this IP
	FirstSeen    time.Time            // When we first saw this IP
	LastActivity time.Time            // Last login attempt (success or fail)
}

IPProfile tracks login activity from a single IP

type LoginEvent

type LoginEvent struct {
	User      string            // Username that logged in
	IP        string            // Source IP address
	Time      time.Time         // When the login occurred
	Service   string            // Service name (ssh, directadmin, webmail, panel, etc.)
	Success   bool              // true = successful login, false = failed attempt
	Method    string            // Auth method (password, publickey, session, etc.)
	Extra     map[string]string // Additional metadata (port, protocol, etc.)
	Timestamp int64             // Unix timestamp for correlation
}

LoginEvent represents a single login attempt (success or failure)

type LoginMonStatusExtra added in v1.110.0

type LoginMonStatusExtra struct {
	Mode                string           `json:"mode"`
	SuricataAvailable   bool             `json:"suricata_available"`
	Services            string           `json:"services"`
	Detectors           []string         `json:"detectors"`
	TotalDetections     int64            `json:"total_detections"`
	TotalBans           int64            `json:"total_bans"`
	TotalEscalations    int64            `json:"total_escalations"`
	TotalPermanent      int64            `json:"total_permanent"`
	UniqueIPs           int64            `json:"unique_ips"`
	DetectionsIPv4      int64            `json:"detections_ipv4"`
	DetectionsIPv6      int64            `json:"detections_ipv6"`
	BansIPv4            int64            `json:"bans_ipv4"`
	BansIPv6            int64            `json:"bans_ipv6"`
	TrackedIPs          int              `json:"tracked_ips"`
	DetectionsByService map[string]int64 `json:"detections_by_service"`
	BansByService       map[string]int64 `json:"bans_by_service"`
	DetectionsByReason  map[string]int64 `json:"detections_by_reason"`
	BansByReason        map[string]int64 `json:"bans_by_reason"`

	// v1.113 subnet aggregation (D-LOGINMON-EXIM-SUBNET-ROTATION-GAP).
	// All fields zero-value-omittable on hosts where the feature is disabled,
	// so the wire format for existing readers stays byte-equivalent at zero.
	SubnetPressureCount int64 `json:"subnet_pressure_count,omitempty"` // Cumulative observe-mode pressure events.
	SubnetBansTotal     int64 `json:"subnet_bans_total,omitempty"`     // Cumulative CIDR bans (enforce mode).
	SubnetWatchActive   int64 `json:"subnet_watch_active,omitempty"`   // Active prefixes being watched (gauge).
}

LoginMonStatusExtra is the typed status payload for the LoginMon module's Status().Extra field. Field names map to legacy map[string]any keys via JSON tags byte-for-byte; R-12 introduces type-safety without an API change.

func (LoginMonStatusExtra) ToExtraInfo added in v1.110.0

func (e LoginMonStatusExtra) ToExtraInfo() module.ExtraInfo

ToExtraInfo serializes the typed struct into the module.ExtraInfo map[string]any contract expected by module.Status.Extra.

type LoginProfile

type LoginProfile struct {
	User          string               // Username
	LastIP        string               // Last IP this user logged in from
	LastCountry   string               // Last country (from GeoIP)
	LastASN       string               // Last ASN (ISP/provider)
	LastLoginTime time.Time            // Last successful login timestamp
	KnownIPs      map[string]time.Time // All IPs this user has logged in from (IP -> last seen)
	FailedLogins  int                  // Count of recent failed attempts
	TotalLogins   int                  // Total successful logins
	FirstSeen     time.Time            // When we first saw this user
}

LoginProfile tracks historical behavior for a single user

type LoginState

type LoginState struct {
	Users map[string]*LoginProfile // User -> profile
	IPs   map[string]*IPProfile    // IP -> profile
	// contains filtered or unexported fields
}

LoginState maintains in-memory state for all users and IPs

func NewLoginState

func NewLoginState() *LoginState

NewLoginState creates a new login monitor state

type Mode

type Mode string

Mode represents the operating mode

const (
	ModeAuto     Mode = "auto"
	ModeClassic  Mode = "classic"
	ModeSuricata Mode = "suricata"
	ModeHybrid   Mode = "hybrid"
)

type Module

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

Module implements the login monitor module

func New

func New() *Module

New creates a new login monitor module

func (*Module) Init

func (m *Module) Init(bus *eventbus.Bus) error

Init initializes the module with the event bus

func (*Module) Name

func (m *Module) Name() string

Name returns the module identifier

func (*Module) Start

func (m *Module) Start(ctx context.Context) error

Start begins the module's background work

func (*Module) Status

func (m *Module) Status() module.Status

Status returns the current module status

func (*Module) Stop

func (m *Module) Stop() error

Stop gracefully shuts down the module

type ReputationInfo

type ReputationInfo struct {
	BadFeeds      int       // Number of threat feeds containing this IP
	SuricataHits  int       // Number of Suricata alerts for this IP
	NFTBanHistory int       // Number of times previously banned by NFTBan
	LastBanTime   time.Time // When this IP was last banned
	BanReason     string    // Reason for last ban (ssh_brute, web_exploit, etc.)
	IsWhitelisted bool      // Is this IP in the whitelist?
}

ReputationInfo contains threat intelligence for an IP

type RiskScore

type RiskScore struct {
	Score       float64            // Overall risk score (0.0 = safe, 1.0 = maximum risk)
	Factors     map[string]float64 // Individual risk factors and their contributions
	Reason      string             // Human-readable explanation
	Recommended string             // Recommended action (allow, alert, block_short, block_long, block_permanent)
}

RiskScore represents the computed risk level for a login event

Directories

Path Synopsis
============================================================================= NFTBan v1.79.2 - distroconf reader (BUG-15) ============================================================================= SPDX-License-Identifier: MPL-2.0 Package: distroconf Purpose: Read /etc/nftban/distros/<distro>.conf and expose [paths] as the
============================================================================= NFTBan v1.79.2 - distroconf reader (BUG-15) ============================================================================= SPDX-License-Identifier: MPL-2.0 Package: distroconf Purpose: Read /etc/nftban/distros/<distro>.conf and expose [paths] as the
Package pipeline contains the v1.80 Go detection pipeline foundation.
Package pipeline contains the v1.80 Go detection pipeline foundation.
aggregate
Package aggregate implements the v1.80 aggregation layer.
Package aggregate implements the v1.80 aggregation layer.
dedup
Package dedup provides a bounded LRU sieve that suppresses duplicate events.
Package dedup provides a bounded LRU sieve that suppresses duplicate events.
event
Package event defines the canonical data types passed through the v1.80 detection pipeline.
Package event defines the canonical data types passed through the v1.80 detection pipeline.
normalize
Package normalize canonicalizes NormalizedEvent fields so downstream stages (dedup, aggregate) operate on stable, comparable values.
Package normalize canonicalizes NormalizedEvent fields so downstream stages (dedup, aggregate) operate on stable, comparable values.
parser/directadmin
Package directadmin implements a Parser for DirectAdmin's login.log format.
Package directadmin implements a Parser for DirectAdmin's login.log format.
parser/dovecot
Package dovecot implements a Parser for Dovecot imap-login/pop3-login auth-failed lines.
Package dovecot implements a Parser for Dovecot imap-login/pop3-login auth-failed lines.
parser/exim
Package exim implements a Parser for Exim mainlog auth-failure lines.
Package exim implements a Parser for Exim mainlog auth-failure lines.
runtime
Package runtime is the composition root of the v1.80 pipeline.
Package runtime is the composition root of the v1.80 pipeline.
source
Package source defines the Source abstraction for the v1.80 pipeline.
Package source defines the Source abstraction for the v1.80 pipeline.
watcher
Package watcher defines the file-tailing abstraction for the v1.80 pipeline.
Package watcher defines the file-tailing abstraction for the v1.80 pipeline.

Jump to

Keyboard shortcuts

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