nftables is a surprisingly complex beast, and sometimes you just need to see exactly what’s happening to a packet as it navigates your ruleset. The nft monitor command is your best friend here, allowing you to watch packets flow through nftables in real-time.
Let’s see nft monitor in action. Imagine you have a simple nftables ruleset like this:
table ip filter {
chain input {
type filter hook input priority 0; policy accept;
tcp dport 22 counter accept
udp dport 123 counter accept
ip saddr 192.168.1.100 counter drop
ct state invalid counter drop
}
}
Now, to monitor packets hitting the input chain of the ip filter table, you’d run:
sudo nft monitor ip filter input
If a packet arrives on your eth0 interface destined for port 22 (SSH), you’ll see output similar to this:
[ 123.456789] ip filter input: iifname "eth0" tcp dport 22 counter accept
This tells you that the packet, arriving on eth0, matched the tcp dport 22 rule in the input chain of the ip filter table, and the accept action was taken. The counter here is also incremented, which you can verify with sudo nft list counters ip filter input.
If a packet from 192.168.1.100 arrives, you’d see:
[ 124.123456] ip filter input: ip saddr 192.168.1.100 counter drop
This shows the packet was dropped by the rule matching the source IP.
The real power comes when you have more complex rules, especially those involving connection tracking (ct), NAT, or custom sets. For instance, if a packet is flagged as invalid by the connection tracking subsystem:
[ 125.987654] ip filter input: ct state invalid counter drop
This output is invaluable for debugging why a legitimate packet might be getting dropped. You can see which rule it actually hit, not just which rule you thought it should hit.
The nft monitor command has several useful options. You can specify a particular hook (input, output, prerouting, postrouting, input for the inet family) or even a specific chain within a table. If you want to monitor all packets processed by a table, you can omit the chain name: sudo nft monitor ip filter.
The output format is generally [timestamp] table chain: rule_description. The rule_description is a simplified representation of the matching criteria and the action taken. This simplification is key to keeping the output readable while still providing the necessary debugging information.
What most people don’t realize is that nft monitor doesn’t just show accepted or dropped packets. It shows every packet that traverses the specified chain and matches any rule. This includes packets that are passed through to the next chain, packets that are accepted, dropped, rejected, or even those that just hit a rule with no explicit action (which, by default, means the packet processing continues to the next rule in the chain). This comprehensive view is crucial for understanding the flow, especially when dealing with complex logic that might involve jumping to other chains or using verdict modifiers.
To get a deeper understanding of the packet’s state before it hits your rules, you can combine nft monitor with tools like tcpdump or wireshark. tcpdump -ni eth0 -s 0 -w packet.pcap can capture the raw packets, and then you can use nft monitor to see how nftables is interpreting and acting upon them.
The next hurdle you’ll likely encounter after mastering nft monitor is understanding how verdict modifiers like accept, drop, reject, continue, and jump interact with packet flow and connection tracking states.