FreeBSD.software
Home/Guides/Suricata on FreeBSD: IDS/IPS Review
review·2026-04-09·13 min read

Suricata on FreeBSD: IDS/IPS Review

Review of Suricata on FreeBSD: intrusion detection and prevention, rule management, inline mode with PF/IPFW, performance on FreeBSD, and comparison with Snort.

Suricata on FreeBSD: IDS/IPS Review

Suricata is an open-source network threat detection engine developed by the Open Information Security Foundation (OISF). It performs intrusion detection (IDS), intrusion prevention (IPS), and network security monitoring by inspecting network traffic against a large rule set of known attack patterns, protocol anomalies, and policy violations. Suricata processes traffic at multi-gigabit speeds using multi-threading, supports Snort-compatible rules, and adds protocol-specific detection for HTTP, TLS, DNS, SSH, SMTP, and dozens of other protocols through its built-in application-layer parsers.

FreeBSD is a strong platform for Suricata. The kernel's netmap framework provides high-performance packet capture, kqueue handles event notification efficiently, and PF or IPFW can divert traffic to Suricata for inline IPS mode. This review covers Suricata's capabilities, FreeBSD installation, IDS and IPS configuration, rule management, performance characteristics, and how it compares with Snort.

What Suricata Does

Suricata operates in three modes:

IDS (Intrusion Detection System). Suricata passively monitors network traffic by reading packets from a network interface (or pcap file). It matches traffic against rules and generates alerts. It does not block or modify traffic. This is the safest mode for initial deployment because misconfigured rules cannot disrupt legitimate traffic.

IPS (Intrusion Prevention System). Suricata sits inline in the traffic path and can drop, reject, or modify packets that match rules. On FreeBSD, inline mode works through divert sockets with PF or IPFW, or through netmap for high-performance deployments.

NSM (Network Security Monitoring). Suricata logs protocol-level metadata (HTTP transactions, DNS queries, TLS certificates, file extractions) regardless of whether traffic matches a rule. This provides forensic data for incident investigation and threat hunting.

Detection Capabilities

Suricata's detection engine handles:

  • Signature-based detection: matching traffic against known patterns (Snort/Suricata rules)
  • Protocol anomaly detection: identifying deviations from protocol specifications (e.g., malformed HTTP headers, invalid TLS handshakes)
  • Application-layer inspection: deep parsing of HTTP, TLS, DNS, SSH, SMTP, FTP, SMB, DCERPC, DHCP, SNMP, SIP, MQTT, and more
  • File extraction: extracting files from HTTP, SMTP, FTP, NFS, and SMB sessions for analysis or storage
  • TLS/SSL inspection: logging certificate details, JA3/JA3S fingerprints, and detecting anomalous TLS behavior
  • DNS logging: full query/response logging for passive DNS analysis
  • Flow tracking: maintaining state for TCP connections and UDP flows
  • Lua scripting: custom detection logic for scenarios not covered by the rule language

Installation on FreeBSD

Binary Package

sh
pkg install suricata

This installs Suricata with its dependencies. The configuration directory is /usr/local/etc/suricata/. The main configuration file is /usr/local/etc/suricata/suricata.yaml.

Enable Suricata:

sh
sysrc suricata_enable="YES"

Ports Installation

For custom build options (Rust support for newer protocol parsers, LuaJIT, hyperscan for accelerated pattern matching):

sh
cd /usr/ports/security/suricata make config make install clean

Enable Hyperscan in the build options if your CPU supports it (Intel SSE 4.2 or later). Hyperscan dramatically accelerates multi-pattern matching -- the core operation of signature-based detection.

Initial Setup

Create required directories:

sh
mkdir -p /var/log/suricata mkdir -p /usr/local/etc/suricata/rules

Download the default rule set:

sh
pkg install suricata-update suricata-update

suricata-update downloads the Emerging Threats Open rule set by default and writes rules to /var/lib/suricata/rules/suricata.rules.

Verify the configuration:

sh
suricata -T -c /usr/local/etc/suricata/suricata.yaml

IDS Configuration

Basic IDS Setup

Edit /usr/local/etc/suricata/suricata.yaml:

yaml
# Network variables vars: address-groups: HOME_NET: "[10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12]" EXTERNAL_NET: "!$HOME_NET" HTTP_SERVERS: "$HOME_NET" SMTP_SERVERS: "$HOME_NET" SQL_SERVERS: "$HOME_NET" DNS_SERVERS: "$HOME_NET" port-groups: HTTP_PORTS: "80" SHELLCODE_PORTS: "!80" SSH_PORTS: "22" # Capture interface af-packet: - interface: em0 cluster-id: 99 cluster-type: cluster_flow defrag: yes use-mmap: yes tpacket-v3: yes # Default rule path default-rule-path: /var/lib/suricata/rules rule-files: - suricata.rules # Output configuration outputs: - eve-log: enabled: yes filetype: regular filename: /var/log/suricata/eve.json types: - alert: payload: yes payload-printable: yes packet: yes - http: extended: yes - dns - tls: extended: yes - files: force-magic: yes - flow - ssh - smtp - fast: enabled: yes filename: /var/log/suricata/fast.log

The HOME_NET variable is critical. Set it to your internal network ranges. Rules use $HOME_NET and $EXTERNAL_NET to determine traffic direction. Incorrect values cause missed alerts and false positives.

Start in IDS Mode

sh
service suricata start

Or manually for testing:

sh
suricata -c /usr/local/etc/suricata/suricata.yaml -i em0

Check that alerts are being generated:

sh
tail -f /var/log/suricata/fast.log

Check EVE JSON output for detailed logs:

sh
tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'

IPS Configuration (Inline Mode)

IPS with PF Divert

On FreeBSD, the recommended inline IPS method uses PF's divert-to action to send traffic through Suricata:

First, ensure the ipdivert kernel module is loaded:

sh
kldload ipdivert echo 'ipdivert_load="YES"' >> /boot/loader.conf

Configure PF to divert traffic:

sh
# /etc/pf.conf # Divert all traffic on the external interface to Suricata pass in on em0 divert-to 127.0.0.1 port 8000 pass out on em0 divert-to 127.0.0.1 port 8000

Reload PF:

sh
pfctl -f /etc/pf.conf

Configure Suricata for IPS mode in suricata.yaml:

yaml
# Replace af-packet section with: ipfw: - ipfw-divert-port: 8000

Start Suricata in IPS mode:

sh
suricata -c /usr/local/etc/suricata/suricata.yaml --ipfw -D

In /etc/rc.conf:

sh
sysrc suricata_flags="--ipfw"

IPS with IPFW Divert

Alternatively, use IPFW's divert mechanism:

sh
# Enable IPFW kldload ipfw ipdivert sysrc firewall_enable="YES" sysrc firewall_type="open" # Add divert rules ipfw add 100 divert 8000 ip from any to any via em0

IPS Rule Actions

In IPS mode, rules can use these actions:

  • alert -- generate an alert but do not block
  • drop -- silently drop the packet
  • reject -- drop the packet and send a TCP RST or ICMP unreachable
  • pass -- allow the packet and stop processing further rules

Modify rule actions for IPS. For example, change an alert rule to a drop rule:

shell
# Original alert rule alert http $EXTERNAL_NET any -> $HTTP_SERVERS any (msg:"SQL injection attempt"; content:"UNION SELECT"; nocase; sid:1000001; rev:1;) # Modified for IPS - drop instead of alert drop http $EXTERNAL_NET any -> $HTTP_SERVERS any (msg:"SQL injection attempt"; content:"UNION SELECT"; nocase; sid:1000001; rev:1;)

Use suricata-update with a drop filter to convert alert rules to drop rules selectively:

sh
# /usr/local/etc/suricata/drop.conf # Convert specific SIDs to drop re:ET TROJAN re:ET EXPLOIT
sh
suricata-update --drop-conf /usr/local/etc/suricata/drop.conf

IPS Safety Practices

Running Suricata inline means misconfigured rules will drop legitimate traffic. Follow these practices:

  1. Start in IDS mode. Run for at least a week before enabling IPS. Review all alerts for false positives.
  2. Use a threshold. Do not drop on the first match. Use the threshold keyword to require multiple matches:
shell
drop tcp any any -> $HOME_NET 22 (msg:"SSH brute force"; flow:to_server; threshold:type both, track by_src, count 5, seconds 60; sid:1000002; rev:1;)
  1. Whitelist known traffic. Create pass rules for traffic you know is legitimate.
  2. Monitor drops. Track dropped traffic in the EVE log and review regularly.

Rule Management

Rule Sources

  • Emerging Threats Open (ET Open): free, community-maintained rules. Good baseline coverage. Updated daily.
  • Emerging Threats Pro (ET Pro): commercial rules with additional coverage, faster updates, and fewer false positives. Approximately $900/year per sensor.
  • Suricata's built-in rules: protocol anomaly detection rules bundled with Suricata.
  • Custom rules: rules you write for your specific environment.

suricata-update

suricata-update is the standard tool for managing rules:

sh
# Update rules from default sources suricata-update # List available rule sources suricata-update list-sources # Enable a source suricata-update enable-source et/pro secret-code=YOUR_CODE # Update and reload suricata-update suricatasc -c reload-rules

Disabling Noisy Rules

Some rules generate excessive false positives. Disable them:

sh
# /usr/local/etc/suricata/disable.conf # Disable by SID 2210000 2210001 # Disable by regex on rule message re:ET INFO # Disable entire category group:emerging-info.rules
sh
suricata-update --disable-conf /usr/local/etc/suricata/disable.conf

Writing Custom Rules

shell
# Alert on outbound DNS queries to suspicious TLDs alert dns $HOME_NET any -> any any (msg:"DNS query for suspicious TLD"; dns.query; content:".xyz"; nocase; endswith; sid:9000001; rev:1;) # Alert on TLS connections with expired certificates alert tls any any -> any any (msg:"Expired TLS certificate"; tls.cert_expired; sid:9000002; rev:1;) # Alert on HTTP POST to .php with large body (potential webshell upload) alert http $EXTERNAL_NET any -> $HTTP_SERVERS any (msg:"Large POST to PHP file"; flow:to_server,established; http.method; content:"POST"; http.uri; content:".php"; endswith; http.request_body; content:|00|; offset:0; depth:1; isdataat:100000; sid:9000003; rev:1;) # Alert on SSH with non-standard port alert ssh any any -> $HOME_NET !22 (msg:"SSH on non-standard port"; sid:9000004; rev:1;)

Save custom rules to /usr/local/etc/suricata/rules/local.rules and add to suricata.yaml:

yaml
rule-files: - suricata.rules - /usr/local/etc/suricata/rules/local.rules

Performance on FreeBSD

Threading Model

Suricata uses multi-threading to distribute packet processing across CPU cores. On FreeBSD, configure threading in suricata.yaml:

yaml
threading: set-cpu-affinity: yes cpu-affinity: - management-cpu-set: cpu: [ 0 ] - receive-cpu-set: cpu: [ 1 ] - worker-cpu-set: cpu: [ 2, 3, 4, 5 ] mode: "exclusive" prio: default: "high"

netmap for High-Performance Capture

FreeBSD's netmap framework provides zero-copy packet capture, dramatically reducing CPU overhead for packet I/O:

yaml
# suricata.yaml netmap: - interface: em0 threads: 4 cluster-type: cluster_flow

Ensure the netmap module is loaded:

sh
kldload netmap echo 'netmap_load="YES"' >> /boot/loader.conf

With netmap on a 4-core server, Suricata can inspect 5-10 Gbps of traffic depending on the rule set size and traffic composition.

Benchmarks

On a FreeBSD 14.x server with a 6-core CPU and 32 GB RAM, using ET Open rules (approximately 40,000 rules):

  • 1 Gbps link, mixed traffic: 0-5% packet loss in IDS mode, 15-25% CPU across all cores
  • 5 Gbps link (netmap): 0-2% packet loss in IDS mode, 50-70% CPU
  • 10 Gbps link (netmap): 3-10% packet loss depending on traffic mix, near full CPU utilization
  • Memory usage: 2-4 GB with full ET Open rule set and flow tracking

Factors that impact performance:

  • Rule count: more rules = more pattern matching overhead. Disable rules you do not need.
  • Protocol depth: deep HTTP inspection is slower than simple TCP signature matching.
  • Flow tracking: tracking all flows uses significant memory. Tune flow.memcap and flow.hash-size.
  • Logging: EVE JSON logging with full payloads generates high disk I/O. Log to a separate disk or reduce verbosity.

Memory Tuning

yaml
# suricata.yaml flow: memcap: 1gb hash-size: 131072 prealloc: 65536 stream: memcap: 2gb reassembly: memcap: 2gb detect: profile: high sgh-mpm-context: auto

EVE JSON Log Analysis

Suricata's EVE (Extensible Event Format) JSON log is its primary output. Each line is a JSON object describing an event.

Alert Events

json
{ "timestamp": "2026-04-09T14:30:22.123456+0000", "event_type": "alert", "src_ip": "203.0.113.50", "dest_ip": "10.0.0.11", "proto": "TCP", "alert": { "action": "allowed", "gid": 1, "signature_id": 2024897, "signature": "ET SCAN Potential SSH Scan", "category": "Attempted Information Leak", "severity": 2 } }

Analyzing Logs

sh
# Top 10 alert signatures jq -r 'select(.event_type=="alert") | .alert.signature' /var/log/suricata/eve.json | sort | uniq -c | sort -rn | head -10 # All alerts from a specific source IP jq 'select(.event_type=="alert" and .src_ip=="203.0.113.50")' /var/log/suricata/eve.json # DNS queries for a specific domain jq 'select(.event_type=="dns" and .dns.rrname=="malware.example.com")' /var/log/suricata/eve.json # TLS connections with expired certificates jq 'select(.event_type=="tls" and .tls.notafter < "2026-04-09")' /var/log/suricata/eve.json

Integration with SIEM

Feed EVE logs to Elasticsearch, Splunk, or Graylog for centralized analysis:

sh
# Filebeat configuration to ship EVE logs pkg install beats
yaml
# /usr/local/etc/beats/filebeat.yml filebeat.inputs: - type: log paths: - /var/log/suricata/eve.json json.keys_under_root: true json.add_error_key: true output.elasticsearch: hosts: ["http://elasticsearch:9200"] index: "suricata-%{+yyyy.MM.dd}"

Suricata vs Snort

Snort is Suricata's primary competitor and predecessor. Both use the same rule format (Suricata supports Snort rules with extensions).

Multi-threading. Suricata is multi-threaded from the ground up. Snort 2.x is single-threaded. Snort 3.x added multi-threading but Suricata's implementation is more mature and performs better at high traffic rates. For any link above 1 Gbps, Suricata has a significant performance advantage.

Protocol parsing. Suricata includes built-in application-layer parsers written in Rust for HTTP, TLS, DNS, SSH, SMTP, FTP, SMB, DCERPC, NFS, MQTT, and more. Snort 3 has improved protocol inspection through its appid system, but Suricata's parser library is broader and more actively developed.

Rule compatibility. Suricata runs Snort rules. It also extends the rule language with additional keywords for protocol-specific matching (e.g., dns.query, tls.sni, http.uri, ja3.hash). Rules written with Suricata-specific keywords do not work in Snort.

NSM capabilities. Suricata's EVE JSON logging provides comprehensive network metadata (HTTP transactions, DNS queries, TLS certificates, flow records) that Snort does not match. This makes Suricata more useful for threat hunting and forensics, not just alerting.

FreeBSD support. Both run on FreeBSD, but Suricata's FreeBSD support is stronger. It uses netmap for high-performance capture and integrates with PF/IPFW for inline IPS. Snort on FreeBSD works but has historically received less testing than on Linux.

Community and rules. Snort has a larger installed base and Talos (Cisco) provides commercial rules. ET Open and ET Pro rules are the primary source for Suricata. Both rule sets cover similar threats.

Licensing. Suricata is GPLv2. Snort 3 has a more complex license (GPLv2 with additional terms from Cisco). Both are open-source, but Suricata's governance (OISF, a non-profit) is more independent.

Recommendation. Choose Suricata for new deployments on FreeBSD. It is faster, has better protocol analysis, produces richer logs, and has stronger FreeBSD integration. Choose Snort only if you have an existing investment in Snort rules, configurations, and operational procedures that would be costly to migrate.

Integration with PF

Suricata and PF work together in two ways on FreeBSD.

IPS mode: PF diverts traffic to Suricata for inspection (covered in the IPS section above).

Reactive blocking: Suricata detects threats in IDS mode and feeds offending IP addresses to a PF table for blocking:

sh
# Create a PF table for Suricata-blocked IPs # /etc/pf.conf table <suricata_block> persist block quick from <suricata_block>
sh
# Script to add IPs from Suricata alerts to PF table cat > /usr/local/bin/suricata-to-pf.sh << 'SCRIPT' #!/bin/sh tail -F /var/log/suricata/eve.json | \ jq -r 'select(.event_type=="alert" and .alert.severity<=2) | .src_ip' | \ while read IP; do pfctl -t suricata_block -T add "$IP" 2>/dev/null done SCRIPT chmod +x /usr/local/bin/suricata-to-pf.sh

Run this as a daemon or use the suricata-update tool with a PF output plugin.

For a complete PF firewall setup, see the PF firewall guide. For broader FreeBSD hardening, see the hardening guide.

FAQ

Q: Can Suricata run inside a FreeBSD jail?

A: For IDS mode with packet capture from a mirrored port, yes -- but the jail needs access to the network interface (using vnet jails). For IPS mode with divert sockets, run Suricata on the host, not in a jail, since divert requires kernel-level integration.

Q: How often should I update Suricata rules?

A: Daily. ET Open rules are updated multiple times per day to cover new threats. Run suricata-update via cron and reload rules: suricatasc -c reload-rules. Rule reloads do not interrupt traffic inspection.

Q: Does Suricata support TLS decryption?

A: Suricata does not perform man-in-the-middle TLS decryption. It inspects TLS metadata (SNI, certificate fields, JA3 fingerprints) without decrypting the payload. For full TLS inspection, deploy a TLS-terminating proxy upstream and feed decrypted traffic to Suricata.

Q: How much RAM does Suricata need?

A: Minimum 4 GB for a production deployment with ET Open rules. 8-16 GB recommended for 1-10 Gbps links. Memory usage scales with rule count, flow tracking, and stream reassembly settings.

Q: Can Suricata detect encrypted traffic threats?

A: It can detect threats based on TLS metadata (known malicious certificate fingerprints, JA3/JA3S hashes, anomalous TLS behavior, suspicious SNI values) without decrypting the traffic. Encrypted payload content is not inspectable.

Q: What is the performance impact of running Suricata inline (IPS) vs passive (IDS)?

A: IPS mode adds approximately 50-200 microseconds of latency per packet due to divert socket overhead. Throughput is typically 10-20% lower than IDS mode. Use netmap in IPS mode for the best performance.

Q: How do I tune Suricata for fewer false positives?

A: Start by running in IDS mode and reviewing alerts for a week. Disable noisy rules with suricata-update --disable-conf. Tune HOME_NET to match your network exactly. Add pass rules for known legitimate traffic. Enable only rule categories relevant to your environment (e.g., disable Windows malware rules if you only run FreeBSD servers).

Q: Can Suricata and Snort run simultaneously?

A: Technically yes, but there is no practical benefit. They would inspect the same traffic and generate duplicate alerts. Choose one.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.