Nftables processes rules in a specific order based on their priority and hook, allowing for fine-grained control over network traffic.
Let’s see nftables in action. Imagine we have a simple firewall that allows established connections, drops invalid packets, and then allows everything else.
# Create a table named 'inet filter'
nft add table inet filter
# Add a chain named 'input' to the 'inet filter' table with type 'filter' and hook 'input'
# The priority '0' is the default for most filtering, but we can change it.
nft add chain inet filter input { type filter hook input priority 0 \; }
# Add a chain named 'output' to the 'inet filter' table with type 'filter' and hook 'output'
nft add chain inet filter output { type filter hook output priority 0 \; }
# Add a chain named 'forward' to the 'inet filter' table with type 'filter' and hook 'forward'
nft add chain inet filter forward { type filter hook forward priority 0 \; }
# Add a rule to the 'input' chain: accept packets belonging to established or related connections.
# Priority -150 is higher than 0, meaning it's evaluated earlier.
nft add rule inet filter input meta ctstate established,related accept
# Add a rule to the 'input' chain: drop invalid packets.
# Priority -100 is also higher than 0, evaluated before the default priority.
nft add rule inet filter input meta ctstate invalid drop
# Add a rule to the 'input' chain: accept all other incoming traffic.
# This rule has the default priority 0.
nft add rule inet filter input accept
In this example, priority 0 is the standard priority for filtering. Rules with priorities like -150 (established,related) and -100 (invalid) are evaluated before the rules at priority 0. This means that packets identified as established/related or invalid are handled first, and then any remaining packets are subject to the rules at priority 0.
The hook specifies when in the packet’s journey the ruleset is evaluated. The input hook processes packets destined for the local machine, output for packets originating from the local machine, and forward for packets passing through the machine.
The real magic happens with priorities. Nftables has a range of priorities, and hooks are associated with specific priority ranges. For the input hook, common priorities are:
0(default filter): General packet filtering.100(mangle): Modifying packet headers.-100(raw): For packets that haven’t yet been seen by the connection tracker.-150(conntrack): For packets that have already been processed by the connection tracker.
This means that a packet arriving at the input hook will first be checked against rules with the lowest (most negative) priority, and then proceed to higher priorities. So, a packet destined for your machine will first be evaluated by conntrack rules (priority -150), then raw rules (priority -100), and finally by filter rules (priority 0).
If you wanted to ensure that certain traffic is always allowed before any filtering, you might place it in a chain with a very low priority (e.g., -200). Conversely, if you have a specific logging rule you want to apply to all packets that reach the filter hook, you might give it a priority slightly higher than 0, like 1.
The ctstate (connection state) match is a prime example of why priorities matter. ctstate established,related rules are typically placed at a very low priority (-150) so that the firewall can quickly accept legitimate, ongoing traffic without inspecting it further with other rules. This is a performance optimization. Similarly, ctstate invalid is often placed at a slightly higher priority (-100) to drop malformed packets early.
When you add rules, they are placed at the end of the chain for their specified priority. If you need to insert a rule at a specific position within a priority level, you can use the insert keyword instead of add rule. For instance, nft insert rule inet filter input priority 0 position 1 accept. This would insert the rule as the second rule at priority 0.
The most surprising thing about nftables priority and hooks is how the system prioritizes processing based on negative numbers meaning earlier evaluation. It’s counterintuitive if you’re used to thinking of higher numbers as more important or earlier. This negative scale allows for a dedicated space for critical, early-stage packet handling like connection tracking and invalid packet dropping, ensuring performance and security before more complex filtering logic is applied.
The next concept to explore is how nftables handles sets and maps for efficient rule management.