suricata

package
v1.38.0 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2026 License: MPL-2.0 Imports: 23 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NormalizeCategory

func NormalizeCategory(category string) string

NormalizeCategory normalizes a Suricata category string for matching - Lowercase - Trim whitespace - Replace spaces/underscores with hyphens Example: "Attempted Administrator Privilege Gain" -> "attempted-administrator-privilege-gain"

func ParseProxyNetworks

func ParseProxyNetworks(cidrs []string) ([]*net.IPNet, error)

ParseProxyNetworks parses CIDR strings into IPNet slice

Types

type ActorTrust

type ActorTrust string

ActorTrust represents the trust level of the resolved actor IP

const (
	ActorDirect         ActorTrust = "direct"
	ActorProxyTrusted   ActorTrust = "proxy_trusted"
	ActorProxyUntrusted ActorTrust = "proxy_untrusted"
)

func ResolveActorIP

func ResolveActorIP(srcIP string, http *HTTPDetails, proxyCfg ProxyTrustConfig) (actorIP string, trust ActorTrust)

ResolveActorIP determines the real client IP, handling trusted proxies Security: XFF is ONLY trusted when source IP is in trusted proxy networks

type AlertDetails

type AlertDetails struct {
	SID       int                 `json:"sid,omitempty"`       // Suricata Signature ID
	GID       int                 `json:"gid,omitempty"`       // Generator ID
	Rev       int                 `json:"rev,omitempty"`       // Revision
	Signature string              `json:"signature,omitempty"` // Full signature text
	Category  string              `json:"category,omitempty"`  // Alert category
	Severity  int                 `json:"severity,omitempty"`  // 1-4 (1=high)
	Action    string              `json:"action,omitempty"`    // "allowed", "blocked"
	Metadata  map[string][]string `json:"metadata,omitempty"`
}

AlertDetails contains Suricata alert data

type BanHandler

type BanHandler interface {
	BanIP(ip string, duration time.Duration, reason string) error
}

BanHandler defines the interface for banning IPs

type Config

type Config struct {
	GlobalEnabled    bool
	DefaultThreshold int
	DefaultBanTime   time.Duration
	DefaultAction    string
	ScoreDecay       time.Duration
	Filters          map[string]*FilterConfig
}

Config holds the complete Suricata filter configuration

func LoadConfig

func LoadConfig(configDir string) (*Config, error)

LoadConfig loads Suricata filter configuration from files Loads filters.conf first, then filters.conf.local overrides

func (*Config) GetEnabledFilters

func (c *Config) GetEnabledFilters() map[string]*FilterConfig

GetEnabledFilters returns only enabled filters

func (*Config) GetFilter

func (c *Config) GetFilter(name string) (*FilterConfig, bool)

GetFilter returns a specific filter by name

type DDoSCounterFunc added in v1.38.0

type DDoSCounterFunc func(ip string) int

DDoSCounterFunc returns the current packets-per-second rate for an IP.

type DNSDetails

type DNSDetails struct {
	Type   string   `json:"type,omitempty"`   // "query" or "answer"
	RRType string   `json:"rrtype,omitempty"` // A, AAAA, MX, etc.
	RRName string   `json:"rrname,omitempty"` // Query name
	RCode  string   `json:"rcode,omitempty"`  // Response code
	RData  []string `json:"rdata,omitempty"`  // Response data
}

DNSDetails contains DNS-specific event data

type EveAlert

type EveAlert struct {
	Timestamp string `json:"timestamp"`
	EventType string `json:"event_type"`
	SrcIP     string `json:"src_ip"`
	SrcPort   int    `json:"src_port"`
	DestIP    string `json:"dest_ip"`
	DestPort  int    `json:"dest_port"`
	Proto     string `json:"proto"`
	Alert     struct {
		SignatureID int    `json:"signature_id"`
		Signature   string `json:"signature"`
		Category    string `json:"category"`
		Severity    int    `json:"severity"` // 1=High, 2=Medium, 3=Low, 4=Info
		Action      string `json:"action"`
	} `json:"alert"`
	HTTP *struct {
		Hostname string `json:"hostname"`
		URL      string `json:"url"`
		Method   string `json:"http_method"`
	} `json:"http,omitempty"`
	SSH *struct {
		Client  string `json:"client"`
		Server  string `json:"server"`
		Version string `json:"proto_version"`
	} `json:"ssh,omitempty"`
}

EveAlert represents a Suricata eve.json alert entry

type EveAlertFields

type EveAlertFields struct {
	Action    string              `json:"action"`
	GID       int                 `json:"gid"`
	SID       int                 `json:"signature_id"`
	Rev       int                 `json:"rev"`
	Signature string              `json:"signature"`
	Category  string              `json:"category"`
	Severity  int                 `json:"severity"`
	Metadata  map[string][]string `json:"metadata,omitempty"`
}

EveAlertFields represents alert fields in EVE JSON

type EveDNS

type EveDNS struct {
	Type   string   `json:"type"`
	RRType string   `json:"rrtype"`
	RRName string   `json:"rrname"`
	RCode  string   `json:"rcode"`
	RData  []string `json:"rdata"`
}

EveDNS represents DNS fields in EVE JSON

type EveEvent

type EveEvent struct {
	Timestamp   string `json:"timestamp"`
	EventType   string `json:"event_type"`
	SrcIP       string `json:"src_ip"`
	SrcPort     int    `json:"src_port"`
	DestIP      string `json:"dest_ip"`
	DestPort    int    `json:"dest_port"`
	Proto       string `json:"proto"`
	AppProto    string `json:"app_proto"`
	FlowID      uint64 `json:"flow_id"`
	TxID        int    `json:"tx_id,omitempty"`
	CommunityID string `json:"community_id,omitempty"`

	// HTTP fields (when event_type=http or embedded in alert)
	HTTP *EveHTTP `json:"http,omitempty"`

	// TLS fields
	TLS *EveTLS `json:"tls,omitempty"`

	// Alert fields
	Alert *EveAlertFields `json:"alert,omitempty"`

	// DNS fields
	DNS *EveDNS `json:"dns,omitempty"`

	// SSH fields
	SSH *EveSSH `json:"ssh,omitempty"`
}

EveEvent represents a raw Suricata EVE JSON event (extended fields) This extends the basic EveAlert with additional L7 protocol support

type EveHTTP

type EveHTTP struct {
	Hostname    string `json:"hostname"`
	URL         string `json:"url"`
	Method      string `json:"http_method"`
	Status      int    `json:"status"`
	UserAgent   string `json:"http_user_agent"`
	Referer     string `json:"http_refer"`
	XFF         string `json:"xff"`
	ContentType string `json:"http_content_type"`
	Length      int64  `json:"length"`
	Protocol    string `json:"protocol"`
}

EveHTTP represents HTTP fields in EVE JSON

type EveReader

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

EveReader reads and parses Suricata eve.json log file

func NewEveReader

func NewEveReader(evePath string, matcher *FilterMatcher) (*EveReader, error)

NewEveReader creates a new eve.json reader

func (*EveReader) Close

func (r *EveReader) Close() error

Close closes the eve.json file

func (*EveReader) ReadEvent

func (r *EveReader) ReadEvent() (*Event, error)

ReadEvent reads the next event from eve.json Returns nil if no event available (non-blocking)

func (*EveReader) ReadEvents

func (r *EveReader) ReadEvents(events chan<- *Event, stopChan <-chan struct{}) error

ReadEvents continuously reads events from eve.json using inotify when available, falling back to polling if inotify setup fails.

type EveSSH

type EveSSH struct {
	Client *struct {
		ProtoVersion    string `json:"proto_version"`
		SoftwareVersion string `json:"software_version"`
	} `json:"client,omitempty"`
	Server *struct {
		ProtoVersion    string `json:"proto_version"`
		SoftwareVersion string `json:"software_version"`
	} `json:"server,omitempty"`
}

EveSSH represents SSH fields in EVE JSON

type EveTLS

type EveTLS struct {
	SNI     string `json:"sni"`
	Version string `json:"version"`
	Subject string `json:"subject"`
	Issuer  string `json:"issuerdn"`
	JA3     *struct {
		Hash string `json:"hash"`
	} `json:"ja3,omitempty"`
	JA3S *struct {
		Hash string `json:"hash"`
	} `json:"ja3s,omitempty"`
	Fingerprint string `json:"fingerprint,omitempty"`
	Serial      string `json:"serial,omitempty"`
	NotBefore   string `json:"notbefore,omitempty"`
	NotAfter    string `json:"notafter,omitempty"`
}

EveTLS represents TLS fields in EVE JSON

type Event

type Event struct {
	Timestamp   time.Time
	EventType   string // "alert", "http", "ssh", etc.
	SrcIP       string
	SrcPort     int
	DestIP      string
	DestPort    int
	Proto       string
	SignatureID int
	Signature   string
	Category    string
	Severity    int    // 1=High, 2=Medium, 3=Low, 4=Info
	Filter      string // Matched filter name (e.g., "ssh", "http")
}

Event represents a normalized Suricata event for NFTBan processing

type EventLogger

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

EventLogger logs Suricata events and actions to file

func NewEventLogger

func NewEventLogger(logPath string) (*EventLogger, error)

NewEventLogger creates a new event logger

func (*EventLogger) Close

func (l *EventLogger) Close() error

Close closes the log file

func (*EventLogger) LogBanAction

func (l *EventLogger) LogBanAction(ip string, filter string, score int, threshold int, banTime time.Duration, reason string) error

LogBanAction logs a Suricata-triggered ban action with score details

func (*EventLogger) LogError

func (l *EventLogger) LogError(context string, err error) error

LogError logs an error

func (*EventLogger) LogEvent

func (l *EventLogger) LogEvent(event *Event, score int, threshold int, action string, decision string) error

LogEvent logs a Suricata event with calculated score

type FeedsLookupFunc added in v1.38.0

type FeedsLookupFunc func(ip string) bool

FeedsLookupFunc checks if an IP appears in threat intelligence feeds. Returns true if the IP is listed.

type FilterConfig

type FilterConfig struct {
	Name        string
	Enabled     bool
	Keywords    []string
	Threshold   int
	BanTime     time.Duration
	Action      string        // "log", "observe", "ban"
	BanType     string        // "temporary", "permanent", "escalate"
	MaxBans     int           // For escalate: after X temp bans, go permanent
	Period      time.Duration // For escalate: count bans in this period
	Description string
}

FilterConfig represents a single Suricata filter configuration

type FilterMatcher

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

FilterMatcher handles matching Suricata signatures to filters

func NewFilterMatcher

func NewFilterMatcher(config *Config) *FilterMatcher

NewFilterMatcher creates a new filter matcher

func (*FilterMatcher) GetFilterForEvent

func (fm *FilterMatcher) GetFilterForEvent(signature, category string) (string, *FilterConfig)

GetFilterForEvent determines which filter matches an event Tries signature first, then category, returns first match

func (*FilterMatcher) MatchCategory

func (fm *FilterMatcher) MatchCategory(category string) (string, *FilterConfig)

MatchCategory matches a Suricata category against configured filters

func (*FilterMatcher) MatchSignature

func (fm *FilterMatcher) MatchSignature(signature string) (string, *FilterConfig)

MatchSignature matches a Suricata signature against configured filters Returns the matching filter name, or empty string if no match

type GeobanCheckFunc added in v1.38.0

type GeobanCheckFunc func(ip string) (country string, highRisk bool)

GeobanCheckFunc returns the country code for an IP and whether it belongs to a high-risk country list.

type HTTPDetails

type HTTPDetails struct {
	Method      string `json:"method"`
	Host        string `json:"host,omitempty"`
	URI         string `json:"uri,omitempty"`
	Status      int    `json:"status,omitempty"`
	UserAgent   string `json:"user_agent,omitempty"`
	Referer     string `json:"referer,omitempty"`
	XFF         string `json:"xff,omitempty"` // X-Forwarded-For (untrusted unless proxy verified)
	ContentType string `json:"content_type,omitempty"`
	Length      int64  `json:"length,omitempty"`
	Protocol    string `json:"protocol,omitempty"` // HTTP/1.1, HTTP/2
}

HTTPDetails contains HTTP-specific event data

type IPCBanHandler

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

IPCBanHandler implements BanHandler using IPC to the nftband daemon This is the correct architecture: suricata module sends ban requests via IPC, and the daemon handles the actual netlink operations.

func NewIPCBanHandler

func NewIPCBanHandler() (*IPCBanHandler, error)

NewIPCBanHandler creates a new ban handler that uses IPC to communicate with nftband

func NewIPCBanHandlerWithSocket

func NewIPCBanHandlerWithSocket(socketPath string) (*IPCBanHandler, error)

NewIPCBanHandlerWithSocket creates a ban handler with a custom socket path (for testing)

func NewNetlinkBanHandler

func NewNetlinkBanHandler() (*IPCBanHandler, error)

NewNetlinkBanHandler is DEPRECATED - use NewIPCBanHandler instead This function now returns an IPCBanHandler for backward compatibility

func (*IPCBanHandler) BanIP

func (h *IPCBanHandler) BanIP(ip string, duration time.Duration, reason string) error

BanIP bans an IP by sending a request to the nftband daemon via IPC

func (*IPCBanHandler) Close

func (h *IPCBanHandler) Close()

Close closes the ban handler (IPC client has no cleanup needed)

type IPScore

type IPScore struct {
	IP           string
	CurrentScore int
	Events       []time.Time // Timestamps of recent events (capped to MaxEventsPerIP)
	LastUpdate   time.Time
	TotalEvents  int
	// contains filtered or unexported fields
}

IPScore tracks scoring for a single IP address

type Processor

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

Processor handles the main Suricata event processing loop

func NewProcessor

func NewProcessor(cfg *ProcessorConfig) (*Processor, error)

NewProcessor creates a new Suricata event processor

func (*Processor) GetScores

func (p *Processor) GetScores() map[string]*IPScore

GetScores returns all current IP scores

func (*Processor) GetStats

func (p *Processor) GetStats() map[string]interface{}

GetStats returns current processor statistics

func (*Processor) Start

func (p *Processor) Start() error

Start starts the processor

func (*Processor) Stop

func (p *Processor) Stop() error

Stop stops the processor

type ProcessorConfig

type ProcessorConfig struct {
	ConfigDir  string
	EvePath    string
	LogPath    string
	BanHandler BanHandler
}

ProcessorConfig holds configuration for the processor

type ProxyTrustConfig

type ProxyTrustConfig struct {
	Enabled         bool
	Networks        []*net.IPNet
	RejectPrivateIP bool // Reject private IPs from XFF
}

ProxyTrustConfig configures trusted proxy handling for actor IP resolution

type RateGateConfig

type RateGateConfig struct {
	MinEvents int // Minimum events per IP
	WindowSec int // Time window in seconds
}

RateGateConfig holds rate gate configuration for a module

type Router

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

Router handles deterministic priority-based alert routing

func LoadRoutingConfig

func LoadRoutingConfig(configPath string) (*Router, error)

LoadRoutingConfig loads routing configuration from a file

func NewRouter

func NewRouter() *Router

NewRouter creates a new Router with default configuration

func (*Router) CheckRateGate

func (r *Router) CheckRateGate(module string, srcIP string) bool

CheckRateGate checks if an event meets the rate threshold for a module Returns true if the event meets the threshold (enough events in window) For example, DDoS requires 10 events from same IP in 10 seconds

func (*Router) CleanupExpired

func (r *Router) CleanupExpired()

CleanupExpired cleans up expired rate gate events and dedup cache entries

func (*Router) GetPriority

func (r *Router) GetPriority(module string) int

GetPriority returns the priority for a module

func (*Router) GetRateGate

func (r *Router) GetRateGate(module string) (RateGateConfig, bool)

GetRateGate returns the rate gate configuration for a module

func (*Router) GetScoreCap

func (r *Router) GetScoreCap(module string) (ScoreCapConfig, bool)

GetScoreCap returns the score cap configuration for a module

func (*Router) GetStats

func (r *Router) GetStats() map[string]interface{}

GetStats returns router statistics

func (*Router) IsDuplicate

func (r *Router) IsDuplicate(event *Event) bool

IsDuplicate checks if an event has been seen before

func (*Router) IsEnabled

func (r *Router) IsEnabled() bool

IsEnabled returns whether routing is enabled

func (*Router) RecordEvent

func (r *Router) RecordEvent(srcIP string, timestamp time.Time)

RecordEvent records an event for rate gate tracking

func (*Router) Route

func (r *Router) Route(event *Event) (module string, reason string)

Route determines which module should handle an event Returns the winning module and a reason string for logging

Routing precedence (highest to lowest):

  1. SID overrides (explicit SID -> module mapping)
  2. Category mapping (normalized category -> module)
  3. Service/port constraints (proto + dest_port -> module)
  4. Keyword patterns (substring matching)
  5. Apply tiebreak rules if multiple matches
  6. Apply priority arbitration (ddos > portscan > login > other)

type RouterConfig

type RouterConfig struct {
	Enabled bool

	// Priority levels per module (higher number = higher priority)
	Priorities map[string]int

	// Deduplication TTL in seconds
	DedupTTL int

	// DDoS rate gate settings
	DDosRateGateThreshold int
	DDosRateGateWindow    int
}

RouterConfig holds routing configuration

type SSHDetails

type SSHDetails struct {
	Client struct {
		Version  string `json:"version,omitempty"`
		Software string `json:"software,omitempty"`
	} `json:"client,omitempty"`
	Server struct {
		Version  string `json:"version,omitempty"`
		Software string `json:"software,omitempty"`
	} `json:"server,omitempty"`
}

SSHDetails contains SSH-specific event data

type ScoreCapConfig

type ScoreCapConfig struct {
	MaxScore  int // Maximum score per window
	WindowSec int // Time window in seconds
}

ScoreCapConfig holds score cap configuration for a module

type Scorer

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

Scorer calculates threat scores for IPs based on Suricata events Implements bounded memory via LRU eviction and per-IP event caps. Protects against CWE-400 (Uncontrolled Resource Consumption).

func NewScorer

func NewScorer(config *Config) *Scorer

NewScorer creates a new scorer with bounded memory

func (*Scorer) AddEvent

func (s *Scorer) AddEvent(event *Event) int

AddEvent processes a new event and updates IP score

func (*Scorer) GetAllScores

func (s *Scorer) GetAllScores() map[string]*IPScore

GetAllScores returns all current IP scores

func (*Scorer) GetIPScore

func (s *Scorer) GetIPScore(ip string) *IPScore

GetIPScore returns full scoring details for an IP

func (*Scorer) GetScore

func (s *Scorer) GetScore(ip string) int

GetScore returns the current score for an IP

func (*Scorer) GetStats

func (s *Scorer) GetStats() map[string]int

GetStats returns memory usage statistics for monitoring

func (*Scorer) ResetScore

func (s *Scorer) ResetScore(ip string)

ResetScore resets the score for an IP (e.g., after banning)

func (*Scorer) SetDDoSCounter added in v1.38.0

func (s *Scorer) SetDDoSCounter(fn DDoSCounterFunc)

SetDDoSCounter wires the DDoS PPS counter integration.

func (*Scorer) SetFeedsLookup added in v1.38.0

func (s *Scorer) SetFeedsLookup(fn FeedsLookupFunc)

SetFeedsLookup wires the feeds intelligence integration.

func (*Scorer) SetGeobanCheck added in v1.38.0

func (s *Scorer) SetGeobanCheck(fn GeobanCheckFunc)

SetGeobanCheck wires the geoban country-risk integration.

func (*Scorer) Stop

func (s *Scorer) Stop()

Stop stops the scorer

type TLSDetails

type TLSDetails struct {
	SNI         string `json:"sni,omitempty"`
	JA3         string `json:"ja3,omitempty"`
	JA3S        string `json:"ja3s,omitempty"`
	JA4         string `json:"ja4,omitempty"`
	Version     string `json:"version,omitempty"`
	Subject     string `json:"subject,omitempty"`
	Issuer      string `json:"issuer,omitempty"`
	Fingerprint string `json:"fingerprint,omitempty"`
	Serial      string `json:"serial,omitempty"`
	NotBefore   string `json:"not_before,omitempty"`
	NotAfter    string `json:"not_after,omitempty"`
}

TLSDetails contains TLS-specific event data

type ThreatEvent

type ThreatEvent struct {
	// Identity
	EventID   string          `json:"event_id"`
	Timestamp time.Time       `json:"timestamp"`
	Sensor    string          `json:"sensor,omitempty"`
	EventType ThreatEventType `json:"event_type"`
	FlowID    uint64          `json:"flow_id,omitempty"`
	TxID      int             `json:"tx_id,omitempty"`

	// Actor (resolved real client IP)
	ActorIP    string     `json:"actor_ip"`
	ActorTrust ActorTrust `json:"actor_trust"`
	ActorKey   string     `json:"actor_key"` // stable key for aggregation (usually ActorIP)

	// Network layer
	SrcIP    string `json:"src_ip"`
	DstIP    string `json:"dst_ip"`
	Proto    string `json:"proto"`
	AppProto string `json:"app_proto,omitempty"`
	SrcPort  int    `json:"src_port,omitempty"`
	DstPort  int    `json:"dst_port,omitempty"`

	// Correlation
	CommunityID       string `json:"community_id,omitempty"`
	ObservedDirection string `json:"direction,omitempty"` // "inbound", "outbound"

	// Protocol-specific details
	HTTP  *HTTPDetails  `json:"http,omitempty"`
	TLS   *TLSDetails   `json:"tls,omitempty"`
	Alert *AlertDetails `json:"alert,omitempty"`
	DNS   *DNSDetails   `json:"dns,omitempty"`
	SSH   *SSHDetails   `json:"ssh,omitempty"`

	// Scoring (computed by scorer)
	Score      float64            `json:"score,omitempty"`
	Category   string             `json:"category,omitempty"`
	Confidence float64            `json:"confidence,omitempty"`
	Features   map[string]float64 `json:"features,omitempty"`
}

ThreatEvent is the canonical event model for all Suricata events This extends the basic Event struct with L7 deep packet inspection fields

func MapEVEToThreatEvent

func MapEVEToThreatEvent(eve *EveEvent, sensor string, proxyCfg ProxyTrustConfig) (*ThreatEvent, error)

MapEVEToThreatEvent converts a raw Suricata EVE event to canonical ThreatEvent

type ThreatEventType

type ThreatEventType string

ThreatEventType represents the type of Suricata event

const (
	ThreatEventTypeHTTP  ThreatEventType = "http"
	ThreatEventTypeTLS   ThreatEventType = "tls"
	ThreatEventTypeDNS   ThreatEventType = "dns"
	ThreatEventTypeSSH   ThreatEventType = "ssh"
	ThreatEventTypeAlert ThreatEventType = "alert"
	ThreatEventTypeFlow  ThreatEventType = "flow"
)

type TiebreakCondition

type TiebreakCondition struct {
	Type  string // "dest_port", "keyword", "category", "rate_gate"
	Value string // The value to match
}

TiebreakCondition represents a single condition in a tiebreak rule

type TiebreakRule

type TiebreakRule struct {
	Conditions []TiebreakCondition
	Winner     string
}

TiebreakRule represents a tiebreak rule

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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