Netfilter hooks
nftables uses mostly the same Netfilter infrastructure as legacy iptables. The hook infrastructure, Connection Tracking System, NAT engine, logging infrastructure, and userspace queueing remain the same. Only the packet classification framework is new.
Netfilter hooks into Linux networking packet flows
The following schematic shows packet flows through Linux networking:
Traffic flowing to the local machine in the input path sees the prerouting and input hooks. Then, the traffic that is generated by local processes follows the output and postrouting path.
If you configure your Linux box to behave as a router, do not forget to enable forwarding via:
echo 1 > /proc/sys/net/ipv4/ip_forward
Then packets that are not addressed to your local system will be seen from the forward hook. Such forwarded packets follow the path: prerouting, forward and postrouting.
In a major change from iptables, which predefines chains at every hook (i.e. INPUT chain in filter table), nftables predefines no chains at all. You must must explicitly create a base chain at each hook at which you want to filter traffic.
Ingress hook
The ingress hook was added in Linux kernel 4.2. Unlike the other netfilter hooks, the ingress hook is attached to a particular network interface.
You can use nftables with the ingress hook to enforce very early filtering policies that take effect even before prerouting. Do note that at this very early stage, fragmented datagrams have not yet been reassembled. So, for example, matching ip saddr and daddr works for all ip packets, but matching L4 headers like udp dport works only for unfragmented packets, or the first fragment.
The ingress hook provides an alternative to tc ingress filtering. You still need tc for traffic shaping/queue management.
Hooks by family and chain type
Chain type | Hooks | ||||||
---|---|---|---|---|---|---|---|
ingress | prerouting | forward | input | output | postrouting | egress | |
inet | |||||||
filter | Yes | Yes | Yes | Yes | Yes | Yes | No |
nat | No | Yes | No | Yes | Yes | Yes | No |
route | No | No | No | No | Yes | No | No |
ip6 | |||||||
filter | No | Yes | Yes | Yes | Yes | Yes | No |
nat | No | Yes | No | Yes | Yes | Yes | No |
route | No | No | No | No | Yes | No | No |
ip | |||||||
filter | No | Yes | Yes | Yes | Yes | Yes | No |
nat | No | Yes | No | Yes | Yes | Yes | No |
route | No | No | No | No | Yes | No | No |
arp | |||||||
filter | No | No | No | Yes | Yes | No | No |
nat | No | No | No | No | No | No | No |
route | No | No | No | No | No | No | No |
bridge | |||||||
filter | No | Yes | Yes | Yes | Yes | Yes | No |
nat | No | No | No | No | No | No | No |
route | No | No | No | No | No | No | No |
netdev | |||||||
filter | Yes | No | No | No | No | No | No |
nat | No | No | No | No | No | No | No |
route | No | No | No | No | No | No | No |
Priority within hook
Within a given hook, Netfilter performs operations in order of increasing numerical priority. Each nftables base chain and flowtable is assigned a priority that defines its ordering among other base chains and flowtables and Netfilter internal operations at the same hook. For example, a chain on the prerouting hook with priority -300 will be placed before connection tracking operations.
The following table shows Netfilter priority values, check the nft manpage for reference.
nftables Families | Hooks | nft Keyword | Value | Netfilter Internal Priority | Description |
---|---|---|---|---|---|
prerouting | -450 | NF_IP_PRI_RAW_BEFORE_DEFRAG | |||
inet, ip, ip6 | prerouting | -400 | NF_IP_PRI_CONNTRACK_DEFRAG | Packet defragmentation / datagram reassembly | |
inet, ip, ip6 | all | raw | -300 | NF_IP_PRI_RAW | Traditional priority of the raw table placed before connection tracking operation |
-225 | NF_IP_PRI_SELINUX_FIRST | SELinux operations | |||
inet, ip, ip6 | prerouting, output | -200 | NF_IP_PRI_CONNTRACK | Connection tracking processes run early in prerouting and output hooks to associate packets with tracked connections. | |
inet, ip, ip6 | all | mangle | -150 | NF_IP_PRI_MANGLE | Mangle operation |
inet, ip, ip6 | prerouting | dstnat | -100 | NF_IP_PRI_NAT_DST | Destination NAT |
inet, ip, ip6, arp, netdev | all | filter | 0 | NF_IP_PRI_FILTER | Filtering operation, the filter table |
inet, ip, ip6 | all | security | 50 | NF_IP_PRI_SECURITY | Place of security table, where secmark can be set for example |
inet, ip, ip6 | postrouting | srcnat | 100 | NF_IP_PRI_NAT_SRC | Source NAT |
postrouting | 225 | NF_IP_PRI_SELINUX_LAST | SELinux at packet exit | ||
inet, ip, ip6 | postrouting | 300 | NF_IP_PRI_CONNTRACK_HELPER | Connection tracking helpers, which identify expected and related packets. | |
inet, ip, ip6 | input, postrouting | INT_MAX | NF_IP_PRI_CONNTRACK_CONFIRM | Connection tracking adds new tracked connections at final step in input & postrouting hooks. | |
bridge | prerouting | dstnat | -300 | NF_BR_PRI_NAT_DST_BRIDGED | |
bridge | all | filter | -200 | NF_BR_PRI_FILTER_BRIDGED | |
bridge | 0 | NF_BR_PRI_BRNF | |||
bridge | output | out | 100 | NF_BR_PRI_NAT_DST_OTHER | |
bridge | 200 | NF_BR_PRI_FILTER_OTHER | |||
bridge | postrouting | srcnat | 300 | NF_BR_PRI_NAT_SRC |
Starting with nftables 0.9.6 you may set priority using keywords instead of numbers. (Note that the same keyword maps to different numerical priorities in the bridge family vs. the other families.) You can also specify priority as an integral offset from a keyword, i.e. mangle - 5 is equivalent to numerical priority -155.
It's possible to specify keyword priorities even in family/hook combinations where they don't make logical sense. Recall that the relative numerical ordering of priorities within a given hook is all that matters as far as Netfilter is concerned. Keep in mind that this relative ordering includes packet defragmentation, connection tracking and other Netfilter operations as well as your nftables base chains and flowtables.