Firewall Backends & Fallback Chain
April 18, 2026 · View on GitHub
Synapse enforces access rules through one of four firewall backends, selected automatically at startup. Every backend applies the same rule set — what differs is where in the network stack enforcement happens and what additional capabilities are available.
Fallback chain
┌─────────────────────────────────────────────────────────────────┐
│ XDP / eBPF │
│ Kernel pre-routing — packet dropped before socket buffer │
│ Fastest. BPF stats. TCP fingerprinting. CIDR LPM Trie. │
└───────────────────────────┬─────────────────────────────────────┘
│ XDP unavailable (driver/kernel)
▼
┌─────────────────────────────────────────────────────────────────┐
│ nftables │
│ Kernel netfilter — post-routing, pre-userspace │
│ Same CIDR rules. No BPF stats. No kernel-level fingerprinting.│
└───────────────────────────┬─────────────────────────────────────┘
│ nftables unavailable
▼
┌─────────────────────────────────────────────────────────────────┐
│ iptables │
│ Legacy netfilter — wider kernel compatibility │
│ Same CIDR rules. No BPF stats. No kernel-level fingerprinting.│
└───────────────────────────┬─────────────────────────────────────┘
│ iptables unavailable
▼
┌─────────────────────────────────────────────────────────────────┐
│ Userland (none) │
│ Application-layer check inside the Synapse process │
│ Proxy mode only. Agent mode has no packet enforcement. │
└─────────────────────────────────────────────────────────────────┘
When firewall.mode is auto (the default), Synapse logs the selected backend at startup:
INFO Firewall backend: XDP/BPF
# or
WARN XDP/BPF not available - trying fallback backends
INFO Firewall backend: nftables
Capability comparison
| Capability | XDP/eBPF | nftables | iptables | Userland |
|---|---|---|---|---|
| CIDR access rules (allow/block) | ✅ | ✅ | ✅ | ✅ proxy only |
| Dynamic rule updates (no restart) | ✅ | ✅ | ✅ | ✅ |
| IPv4 rule capacity | 4,194,304 | OS limit | OS limit | unlimited |
| IPv6 rule capacity | 1,048,576 | OS limit | OS limit | unlimited |
| CIDR coalescing before load | ✅ | ✅ | ✅ | ✅ |
| Drop latency | kernel pre-routing | kernel post-routing | kernel post-routing | userspace |
| BPF statistics & counters | ✅ | ❌ | ❌ | ❌ |
| Per-IP drop tracking | ✅ | ❌ | ❌ | ❌ |
| Kernel-level TCP fingerprinting | ✅ | ❌ | ❌ | ❌ |
| IDS active blocking | ✅ | ✅ | ✅ | ❌ |
| Agent mode enforcement | ✅ | ✅ | ✅ | ❌ |
| Proxy mode enforcement | ✅ | ✅ | ✅ | ✅ |
Backend details
XDP / eBPF
The preferred backend. eBPF programs are loaded into the kernel and attached to the NIC driver's XDP hook. Packets are inspected and dropped in the network driver interrupt handler — before the packet is copied into the socket buffer, before any userspace process sees it.
What you get:
- Sub-microsecond drop latency at any packet rate
- BPF statistics: total packets processed/dropped, per-IP drop counters (tracked in kernel LRU map)
- TCP fingerprinting (JA4T/JA4TS) captured directly in the XDP program
- LPM Trie for CIDR lookups: O(1) regardless of rule count
- Full CIDR coalescing applied before loading rules into the BPF map
Requirements:
- Linux kernel 4.18+ (5.4+ recommended)
- BTF (
/sys/kernel/btf/vmlinuxmust exist) - NIC driver with XDP support — most modern drivers (virtio-net, i40e, mlx5, ixgbe, etc.)
CAP_BPFandCAP_NET_ADMIN(orCAP_SYS_ADMINon older kernels)- libbpf available at runtime
Check:
bpftool map show name banned_ips # shows the LPM Trie map
bpftool map show name ipv4_banned_stats # shows the stats counter
ip link show eth0 | grep xdp # shows XDP program attached
nftables
Fallback when XDP is unavailable. Rules are loaded into the Linux netfilter subsystem via nftables. Packets are evaluated post-routing after the NIC driver, but still in kernel space before the socket buffer is processed.
What you get:
- Kernel-level enforcement without eBPF/XDP requirements
- Same CIDR allow/block rules
- Works on any kernel with nftables (3.13+)
What you lose vs XDP:
- No BPF statistics or per-IP drop counters
- No kernel-level TCP fingerprinting (JA4T still available via userspace capture)
- Higher latency than XDP (post-routing vs pre-routing)
- No LPM Trie — rule evaluation is linear for large lists
Requirements:
- Linux kernel 3.13+
nftbinary installed (apt install nftables/dnf install nftables)CAP_NET_ADMIN
Check:
nft list tables # shows Synapse tables if active
nft list ruleset
iptables
Legacy fallback. Uses the older iptables/ip6tables interface to the netfilter subsystem. Functionally similar to nftables at the enforcement layer.
What you get:
- Maximum kernel compatibility (any kernel with netfilter)
- Same CIDR allow/block rules
What you lose vs XDP:
- Same as nftables, plus: iptables is deprecated upstream and may not be available on newer distributions without the legacy package
What you lose vs nftables:
- Slower rule insertion for large rule sets (iptables-legacy uses linear traversal per rule)
- No atomic rule replacement — rules are updated one at a time
Requirements:
iptablesbinary (apt install iptables/ already present on most systems)CAP_NET_ADMIN
Check:
iptables -L SYNAPSE_INPUT -n --line-numbers 2>/dev/null
ip6tables -L SYNAPSE_INPUT -n --line-numbers 2>/dev/null
Userland (none)
Last resort, or deliberately chosen via firewall.mode: "none". Access rules are evaluated inside the Synapse process as each connection is accepted.
What you get:
- Works everywhere — no kernel or capability requirements
- Full CIDR matching still applied (same rule set)
Critical limitations:
- Agent mode: no enforcement. Without a kernel firewall, the agent cannot drop packets — the process has no visibility into connections it doesn't own. Blocked CIDRs will still reach your services.
- Proxy mode only: enforcement happens at the point where Synapse accepts the connection, before proxying to the upstream. Blocked IPs receive a rejection at the application layer.
- No BPF stats, no kernel-level fingerprinting, IDS cannot block (only detect)
- Higher CPU cost per connection vs kernel-level enforcement
Configuration
firewall:
mode: "auto" # auto | xdp | nftables | iptables | none
mode value | Behaviour |
|---|---|
auto | Select highest available: XDP → nftables → iptables → none |
xdp | Force XDP; startup fails if XDP is unavailable |
nftables | Force nftables; startup fails if nftables is unavailable |
iptables | Force iptables; startup fails if iptables is unavailable |
none | Userland enforcement only (see limitations above) |
# Environment variable
FIREWALL_MODE=auto # same as firewall.mode
Windows
Windows does not use the Linux netfilter stack. Synapse uses the following Windows-specific capture and enforcement path:
| Available | Capture | Enforcement |
|---|---|---|
| eBPF for Windows (recommended) | AF_XDP — kernel-level packet capture | eBPF programs drop packets at kernel level |
| WPF/NDIS driver (fallback) | NDIS intermediate driver — kernel-level capture | Driver-level packet filter |
| Neither | Raw socket capture (limited) | Userland enforcement only (proxy mode) |
Install eBPF for Windows with the -WithEBPF flag during setup:
powershell -ExecutionPolicy Bypass -File install.ps1 -WithEBPF
Requires test signing mode: bcdedit /set testsigning on (then reboot).
Diagnostics
Identify the active backend at startup
Search the Synapse log:
grep -i "firewall\|backend\|XDP\|nftables\|iptables" /var/log/synapse/app.log | head -20
Expected messages:
| Message | Meaning |
|---|---|
Firewall backend: XDP/BPF | XDP active |
XDP/BPF not available - trying fallback backends | XDP failed, trying next |
Firewall backend: nftables | nftables active |
Firewall backend: iptables | iptables active |
Firewall backend: none (userland) | No kernel firewall |
Verify XDP is attached
# Check XDP program on interface
ip link show eth0 | grep xdp
# List BPF maps
bpftool map show name banned_ips
bpftool map show name recently_banned_ips
# Count loaded rules
bpftool map dump name banned_ips | grep -c prefixlen
# Check stats counters
bpftool map dump name ipv4_banned_stats
bpftool map dump name total_packets_processed
Verify nftables/iptables rules
# nftables
nft list tables
nft list chain inet synapse input 2>/dev/null
# iptables
iptables -n -L SYNAPSE_INPUT 2>/dev/null | head -20
Common reasons XDP fails
| Symptom | Cause | Fix |
|---|---|---|
EPERM / permission denied | Missing CAP_BPF or CAP_NET_ADMIN | Run as root, or add capabilities to the systemd unit |
BTF not found | /sys/kernel/btf/vmlinux missing | Enable CONFIG_DEBUG_INFO_BTF=y in kernel config, or upgrade kernel |
XDP not supported by driver | NIC driver has no XDP support | Use firewall.mode: nftables or switch to a supported driver/NIC |
| Falls back silently in container | Container lacks CAP_BPF / NET_ADMIN | Add --cap-add BPF --cap-add NET_ADMIN to Docker run, or use nftables mode |
vmlinux.h error at build | BTF headers not present at compile time | Install linux-headers or use a pre-built release binary |
| Works but no stats | XDP in SKB mode instead of native | Force native XDP with a supported driver; SKB mode is a driver fallback |