nftables
nftables is a netfilter project that aims to replace the existing ip-, ip6-, arp-, and ebtables framework. It provides a new packet filtering framework, a new user-space utility (nft), and a compatibility layer for ip- and ip6tables. It uses the existing hooks, connection tracking system, user-space queueing component, and logging subsystem of netfilter.
You can also visit the official nftables wiki page for more information.
The first release is available in Linux 3.13, which is in the core repository (linux), and nftables (the user-space components) is available in the extra repository (nftables), and on the AUR in package nftables-gitAUR.
Contents
Overview
nftables consists of three main components: a kernel implementation, the libnl netlink communication and the nftables user-space front-end. The kernel provides a netlink configuration interface, as well as run-time rule-set evaluation using a small classification language interpreter. libnl contains the low-level functions for communicating with the kernel; the nftables front-end is what the user interacts with.
nft
nftables' user-space utility nft
now performs most of the rule-set evaluation before handing rule-sets to the kernel. Because of this, nftables provides no default tables or chains; although, a user can emulate an iptables-like setup.
It works in a fashion similar to ifconfig or iproute2. The commands are a long, structured sequence rather than using argument switches like in iptables. For example:
nft add rule ip6 filter input ip6 saddr ::1 accept
add
is the command. rule
is a subcommand of add
. ip6
is an argument of rule
, telling it to use the ip6 family. filter
and input
are arguments of rule
specifying the table and chain to use, respectively. The rest that follows is a rule definition, which includes matches (ip
), their parameters (saddr
), parameter arguments (::1
), and jumps (accept
).
The following is an incomplete list of the commands available in nft:
list tables [family] table [family] <name> chain [family] <table> <name> add table [family] <name> chain [family] <table> <name> [chain definitions] rule [family] <table> <chain> <rule definition> table [family] <name> (shortcut for `add table`) insert rule [family] <table> <chain> <rule definition> delete table [family] <name> chain [family] <table> <name> rule [family] <table> <handle> flush table [family] <name> chain [family] <table> <name>
family
is optional, but it will default to ip
.
Tables
The purpose of tables is to hold chains. Unlike tables in iptables, there are no built-in tables in nftables. Tables can have one of five families specified, which unifies the various iptables utilities into one:
nftables family | iptables utility |
---|---|
ip | iptables |
ip6 | ip6tables |
inet | iptables and ip6tables |
arp | arptables |
bridge | ebtables |
ip
is the default family.
inet
requires Linux >=3.15 and allows for the unification of the ip and ip6 families to make defining rules for both easier.
Listing
You can list the current tables in a family with the nft list
command.
# nft list tables # nft list tables ip6
You can list a full table definition by specifying a table name:
# nft list table foo # nft list table ip6 foo
Creation
Tables can be added via two commands — one just being a shortcut for the other. Here is an example of how to add an ip table called foo and an ip6 table called foo:
# nft add table foo # nft table ip6 foo
You can have two tables with the same name as long as they are in different families.
Deletion
Tables can only be deleted if there are no chains in them.
# nft delete table foo # nft delete table ip6 foo
Chains
The purpose of chains is to hold rules. Unlike chains in iptables, there are no built-in chains in nftables. This means that if no chain uses any types or hooks in the netfilter framework, packets that would flow through those chains will not be touched by nftables, unlike iptables.
Listing
The nft list table foo
command will list all the chains in the foo table. You can also list rules from an individual chain.
# nft list chain foo bar # nft list chain ip6 foo bar
These commands will list the bar
chains in the ip and ip6 foo
tables.
Creation
Chains can be added when a table is created in a file definition or one at time via the nft add chain
command.
# nft add chain foo bar # nft add chain ip6 foo bar
These commands will add a chain called bar
to the ip and ip6 foo
tables.
Properties
Because nftables has no built-in chains, it allows chains to access certain features of the netfilter framework.
# nft add chain filter input \{ type filter hook input priority 0\; \}
This command tells nftables to add a chain called input
to the filter
table and defines its type, hook, and priority. These properties essentially replace the built-in tables and chains in iptables.
Types
There are three types a chain can have and they correspond to the tables used in iptables:
- filter
- nat
- route (mangle)
Hooks
There are five hooks a chain can use and they correspond to the chains used in iptables:
- input
- output
- forward
- prerouting
- postrouting
Priorities
Priorities tell nftables which chains packets should pass through first. They are integers, and the higher the integer, the higher the priority.
Deletion
Chains can only be deleted if there are no rules in them.
# nft delete chain foo bar # nft delete chain ip6 foo bar
These commands delete the bar
chains from the ip and ip6 foo
tables.
Rules
The purpose of rules is to identify packets (match) and carry out tasks (jump). Like in iptables, there are various matches and jumps available, though not all of them are feature-complete in nftables.
Listing
You can list the current rules in a table with the nft list
command, using the same method as listing a table. You can also list rules from an individual chain.
# nft list chain foo bar # nft list chain ip6 foo bar
These commands will list the rules in the bar
chains in the ip and ip6 foo
tables.
Creation
Rules can be added when a table is created in a file definition or one at time via the nft add rule
command.
# nft add rule foo bar ip saddr 127.0.0.1 accept # nft add rule ip6 foo bar ip saddr ::1 accept
These commands will add a rule to the bar
chains in the ip and ip6 foo
tables that matches an ip
packet when its saddr
(source address) is 127.0.0.1 (IPv4) or ::1 (IPv6) and accepts those packets.
Matches
There are various matches available in nftables and, for the most part, coincide with their iptables counterparts. The most noticeable difference is that there are no generic or implicit matches anymore. A generic match was one that was always available, such as --protocol
or --source
. Implicit matches were protocol-specific, such as --sport
when a packet was determined to be TCP.
The following is an incomplete list of the matches available:
- meta (meta properties, e.g. interfaces)
- icmp (ICMP protocol)
- icmpv6 (ICMPv6 protocol)
- ip (IP protocol)
- ip6 (IPv6 protocol)
- tcp (TCP protocol)
- udp (UDP protocol)
- sctp (SCTP protocol)
- ct (connection tracking)
The following is an incomplete list of match arguments (for a more complete list, see man 8 nft
):
meta: oif <output interface INDEX> iif <input interface INDEX> oifname <output interface NAME> iifname <input interface NAME> (oif and iif accept string arguments and are converted to interface indexes) (oifname and iifname are more dynamic, but slower because of string matching) icmp: type <icmp type> icmpv6: type <icmpv6 type> ip: protocol <protocol> daddr <destination address> saddr <source address> ip6: daddr <destination address> saddr <source address> tcp: dport <destination port> sport <source port> udp: dport <destination port> sport <source port> sctp: dport <destination port> sport <source port> ct: state <new | established | related | invalid>
Jumps
Jumps work the same as they do in iptables, except multiple jumps can now be used in one rule.
# nft add rule filter input tcp dport 22 log accept
The following is an incomplete list of jumps:
- accept (accept a packet)
- reject (reject a packet)
- drop (drop a packet)
- snat (perform source NAT on a packet)
- dnat (perform destination NAT on a packet)
- log (log a packet)
- counter (keep a counter on a packet; counters are optional in nftables)
- return (stop traversing the chain)
- jump <chain> (jump to another chain)
- goto <chain> (jump to another chain, but do not return)
Insertion
Rules can be prepended to chains with the nft insert rule
command.
# nft insert rule filter input ct state established,related accept
Deletion
Individual rules can only be deleted by their handles. The nft --handle list
command must be used to determine rule handles. Note the --handle
switch, which tells nft
to list handles in its output.
The following determines the handle for a rule and then deletes it. The --number
argument is useful for viewing some numeric output, like unresolved IP addresses.
# nft --handle --numeric list chain filter input
table ip fltrTable { chain input { type filter hook input priority 0; ip saddr 127.0.0.1 accept # handle 10 } }
# nft delete rule fltrTable input handle 10
All the chains in a table can be flushed with the nft flush table
command. Individual chains can be flushed using either the nft flush chain
or nft delete rule
commands.
# nft flush table foo # nft flush chain foo bar # nft delete rule ip6 foo bar
The first command flushes all of the chains in the ip foo
table. The second flushes the bar
chain in the ip foo
table. The third deletes all of the rules in bar
chain in the ip6 foo
table.
Atomic Reloading
Flush the current ruleset :
# echo "flush ruleset" > /tmp/nftables
Dump the current ruleset:
# nft list ruleset >> /tmp/nftables
Now you can edit /tmp/nftables and apply your changes with:
# nft -f /tmp/nftables
File Definitions
File definitions can be used by the nft -f
command, which acts like the iptables-restore
command.
However, unlike iptables-restore
, this command does not flush out your existing ruleset, to do so you have
to prepend the flush command.
/etc/nftables/filter.rules
flush table ip filter table ip filter { chain input { type filter hook input priority 0; ct state established,related accept ip saddr 127.0.0.1 accept tcp dport 22 log accept reject } }
To export your rules (like iptables-save
):
# nft list ruleset
Getting Started
The below example shows nft commands to configure a basic IPv4 only firewall. If you want to filter both IPv4 and IPv6 you should look at the other examples in /usr/share/nftables
or just start with the default provided in /etc/nftables.conf
which already works with IPv4/IPv6.
To get an iptables-like chain set up, you will first need to use the provided IPv4 filter file:
# nft -f /usr/share/nftables/ipv4-filter
To list the resulting chain:
# nft list table filter
Drop output to a destination:
# nft add rule ip filter output ip daddr 1.2.3.4 drop
Drop packets destined for local port 80:
# nft add rule ip filter input tcp dport 80 drop
Delete all rules in a chain:
# nft delete rule filter output
Samples
Simple IP/IPv6 Firewall
firewall.rules
# A simple firewall flush ruleset table firewall { chain incoming { type filter hook input priority 0; # established/related connections ct state established,related accept # invalid connections ct state invalid drop # loopback interface iifname lo accept # icmp icmp type echo-request accept # open tcp ports: sshd (22), httpd (80) tcp dport {ssh, http} accept # everything else drop } } table ip6 firewall { chain incoming { type filter hook input priority 0; # established/related connections ct state established,related accept # invalid connections ct state invalid drop # loopback interface iifname lo accept # icmp # routers may also want: mld-listener-query, nd-router-solicit icmpv6 type {echo-request,nd-neighbor-solicit} accept # open tcp ports: sshd (22), httpd (80) tcp dport {ssh, http} accept # everything else drop } }
Limit rate IP/IPv6 Firewall
firewall.2.rules
table firewall { chain incoming { type filter hook input priority 0; # no ping floods: ip protocol icmp limit rate 10/second accept ip protocol icmp drop ct state established,related accept ct state invalid drop iifname lo accept # avoid brute force on ssh: tcp dport ssh limit rate 15/minute accept reject } } table ip6 firewall { chain incoming { type filter hook input priority 0; # no ping floods: ip6 nexthdr icmpv6 limit rate 10/second accept ip6 nexthdr icmpv6 drop ct state established,related accept ct state invalid drop # loopback interface iifname lo accept # avoid brute force on ssh: tcp dport ssh limit rate 15/minute accept reject } }
Jump
When using jumps in config file, it is necessary to define the target chain first. Otherwise one could end up with Error: Could not process rule: No such file or directory
.
jump.rules
table inet filter { chain web { tcp dport http accept tcp dport 8080 accept } chain input { type filter hook input priority 0; ip saddr 10.0.2.0/24 jump web drop } }
Loading rules at boot
To automatically load rules on system boot, simply enable the nftables systemd service by executing systemctl enable nftables
The rules will be loaded from /etc/nftables.conf
by default.
Logging to Syslog
If you use a Linux kernel < 3.17, you have to modprobe xt_LOG
to enable logging.