Overview
Relevant Files
README.mdSECURITY.mdsrc/suricata.hsrc/suricata.c
Suricata is a high-performance, open-source network intrusion detection system (IDS), intrusion prevention system (IPS), and network security monitoring (NSM) engine developed by the Open Information Security Foundation (OISF). It analyzes network traffic in real-time or from packet capture files to detect malicious activity based on configurable detection rules.
Core Capabilities
Suricata operates in three primary modes:
- IDS Mode - Passive traffic analysis and detection logging
- IPS Mode - Active inline threat prevention and packet modification
- Firewall Mode - Network-level access control and filtering
The engine processes packets through a multithreaded pipeline that decodes protocols, manages network flows, parses application-layer data, and matches signatures against configurable rules.
Architecture Overview
Loading diagram...
Key Features
- Multi-Protocol Support - HTTP, DNS, TLS, SMB, FTP, SSH, QUIC, and 30+ others
- Flexible Rule Language - Powerful detection syntax with content matching, regex, and protocol-specific keywords
- Multiple Capture Methods - PCAP, AF_PACKET, AF_XDP, DPDK, Netmap, PF_RING, and more
- Hybrid Implementation - C for performance-critical paths, Rust for safety and protocol parsing
- Comprehensive Logging - JSON-based EVE output with file extraction and metadata
- Plugin System - Extensible architecture for custom capture and output modules
Security & Quality
Suricata prioritizes security through rigorous QA processes including static analysis, runtime sanitizers, regression testing, and fuzz testing. The project maintains strict code quality standards and follows a comprehensive security policy with CVE tracking and responsible disclosure practices.
Getting Started
The engine is configured via YAML files and supports command-line options for runtime customization. It can run as a daemon, process offline PCAP files, or integrate with packet queuing systems for inline deployment. Comprehensive documentation and community support are available at suricata.io.
Architecture & Data Flow
Relevant Files
src/packet.hsrc/flow.hsrc/detect.hsrc/detect-engine.hsrc/decode.hsrc/flow-worker.c
Suricata processes network traffic through a multi-stage pipeline that decodes packets, tracks flows, and applies detection rules. Understanding this architecture is essential for extending the engine or debugging detection issues.
Packet Decoding & Flow Setup
Packets enter the system through various sources (pcap, AF_PACKET, DPDK, etc.) and are decoded by the decode layer. The Packet structure (defined in decode.h) contains the raw packet data and parsed protocol headers (IPv4, IPv6, TCP, UDP, ICMP, etc.). Each packet is assigned to a flow using FlowSetupPacket(), which calculates a hash value for flow lookup and balancing across worker threads.
The Flow structure (in flow.h) is the central data structure for tracking bidirectional communication. It stores:
- Flow identity: source/destination addresses, ports, protocol, VLAN IDs
- State: TCP connection state, application protocol detection status
- Metadata: timeout policies, flags, packet/byte counters
- Application layer state: parsed protocol data (HTTP, DNS, TLS, etc.)
- Detection state: signature group heads (SGH) for rule matching
Flow Worker Pipeline
Flow workers (in flow-worker.c) are single-threaded modules that handle all flow-related operations while holding the flow lock. Each worker performs:
- Flow lookup/creation using hash table
- Stream tracking & reassembly for TCP
- Application layer parsing (protocol detection & state updates)
- Detection (rule matching against packets and transactions)
This design ensures thread-safe flow access without contention.
Detection Engine Architecture
The detection engine (detect.h, detect-engine.h) organizes rules hierarchically:
Flow Direction (toserver/toclient)
└─ Protocol (TCP/UDP/ICMP/etc.)
└─ Destination Port
└─ Signature Group Head (SGH)
└─ Rules & Inspection Engines
Rules are classified by type: SIG_TYPE_PKT (packet-level), SIG_TYPE_STREAM (stream reassembly), SIG_TYPE_APP_TX (application transaction), and others. Each signature contains match conditions organized into lists (DETECT_SM_LIST_MATCH, DETECT_SM_LIST_PMATCH, etc.).
Inspection Engines
Three inspection engines handle different data types:
- Packet Inspection Engine: Matches against raw packet payloads
- App Layer Inspection Engine: Matches against parsed application data (HTTP requests, DNS queries, etc.)
- Frame Inspection Engine: Matches against protocol frames (HTTP/2 frames, etc.)
Each engine uses a prefilter (typically MPM—multi-pattern matching) to quickly narrow candidate rules, then applies full rule matching.
Data Flow Diagram
Loading diagram...
Key Concepts
Flow Flags: Control flow behavior (FLOW_ACTION_DROP, FLOW_NOPAYLOAD_INSPECTION, FLOW_HAS_ALERTS, etc.). Set during detection to influence subsequent packet handling.
Application Protocol Detection: Determined via pattern matching, probing parsers, or expectations. Once detected, the flow's alproto field guides which inspection engines are used.
Signature Groups: Pre-compiled rule sets organized by protocol and port. Dramatically reduce the number of rules evaluated per packet.
Thread Safety: Flows use mutexes (or RWLocks) to protect concurrent access. Flow headers (addresses, ports) are read-only after initialization, allowing lock-free lookups.
Packet Processing & Decoding
Relevant Files
src/decode.hsrc/decode.csrc/packet-queue.hsrc/source-pcap.csrc/source-af-packet.c
Suricata's packet processing pipeline begins with capture from network interfaces and proceeds through systematic protocol decoding. The system supports multiple packet sources including libpcap, AF_PACKET sockets, and specialized hardware interfaces.
Packet Acquisition
Packets are captured through pluggable source modules. The primary sources are:
- PCAP: Live capture via libpcap with BPF filtering support
- AF_PACKET: Linux kernel socket-based capture with eBPF acceleration
- Hardware: DPDK, Napatech, and PF_RING for high-performance scenarios
Each source maintains a PacketQueue (FIFO structure with mutex and condition variables) to pass packets to decoder threads. The queue supports both locked and lock-free variants for performance optimization.
Packet Structure
The Packet structure is the central data container, organized into layers:
- L2 (Link Layer): Ethernet headers and VLAN information
- L3 (Network Layer): IPv4, IPv6, or ARP headers with checksum validation
- L4 (Transport Layer): TCP, UDP, ICMP, SCTP, GRE, or ESP headers
- Payload: Application data with length tracking
Packets support tunneling through a root-child relationship, enabling recursive decoding of encapsulated protocols (GRE, VXLAN, Geneve, Teredo).
Decoding Pipeline
Loading diagram...
Each protocol has a dedicated decoder function (DecodeIPV4, DecodeTCP, etc.) that validates headers, extracts metadata, and sets protocol-specific pointers. Decoders check layer limits to prevent stack exhaustion from deeply nested packets.
Key Features
Checksum Validation: Configurable modes (disabled, enabled, auto-detect, RX-only, kernel offload) balance security and performance.
Fragment Reassembly: IPv4 and IPv6 fragments are tracked and reassembled before detection, with memory caps and timeout handling.
Event Tracking: Decoder events (invalid headers, truncation, etc.) are recorded per-packet for alerting and statistics.
Tunnel Handling: Tunneled packets increment recursion counters and disable parent payload inspection to avoid duplicate analysis.
Memory Management: Packets use flexible storage—inline for typical sizes, extended allocation for jumbo frames. Pool-based allocation reduces allocation overhead.
Packet Lifecycle
- Acquire from source (capture thread)
- Enqueue to packet pool or allocate
- Decode layers sequentially
- Create tunnel packets if needed
- Pass to flow engine and detection
- Generate alerts and logs
- Return to pool or free
The system tracks packet sources (PKT_SRC_WIRE, PKT_SRC_DECODER_IPV4, etc.) to distinguish original captures from synthetic packets created during processing.
Detection Engine & Rule Matching
Relevant Files
src/detect-engine.c– Core detection engine initialization and managementsrc/detect-engine.h– Detection engine data structures and APIsrc/detect-parse.c– Rule parsing and signature compilationsrc/detect-engine-prefilter.h– Prefilter engine for fast rule eliminationsrc/detect-engine-mpm.h– Multi-pattern matching (MPM) setupsrc/util-mpm-ac.c– Aho-Corasick MPM implementationsrc/detect.c– Packet inspection and rule matching execution
Overview
The detection engine is Suricata's core pattern matching and rule evaluation system. It transforms text-based rules into optimized data structures, then rapidly matches incoming packets against thousands of rules using multi-pattern matching (MPM) and prefiltering techniques.
Architecture
The detection engine operates in two phases:
Initialization Phase:
- Rules are parsed into
Signaturestructures containing keywords and conditions - Signatures are grouped into
SigGroupHead(SGH) containers based on protocol, direction, and port - Fast patterns (content keywords) are extracted and compiled into MPM automata (typically Aho-Corasick)
- Prefilter engines are registered for efficient rule elimination
Runtime Phase:
- Incoming packets are matched against prefilter engines to identify candidate rules
- Matching rules undergo full inspection (header checks, content matching, state evaluation)
- Alerts are generated and post-match actions (flowbits, thresholds) are applied
Key Data Structures
DetectEngineCtx – Global detection context holding all signatures, MPM configurations, and rule groups. Created once at startup and shared across threads.
Signature – Individual rule with flags, addresses, ports, protocol, and match arrays organized by list type (packet matches, payload matches, post-match actions).
SigGroupHead – Container for signatures matching a specific protocol/port combination. Holds prefilter engines and MPM contexts for fast pattern matching.
PrefilterEngine – Lightweight filter that quickly eliminates non-matching rules before expensive full inspection. Examples: MPM search, IP-only checks, protocol detection.
Rule Matching Flow
Loading diagram...
Multi-Pattern Matching (MPM)
The MPM engine searches for multiple content patterns simultaneously in packet data. Aho-Corasick is the default implementation, building a finite automaton from all patterns in a rule group. When a pattern matches, the corresponding rule is added to a candidate queue for full inspection.
Key optimization: Only rules with matching fast patterns proceed to expensive operations like regex evaluation or state inspection.
Prefiltering Strategy
Prefilters run before full rule inspection to eliminate non-matching rules:
- MPM Prefilter – Fast pattern search using compiled automata
- IP-Only Prefilter – Rules matching only IP headers (no payload inspection)
- Protocol Detection – Rules triggered when protocol is identified
- App-Layer Prefilters – Transaction-specific matching for HTTP, DNS, etc.
- Frame Prefilters – Protocol frame-level matching
Thread Safety
Each worker thread maintains a DetectEngineThreadCtx with thread-local state: MPM thread contexts, alert queues, variable storage, and inspection buffers. The shared DetectEngineCtx is read-only during packet processing, allowing lock-free parallel inspection.
Flow Management & State Tracking
Relevant Files
src/flow.h– Flow structure definition and flagssrc/flow.c– Core flow initialization and lifecyclesrc/flow-hash.c– Flow hash table and lookup operationssrc/flow-manager.c– Flow timeout and cleanup managementsrc/flow-worker.c– Per-thread flow processingsrc/flow-timeout.c– Flow timeout detection and pseudo-packet generationsrc/stream-tcp.c– TCP-specific flow state tracking
Overview
Flows represent bidirectional network connections tracked by Suricata. Each flow maintains state across multiple packets, enabling stream reassembly, protocol detection, and stateful inspection. The flow management system handles creation, lookup, timeout detection, and cleanup of flows while managing memory constraints.
Flow Structure & State
The Flow structure contains:
- Header fields (static after init): source/destination addresses, ports, protocol, VLAN IDs
- State tracking:
flow_state(NEW, ESTABLISHED, CLOSED, BYPASSED),flags(32-bit bitmap for protocol detection, inspection policies, alerts) - Timing:
startts(creation time),lastts(last packet time),timeout_policy(seconds until timeout) - Protocol context:
protoctx(TCP session, UDP state),alproto(application layer protocol) - Statistics: packet/byte counts in both directions, TTL tracking
Flow states transition through a lifecycle:
NEW → ESTABLISHED → CLOSED
↓
BYPASSED (local or capture offload)
State changes trigger timeout policy updates via FlowUpdateState().
Hash Table & Lookup
Flows are stored in a hash table with chained buckets. Each FlowBucket contains:
head: linked list of active flowsevicted: flows pending cleanupnext_ts: atomic timestamp for timeout optimization
Lookup process:
- Calculate flow hash from packet (src/dst IP, ports, protocol)
- Lock the bucket
- Walk the chain comparing flow keys
- Check timeout status during walk
- Create new flow if not found and memory allows
The hash table is pre-allocated at startup (default 65536 buckets) with configurable memory cap (default 32 MB).
Flow Lifecycle
Creation: FlowGetFlowFromHash() allocates a new flow, initializes it with FlowInit(), and sets state to NEW. Flows are locked during creation.
Active phase: Packets update lastts and flow state. Protocol detection progresses through pattern matching, probing parsers, and expectations. Flags track which detection methods completed.
Timeout detection: The Flow Manager thread periodically scans buckets checking if lastts + timeout_policy < current_time. Timed-out flows are moved to the evicted list.
Cleanup: The Flow Recycler thread processes evicted flows, logging them, clearing protocol state, and returning them to the spare pool for reuse.
Emergency Mode
When memory pressure exceeds the memcap, Suricata enters emergency mode:
- Timeout values shrink dramatically (e.g., established TCP: 30s → 5s)
- Flow Manager wakes up more frequently
- Flows are aggressively pruned from the hash
- New flow creation may be blocked
The flow_flags atomic tracks emergency state globally.
Pseudo-Packets & Forced Reassembly
When a flow times out or closes, the system may inject pseudo-packets to trigger final stream reassembly and detection. FlowNeedsReassembly() checks if unprocessed segments or frames exist, and FlowPseudoPacketSetup() constructs packets with PKT_PSEUDO_STREAM_END flag.
Thread Safety
- Flow header (addresses, ports): read-only after init, no lock needed
- Flow state: protected by
FLOWLOCK_MUTEX(orFLOWLOCK_RWLOCK) - Bucket operations: protected by
FBLOCK_MUTEX - Global counters: atomic operations (
SC_ATOMIC_*)
Workers hold the flow lock during packet processing. The Flow Manager holds bucket locks during timeout scans.
Application Layer Protocols
Relevant Files
src/app-layer.csrc/app-layer.hsrc/app-layer-parser.csrc/app-layer-parser.hsrc/app-layer-protos.hsrc/app-layer-detect-proto.csrc/app-layer-htp.csrc/app-layer-ssl.crust/src/applayer.rsrust/src/dns/dns.rsrust/src/smb/mod.rs
Suricata's application layer (L7) subsystem provides protocol detection, parsing, and inspection for 30+ protocols including HTTP/1.1, HTTP/2, DNS, TLS, SSH, SMB, QUIC, and many others. The system is designed for extensibility, supporting both C and Rust implementations.
Protocol Architecture
The application layer operates in two phases: protocol detection and parsing. When a flow begins, Suricata attempts to identify the protocol using probing parsers or pattern matching. Once identified, the appropriate parser processes the stream data and extracts transactions for rule inspection.
Protocols are registered with unique identifiers (AppProto enum) defined in app-layer-protos.h. Each protocol can operate over TCP, UDP, or both, with configurable ports and detection strategies.
Protocol Registration
Protocols register through a two-step process:
- Protocol Detection Registration via
SCAppLayerRegisterProtocolDetection()- registers probing functions and default ports - Parser Registration via
AppLayerRegisterParser()- registers parsing callbacks and state management functions
// Example: DNS protocol registration
if (SCAppLayerProtoDetectConfProtoDetectionEnabled("udp", "dns")) {
let alproto = applayer_register_protocol_detection(&parser, 1);
if (SCAppLayerParserConfParserEnabled("udp", "dns")) {
AppLayerRegisterParser(&parser, alproto);
}
}
Parsing Pipeline
Loading diagram...
Key Components
Protocol Detection uses two strategies: pattern matching (PM) for known signatures and probing parsers (PP) for stateful detection. The detection engine maintains per-flow state and can reverse-detect protocols when needed.
Parsers implement state machines that consume stream data incrementally. They return AppLayerResult indicating success, error, or incomplete data requiring more bytes. Parsers extract transactions—logical protocol units like HTTP requests or DNS queries—for inspection.
Transactions are the inspection unit. Each transaction has metadata (direction, state, events) and can be inspected independently. The system supports transaction-level detection keywords like http.method, dns.query, and tls.version.
Supported Protocols
Core protocols: HTTP/1.1, HTTP/2, DNS, TLS, SSH, FTP, SMTP, SMB, DCERPC, QUIC, IKE, Kerberos, LDAP, MQTT, PostgreSQL, RDP, RFB, SIP, Telnet, WebSocket, NFS, NTP, TFTP, DHCP, DNP3, Modbus, EtherNet/IP, BitTorrent DHT, mDNS, POP3.
Rust vs C Implementation
Modern protocols are implemented in Rust (rust/src/) for memory safety, while legacy protocols remain in C. Both use the same registration interface through FFI bindings. Rust parsers define a RustParser struct with function pointers for probing, parsing, state management, and logging.
Configuration
Protocol detection and parsing are configurable via YAML. Administrators can enable/disable protocols, specify custom ports, and tune parser behavior (body limits, compression handling, etc.). Configuration is loaded during initialization and affects which parsers are registered.
Output & Logging System
Relevant Files
src/output.csrc/output-eve.csrc/output-json.csrc/output-filestore.csrc/log-stats.c
Suricata's output and logging system is a modular, hierarchical architecture that handles diverse event types through pluggable output modules. The system supports multiple formats (JSON/EVE, fast log, syslog) and destinations (files, sockets, Redis).
Architecture Overview
The logging system uses a root logger hierarchy with two levels:
- Root Loggers - Core logging entry points registered at startup (packet loggers, transaction loggers, flow loggers, stats loggers)
- Output Modules - Specific implementations that handle configuration and format (e.g., JSON alert, DNS log, HTTP log)
Root loggers are registered independently of configuration, then activated based on what's enabled in the config file. This separation allows flexible composition of logging pipelines.
Loading diagram...
Module Registration System
Output modules are registered through specialized functions based on their type:
- Packet Modules - Log individual packets (e.g., pcap, packet data)
- Transaction Modules - Log application-layer transactions (HTTP, DNS, TLS, etc.)
- File Modules - Log file metadata and content
- Flow Modules - Log flow-level events
- Stats Modules - Log performance statistics
- Streaming Modules - Log streaming data (TCP payload)
Each module provides initialization, logging, and optional flush/thread management functions. The system supports both parent modules and sub-modules for hierarchical organization.
EVE (Extensible Validation Environment) JSON Format
EVE is Suricata's primary structured output format. Key features:
- Unified JSON schema with common fields (timestamp, flow_id, event_type, src_ip, dest_ip, proto)
- Extensible callbacks - Custom code can register callbacks to inject additional fields
- File type plugins - Support for custom output destinations (regular files, Unix sockets, Redis)
- Metadata support - Includes flow variables, packet variables, and flow bits
- Community ID - Optional flow fingerprinting for correlation across tools
EVE events include protocol-specific data (HTTP headers, DNS queries, TLS certificates, etc.) alongside network 5-tuple information.
File Storage and Rotation
The filestore module handles extracted file storage with:
- SHA256-based organization - Files stored in hierarchical directories by hash
- Concurrent file limits - Configurable maximum open files to prevent resource exhaustion
- Atomic operations - Temporary files renamed to final location to ensure consistency
- Metadata logging - File information logged to JSON with size, hash, and state
File rotation is managed through a flag registry system where modules register flags that get set when rotation is requested.
Statistics Logging
The stats logger outputs performance metrics at configurable intervals:
- Per-thread counters - Thread-specific statistics aggregated from detection engine
- Uptime tracking - Engine uptime formatted as days, hours, minutes, seconds
- Configurable output - Can log totals, per-thread breakdowns, or null counters
- Text format - Human-readable table format with counter names and values
Thread Safety and Performance
- Thread-local storage - Each logging thread maintains its own buffer and context
- Lazy initialization - Loggers only initialized if enabled in configuration
- Buffer management - Memory buffers expand dynamically to handle large events
- Flush operations - Periodic flushing ensures timely output without blocking
Threading & Run Modes
Relevant Files
src/tm-threads.c- Thread creation and managementsrc/tm-threads.h- Thread structures and APIssrc/tm-modules.c- Thread module registrysrc/tm-modules.h- Thread module definitionssrc/runmodes.c- Run mode registration and dispatchsrc/runmodes.h- Run mode enumerationssrc/util-runmodes.c- Run mode setup utilitiessrc/runmode-af-packet.c- AF_PACKET run mode implementations
Thread Architecture
Suricata uses a modular threading system where work is organized into thread modules (TmModule) that can be chained together in a pipeline within a single thread. Each thread has a linked list of TmSlot objects representing processing stages.
Key thread types include:
- Receive threads - Capture packets from network interfaces
- Decode threads - Parse packet headers and protocols
- FlowWorker threads - Perform detection and flow processing
- Verdict threads - Apply IPS actions (drop, reject, etc.)
- Management threads - Handle flow cleanup, statistics, and maintenance
Threads are created via TmThreadCreate() and spawned with TmThreadSpawn(), which initializes pthread attributes and manages thread lifecycle flags (THV_INIT_DONE, THV_RUNNING, THV_KILL, etc.).
Run Modes
Run modes define how threads are organized and how work is distributed. The three primary modes are:
Single Mode - One thread handles all work (receive, decode, detect, output). Used for testing or single-interface scenarios.
Workers Mode - N threads, each independently handling all tasks for packets they receive. Each worker thread contains a complete pipeline: receive → decode → detect → output. Scales linearly with CPU cores.
AutoFP Mode - Specialized multi-threaded mode with flow-based load balancing. Receive threads feed packets into pickup queues, and N detect threads pull from these queues. Packets from the same flow always go to the same detect thread, ensuring flow state consistency without locks.
Queue System
Threads communicate via Tmq (thread module queues). Each thread has an input queue and output queue with associated handlers. AutoFP mode creates N pickup queues (one per detect thread) and uses a flow hash to route packets: flow_hash % thread_count determines which pickup queue receives the packet.
Thread Module Registration
Thread modules are registered in a global array tmm_modules[TMM_SIZE]. Each module defines:
ThreadInit()- Per-thread initializationFunc()- Packet processing functionPktAcqLoop()- Packet acquisition loop (for receive modules)Management()- Management thread functionflags- Module type flags (TM_FLAG_RECEIVE_TM, TM_FLAG_DECODE_TM, etc.)
Modules are looked up by name and appended to thread pipelines via TmSlotSetFuncAppend().
Run Mode Dispatch
RunModeDispatch() selects and executes the appropriate run mode based on configuration. It registers all available run modes, validates queue state, and spawns management threads (flow manager, statistics, logging). The active run mode string is stored globally and can be queried via RunmodeGetActive().
Rust Integration & Protocol Parsers
Relevant Files
rust/src/lib.rsrust/src/applayer.rsrust/src/dns/mod.rsrust/src/http2/mod.rsrust/src/quic/mod.rssrc/app-layer-parser.hsrc/app-layer-register.c
Suricata is a hybrid C and Rust application. The Rust layer provides high-performance protocol parsers and detection modules that integrate seamlessly with the C core through FFI (Foreign Function Interface). This architecture combines Rust's memory safety with C's performance and existing infrastructure.
Architecture Overview
Loading diagram...
Protocol Parser Registration
Each Rust protocol parser follows a standardized registration pattern. Parsers are defined as RustParser structures containing function pointers for parsing, state management, and event handling.
Key Registration Steps:
- Protocol Detection - Register probing functions that identify the protocol from packet data
- Parser Registration - Register parsing callbacks for both directions (to-server, to-client)
- State Management - Provide allocation and cleanup functions for parser state
- Transaction Handling - Define transaction creation, retrieval, and completion callbacks
Example: DNS Parser Registration
pub unsafe extern "C" fn SCRegisterDnsUdpParser() {
let parser = RustParser {
name: b"dns\0".as_ptr() as *const c_char,
default_port: "[53]".as_ptr(),
ipproto: IPPROTO_UDP,
probe_ts: Some(probe_udp),
probe_tc: Some(probe_udp),
state_new,
state_free,
parse_ts: parse_request,
parse_tc: parse_response,
get_tx_count: state_get_tx_count,
get_tx: state_get_tx,
// ... additional callbacks
};
let alproto = applayer_register_protocol_detection(&parser, 1);
AppLayerRegisterParser(&parser, alproto);
}
Core Components
StreamSlice - Represents a chunk of network data passed from C to Rust parsers. Handles both regular data and gaps in the stream.
AppLayerTxData - Transaction metadata tracking logging state, file operations, detection progress, and decoder events. Bridges Rust transactions with the C detection engine.
AppLayerResult - Parser return value indicating consumed bytes, incomplete data, or errors.
Supported Protocols
Rust implementations include DNS, HTTP/2, QUIC, SMB, DCERPC, SSH, SIP, MQTT, PostgreSQL, RDP, Kerberos, LDAP, NFS, and many others. Each parser handles protocol-specific framing, state machines, and event generation.
FFI Integration Points
- Parser Functions -
ParseFncallbacks receive flow context, parser state, and stream data - Probing Functions -
ProbeFncallbacks identify protocols from initial packet bytes - Event System - Parsers generate events via
AppLayerEventderive macro, automatically bridged to C - Detection Keywords - Rust detection modules register keywords with the C detection engine
- Logging - Parsers output JSON via
JsonBuilder, integrated with Suricata's logging pipeline
Performance Considerations
Rust parsers benefit from memory safety without garbage collection, enabling efficient streaming parsing. The nom parser combinator library provides zero-copy parsing for most protocols. State machines are optimized for minimal allocations, with transaction pooling for high-throughput scenarios.
Configuration & Rule Management
Relevant Files
src/conf.csrc/conf-yaml-loader.csrc/detect-parse.crules/README.mdsuricata.yaml.in
Suricata uses a hierarchical YAML-based configuration system and a rule-based detection engine. Both are critical to the engine's operation and flexibility.
Configuration System
The configuration system is built on a tree of SCConfNode structures that represent key-value pairs in a hierarchical namespace. Configuration is loaded from YAML files using the libyaml parser, with support for includes and prefixes.
Key Components:
- YAML Loader (
conf-yaml-loader.c): Parses YAML files with version validation (1.1), recursion limits (128 levels), and error handling. Supports!includedirectives for splitting configuration across multiple files. - Configuration Tree (
conf.c): Maintains an in-memory tree ofSCConfNodeobjects. Nodes are accessed via dot-notation paths (e.g.,detect.profile). The tree supports lookups, creation, and value retrieval with type conversion (int, bool, string). - Thread Safety: Configuration is set during initialization only. Multiple threads can safely read configuration data.
Configuration Sections in suricata.yaml.in:
vars: Network and port variables for rulesoutputs: Alert and event logging (EVE JSON, fast.log, etc.)detect: Detection engine tuning (profile, recursion limits, grouping)app-layer: Protocol parsers (HTTP, DNS, TLS, SMB, etc.)stream: TCP stream reassembly settingshost: Host tracking and memory limitspcap,af-packet,dpdk: Packet acquisition interfaces
Rule System
Rules are the core detection mechanism. Each rule is parsed into a Signature structure containing protocol, addresses, ports, and match options.
Rule Structure:
action protocol src_addr src_port direction dst_addr dst_port (options)
Example:
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET"; flow:established,to_server; http.method; content:"GET"; sid:1;)
Parsing Flow (detect-parse.c):
- Basics: Extract action, protocol, addresses, ports, direction
- Options: Parse rule options (content, flow, http.method, etc.) sequentially
- Validation: Check SID presence, requirements, and rule type
Rule Components:
- Action:
alert,drop,pass,reject,rejectsrc,rejectdst,rejectboth,config - Protocol:
tcp,udp,icmp,ip, application-layer (http, dns, tls, etc.) - Direction:
->(unidirectional),<>(bidirectional),=>(transactional) - Addresses/Ports: IP lists, CIDR notation, variables, negation (
!),any - Options: Keywords like
content,flow,sid,msg,classtype,metadata
Rule Types:
- pkt: Packet-level matching (headers, payload)
- pkt_stream: Packet and stream reassembly
- app-layer: Application protocol inspection
- pd_only: Protocol detection only
- iponly: IP-only rules (no payload)
Reserved SID Allocations (rules/README.md):
Signature IDs are allocated by component and protocol to prevent conflicts:
- Decoder: 2200000-2200999
- Stream: 2210000-2210999
- HTTP: 2221000-2221999
- DNS: 2240000-2240999
- TLS: 2230000-2230999
- SMB: 2225000-2225999
- (and many others for app-layer protocols)
Configuration Lookup
Configuration values are retrieved using dot-notation paths:
SCConfNode *node = SCConfGetNode("detect.profile");
const char *value = node->val;
Lookups support defaults, type conversion, and child value extraction. The system validates YAML version and handles malformed files gracefully.