Linux packet filtering is implemented by Netfilter, a kernel framework that
exposes hooks in the networking stack. iptables and nftables are not
independent firewalls: they are userspace interfaces for programming packet
classification and actions at those hooks.
iptables is the historical interface. Native nftables, configured with the
nft command, replaces the separate iptables, ip6tables, arptables, and
ebtables rule-management models with one language and one Netlink API.
Compatibility tools can still accept iptables syntax while writing to the
nftables kernel backend, so the command name alone does not identify the active
implementation.
Netfilter Packet Flow #
Netfilter invokes registered operations as a packet moves through the network stack:
The routing decision determines which path follows:
- Packets addressed to a local socket traverse
preroutingandinput. - Packets routed through the host traverse
prerouting,forward, andpostrouting. - Packets created locally traverse
outputandpostrouting. - An optional, device-specific
ingresshook runs beforeprerouting.
The ingress hook can reject traffic before later networking work occurs, but IP fragments have not yet been reassembled there. A rule that reads a TCP or UDP header therefore cannot classify noninitial fragments at that point.
Hook names describe positions in packet processing, not built-in rules. nftables creates no chains by default; a ruleset must explicitly attach a base chain to each required hook.
Three Interfaces and Two Kernel APIs #
Current systems can expose three command interfaces backed by two different kernel rule APIs:
iptables-legacyprograms the historicalx_tableskernel API.iptables-nftaccepts iptables syntax but programsnf_tablesthrough the compatibility layer andnft_compat.nftuses the native nftables language and thenf_tablesNetlink API.
The nftables backend compiles rules into instructions for an in-kernel, network-specific virtual machine. It reuses the existing Netfilter hook, connection-tracking, NAT, logging, queueing, and other supporting infrastructure.
Determine the selected iptables backend rather than inferring it from the binary name:
iptables --version
readlink -f "$(command -v iptables)"A version string containing (nf_tables) identifies the nftables backend.
Distribution alternatives or symlinks can change the selection.
The iptables Model #
iptables organizes rules into predefined tables and built-in chains. The main IPv4 tables are:
| Table | Primary Purpose |
|---|---|
filter | Accept or reject packets through INPUT, FORWARD, and OUTPUT. |
nat | Create address or port translations for new connections. |
mangle | Modify packet fields and marks for specialized processing. |
raw | Run before connection tracking, including NOTRACK decisions. |
security | Apply security marks used by Linux security modules. |
Rules in a chain are evaluated in order. Matches select packets by interface, address, protocol, port, connection state, mark, or an extension-specific property. A target then accepts, drops, rejects, logs, translates, or transfers control to another chain.
IPv4 and IPv6 use separate commands and rulesets:
iptables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 \
-m conntrack --ctstate NEW -j ACCEPTIncremental iptables-legacy changes require reading, modifying, and replacing
a table. Concurrent writers therefore coordinate through an xtables lock.
iptables-restore is preferable to a shell script containing many independent
iptables -A commands because it replaces a complete table rather than
exposing a sequence of partial policies.
The nftables Model #
nftables uses a hierarchy of families, tables, chains, rules, and stateful objects:
- A family selects the packet domain:
ip,ip6,inet,arp,bridge, ornetdev. - A table is a namespace for chains, sets, maps, counters, and flowtables.
- A base chain attaches to a Netfilter hook and declares a chain type, priority, and optional default policy.
- A regular chain has no hook and is reached through
jumporgoto. - A rule evaluates expressions from left to right and executes statements when the expressions match.
The inet family lets one ruleset process IPv4 and IPv6 traffic. Protocol-
specific expressions still select one protocol family; for example, ip saddr
matches IPv4 addresses and ip6 saddr matches IPv6 addresses.
A Dual-Stack Host Firewall #
The following file defines a stateful, default-deny input policy while allowing loopback traffic, replies, diagnostic ICMP, and SSH from an IPv4 administration network:
#!/usr/sbin/nft -f
flush ruleset
table inet firewall {
set admin_ipv4 {
type ipv4_addr
flags interval
elements = { 192.0.2.0/24 }
}
chain input {
type filter hook input priority filter
policy drop
ct state invalid drop
ct state established,related accept
iifname "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
ip saddr @admin_ipv4 tcp dport 22 accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output {
type filter hook output priority filter
policy accept
}
}Validate and load a file as a single transaction:
nft --check --file /etc/nftables.conf
nft --file /etc/nftables.conf
nft list rulesetnft --file parses the complete batch and submits it as one kernel
transaction. If any command fails, the transaction is not partially committed.
Placing flush ruleset in the same file replaces the managed ruleset
atomically. Omitting the flush while repeatedly loading an additive file can
create duplicate rules.
Do not use flush ruleset when another service owns unrelated nftables tables.
In that case, replace only the tables assigned to the current component.
Hooks, Priorities, and Verdicts #
A base chain declaration controls when it runs:
type filter hook input priority filter; policy drop;type filterselects ordinary packet filtering.hook inputattaches the chain to locally delivered traffic.priority filterplaces it at the standard filtering priority, numerically zero.policy dropapplies when evaluation reaches the end without another verdict.
Several base chains can attach to the same hook. Netfilter evaluates them in ascending numerical priority, including internal operations such as defragmentation, connection tracking, destination NAT, and source NAT.
An accept verdict ends the current chain, but a later base chain at the same
hook can still drop the packet. A drop verdict discards the packet
immediately. Firewall analysis must therefore include every base chain at the
hook, not only the first chain that returns accept.
Regular-chain control flow also differs:
jump service_checksenters another chain and returns when that chain reaches its end.goto service_checkstransfers control without returning to the calling chain.returnresumes the calling chain or applies the base-chain policy when returning from a base chain.
Connection Tracking #
The nf_conntrack subsystem associates packets with flows. Both iptables and
nftables use it for stateful filtering and NAT. Common states are:
| State | Meaning |
|---|---|
new | A valid packet starts or belongs to a flow that has not exchanged traffic in both directions. |
established | Conntrack has observed valid traffic in both directions. |
related | A new flow is associated with an existing tracked connection. |
invalid | The packet cannot be associated with a valid tracked flow. |
untracked | Earlier policy explicitly excluded the packet from tracking. |
Stateful rules admit reply traffic without opening every ephemeral destination port:
ct state established,related accept
ct state invalid dropConntrack consumes finite kernel memory. If its table reaches
nf_conntrack_max, the kernel cannot track additional flows and can drop new
traffic. Monitor both values:
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_maxRaising the maximum without calculating memory use only moves the resource limit. High-flow systems also require timeout review, traffic validation, and capacity monitoring.
Network Address Translation #
Stateful NAT creates a translation binding from the first packet of a tracked flow. Later packets use conntrack state rather than reevaluating every NAT rule. Filtering therefore belongs in filter chains, not NAT chains.
A router can define destination and source NAT as follows:
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat
tcp dport 443 dnat ip to 192.0.2.20:8443
}
chain postrouting {
type nat hook postrouting priority srcnat
oifname "wan0" masquerade
}
}NAT in the inet family requires Linux 5.2 or later. Older kernels require
separate ip and ip6 NAT tables.
- DNAT commonly runs at
prerouting, before the forwarding route is selected. - SNAT and masquerading commonly run at
postrouting, after route selection. redirectsends traffic to the local machine.masqueradederives the source address from the output interface and is appropriate when that address can change.
NAT is not a security policy. A translated packet must still pass the relevant input or forward filtering policy.
Sets, Maps, and Concatenations #
iptables rulesets often express repeated values as linear rules or depend on
the separate ipset facility. nftables integrates typed data structures:
set web_ports {
type inet_service
elements = { 80, 443 }
}
map service_targets {
type inet_service : ipv4_addr
elements = {
80 : 192.0.2.10,
443 : 192.0.2.20
}
}- A set answers whether a key is present.
- A map returns a value for a key.
- A verdict map returns a verdict such as
accept,drop, orjump chain. - A concatenation combines fields, such as source address and destination port, into one compound key.
Named sets can be updated without rebuilding every rule that references them. Interval sets represent address and port ranges compactly. Maps and concatenations reduce long sequences of nearly identical rules because lookup selects data or control flow directly.
Counters, Logging, and Tracing #
Rules count traffic only when they contain a counter statement or reference a named counter:
tcp dport 22 counter acceptLogging is a nonterminal statement, so one rule can both log and decide:
ct state invalid log prefix "invalid: " limit rate 10/second dropRate limiting is necessary because packet-triggered logging can consume CPU, storage, and logging-service capacity.
nftables tracing records rule traversal for selected packets. Enable tracing with a narrowly scoped rule:
meta l4proto tcp tcp dport 443 meta nftrace set 1Then observe events:
nft monitor traceRemove the trace rule after diagnosis because broad tracing can generate a large event stream.
Migrating from iptables #
Migration has two distinct targets:
- Compatibility migration changes the kernel backend while retaining
iptables syntax.
iptables-nft-restoreloads an iptables-save file intonf_tables. - Native migration converts and then redesigns the policy in nftables syntax.
Inventory all active rule owners before changing either backend:
iptables --version
iptables-legacy-save
ip6tables-legacy-save
nft list rulesetThe translation tools do not alter the live ruleset:
iptables-legacy-save > iptables-v4.save
ip6tables-legacy-save > iptables-v6.save
iptables-restore-translate -f iptables-v4.save > rules-v4.nft
ip6tables-restore-translate -f iptables-v6.save > rules-v6.nftTranslation is a starting point because it preserves the old structure. Review the output for:
- unsupported or partially supported xtables extensions;
- duplicated IPv4 and IPv6 rules that can become one
inetrule; - repeated rules that should become sets, maps, or verdict maps;
- chain policies, counters, logging rates, and NAT behavior;
- dependencies on marks, routing policy, interfaces, namespaces, or connection-tracking helpers; and
- rules inserted dynamically by container engines, virtual-machine managers, intrusion-prevention tools, or firewall frontends.
iptables-nft is useful as a transition interface because its changes are
atomic and visible through nft list ruleset. It still represents xtables
semantics, and some extensions can remain wrapped through nft_compat rather
than becoming native nftables expressions.
Coexistence and Rule Ownership #
Do not operate iptables-legacy and nftables as independent administrators of
the same traffic. The legacy x_tables rules and nf_tables rules are separate
kernel rulesets, and neither command view gives a complete policy. A packet can
traverse both, producing failures that resemble missing or contradictory
rules.
iptables-nft and nft share the nf_tables backend, but shared storage does
not imply shared ownership. Editing compatibility-generated chains with native
commands can violate assumptions made by the tool that created them.
Assign ownership explicitly:
- Use one service to load the host firewall.
- Give orchestration systems separate tables when they support that model.
- Determine whether firewalld, container engines, Kubernetes components, virtual-machine managers, VPN software, and ban tools add rules.
- Do not flush tables owned by another component.
- Persist rules through the distribution’s nftables service or the selected firewall manager, not through competing boot scripts.
Backend support varies by software version and distribution packaging. Inspect the deployed system instead of assuming that a tool name implies legacy or native nftables behavior.
Project Status #
nftables has been available in the upstream Linux kernel since version 3.13. The Netfilter project has considered the original xtables/setsockopt tools legacy since June 2018, while continuing to provide iptables-compatible tools over the nftables backend.
Current iptables packages therefore serve two roles: maintaining existing
legacy deployments and providing a compatibility path to nf_tables.
Kernel, nftables, and iptables versions remain distribution-specific; verify
the deployed backend and required feature versions instead of relying on a
distribution release name.
Operational Checklist #
- Keep an out-of-band console available before changing a remote host’s input policy.
- Validate files with
nft --check --filebefore applying them. - Load complete changes with
nft --fileinstead of issuing an ordered shell sequence. - Establish loopback and management access before enforcing a default-drop policy.
- Review all base chains and priorities at each hook.
- Monitor counters, logs, conntrack capacity, and ruleset changes.
- Treat NAT, packet filtering, routing, and traffic control as separate policies because one does not replace the others.
- Keep one authoritative owner for each table and document dynamically managed tables.
For new Linux firewall designs, native nftables provides the clearest model,
dual-stack inet rules, integrated sets and maps, and transactional updates.
iptables compatibility remains valuable for existing applications, but it
should be treated as a migration mechanism rather than the architecture for a
new ruleset.
References #
- Netfilter: nftables Project
- nftables Wiki: Netfilter Hooks
- nftables Wiki: Configuring Tables
- nftables Wiki: Configuring Chains
- nftables Wiki: nftables Families
- nftables Wiki: Connection Tracking
- nftables Wiki: Network Address Translation
- nftables Wiki: Sets
- nftables Wiki: Maps
- nftables Wiki: Verdict Maps
- nftables Wiki: Concatenations
- nftables Wiki: Atomic Rule Replacement
- nftables Wiki: Ruleset Tracing
- nftables Wiki: Moving from iptables to nftables
xtables-nft(8)xtables-translate(8)
Comments
Read or comment on GitHub (sign-in required to comment)