Skip to main content
RunBook Academy

OPNsenseXXXI · Intrusion Detection and SuricataSuricata architecture

Suricata architecture — the engine, the threads, the packet flow, and the rule set

Intermediate⏱ ~14 minsuricatasuricata-scpstop

What you'll learn

  • Describe the packet flow through Suricata from capture to output
  • Explain the role of the decoder, the stream engine, the detection engine, and the output system
  • Identify the thread model and how Suricata scales across CPU cores
  • Recognise the Suricata rule syntax and how rules are evaluated
  • Identify the inputs to detection (signatures, protocol parsers, anomaly settings)

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

Suricata is not a single program that inspects packets. It is a pipeline of stages — capture, decode, stream, detect, output — each handled by a different subsystem, each with its own configuration. The pipeline runs on multiple threads so the engine scales across CPU cores. The operator who understands the pipeline can predict what Suricata can detect and how it will scale; the operator who treats Suricata as a black box cannot. This lesson covers the packet flow through Suricata, the role of each subsystem, the thread model, and the rule format that drives detection.

The packet flow

A packet arriving at a Suricata-monitored interface passes through these stages in order:

    +---------+    +---------+    +---------+    +---------+    +---------+
    | Capture | -> | Decode  | -> | Stream  | -> | Detect  | -> | Output  |
    +---------+    +---------+    +---------+    +---------+    +---------+
  1. Capture — the packet is acquired from a network interface (via libpcap, netmap, or AF_PACKET depending on the deployment) or from an IDS-specific mechanism (e.g., NFQ for IPS in inline mode). On OPNsense, Suricata runs in IDS or IPS mode using netmap for capture.
  2. Decode — the raw bytes are parsed into a packet structure. Suricata understands Ethernet, VLAN tags (802.1Q), IPv4, IPv6, TCP, UDP, ICMP, and many application-layer protocols. The decoder produces a structured representation that downstream stages consume.
  3. Stream — TCP and UDP flows are tracked. The stream engine assembles TCP segments into the application-layer stream so signatures can match across packets (a single HTTP request may span multiple TCP segments). The stream engine also handles flow timeouts, reassembly buffers, and anomaly detection (e.g., overlapping TCP segments).
  4. Detect — the signatures are evaluated against the packet and (for stateful signatures) against the flow. This is the heart of Suricata. The detection engine iterates over the active signature set and matches each signature against the packet’s protocol fields and payload.
  5. Output — the alerts, the flow log, and any other outputs are written. Suricata can write to a unified2 binary log, an EVE JSON log, a fast log, or — on OPNsense — to a database the OPNsense plugin populates for the GUI.

Each stage has its own configuration. The operator who tunes Suricata tunes each stage.

The decoder

The decoder parses the raw bytes into a structure Suricata’s downstream stages understand. The decoder recognises:

  • Layer 2 — Ethernet, VLAN tags (802.1Q), MPLS labels, PPPoE.
  • Layer 3 — IPv4, IPv6, ICMPv4, ICMPv6.
  • Layer 4 — TCP, UDP.
  • Application layer — HTTP, TLS, DNS, SMTP, FTP, SSH, SMB, and many others. Suricata’s application-layer parsers are what allow it to inspect content within the protocol — HTTP request methods, HTTP headers, TLS SNI, DNS query names.

The decoder produces a structured representation (in code, the Packet structure with pointers to decoded protocol fields). The detection engine reads this structure to evaluate signatures.

The stream engine

TCP is a stream protocol; a single application-layer message may span multiple TCP segments. The detection engine needs to see the reassembled stream, not individual segments. The stream engine:

  • Tracks TCP flows by 5-tuple (protocol, source, source port, destination, destination port).
  • Reassembles TCP segments into the byte stream.
  • Handles TCP anomalies (overlapping segments, out-of-order segments, retransmissions).
  • Tracks UDP “flows” (stateless but tracked for context).

The stream engine also produces a “flow record” Suricata can write to the flow log. The flow log shows the operator every connection Suricata saw, regardless of whether a signature fired.

The detection engine

The detection engine evaluates the signatures against each packet (and the flow state). The engine iterates over the signature set and applies three optimisations:

  1. Pre-filtering — before a signature is evaluated against the packet, the engine checks a fast-path filter (the signature’s header conditions: source, destination, protocol, ports). If the pre-filter does not match, the signature is not evaluated against the payload. This makes the common case (header-only mismatch) very fast.
  2. Multi-pattern matching — for signatures that need to match a string in the payload (a content keyword), Suricata uses Aho-Corasick or Hyperscan to find all candidate patterns in a single pass. This is significantly faster than evaluating each signature one at a time.
  3. Flow-based statefulness — a signature that requires the connection to be “established” (the flow:established keyword) is not evaluated against the first SYN packet. The engine checks the flow state before evaluating.

The result: a signature set of 30,000 rules can be evaluated against 1 Gbps of traffic on a modern multi-core CPU. Without the optimisations, the same workload would saturate the CPU.

The output system

The output system writes what Suricata has detected. The common outputs:

  • EVE JSON — a structured JSON log of every alert, flow, protocol event, and anomaly. The OPNsense plugin uses this format and ingests it into a database for the GUI.
  • Unified2 — a binary log format used by some SIEM integrations.
  • Fast log — a simple one-line-per-alert log; legacy format.
  • Stats — periodic counters showing how many packets were processed, how many signatures fired, etc.

The OPNsense operator configures the output through the plugin’s GUI (Services → Intrusion Detection → Settings). The default is EVE JSON to a local file the plugin parses.

The rule format

Suricata rules are text files with one rule per line. The format:

action proto src_ip src_port -> dst_ip dst_port (msg:"...", flow:..., content:"...", sid:..., rev:...)

A typical signature:

alert http any any -> any any (msg:"ET MALWARE Cobalt Strike beacon"; flow:established,to_server; http.uri; content:"/aaa"; sid:2024001; rev:2;)

The fields:

  • actionalert, drop, reject, or pass. In IDS mode, all actions are alert. In IPS mode, the operator can use drop or reject.
  • proto — the protocol (http, tcp, udp, icmp, ip, etc.).
  • src_ip, src_port, dst_ip, dst_port — the source and destination. any matches anything.
  • msg — a human-readable description shown in the alert.
  • flow — the flow state required (established, to_server, to_client).
  • content — the string to match (case-sensitive by default).
  • sid — the signature ID; must be unique.
  • rev — the revision; incremented when the signature is updated.

The signature set on OPNsense comes from Emerging Threats (ET Open ruleset, free) and optionally from Proofpoint ET Pro (paid). The operator can disable individual signatures, modify them, or write custom ones.

Read-only / SafeSuricata build and ruleset
$ suricata --build-info; echo '---'; ls /usr/local/etc/suricata/rules/ | head; echo '---'; grep -c '^alert' /usr/local/etc/suricata/rules/emerging-malware.rules
Suricata 7.0.10
Features: NFQ PCAP_PATTERN_RECORD PMHQ1_PACKET_RING NETMAP AF_PACKET
Lua support: yes
L1 HV: no
Builtin HC: x86_64 SSE4_2 SSE4_1 POPCNT BMI1 BMI2
---
emerging-attack_response.rules
emerging-botcc.portgrouped.rules
emerging-botcc.rules
emerging-dns.rules
emerging-exploit.rules
emerging-malware.rules
emerging-trojan.rules
...
---
417

Illustrative output

Summary

  • Suricata is a pipeline: capture → decode → stream → detect → output. Each stage has its own subsystem.
  • The detection engine is the heart — the cost of running Suricata is dominated by signature evaluation.
  • The thread model scales across CPU cores; one detect thread per core is a typical configuration.
  • The rule format: action proto src -> dst (msg:..., flow:..., content:..., sid:..., rev:...).
  • OPNsense exposes Suricata through a plugin that configures capture, threading, rule set, and output.

Knowledge check · 4 questions

  1. Q1. A Suricata deployment is saturating one CPU core on the detect thread, with packet drops on the capture thread. What is the most likely root cause?

  2. Q2. Suricata's signature evaluation is per-rule (each signature is checked against the packet in sequence), with no cross-rule optimisation.

  3. Q3. Which of the following are the main stages of the Suricata pipeline? Select all that apply.

  4. Q4. A Suricata rule is: alert http any any -> any any (msg:"ET MALWARE Cobalt Strike beacon"; flow:established,to_server; http.uri; content:"/aaa"; sid:2024001; rev:2;). What does the flow:established,to_server clause mean?

Passing score: 75%. Answers are checked in this browser.