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
shpkg 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:
shsysrc suricata_enable="YES"
Ports Installation
For custom build options (Rust support for newer protocol parsers, LuaJIT, hyperscan for accelerated pattern matching):
shcd /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:
shmkdir -p /var/log/suricata mkdir -p /usr/local/etc/suricata/rules
Download the default rule set:
shpkg 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:
shsuricata -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
shservice suricata start
Or manually for testing:
shsuricata -c /usr/local/etc/suricata/suricata.yaml -i em0
Check that alerts are being generated:
shtail -f /var/log/suricata/fast.log
Check EVE JSON output for detailed logs:
shtail -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:
shkldload 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:
shpfctl -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:
shsuricata -c /usr/local/etc/suricata/suricata.yaml --ipfw -D
In /etc/rc.conf:
shsysrc 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 blockdrop-- silently drop the packetreject-- drop the packet and send a TCP RST or ICMP unreachablepass-- 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
shsuricata-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:
- Start in IDS mode. Run for at least a week before enabling IPS. Review all alerts for false positives.
- Use a threshold. Do not drop on the first match. Use the
thresholdkeyword to require multiple matches:
shelldrop 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;)
- Whitelist known traffic. Create pass rules for traffic you know is legitimate.
- 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
shsuricata-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:
yamlrule-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:
yamlthreading: 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:
shkldload 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.memcapandflow.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.