Netfilter and BPF/XDP
On this page
Port forwarding is configured, yet only INPUT is allowed, and connections still fail. First, determine how packets traverse routing and hooks, then discuss rules, tracking, and NAT; XDP/TC operate at different processing layers.
| Lookup Target | Reading Location |
|---|---|
| Packet path and chain control flow | Sections 1–2 |
| Isolated rule experiments and conntrack | Sections 3–4 |
| NAT, BPF, and offload observation | Sections 5–7 |
1. Determine which path the packet takes
External packets destined for local services often pass through PREROUTING and INPUT; packets sent by local processes pass through OUTPUT and POSTROUTING; packets routed via forwarding pass through PREROUTING, FORWARD, and POSTROUTING. Bridging, netdev ingress, tunnels, and offloading involve other paths, so it is incorrect to claim that all packets necessarily traverse all five hooks.
DNAT changes the destination address before routing, allowing traffic originally destined for a gateway address to be forwarded to an internal server. Therefore, packets after port forwarding usually require FORWARD rules, rather than just allowing INPUT.
Within the same hook, execution follows increasing priority values; different base chains can share a hook, but the relative order of chains with the same priority should not be relied upon for policy. See Netfilter hooks.
2. nftables tables, chains, rules, and sets
| Object | Responsibility |
|---|---|
| family | Specifies the protocol/processing domain, e.g., ip, ip6, inet, bridge, netdev |
| table | Organizes objects like chains, sets, and maps; it is not a fixed execution stage itself |
| base chain | Bound to a hook, priority, and policy, serving as an execution entry point |
| regular chain | Entered via jump/goto rules; does not bind to a hook itself |
| rule | Match expressions and actions evaluated in order |
| set / map | Express set queries or key-to-value mappings, reducing redundant rules |
nftables still evaluates rules in chain order; it does not completely eliminate linear rule checking. Sets can improve expression and specific query efficiency, but one cannot unconditionally claim that "any nft ruleset is traversed only once and is faster than iptables."
iptables commands may use the nft backend; one cannot determine the underlying legacy xtables solely by command name. When multiple tools manage the configuration together, confirm the actual backend and current ruleset.
Why 'accept' is not always the final pass
In a base chain, 'accept' terminates processing for that chain, but subsequent base chains for the same hook or later hooks can still drop. 'drop' usually terminates further processing of that packet immediately. The control flow for regular chain returns/jumps and base chain policies is different.
| Execution Location | Action on Source | Is it finally allowed? |
|---|---|---|
| input base chain, priority 0 | accept SSH | Not yet; subsequent chains will still process |
| input base chain, priority 10 | drop that source | Packet is rejected |
Two chains jointly determine the result. Repeatedly adding 'accept' at the end of the first chain does not override the 'drop' in the second chain. See nftables chain configuration.
Below, two base chains with different priorities are fixed to change the destination port and source conditions respectively. After an 'accept' in one chain, subsequent chains can still reject; 'drop' causes subsequent rules to lose the opportunity to execute.
Accept terminates processing of the current base chain; subsequent chains can still reject; drop terminates this path. Multiple base chains for the same hook execute in ascending order of priority.
3. A learning ruleset that only counts
Save as observe.nft. It does not change the default accept policy; it counts packets passing through the chain from three main paths separately; it is not a complete security policy.
table inet kb_observe {
chain input {
type filter hook input priority 0; policy accept;
counter
}
chain forward {
type filter hook forward priority 0; policy accept;
counter
}
chain output {
type filter hook output priority 0; policy accept;
counter
}
}
On a machine supporting unprivileged user/network namespaces, you can check and load using a fresh network namespace:
-c checks without applying the transaction, but still requires relevant kernel support and permissions. There are no external interfaces connected here; the namespace is reclaimed when the process ends. If the system disables unprivileged namespaces, this example will fail and should not be directly changed to load on the host firewall. Actual traffic capture still requires creating test interfaces and load within the same namespace.
nft's batch transactions avoid partial update windows caused by user-space commands executed one by one, but this does not mean that existing conntrack/NAT states are rebuilt along with rule changes.
4. Conntrack state is not TCP socket state
conntrack records protocol, bidirectional tuple, zone, state, and timers, etc. It can handle TCP and also establish flow tracking for connectionless protocols like UDP. ct state established and TCP ESTAB displayed by ss are not the same state machine.
NEW, ESTABLISHED, RELATED, INVALID, and UNTRACKED describe the tracking perspective. RELATED can include associated ICMP errors or relationships established by controlled helpers; notrack needs to be executed early enough and will change NAT/rule behavior that depends on tracking.
The creation, confirmation, timeout, and destruction of table entries differ from the opening and closing of application sockets. When observing table fullness, check new flow rates, timeouts, zones, memory, and anomalous traffic; one cannot assume that simply increasing nf_conntrack_max solves the problem. count/max are capacity observations, not end-to-end health indicators.
5. NAT establishes mappings; subsequent packets reuse state
Typical stateful NAT uses the first packet of a flow to establish a binding; subsequent packets are transformed based on the mapping saved in conntrack, rather than each packet re-traversing the NAT chain to select a new mapping. After modifying NAT rules, existing flows may continue to use the old mapping.
| Direction | Address Change |
|---|---|
| Client initiates | 10.0.0.8:40000 accesses 198.51.100.20:443 |
| Gateway source translation | Source address becomes 203.0.113.5:51000 |
| Return traffic | Sent to gateway 51000, restored to client 40000 based on reverse state |
These addresses are for deduction only. Restoring return packets depends on existing mappings; NAT cannot be understood merely as one-way string replacement.
SNAT usually selects the source mapping at egress; MASQUERADE works based on the egress interface address and has interface state change-related processing. DNAT often changes the destination in PREROUTING/OUTPUT. Do not write nat INPUT chain as the universal location for "DNAT to local machine"; its source translation support should be understood separately.
Beyond mapping: Forwarding permission and return routing must still hold
NAT does not automatically enable IP forwarding, fix return routing, or allow FORWARD. Hairpin access may also require corresponding source translation so that return traffic passes through the same stateful device. See NAT documentation.
6. XDP and TC: Processing location determines available information
Native XDP is located in the early driver receive path, allowing packets to be dropped, sent back, or redirected with less protocol stack overhead; generic XDP is already in the skb path, and hardware offload depends on NIC support. The three cannot be mixed into a fixed "pre-skb hook."
XDP_PASS indicates continuing to subsequent stack processing; XDP_TX indicates sending back from the receiving device; XDP_REDIRECT depends on the correct redirect target and related preparation. Return actions are not complete substitutes for creating routes, modifying MACs, updating checksums, or maintaining connection tracking.
TC processes skbs and is suitable for combining functions like queuing, classification, address modification, and redirection. Direct-action uses TC_ACT_* and cannot copy XDP constants as return values. Socket filter control is handed over to the socket's receive data, not a "socket creation hook."
BPF helpers have limited interfaces for conntrack, routing, etc., but availability and responsibility vary by type/version; one cannot assume the program inherits the entire Netfilter state and rules by default. Program types refer to eBPF Program Types.
7. Traffic offloading changes observable paths
Netfilter flowtable and hardware offloading can allow established flows to take shorter paths. The establishment of first-packet policies and the actual traversal location and counting of subsequent traffic need to be analyzed together; a FORWARD counter not increasing per packet does not necessarily mean all traffic has stopped.
Empty packet capture: Locate the observation point first, then judge if packets arrive
Similarly, XDP dropping packets early may occur before the regular packet socket capture point. Local tcpdump not seeing it could mean packets didn't arrive, or they were processed earlier. Troubleshooting should combine physical port counters, XDP/TC status, Netfilter trace/counters, and socket status to narrow the scope layer by layer. See flowtable documentation.