Introduction
A Next-Generation Firewall (NGFW) goes beyond port/protocol filtering to include application-layer inspection, intrusion prevention (IDS/IPS), SSL/TLS decryption, and threat intelligence integration. While commercial appliances (Palo Alto, Fortinet) dominate the enterprise market, the same capabilities can be built using open-source components: nftables for stateful filtering with dynamic sets, Suricata for IDS/IPS with emerging-threats rules, and OPNsense for a unified management interface with VLANs, traffic shaping, and captive portal.
This guide covers building an NGFW policy architecture with nftables (including dynamic allowlists/blocklists), deploying Suricata in IPS mode with rule management, configuring OPNsense as a complete NGFW with VLAN segmentation and traffic shaping, and a reference policy design for zero trust network segmentation.
nftables: Modern Linux Stateful Firewall
nftables is the successor to iptables, providing a cleaner syntax and native support for sets, maps, and dynamic rule updates — essential for NGFW capabilities.
Basic Stateful Policy with Application Filtering
#!/usr/bin/nft -f
table inet ngfw {
# Define sets for dynamic allow/block lists
set blocklist {
type ipv4_addr
flags timeout
auto-merge
elements = { 185.220.101.0/24 timeout 1h, 51.15.0.0/16 timeout 1d }
}
set allowlist {
type ipv4_addr
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
}
# Dynamic sets for threat intelligence feeds
set emerging_threats {
type ipv4_addr
flags timeout
auto-merge
}
chain input {
type filter hook input priority 0; policy drop;
# Allow established connections (stateful)
ct state established,related accept
# Allow loopback
iif lo accept
# Block known bad IPs
ip saddr @blocklist drop
ip saddr @emerging_threats drop
# Allow management access (jump to mgmt chain)
tcp dport { 22, 443 } ip saddr @allowlist accept
# Log and drop everything else
log prefix "NGFW-DROP: " accept
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state established,related accept
ip saddr @blocklist drop
ip saddr @emerging_threats drop
# Application-level forwarding rules
tcp dport 80 jump web_filter
tcp dport 443 jump tls_inspect
}
chain web_filter {
# HTTP application inspection
tcp dport 80 log prefix "HTTP: "
# Add Suricata integration point
queue num 1
}
chain tls_inspect {
# Forward to SSL inspection proxy
tcp dport 443 log prefix "TLS: "
queue num 1
}
}
Adding IPs to the Blocklist Dynamically
# Add a timeout-entry to the blocklist (auto-expires after 1 hour)
nft add element inet ngfw blocklist { 203.0.113.5 timeout 1h }
# Load threat intelligence feed (run via cron)
curl -s https://rules.emergingthreats.net/blockips/compromised-ips.txt | \
while read ip; do
nft add element inet ngfw emerging_threats { $ip timeout 6h }
done
Suricata IDS/IPS Integration
Suricata operates in IPS mode when it receives packets via nftables queue:
# Install Suricata
sudo apt install suricata
# /etc/suricata/suricata.yaml — IPS mode configuration
af-packet:
- interface: eth0
cluster-id: 1
cluster-type: cluster_flow
defrag: yes
# IPS mode (inline)
copy-mode: ips
copy-iface: eth1
Rule Management
# Update Emerging Threats rules (free community ruleset)
sudo suricata-update
sudo systemctl restart suricata
# Custom local rules
cat >> /etc/suricata/rules/local.rules << 'RULES'
# Alert on SQL injection attempts
alert http any any -> $HOME_NET any (
msg:"SQL Injection Attempt";
content:"SELECT|20|*|20|FROM|20|";
nocase; sid:1000001; rev:1;
)
# Block known malware C2 patterns
drop tls $EXTERNAL_NET any -> $HOME_NET any (
msg:"Malware C2 - Known Bad Certificate";
tls.cert_subject; content:"evil.example.com";
sid:1000002; rev:1;
)
# Alert on data exfiltration via DNS
alert dns $HOME_NET any -> $EXTERNAL_NET any (
msg:"Possible DNS Tunneling - Long Subdomain";
dns.query; length:>50; sid:1000003; rev:1;
)
RULES
# Load custom rules
sudo suricata-update --local /etc/suricata/rules/local.rules
sudo systemctl restart suricata
Check Suricata Alerts
# View real-time alerts
tail -f /var/log/suricata/fast.log
# Example output:
# 05/18/2026-14:23:01.234567 [**] [1:1000001:1] SQL Injection Attempt [**]
# [Classification: Attempted SQL Injection] [Priority: 1]
# {TCP} 10.0.1.100:54321 -> 10.0.2.10:80
# Stats dashboard
suricatasc -c dump-counters
OPNsense NGFW Configuration
OPNsense provides a web UI for managing nftables + Suricata + traffic shaping:
# Install OPNsense
# Download from https://opnsense.org/download/ and write to hardware/VM
# Initial CLI setup:
# - Set LAN IP: 192.168.1.1/24
# - Set WAN: DHCP (or static)
# - Enable SSH for remote management
VLAN Segmentation
Configure VLANs in the OPNsense web UI (Interfaces → Other Types → VLAN):
VLAN 10 — Management (10.0.10.0/24) — IT admins only
VLAN 20 — Corporate (10.0.20.0/24) — Employee workstations
VLAN 30 — Guest (10.0.30.0/24) — Internet-only access
VLAN 40 — IoT (10.0.40.0/24) — Devices, no internet access
VLAN 50 — DMZ (10.0.50.0/24) — Public-facing servers
Firewall Rules with Application Detection
# OPNsense firewall rule pseudocode (configured via Web UI or config.xml):
#
# Rule 1: Allow Management to any (IT team)
# Source: VLAN 10
# Destination: any
# Application: any
# Log: enabled
#
# Rule 2: Corporate to internet (web only)
# Source: VLAN 20
# Destination: any
# Application: HTTP, HTTPS, DNS
# Suricata: enabled
# SSL Inspection: enabled
#
# Rule 3: Guest to internet (isolated)
# Source: VLAN 30
# Destination: any
# Application: HTTP, HTTPS
# Block: all other ports
#
# Rule 4: IoT to internal only
# Source: VLAN 40
# Destination: 10.0.0.0/8 (internal)
# Application: MQTT, HTTPS (API calls only)
# Internet: blocked
#
# Rule 5: DMZ to internal (specific ports only)
# Source: VLAN 50
# Destination: 10.0.20.50 (database server)
# Port: 5432 (PostgreSQL)
# Application: PostgreSQL protocol
Traffic Shaping (QoS)
# Limit guest WiFi bandwidth
# Firewall → Shaper → By Interface
# Guest interface: max 50 Mbps down, 10 Mbps up, burst 10s
# Prioritize VoIP traffic
# Firewall → Shaper → By Protocol
# SIP/RTP: priority 7 (highest), guaranteed 1 Mbps per call
Reference NGFW Policy Architecture
Layer 1: Network segmentation (VLANs)
Layer 2: Stateful firewall (nftables stateful inspection)
Layer 3: Application identification (nftables port + DPI)
Layer 4: Intrusion prevention (Suricata IPS)
Layer 5: SSL/TLS inspection (forward proxy)
Layer 6: Threat intelligence (dynamic blocklist feeds)
Layer 7: User identity (VPN auth, 802.1x)
Layer 8: Traffic shaping (QoS per VLAN/application)
Resources
- nftables Wiki — Set and map documentation, queue integration
- Suricata User Guide — IPS mode, rule management, performance tuning
- OPNsense Documentation — VLANs, firewall rules, traffic shaping
- Emerging Threats Open Ruleset — Free IDS/IPS rules
- NIST SP 800-41 Rev 1: Firewall Guidelines
Comments