stats

Nftables

Linux's Programmable Packet Filter

A photograph of a dam

Nftables is a programmable packet filter for Linux in which the matching mechanism is implemented as virtual-machine subprograms compiled to pseudocode while the rule management tool is in use. It is a high-performance and highly flexible apparatus integrated with the Netfilter subsystem, useful not only for building firewalls, but also for translating addresses, classifying, counting, and routing traffic. Writing rules bears some resemblance to event-driven programming.

The first version of this article was written in 2015. The text retains its historical background, but the description of nftables, its examples, and its diagrams were updated in 2026 to reflect the contemporary nft tool and Linux kernel interfaces.

Introduction

A network firewall, also known as a firewall, is an active network component whose job is to filter traffic – that is, to manage the mutual visibility of network stations so that infrastructure or a system can be protected from intruders. There are hardware firewalls, but there are also software firewalls built into operating systems. The latter need not be less efficient than hardware devices, and they are often considerably more flexible to operate and offer more innovative features. Their disadvantage is the failure rate of devices composed of many components (computers), as well as the possibility that the system may be burdened by other workloads.

A firewall may operate at different layers of the ISO/OSI model. We therefore encounter firewalls that control traffic at the frame level (the data-link layer), at the IP level (the network layer), and at the level of TCP and UDP handling (the transport layer). More advanced devices, known as application firewalls, inspect packet contents and provide protection at the application layer (for example, for HTTP or SMTP). As a rule, however, all firewalls serve the same purpose: they control who may communicate with whom and in what manner.

In very broad and simplified terms, the data-link layer handles communication between one station and another over the same medium (for example, within an Ethernet segment); the network layer allows information to be exchanged between operating systems identified independently of the medium (for example, by IP addresses); and the transport layer identifies particular running programs within the communicating systems (for example, by port number).

The data-link layer resembles a delivery truck, the network layer a trailer carrying goods addressed to a particular destination, and the transport layer packages marked with apartment numbers that should reach the appropriate residents. The contents of a package belong to the layer of the specific application – the application layer.

The process of placing the contents of higher layers in the containers of lower layers is called encapsulation, while the reverse process is called decapsulation.

In the truck analogy, a firewall resembles someone who stops the vehicle and performs an inspection. Depending on that person’s competence and authority, the inspection may be limited to checking where the driver is going (the data-link layer), examining the route and the condition of the trailer (the network layer), checking particular packages (the transport layer), or even searching the contents of the shipments (the application layer).

History

Let us recall how packet filtering in the Linux kernel has evolved over the years.

Ipfwadm

Even before the 2.0 line, Linux included a simple packet-filtering mechanism. In the 2.0 kernel, its rules were controlled by a tool called ipfwadm (IP Firewall Administration). The appropriate support had to be enabled when configuring the kernel, but the filter itself was part of the kernel rather than an external patch.

With ipfwadm and the command of the same name, an administrator could establish rules in one of several predefined sets:

  • input (incoming packets),
  • output (packets leaving the system),
  • forwarding (packets forwarded between interfaces),
  • accounting (all packets subject to counting).

The firewall worked by matching each network packet against successive rules in the appropriate set, depending on whether the packet was generated locally, forwarded, or destined for the system. The filter recognized IP, TCP, UDP, and ICMP. It also allowed one of the following handling strategies to be applied:

  • accept the packet (accept),
  • reject the packet (reject),
  • ignore the packet (deny).

Ipfwadm also supported simple one-to-one or many-to-one source-address translation, known as address or subnet masquerading.

Consider a command that appends to the input rule set a rule blocking TCP packets sent from the station at 192.168.0.2 to port 80:

ipfwadm -I -a deny -P tcp -S 192.168.0.2 -D 0.0.0.0/0 80
ipfwadm -I -a deny -P tcp -S 192.168.0.2 -D 0.0.0.0/0 80

The -a option with the value deny specifies the so-called rule target, while the protocol, addresses, and port number are the match criteria. The same or similar terms appear in all firewalls.

The criteria available to this firewall included addresses, port numbers, protocols, network interface names, and certain packet-header flags. If an administrator wanted to enable port forwarding, they had to use either the ipautofw tool running in user space or ipportfw, which relied on kernel mechanisms.

Ipchains

The arrival of the 2.2 kernel line brought an improved traffic-control mechanism called ipchains (Linux IP Firewalling Chains). It was based on ipfwadm code, with improvements to maximum packet-counter values and the filtering of malformed or malicious headers. It also introduced support for more network protocols and inverse rule matching. The division into sets remained unchanged, but those sets were now called chains.

A tree-shaped rule structure was new. Ipfwadm offered several sets to which filtering rules could be added, while ipchains made it possible to create custom sets – hence the change in terminology. Reusable groups of filters could be placed in separate namespaces (user-defined chains), after which rules in the built-in chains (such as input, output, and forward) could send part of the traffic to one of those user-defined chains for further processing.

Because new rule chains could be added, their identifiers could also be used as targets. Instead of accept or reject, the target of a rule could transfer a packet to an administrator-defined chain. A return target was also added; it returns control to the parent chain from which the matching packet was sent. The masq and redirect targets were introduced to support IP masquerading and a transparent proxy.

It is worth noting that ipchains itself also added a replace operation, which made it possible to replace a rule without first deleting and then re-adding it.

Netfilter and iptables

The 2.4 kernel series brought something of a breakthrough in network handling. The kernel gained the Netfilter subsystem – the first traffic classifier closely integrated with other networking components and equipped with a unified interface for controlling traffic-management mechanisms. This close integration made much more flexible and precise control strategies possible.

Once Netfilter was ready, the iptables (IP Tables) tool – still in use today – appeared for controlling packet-filter and Network Address Translation (NAT) settings. A firewall managed with this software requires the appropriate kernel modules, such as x_tables and ip_tables. Filters added to the kernel later are managed with additional programs: ip6tables for IPv6, arptables for ARP traffic, and ebtables for filtering at the network-bridge level.

Netfilter introduced the following improvements over the preceding filtering code:

  • stateful inspection at the protocol level (IPv4 and IPv6) and application level (IPv4);

  • port forwarding without services running in user space;

  • complete NAT support (one-to-one and one-to-many);

  • integration with the Quality of Service (QoS) subsystem;

  • integration with IP sets, which store IP addresses in efficient data structures.

Beyond the built-in input, output, and forward rule chains, the iptables subsystem introduced prerouting and postrouting. The first is examined before a routing decision is made (or the packet is recognized as destined for a local process), while the second is examined after that decision, when the packet is about to leave the system. This is made possible by hooks. Hooks allow other kernel modules – for example, x_tables and ip_tables, or nf_tables – to register functions with Netfilter to which datagrams are sent at different stages of packet and frame processing.

Iptables tables

In iptables, rule chains are not the highest level of abstraction; they belong to tables. These are collections of chains that control different firewall functions – for example, one table handles address translation (NAT), while another handles filtering.

Tables do not come from Netfilter itself. They are the way iptables organizes rules to reflect the respective stages of a packet’s journey through the networking stack. Each table contains certain built-in chains to which packets arrive from previously registered hooks. Tables should not be imagined as individual transit points: a packet may visit several of them more than once, although on successive visits it enters different built-in chains.

Flow paths

Although tables and their rule chains are not intrinsic to Netfilter, they make it easier to understand exactly how packets are classified. An example diagram by Jan Engelhardt, showing the path a packet takes through successive parts of the network-handling mechanism, is available on Wikimedia Commons and by clicking the image below.

Packet-flow paths through the Netfilter subsystem of the Linux kernel

Packet-flow paths through the Netfilter subsystem of the Linux kernel

Let us recall the functions of the individual iptables tables and the built-in chains to which network packets are directed through Netfilter hooks:

  • the raw table:
    • chains: prerouting, output;
    • purpose: very early processing, primarily disabling tracking for selected packets and setting parameters of the conntrack mechanism;
  • the filter table:
    • chains: input, forward, output;
    • purpose: filtering network traffic;
  • the nat table:
    • chains: prerouting, output, postrouting;
    • purpose: address translation (NAT);
  • the mangle table:
    • chains: prerouting, input, forward, output, postrouting;
    • purpose: modifying packets;
  • the security table:
    • chains: input, forward, output;
    • purpose: integration with Mandatory Access Control (MAC) mechanisms such as SELinux.

Connection tracking and stateful inspection

Because Netfilter includes a connection tracking module, every examined packet may be marked with one of several abstract states inferred from the observed flow:

  • new – a valid beginning of communication has been seen, so far in one direction only;
  • established – valid traffic has been seen in both directions;
  • related – a connection is expected on the basis of another connection that was tracked earlier;
  • invalid – the packet does not match the expected behavior of the tracked flow;
  • untracked – the packet was explicitly excluded from tracking.

Connection tracking and the marking of packets passing through rule sets allow an administrator to use state-based decision criteria.

Packets are assigned states immediately after processing in the prerouting chain of the raw table. This is also where special rules may influence which tracking modules are used in particular cases. In practice, connection tracking relies not only on information from transport-layer headers, such as TCP headers, but also on application data carried in packets.

FTP is an example in which transport-layer headers alone are insufficient. An FTP session uses two TCP connections: one for issuing commands and another for transferring files. Establishing a connection to port 21 and sending a file-download request causes the server to tell the client which port it must connect to in order to retrieve the data. To track that newly established connection and assign its packets the related state, the firewall must somehow inspect the application-layer message – the dialog between client and server – and use the detected text string containing the port number to create an entry in the connection-tracking table. A helper module makes this possible. In nftables, one should not assume that such a helper will be assigned automatically on the basis of a port number. The administrator defines a ct helper object and assigns it explicitly with ct helper set. Rules that permit related traffic should also constrain the destination address so that the helper does not open an unintended port-forwarding path.

Targets

The Netfilter-based iptables tool supports a larger collection of rule targets than its predecessors. The basic set is as follows:

  • accept – accept the packet;
  • reject – reject the packet and inform the other party;
  • drop – block the packet (formerly deny);
  • queue – pass the packet to a user-space process;
  • return – return to the parent chain.

In addition to those listed above, there are targets specific to particular tables and chains, such as log, mark, and mirror, but we will not discuss them here.

Nftables

Nftables (Netfilter Tables) is a mechanism for managing packet classification and processing in the Linux kernel and the successor to iptables. The project was started in 2008 by Patrick McHardy. As its name suggests, nftables also uses the Netfilter subsystem and also organizes its rules in tables. Its firewall code was written from scratch and is not based on iptables, although the organization of rules into chains and tables was retained.

Components

Nftables consists of several components:

  • in-kernel processing subprograms;
  • the libmnl library, which handles communication through Netlink sockets;
  • the libnftnl library, which exposes the nftables API through libmnl;
  • the libnftables library, which provides a high-level interface including a JSON representation;
  • user-space software – the nft command – for managing rules.

The first kernel release to include nftables appeared in 2014. Today the required libraries and the nft tool are available in the main repositories of GNU/Linux distributions. Building them yourself is necessary mainly when developing the software or using features newer than those offered by your distribution.

Similarities and differences

How does nftables differ from iptables, in brief? The in-kernel Application Binary Interface (ABI) was simplified, the code was made leaner (some fragments were simply duplicated in iptables), error reporting was improved, and an entirely new way of expressing and processing rules was introduced.

Instead of iptables, ebtables, arptables, and ip6tables, there is one command that controls the filters, while the kernel code remains independent of protocols and layers.

As in iptables, rule chains are still placed in tables, but there are no built-in chains permanently attached to Netfilter. An administrator of an nftables firewall may create arbitrary tables and then place arbitrary chains in them. Those chains may – but need not – be associated with selected points along the packet-flow paths.

Generic criteria

Nftables introduces a virtual machine into the kernel that executes pseudocode received from user space. The pseudocode is sent over a Netlink socket by the nft tool after the entered rules have been interpreted and compiled. This makes it easier to add new traffic-filtering functions and strategies: the additional abstraction layer eliminates rigid rule-storage structures.

Using a virtual machine reduces the need to create separate rule structures for every combination of protocol and criterion. It does not eliminate kernel extensions, however: reading genuinely new data or performing a new operation may still require the addition of an appropriate expression or module. The in-kernel code responsible for examining packet-matching criteria is simpler than in earlier mechanisms such as iptables and ipchains. It can read packet payloads, header information, and metadata associated with a packet – such as input and output interfaces or connection-tracking state – while arithmetic, bitwise, and comparison operators allow more sophisticated filters to be assembled from that information.

The virtual machine allows the required operations to be composed without the overhead of passing through unused extension classes. It does not, however, remove the cost of linearly traversing a long chain. That is precisely why sets, maps, and concatenations are such important parts of nftables: they can replace many similar rules with a single lookup.

The virtual-machine approach saves developers’ time and gives administrators flexibility. It was inspired by the Berkeley Packet Filter (BPF) familiar from BSD systems.

During the project’s early years, critics argued that the authors of nftables could have used the existing BPF engine. That discussion concerned the classic BPF of the time and should not be mapped directly onto contemporary eBPF and XDP. Nftables is a stateful Netfilter policy engine integrated with mechanisms such as connection tracking and NAT; eBPF is a more general apparatus for executing verified programs at various points in the kernel. The mechanisms may complement one another rather than merely compete.

An operational example

Consider this simplified diagram of the principal network-traffic paths:

A simplified and updated diagram of packet-flow paths through the Netfilter subsystem, showing hook and chain-type names

A simplified and updated diagram of packet-flow paths through the Netfilter subsystem, showing hook and chain-type names

The names prerouting, input, forward, output, and postrouting denote Netfilter hooks. The colored boxes, by contrast, show the chain type and its customary priority. These are two separate configuration axes: raw, mangle, filter, dstnat, and srcnat are not chain types, but symbolic priority names. The route type makes sense only at the output hook, while a nat chain sees only the first packet of a flow. The position of the route box in the diagram does not assign it a fixed priority – that value is chosen by the administrator.

In nftables, tables are not tied to processing stages. They group chains and other objects associated with a selected protocol family. Base chains and their hooks are created explicitly. The diagram does not mean that every chain shown exists in every configuration; it presents the places where an administrator may put such chains and the customary ordering produced by their priorities.

The next diagram presents the same path from another perspective. It shows which hooks are visited by the three basic traffic classes and which customary priority slots may be occupied within each hook:

Hooks and customary priority slots visited by local, forwarded, and outgoing traffic

Hooks and customary priority slots visited by local, forwarded, and outgoing traffic

The paths can also be written without a diagram:

  • traffic to a local process: ingress → prerouting → routing decision → input;
  • forwarded traffic: ingress → prerouting → routing decision → forward → postrouting → egress;
  • locally generated traffic: output → possible new routing decision → postrouting → egress.

A packet therefore visits a hook, not a table. A table is a namespace for ruleset objects. Multiple base chains may run at one hook, and their order follows their priorities. The values shown are standard reference points, but an administrator may also use intermediate values.

Let us follow the fate of a hypothetical network packet through the diagram. Assume that our system acts only as a transit point – a router – and that the packet’s destination is a web server in a service subnet. Assume also that servers in this subnet use private IP addresses and that our firewall must perform destination-address translation. The input (public) interface is eth0, and the output interface connected to the services is eth1.

This example is fairly universal and helps explain how firewalls using the Netfilter subsystem work:

  1. A frame addressed to the network card arrives on eth0. It contains an IP packet carrying TCP data that requests a connection (the SYN flag is set).

  2. The data-link-layer handler reserves an appropriate structure for processing the frame.

  3. The frame – or, more precisely, the structure representing it – is passed to the QoS subsystem (the ingress queue of the qdisc class). If a netdev ingress or inet ingress chain has been configured, the packet is then processed at that hook, before the network-layer protocol is handled.

  4. The system determines whether the frame should be sent to a bridge interface and forwarded to another segment. Since that is not the case here, frame handling ends and its contents are decapsulated. The IP packet inside is passed to the network-layer handler.

  5. The network-layer handler reserves an appropriate structure and places the IP packet in it.

  6. Packet data is matched against rules in a filter chain at the prerouting hook with a low priority value (the equivalent of the raw table in iptables). Here an administrator may establish a rule that disables stateful inspection for packets with certain properties or assigns them to a selected tracking zone.

  7. If the packet has not been rejected or ignored, it reaches the conntrack subsystem. There, on the basis of its header and data and a comparison with the system connection table, it is marked appropriately, and an entry in that table is created or updated. Any control marks set earlier are taken into account.

  8. The packet may enter a filter chain at the prerouting hook with a priority corresponding to the mangle stage, where it may be marked or modified if the rules say so.

  9. The packet enters a nat chain at the prerouting hook, where its destination address may be changed. A Destination Network Address Translation (DNAT) rule replaces the packet’s public IP address with the private address assigned to the web server in the protected subnet. An appropriate mapping is also maintained in the system so that NAT can modify packets that form replies to the transformed traffic.

  10. After the conntrack lookup, the packet may reach a filter chain at the filter priority. This is where a ct helper object can be assigned explicitly – for example, a helper that analyzes an FTP control connection.

  11. A routing decision is made using the system’s routing tables. The handler determines that the packet is not destined for the local station and must be forwarded through another network interface.

  12. The packet may enter a filter chain at the forward hook with the mangle priority, where it may be marked or modified.

  13. The packet enters a filter chain at the forward hook, where the protective rules reside.

  14. The packet may enter a filter chain at the postrouting hook with the mangle priority, where it may be marked or modified.

  15. The packet enters a nat chain at the postrouting hook, where Source Network Address Translation (SNAT) may be performed. It matches no rule, so NAT is not applied.

  16. The packet reaches the XFRM policy handler, which is responsible for transforming datagrams. Content and headers may be changed here, for example when the Internet Protocol Security (IPsec) suite is in use. Since the system has no XFRM policies, the packet is passed on unchanged.

  17. The packet is encapsulated in a frame addressed to the network station that hosts the web server.

  18. If a netdev egress chain has been configured, the packet is processed there after network-layer handling but before the egress queue of the QoS qdisc class. The frame then enters that queue.

  19. The frame reaches the eth1 network interface and is transmitted through the medium to the destination station.

Architecture

The most general structures in nftables – those that contain the others – are tables. They hold rule chains, sets, maps, flowtables, and stateful objects. We will discuss sets later; for now, it is worth noting that rule chains do not differ in purpose from those known from iptables or ipchains: they allow rules to be grouped.

Through hooks, network packets from the Netfilter subsystem enter chains selected by the administrator. Within a chain, every successive rule processes a packet until a decision is made that it should no longer be examined.

Rules test whether packets can be matched against criteria contained in match expressions. When a match succeeds, the rule’s statements are executed. There are several kinds of statements, the most common of which decide what happens to the packet next. Such decisions are also called verdicts, and their symbolic forms are known as verdict statements.

The architecture of nftables in the context of Netfilter packet-flow paths and hooks

The architecture of nftables in the context of Netfilter packet-flow paths and hooks

The left side of the diagram shows protocol families, the hooks available to them, and the three base-chain types. Not every combination is valid: route works only with the output hook, while nat is intended for hooks associated with address translation.

The right side shows the ruleset data model. A table belongs to one family and forms a namespace for chains, sets, maps, flowtables, and stateful objects. The lower part is a reminder that a rule is a small program: it examines a packet with expressions, executes statements, and may issue a verdict or pass control onward.

Unlike iptables, nftables does not create tables named filter, nat, or mangle in advance, nor does it create built-in chains. Table and chain names belong to the administrator; the family, hook, and priority determine where execution takes place.

Tables

A table is a container for rule chains, sets, maps, flowtables, and stateful objects. It has a name and an assigned protocol family. The distinction between protocol families is necessary because they use different forms of addressing, permit different tests, and expose different Netfilter hooks.

The available protocol families are:

  • ip – Internet Protocol version 4 (IPv4);

  • ip6 – Internet Protocol version 6 (IPv6);

  • inet – the Internet Protocol family combining IPv4 and IPv6;

  • arp – the Address Resolution Protocol (ARP);

  • bridge – protocols associated with network bridges;

  • netdev – traffic handling immediately at the network interface, before a packet enters the ordinary networking-stack path or while it is leaving that path.

Rule chains

A rule chain is a structure containing an ordered sequence of rules that examine passing packets. There are two kinds of chains:

  • regular chains;
  • base chains.

Regular chains can be used to organize rules more clearly. Packets may be sent to them with the jump verdict statement.

Base chains capture packets at selected points in the Netfilter flow path. When creating one, the administrator specifies:

  • the chain type, which may be:

    • filter – a chain that filters packets;
    • nat – a chain for Network Address Translation (NAT); only the first packet of a flow passes through it, while subsequent packets use the recorded binding, so filtering rules should not be placed there;
    • route – a chain whose changes to a packet may cause its route to be recalculated; this type is available only with the output hook;
  • the hook, which determines where the chain is attached to Netfilter:

    • prerouting – packets before a routing decision is made (all packets entering the system);
    • input – packets destined for this system;
    • forward – packets destined for another system, for which this one acts as a router;
    • output – packets originating from this system;
    • postrouting – packets after the routing decision has been made (all packets leaving the system);
  • the priority – an integer or symbolic name that determines the order in which chains attached to the same hook execute. Priority is part of a base-chain declaration; if two chains have the same value, their relative order is undefined.

Tables in the ARP family can use the input and output hooks. The bridge family exposes prerouting, input, forward, output, and postrouting, while netdev exposes ingress and egress. Since kernel 5.10, the inet family has additionally exposed ingress, which runs at the same point as netdev ingress but allows sets and maps to be shared with other inet chains.

The distinction between verdicts also matters. Drop ends Netfilter processing for the packet. Accept ends the current base chain, but does not guarantee that a later chain attached to the same hook with a higher priority will not drop the packet.

Data types

Parameters in chain rules are expressed with data types understood by nftables. During compilation, their symbolic representations are converted into the appropriate pseudocode structures.

Most typed in-memory objects have a fixed size, although memory is allocated dynamically for some types, such as strings.

Basic types

Data types allow the nft tool to validate values, translate symbols, and encode the result as low-level Netlink objects and attributes. The set of types grows as support for additional protocols and metadata is introduced, so the following list is deliberately representative rather than exhaustive:

Area Example types What they describe
general values integer, bitmask, string numbers, bit masks, and strings
date and time time, day, hour instants, relative time, and calendar components
addresses and data-link layer ipv4_addr, ipv6_addr, ether_addr, lladdr, ether_type network- and data-link-layer addresses and the carried protocol type
protocols and services nf_proto, inet_proto, inet_service network families, transport-layer protocols, and service numbers
interfaces and devices iface_index, ifname, iface_type, ifkind, devgroup_type interface indexes, names, kinds, and groups
system, routing, and QoS uid, gid, mark, realm, tc_handle, pkt_type socket owners, marks, routing realms, priorities, and packet types
protocol fields tcp_flag, icmp_type, icmp_code, icmpv6_type, icmpv6_code, arp_op, dccp_pkttype symbolic values of protocol header fields and messages
connection tracking ct_state, ct_dir, ct_status, ct_event, ct_label, ct_id the state, direction, status, events, labels, and identifiers of conntrack entries
control flow verdict decisions such as accept, jump, and return

This division is a functional guide, not a hierarchy of internal classes or structures. Some types are based on others – ct_state, for example, is a bit mask, while ipv4_addr is an integer of fixed width – but they retain their own parsing rules, symbolic names, and compatibility checks.

A host name may be resolved by the tool while rules are loaded, but this does not create a dynamic association with DNS. Concrete addresses obtained at that moment enter the active ruleset. Rules intended to behave deterministically should therefore use addresses or explicitly managed sets.

A set or map definition may name a type directly or use typeof to derive it from an expression, such as typeof ip saddr. The nft describe command shows details about an expression and its type, for example:

nft describe ip saddr
nft describe meta iifname
nft describe ip saddr nft describe meta iifname

Sets and maps

Nftables provides efficient data structures for storing information: sets and maps. They are not data types, but ruleset objects parameterized by an element type or by a key-value type pair. When creating them, one must specify the kinds of values they will hold.

Sets

Sets are collections of elements that store and look up information such as addresses, port numbers, and interface names. That information can then be used as match criteria or as statement parameters.

The kernel chooses a set implementation according to the set’s properties. The administrator describes the required behavior with its type, flags, and an optional performance or memory policy instead of selecting a particular tree or hash-table implementation.

There are anonymous sets and named sets. Anonymous sets are embedded in a rule, as in tcp dport { 22, 443 }, and cannot be referenced by other rules. They are immutable and disappear with the rule. A named set has its own identity, may be shared, and may be updated independently:

set good-addresses {
    type ipv4_addr;
    elements = { 192.168.0.1, 172.30.0.5 }
}
set good-addresses { type ipv4_addr; elements = { 192.168.0.1, 172.30.0.5 } }

Sets may store many of the data types supported by nftables. Concatenations such as ipv4_addr . inet_service are also possible, allowing a single element to represent an address-port pair.

Maps

Maps associate keys with values. They are a natural extension of sets: instead of answering only whether a key exists, they return the corresponding value. The map below determines a mark from the destination port:

map service-marks {
    type inet_service : mark;
    elements = { 22 : 0x1, 443 : 0x2 }
}
map service-marks { type inet_service : mark; elements = { 22 : 0x1, 443 : 0x2 } }

It can be used in a rule as follows:

meta mark set tcp dport map @service-marks
meta mark set tcp dport map @service-marks

Maps may be named, as above, or anonymous and embedded directly in an expression.

Verdict maps

A verdict map, or vmap, is a map whose values are verdicts. It can be thought of as a dictionary that directs processing into the appropriate branch:

meta l4proto vmap {
    tcp : jump handle-tcp,
    udp : jump handle-udp
}
meta l4proto vmap { tcp : jump handle-tcp, udp : jump handle-udp }

A named map has the value type verdict and is referenced with vmap @name. An anonymous map such as the one above is part of a rule; it is not a separate unnamed object.

Intervals (ranges)

Intervals express ranges of values. They use the notation value-value and may appear in sets, maps, and directly in rules:

set local-networks {
    type ipv4_addr;
    flags interval;
    auto-merge;
    elements = { 192.168.0.0/24, 172.30.0.0/16 }
}
set local-networks { type ipv4_addr; flags interval; auto-merge; elements = { 192.168.0.0/24, 172.30.0.0/16 } }

Overlapping intervals do not establish a “most specific range wins” rule. Without auto-merge, a conflict is rejected. In a set with auto-merge enabled, compatible adjacent or overlapping ranges may be combined. In a map, ranges leading to different values may not overlap ambiguously.

Dynamic sets

A named set may have a size limit, a default timeout, and a separate timeout for each element. The timeout flag allows the kernel to remove expired elements, while the add and update statements allow the set to be updated from the packet path:

set temporarily-blocked {
    type ipv4_addr;
    flags timeout;
    timeout 10m;
    size 65535;
}

ip saddr 192.0.2.0/24 update @temporarily-blocked { ip saddr timeout 10m }
set temporarily-blocked { type ipv4_addr; flags timeout; timeout 10m; size 65535; } ip saddr 192.0.2.0/24 update @temporarily-blocked { ip saddr timeout 10m }

Such a set is firewall state, not merely a compact notation for a constant list. Its size and element lifetime should be bounded because its data may originate directly from the packet path.

Stateful objects

Tables may also contain stateful objects with names that allow several rules to share the same state. The simplest examples are counters, limits, and quotas. A counter statement placed directly in a rule maintains state local to that rule, while counter name dropped refers to a named object in the table.

Stateful objects also include connection-tracking configurations: ct helper, ct timeout, and ct expectation. An FTP helper can, for example, be defined and then assigned explicitly to a control connection:

ct helper ftp-standard {
    type "ftp" protocol tcp;
}

chain helpers {
    type filter hook prerouting priority filter;

    ip daddr 192.0.2.10 tcp dport 21 ct helper set "ftp-standard"
}
ct helper ftp-standard { type "ftp" protocol tcp; } chain helpers { type filter hook prerouting priority filter; ip daddr 192.0.2.10 tcp dport 21 ct helper set "ftp-standard" }

Assigning the helper does not itself permit traffic. Filtering rules must still explicitly accept the control connection and the expected related traffic.

Rules

Rules in nftables consist of expressions and statements. Expressions read or calculate values, while statements perform actions. If the packet being examined has properties that match the criteria, the rule’s successive statements execute, and one of them may end further processing.

Expressions

As their name suggests, expressions express values. Those values may be constant, such as network addresses and port numbers, or calculated – for example, from data obtained earlier while examining a packet or from kernel information concerning routing or connection tracking. Every constant expression has a known data type, as does every expression whose value has already been calculated.

Expressions are used primarily in rules to construct packet match criteria, but they are also used to refine statements, for example when parameterizing address translation.

Expressions may be composed of other expressions joined by suitable operators, forming combined expressions.

For the rest of this discussion, we can use the following classification:

  • primary expressions, describing a single value:

    • constant expressions – addresses, ports, numbers, masks, and symbolic names;
    • nonconstant expressions, whose values are read while processing a packet:
      • metadata expressions – kernel information not stored directly in the packet;
      • payload expressions – fields in protocol headers;
      • connection-tracking expressions – data from the conntrack subsystem;
  • combined expressions, built from other expressions:

    • bitwise operations;
    • prefixes;
    • ranges;
    • lists;
    • concatenations;
  • relational expressions, which ask how values relate to one another:

    • basic comparisons;
    • flag matching.

This is a teaching classification, not a closed parser hierarchy. Its branches overlap in places: a payload expression may form part of a concatenation, and the whole concatenation may be one side of a comparison. Contemporary nftables also contains specialized expressions concerning routing, sockets, FIB lookups, number generation, hashing, and operating-system identification from TCP-stack characteristics.

Primary expressions

Constant expressions

Constant expressions are immutable values, such as the address 192.168.0.1, port 443, state established, or interface name "eth0". Symbols are translated in user space when rules are loaded.

Nonconstant expressions

Metadata expressions

Metadata expressions read information associated with a packet but not necessarily stored in its header. The following table lists the parameters used most often:

Expression Result type Meaning
meta length integer (32 bits) packet length in bytes
meta nfproto integer (32 bits) the actual protocol family, useful in an inet table
meta l4proto integer (8 bits) the transport-layer protocol after skipping IPv6 extension headers
meta protocol ether_type the type of protocol carried in a frame
meta mark mark packet mark
meta iif, meta oif iface_index input or output interface index
meta iifname, meta oifname ifname input or output interface name
meta skuid, meta skgid uid, gid owner of the socket from which a local packet originated
meta pkttype pkt_type packet type, such as host, broadcast, or multicast

An interface index and an interface name are not equivalent. A rule using iif or oif can be added only when the interface exists, but remains associated with the same device after it is renamed. iifname and oifname match a name, so they also work in rules prepared before a dynamic interface is created, but stop matching when it is renamed.

The word meta may be omitted where the remainder of an expression is unambiguous, although the explicit form can be easier to read.

Payload expressions

Payload expressions read header fields. The protocol and field name form a natural pair, as in ip saddr, ip6 daddr, tcp dport, udp length, ether saddr, and vlan id.

Expression Result type Meaning
arp operation arp_op ARP operation, such as request or reply
ether saddr, ether daddr ether_addr source or destination Ethernet address
ether type ether_type the type of protocol carried in a frame
ip saddr, ip daddr ipv4_addr source or destination IPv4 address
ip dscp, ip ecn dscp, ecn Differentiated Services and Explicit Congestion Notification fields
ip6 saddr, ip6 daddr ipv6_addr source or destination IPv6 address
ip6 nexthdr inet_proto protocol of the immediately following IPv6 header
tcp sport, tcp dport inet_service source or destination TCP port
tcp flags tcp_flag TCP flags such as syn, ack, or rst
udp sport, udp dport inet_service source or destination UDP port
vlan id integer (12 bits) VLAN identifier

ip6 nexthdr should not be understood to mean “any transport protocol carried by IPv6.” It identifies the immediately following header, which may itself be an extension header. meta l4proto traverses common extension headers and is usually better for distinguishing TCP, UDP, and ICMPv6.

Connection-tracking expressions

Conntrack expressions expose information including state, direction, status, marks, labels, time to expiration, and the tuples in both directions of a connection:

Expression Result type Meaning
ct state ct_state connection state, such as new, established, related, or invalid
ct direction ct_dir packet direction relative to the connection: original or reply
ct status ct_status status flags of the connection-tracking entry
ct mark mark connection mark
ct expiration time time remaining until the entry expires
ct helper string associated conntrack helper module
ct original l3proto, ct reply l3proto nf_proto network-layer protocol for the selected direction
ct original ip saddr, ct reply ip daddr ipv4_addr IPv4 address from the selected direction’s tuple
ct original ip6 saddr, ct reply ip6 daddr ipv6_addr IPv6 address from the selected direction’s tuple
ct original protocol, ct reply protocol inet_proto transport-layer protocol for the selected direction
ct original proto-src, ct reply proto-dst integer (16 bits) port or another transport-layer identifier
ct packets, ct original bytes, ct reply avgpkt integer (64 bits) counters for one direction or their sum
ct zone, ct original zone, ct reply zone integer (16 bits) conntrack zone
ct count, ct id integer (32 bits), ct_id number of current connections or the entry identifier

The most common example is:

ct state established,related accept
ct state established,related accept

The complete set of parameters depends on the versions of the tool and kernel. Here, too, the most reliable documentation for a local installation is nft describe, for example nft describe ct state.

Combined expressions

As their name says, combined expressions consist of other expressions and operations that give them computational meaning.

Bitwise expressions

Bitwise expressions perform operations on individual bits of the values produced by their operands. They consist of an operator and two operands whose values should have numeric types:

OperatorMeaning
&bitwise conjunction
(logical product, AND operation)
|bitwise disjunction
(logical sum, OR operation)
^bitwise symmetric difference
(logical exclusive disjunction, XOR operation)

Prefix expressions

Prefix expressions make it possible to write network prefixes, among other things. They consist of two arguments separated by a slash (/). The first argument should be an address or numeric value, while the second should be an integer specifying the number of significant bits in the first – for example, the bits retained when calculating the network part of an IP address.

Range expressions

Range expressions are implemented with the intervals discussed alongside sets and maps. They consist of two numeric arguments – or expressions that evaluate to a numeric type – separated by a hyphen (-).

List expressions

List expressions, also called expression lists, are sequences of expressions separated by commas (,). The meaning of such a list depends on the type. For a bit mask, tcp flags syn,ack matches when syn, ack, or both flags are set; other bits are ignored. This is not the same as looking up a value in a set: tcp flags { syn, ack } matches only a packet with syn alone or ack alone.

When the listed bits are mutually exclusive, both forms may produce the same result. That is why ct state established,related works intuitively as a match for either of the two states.

Concatenation expressions

Concatenation expressions combine the values of two or more expressions into a single sequence. This is useful when constructing keys for sets that represent multidimensional structures or when matching adjacent header fields.

A concatenation expression is formed from two or more expressions separated by a period (.).

Relational expressions

Relational expressions, also known as match expressions, test relationships between values. They allow actions to be conditional – for example, to occur when an examined packet meets specified criteria.

There are two kinds of match expressions:

  • basic relational expressions;
  • flag comparisons.

Basic relational expressions

A basic relational expression uses an operator to state the relationship between expressions on its left and right sides:

OperatorMeaning
==equal
!=not equal
<less than
<=less than or equal
>greater than
>=greater than or equal

If no operator is given, == is assumed.

When the expression on the right is a set, it is searched for the specified element. The same principle applies when the right side is a range (an interval).

Flag comparisons

The second kind of match expression compares flags. Flags are single-bit elements that may represent logical truth or falsehood. Packet and frame structures combine various flags into one-byte or even multibyte sequences. Although such structures can be represented numerically as integers, they are really collections of parameters whose individual meanings depend on their positions in the sequence.

To determine whether all selected flags are set, the remaining bits must be masked out and the result compared with the expected pattern. The notation on the left side of the slash gives the expected value, and that on the right gives the mask:

tcp flags syn,ack / syn,ack
tcp flags syn,ack / syn,ack

Symbols such as syn, ack, established, and related avoid the need to use numeric mask values. One must nevertheless distinguish a single-bit test, a test for at least one bit from a list, a test for all selected bits, and a lookup of the whole value in a set.

Statements and verdicts

Because nftables rules are small pseudoprograms rather than records with a fixed structure, a packet that meets specified criteria can be subjected to more than one action without creating extra chains or separate rules. Expressions read data and construct criteria, while statements perform actions such as counting, reporting, setting a mark, or controlling subsequent processing. This distinction exists in the nft language even though, after compilation, both kinds of constructs become low-level instructions for the kernel’s virtual machine.

Some statements determine the fate of a packet. These decisions are called verdicts, and the constructs expressing them are called verdict statements.

The following are some of the statements used most often; the list is not exhaustive:

  • decisions (verdicts):

    • accept – accept the packet;
    • drop – block the packet;
    • continue – continue with the next rule;
    • return – return the packet to the parent chain;
    • jump – call the specified chain with the possibility of returning;
    • goto – proceed to the specified chain without remembering a return point;
  • rejection with a response:

    • reject – terminate processing and reject the packet while informing the sender; it is a terminal statement, but not a verdict that can, for example, be used as a value in a verdict map;
  • address translation:

    • snat – translate the packet’s source address (SNAT);
    • dnat – translate the packet’s destination address (DNAT);
    • masquerade – perform SNAT using the output interface’s address;
    • redirect – redirect traffic to the local station;
  • modification:

    • meta mark – set the packet mark;
    • meta priority – set the priority (QoS classification);
    • meta nftrace – enable path tracing within nf_tables;
  • rate-based conditioning:

    • limit rate – match using a token-bucket mechanism; by itself it neither queues nor drops packets, but conditions the execution of subsequent statements;
  • reporting:

    • log – report the packet to the event-logging subsystem;
  • counting:

    • counter – count packets (optional in nftables).

Statements may decide a packet’s fate, but they may also change firewall or packet state. A practical example is the need to report and mark packets at the same time: in nftables, both are done by one rule.

Some nftables rule statements can be parameterized, and their parameters may be determined dynamically from data obtained while examining a packet or by reading kernel-maintained structures such as connection-tracking tables. In practice, this allows network traffic to be managed with exceptional flexibility.

Contemporary practice

For a typical workstation or server firewall, the inet family is a useful starting point because it handles IPv4 and IPv6 together. This does not mean that every expression applies to both protocols: ip saddr still concerns IPv4, while ip6 saddr concerns IPv6. Chains, conntrack states, ports, and much metadata can, however, be shared.

Rules are best kept in a file and loaded as one transaction. The command:

nft -c -f /etc/nftables.conf
nft -c -f /etc/nftables.conf

checks the whole file without applying changes. Removing -c loads it atomically. An error in one command rejects the entire transaction. When working over SSH, keep an additional recovery channel or arrange an automatic return to the previous rules, because valid syntax does not guarantee continued administrative access.

Useful contemporary mechanisms include:

  • named sets and maps, including ones with timeouts and updates from the packet path;
  • concatenations, which allow one lookup to match, for example, an address, protocol, and port;
  • rule handles, visible with nft -a list ruleset, which allow a rule to be removed or replaced precisely;
  • tracing, which can be enabled with meta nftrace set 1 and observed with nft monitor trace;
  • inspection of active hooks with nft list hooks, which shows the actual order of chains and kernel functions such as conntrack and NAT;
  • flowtables, which provide a fast path for established flows;
  • libnftables and its JSON representation, which allow programs to manage rules without parsing the textual output of nft.

In one system, nft, the compatibility commands provided by iptables-nft, managers such as firewalld, and container software often meet. Technically, they may create separate tables and chains, but they should not manage the same part of a ruleset without coordination. Table names do not establish separate firewalls: the final result depends on all chains attached to a given hook, their priorities, and their verdicts.

Summary

A complete example file

The small ruleset below does not block traffic: it retains an accept policy, counts new connections from outside the local network, and marks packets originating from two specified addresses. It uses the inet family shared by IPv4 and IPv6, although both address matches deliberately concern IPv4 only:

An example nftables file
table inet ours {
    set good-addresses {
        type ipv4_addr;
        elements = { 192.168.0.1, 172.30.0.5 }
    }

    chain input {
        type filter hook input priority filter; policy accept;

        ct state new ip saddr != 192.168.0.0/24 counter
        ip saddr @good-addresses meta mark set 31337
    }
}
table inet ours { set good-addresses { type ipv4_addr; elements = { 192.168.0.1, 172.30.0.5 } } chain input { type filter hook input priority filter; policy accept; ct state new ip saddr != 192.168.0.0/24 counter ip saddr @good-addresses meta mark set 31337 } }

After saving the file as /tmp/ours.nft, it can first be checked and then loaded:

nft -c -f /tmp/ours.nft
nft -f /tmp/ours.nft
nft -a list table inet ours
nft -c -f /tmp/ours.nft nft -f /tmp/ours.nft nft -a list table inet ours

The example deliberately omits flush ruleset. That command is appropriate only when the file is the sole owner of the entire nftables configuration; otherwise, it would also remove rules created by other tools.

See also:

Current section: PUB
Categories: