NFQUEUE Firewall Configuration
To leverage the NFQUEUE capture plane, you must explicitly instruct your system firewall to hand packets over to Netify's userspace queue.
Unlike passive alternatives like pcap or tpacketv3, this approach allows Netify to selectively inspect the initial packets of a flow directly through system firewall hooks. This page provides production-ready deployment strategies for both nftables and iptables engines.
Prerequisites
- Netify Agent installed with the NFQUEUE capture plane plugin active
- A Linux system running either nftables or iptables
- Root or administrative privileges to modify firewall rule definitions
The number of queues targetable by the firewall rulesets must strictly align with the instances configuration value found within your Netify Agent interfaces.d configuration file.
Policy Control & Connection Tracking
The implementation examples below contain additional configuration blocks to support conntrack labels (e.g., ct label definitions and targets).
If you are deploying the Netify Agent purely for visibility/metrics and are not utilizing Netify with policy control or flow actions, these label-specific
rules and sets can be safely removed from your script.
nftables Configuration
The modern nftables implementation utilizes high-performance connection tracking (conntrack) labels and limits analysis thresholds up to a 32-packet cap to optimize resource usage. The ruleset below handles both layer 3 NAT-mode and layer 2 Bridge-mode forwarding scenarios.
/etc/netifyd/nftables-init
# /usr/sbin/nft -f - <<'EOF'
# Globals
##############################################################################
# Exempt the following addresses from block policy.
define netify_exempt_ipv4 = {}
define netify_exempt_ipv6 = {
64:ff9b::/96
}
#
# NAT-mode forwarding:
##############################################################################
add table inet netify
flush table inet netify
table inet netify {
set exempt_ipv4 {
type ipv4_addr
flags interval
elements = { $netify_exempt_ipv4 }
}
set exempt_ipv6 {
type ipv6_addr
flags interval
elements = { $netify_exempt_ipv6 }
}
chain forward {
type filter hook forward priority mangle; policy accept
# Initialize labels
ct label set netify-init-nat counter
# Drop flow packets if labelled accordingly...
ct label netify-block \
ip saddr != @exempt_ipv4 ip daddr != @exempt_ipv4 \
counter drop
ct label netify-block \
ip6 saddr != @exempt_ipv6 ip6 daddr != @exempt_ipv6 \
counter drop
# Allow flow packets if labelled accordingly...
ct label netify-allow counter accept
# Otherwise, return if we've "seen" more than 32 packets...
ct packets > 32 counter return
# Otherwise, send packet to Netify Agent for analysis.
counter queue num 0-1 fanout, bypass
}
}
# Bridge-mode forwarding:
##############################################################################
add table bridge netify
flush table bridge netify
table bridge netify {
set exempt_ipv4 {
type ipv4_addr
flags interval
elements = { $netify_exempt_ipv4 }
}
set exempt_ipv6 {
type ipv6_addr
flags interval
elements = { $netify_exempt_ipv6 }
}
chain forward {
type filter hook forward priority 0; policy accept
# Skip non-IP packets...
ether type != { ip, ip6 } counter return
# Initialize labels
ct label set netify-init-bridge counter
# Drop flow packets if labelled accordingly...
ct label netify-block \
ip saddr != @exempt_ipv4 ip daddr != @exempt_ipv4 \
counter drop
ct label netify-block \
ip6 saddr != @exempt_ipv6 ip6 daddr != @exempt_ipv6 \
counter drop
# Allow flow packets if labelled accordingly...
ct label netify-allow counter accept
# Otherwise, return if we've "seen" more than 32 packets...
ct packets > 32 counter return
# Otherwise, send packet to Netify Agent for analysis.
counter queue num 0-1 fanout, bypass
}
}
EOF
For the curious, the IPv6 prefix 64:ff9b::/96 is the IETF "well-known prefix" reserved for NAT64/DNS64 translation. It allows IPv6-only networks (like modern smartphones or cloud datacenters) to transparently communicate with IPv4-only services on the internet. In a typical integration, Netify doesn't need to see this duplicate flow traffic.
iptables Configuration
For deployments standardizing on traditional iptables infrastructure, the mangle table is used to hook and target traffic. These
standalone instructions evaluate flow boundaries utilizing the connbytes extension module, implementing fail-open safeguards
(--queue-bypass) by default.
/etc/netifyd/iptables-init
#!/bin/sh
# Define your target processing chain
CHAIN="FORWARD"
# Initialize connection tracking labels
iptables -t mangle -A $CHAIN -m connlabel --label connlabel-init --set
# Send only first 32-packets of flow to queue 20 (+3 fanout) with fail-open enabled (queue-bypass):
iptables -t mangle -A $CHAIN -m connbytes --connbytes 0:32 --connbytes-dir both --connbytes-mode packets -j NFQUEUE --queue-balance 20:23 --queue-bypass
A slightly more complex implementation demonstrating the use of SKB marks to filter packets going into the queue.
/etc/netifyd/iptables-init
#!/bin/sh
# Define your target processing chain
CHAIN="FORWARD"
# Initialize connection tracking labels
iptables -t mangle -A $CHAIN -m connlabel --label connlabel-init --set
# Queue the first 32 packets, ignore packets with 0x10000000/4 marks, send to
# two queues #0-1 (multi-threaded).
iptables -t mangle -A FORWARD -m mark ! --mark 0x10000000/0xf0000000 \
-m connbytes --connbytes 0:32 --connbytes-dir both --connbytes-mode packets \
-j NFQUEUE --queue-balance 0:1 --queue-bypass
Persistence & Restarts
Firewall rules applied directly via the command line are volatile and will be lost whenever the firewall service restarts or the system reboots. To ensure your NFQUEUE rules persist, you must integrate your initialization script into your system's firewall configuration framework.
For example, in OpenWrt environments, you can automatically run your initialization script by adding a custom include block to the /etc/config/firewall configuration file. This ensures the rules are re-evaluated every time the firewall reloads. Run the following UCI commands to register your script (adjust the path to point to your actual nftables-init or iptables-init location):
OpenWrt UCI Example
# uci add firewall include
# uci set firewall.@include[-1].enabled='1'
# uci set firewall.@include[-1].type='script'
# uci set firewall.@include[-1].path='/etc/netifyd/nftables-init'
# uci set firewall.@include[-1].fw4_compatible='1'
# uci commit firewall
# fw4 reload