nftables - Gentoo wiki (2024)

nftables is the successor to iptables. It replaces the existing iptables, ip6tables, arptables, and ebtables framework. It uses the Linux kernel and a new userspace utility called nft. nftables provides a compatibility layer for the iptables/ip6tables and framework.

Contents

  • 1 Introduction
    • 1.1 Tables
    • 1.2 Chains
      • 1.2.1 IPv4/IPv6/INET/Bridge hooks
      • 1.2.2 ARP hooks
      • 1.2.3 Netdev hooks
    • 1.3 Rules
      • 1.3.1 Matches
      • 1.3.2 Statements
    • 1.4 Sets
  • 2 Installation
    • 2.1 Kernel
    • 2.2 Emerge
  • 3 Configuration
    • 3.1 OpenRC
    • 3.2 systemd
  • 4 Usage
    • 4.1 Tables
      • 4.1.1 Creating tables
      • 4.1.2 Listing tables
      • 4.1.3 Deleting tables
    • 4.2 Chains
      • 4.2.1 Adding chains
      • 4.2.2 Listing chain rules
      • 4.2.3 Deleting chains
    • 4.3 Rules
      • 4.3.1 Adding rules
      • 4.3.2 Listing all rules
      • 4.3.3 Deleting rules
  • 5 Modular Ruleset Management
    • 5.1 Example Modules
      • 5.1.1 Variable definitions
      • 5.1.2 Jumping to the ingress filter
      • 5.1.3 Basic drop filter
      • 5.1.4 Basic ICMP filter
      • 5.1.5 Allow DHCP traffic
      • 5.1.6 Allow inbound and forwarded SSH traffic
      • 5.1.7 Allow outbound and forwarded NTP traffic
      • 5.1.8 NAT LANs
      • 5.1.9 Masquerade Docker Traffic
  • 6 Logging
    • 6.1 Log action
    • 6.2 syslog-ng nftables configuration
  • 7 Examples
  • 8 Troubleshooting
    • 8.1 No such file or directory
    • 8.2 Conflicting intervals
    • 8.3 Connections blocked after nftables restart or reboot
    • 8.4 Family netdev and ingress hook
  • 9 See also
  • 10 External Resources
  • 11 References

Introduction

As with the iptables framework, nftables is built upon rules which specify actions. These rules are attached to chains. A chain can contain a collection of rules and is registered in the netfilter hooks. Chains are stored inside tables. A table is specific for one of the layer 3 protocols. One of the main differences with iptables is that there are no predefined tables and chains anymore.

CODE Configuration hierarchy

Table├─Chain1│ ├─Rule1a│ └─Rule1b├─Chain2│ ├─Rule2a│ ├─Rule2b│ └─Rule2c└─Chain3 └─Rule3a

Note
Both iptables and nftables use the Netfilter framework. Because iptables does not allow for the manual configuration of hooks - the default tables are used for tapping into the Netfilter framework, while nftables requires the hooks to be defined inside of user-defined chains. Iptables also does not support dual stack (inet) configurations or netdev. Other than these differences, they are functionally identical, acting as interfaces for Netfilter.

Tables

A table is a container for chains. Unlike iptables, nftables has no predefined tables (filter, raw, mangle...). An iptables-like structure can be used, but this is not required. Tables must be defined with an address family and name, which can be anything.

The address families used by nftables are documented under man nft 8:

Address familyDescription
ipUsed for IPv4 related chains.
ip6Used for IPv6 related chains.
inetMixed IPv4/IPv6 chains (kernel 3.14 and up).
arpUsed for ARP related chains.
bridgeUsed for bridging related chains.
netdevUsed for chains that filter early in the stack (kernel 4.2 and up).

Note
If a family is not specified, ip is used.

Chains

Chains are used to group rules. As with the tables, nftables does not have any predefined chains. Chains are grouped in base and non-base types. Base chains are registered in one of the netfilter hooks, non-base chains are not. base chains must be defined with a hook type, and priority. In contrast, non-base chains are not attached to a hook and they don't see any traffic by default. They can be used as jump targets to arrange a rule-set in a tree of chains.

The chains used by nftables are documented under man nft 8:

ChainFamiliesHooksDescription
filterallallStandard chain, generally used for filtering.
natip, ip6, natprerouting, input, output, postroutingUsed to perform Native Address Translation using conntrack. Only the first packet of a connection uses this chain.
routeip, ip6outputPackets that traverse this chain type, if about to be accepted, trigger a route lookup if the IP header has changed.

Each address family has different hook capabilities, defined under the respective {name} ADDRESS FAMILY section of man nft 8:

IPv4/IPv6/INET/Bridge hooks

HookDescription
preroutingProcesses all packets entering the system, invoked before the routing process, used for early filtering or changing attributes which would affect routing.
inputProcesses packets destined for the local system.
forwardProcesses packets received by the local system, but destined for another one.
outputProcesses packets sent by the local system (includes NATed packets).
postroutingProcesses all packets leaving the system, regardless of the source.
ingress (Since 5.10)Processes all packets entering the system, before prerouting (and all other layer 3 handlers). Only available to the inet address family.

ARP hooks

HookDescription
inputProcesses ARP packets the local system receives.
outputProcesses ARP packets leaving the local system.

Netdev hooks

HookDescription
ingressProcesses all packets entering the system. Invoked after network taps such as tcpdump, and before layer 3 handlers.
egressProcesses all packets leaving the system. Invoked before tcpdump egress.

Rules

Rules specify what action is taken for a given packet. Rules are attached to chains. Each rule can have an expression to match packets and one or more actions to perform when matching. Unlike iptables, it is possible to specify multiple actions per rule, and counters are off by default. A counter must be specified explicitly in each rule for which packet- and byte-counters are desired.

Each rule has a unique handle number by which it can be distinguished.

The following matches are available:

  • ip: IP protocol.
  • ip6: IPv6 protocol.
  • tcp: TCP protocol.
  • udp: UDP protocol.
  • udplite: UDP-lite protocol.
  • sctp: SCTP protocol.
  • dccp: DCCP protocol.
  • ah: Authentication headers.
  • esp: Encrypted security payload headers.
  • ipcomp: IPcomp headers.
  • icmp: icmp protocol.
  • icmpv6: icmpv6 protocol.
  • ct: Connection tracking.
  • meta: meta properties such as interfaces.

Matches

MatchArgumentsDescription/Example
ipversionIp Header version
hdrlengthIP header length
tosType of Service
lengthTotal packet length
idIP ID
frag-offFragmentation offset
ttlTime to live
protocolUpper layer protocol
checksumIP header checksum
saddrSource address
daddrDestination address
ip6versionIP header version
priority
flowlabelFlow label
lengthPayload length
nexthdrNext header type (Upper layer protocol number)
hoplimitHop limit
saddrSource Address
daddrDestination Address
tcpsportSource port
dportDestination port
sequenceSequence number
ackseqAcknowledgement number
doffData offset
flagsTCP flags
windowWindow
checksumChecksum
urgptrUrgent pointer
udpsportSource port
dportdestination port
lengthTotal packet length
checksumChecksum
udplitesportSource port
dportdestination port
cscovChecksum coverage
checksumChecksum
sctpsportSource port
dportdestination port
vtagVerification tag
checksumChecksum
dccpsportSource port
dportdestination port
ahnexthdrNext header protocol (Upper layer protocol)
hdrlengthAH header length
spiSecurity Parameter Index
sequenceSequence Number
espspiSecurity Parameter Index
sequenceSequence Number
ipcompnexthdrNext header protocol (Upper layer protocol)
flagsFlags
cfiCompression Parameter Index
icmptypeicmp packet type
icmpv6typeicmpv6 packet type
ctstateState of the connection
directionDirection of the packet relative to the connection
statusStatus of the connection
markConnection mark
expirationConnection expiration time
helperHelper associated with the connection
l3protoLayer 3 protocol of the connection
saddrSource address of the connection for the given direction
daddrDestination address of the connection for the given direction
protocolLayer 4 protocol of the connection for the given direction
proto-srcLayer 4 protocol source for the given direction
proto-dstLayer 4 protocol destination for the given direction
metalengthLength of the packet in bytes: meta length > 1000
protocolethertype protocol: meta protocol vlan
priorityTC packet priority
markPacket mark
iifInput interface index
iifnameInput interface name
iiftypeInput interface type
oifOutput interface index
oifnameOutput interface name
oiftypeOutput interface hardware type
pkttypePacket type: unicast, multicast or broadcast
skuidUID associated with originating socket
skgidGID associated with originating socket
rtclassidRouting realm

Statements

Statements represent the action to be performed when a rule matches. They exist in two kinds: Terminal statements, unconditionally terminate the evaluation of the current rules and non-terminal statements that either conditionally or never terminate the current rules. There can be an arbitrary amount of non-terminal statements, but there must be only a single terminal statement.The terminal statements can be:

  • accept: Accept the packet and stop the ruleset evaluation.
  • drop: Drop the packet and stop the ruleset evaluation.
  • reject: Reject the packet with an icmp message.
  • queue: Queue the packet to userspace and stop the ruleset evaluation.
  • continue:
  • return: Return from the current chain and continue at the next rule of the last chain. In a base chain it is equivalent to accept.
  • jump <chain>: Continue at the first rule of <chain>. It will continue at the next rule after a return statement is issued.
  • goto <chain>: Similar to jump, but after the new chain the evaluation will continue at the last chain instead of the one containing the goto statement.

Sets

nftables allows defining anonymous and named sets (dictionaries and maps). For example, the following nft script defines the fullbogons set, adds elements to it and drops packages from the IPs conforming the set.

FILE rules.nft

#!/sbin/nftadd set filter fullbogons { type ipv4_addr; flags interval; }add element filter fullbogons {0.0.0.0/8}add element filter fullbogons {10.0.0.0/8}add element filter fullbogons {41.62.0.0/16}add element filter fullbogons {41.67.64.0/20}add rule filter input iifname eth0 ct state new ip saddr @fullbogons counter drop comment "drop from blacklist"

Installation

Kernel

Example Config: A bare minimum for basic IPv4 firewalling with NAT:

KERNEL Nftables kernel requirements

[*] Networking support ---> Networking options ---> [*] Network packet filtering framework (Netfilter) ---> Core Netfilter Configuration ---> <M> Netfilter connection tracking support <M> Netfilter nf_tables support <M> Netfilter nf_tables conntrack module <M> Netfilter nf_tables counter module <M> Netfilter nf_tables log module <M> Netfilter nf_tables limit module <M> Netfilter nf_tables masquerade support <M> Netfilter nf_tables nat module IP: Netfilter Configuration ---> <M> IPv4 nf_tables support <M> IPv4 packet rejection <M> IP tables support (required for filtering/masq/NAT) <M> Packet filtering <M> REJECT target support <M> iptables NAT support <M> MASQUERADE target support

Additional Common Config: For mixed IPv4 and IPv6 rules combined into one table: CONFIG_NF_TABLES_INET

(If family inet is not enabled, only families ip and ip6 can be used individually)

KERNEL Nftables inet family

[*] Networking support ---> Networking options ---> [*] Network packet filtering framework (Netfilter) ---> Core Netfilter Configuration ---> <M> Netfilter nf_tables support [*] Netfilter nf_tables mixed IPv4/IPv6 tables support

Additional Optional Config: Early filtering based on network device requires netdev tables support: CONFIG_NF_TABLES_NETDEV

KERNEL Nftables netdev family

[*] Networking support ---> Networking options ---> [*] Network packet filtering framework (Netfilter) ---> Core Netfilter Configuration ---> <M> Netfilter nf_tables support [*] Netfilter nf_tables netdev tables support

Nftables is very modular, and has many more options than mentioned here. Certain software likely requires additional features.

Depending on the goal, the bare minimum shown here may suffice, or other additional options can be enabled as modules so the kernel will load them as needed.

Disclaimer: This network section of the kernel changes frequently. More modules = more compatibility (they only load when requested).

Emerge

Install net-firewall/nftables:

root #emerge --ask net-firewall/nftables

Configuration

OpenRC

The init script, /etc/init.d/nftables, supports the following actions:

  • save - Stores the currently loaded ruleset in the location defined by NFTABLES_SAVE, default: /var/lib/nftables/rules-save.
  • reload - Loads the currently loaded ruleset from NFTABLES_SAVE.
  • stop - Intended to be called on system shutdown. If SAVE_ON_STOP is enabled, saves the ruleset.
  • start - Intended to be called on system boot, loads the ruleset from NFTABLES_SAVE.
  • clear - Flushes the currently loaded ruleset, equivalent to nft flush ruleset.
  • list - lists the currently loaded ruleset.

Note
Configuration is available at /etc/conf.d/nftables.

Nftables can be started at boot with:

root #rc-update add nftables default

Warning
Failing to invoke /etc/init.d/nftables save manually after altering the ruleset could result in an older ruleset being loaded if there is an issue during system shutdown and saving the ruleset fails.

systemd

After first setup:

root #touch /var/lib/nftables/rules-save

root #systemctl enable --now nftables-restore

Usage

All nftable commands are executed with the nft utility from net-firewall/nftables.

Tables

Creating tables

The following command adds a table called base_table for the IPv4 and IPv6 layers:

root #nft add table inet base_table

Likewise, a table for arp can be created with

root #nft add table arp base_table

Note
The name "base_table" used here is completely arbitrary. Any name can be used.

Listing tables

The following command lists all tables:

root #nft list tables

table inet base_tabletable arp base_table

The tables can be filtered by type by adding the address family as an argument:

root #nft list tables inet

table inet base_table

The contents of the table base_table can be listed with:

root #nft list table inet base_table

table inet base_table { chain input_filter { type filter hook input priority 0; ct state established,related accept iifname "lo" accept ip protocol icmp accept drop }}

Tip
Adding -a as an argument to the nft command displays the rule handle after the rule.

root #nft -a list table inet base_table

table inet base_table { chain input_filter { type filter hook input priority 0; ct state established,related accept # handle 2 iifname "lo" accept # handle 3 ip protocol icmp accept # handle 4 drop # handle 5 }}

Deleting tables

The following command deletes the table called base_table, which is part of the address family inet:

root #nft delete table inet base_table

Chains

Adding chains

The following command adds a base chain called input_filter to the inet base_table table. It is registered to the input hook with priority 0, and type filter.

root #nft add chain inet base_table input_filter "{type filter hook input priority 0;}"

Note
A non-base chain can be added by not specifying the chain configurations between the curly braces.

Important
Chains cannot be redefined once made, that means the hook type and priority are immutable. The chain must be deleted and redefined to keep the name but change these parameters. Deletion requires all references to the chain are also removed!

Listing chain rules

The rules for a chain can be listed using:

root #nft list chain inet base_table input_filter

table inet base_filter {chain input_filter { type filter hook input priority 0; }}

Deleting chains

Chains can be removed with:

root #nft delete chain inet base_table input_filter

Note
Chains can only be deleted if there are no rules in them, and they are not used as a jump target.

Tip
destroy can be used instead of delete to ensure a chain does not exist. Unlike delete, destroy will not return an error if the chain did not already exist.

Rules

Adding rules

The following command adds a rule to the chain called input_filter, on the base_table table, dropping all incoming traffic to port 80:

root #nft add rule inet base_table input_filter tcp dport 80 drop

Listing all rules

The following command can be used to list all rules in the current ruleset (with handles):

root #nft -a list ruleset

table inet base_table { chain input_filter { # handle 1 type filter hook input priority 0; # handle 2 tcp dport http drop # handle 3 } chain output_filter { # handle 4 type filter hook input priority 0; # handle 5 tcp sport http drop # handle 6 }}

Deleting rules

To delete a rule, the rule's handle number is required:

root #nft delete rule inet base_table input_filter handle 3

Modular Ruleset Management

nft supports atomic rule replacement by using nft -f. Thus it is possible to conveniently manage the rules using files.

Important
When loading rules nft -f, as opposed to calling nft repeatedly in a shell script, failures will result in none of the file's rules being loaded.

Note
Comments may be added to the file by prefixing them with #, but these comments will not be visible in nft list output; they can also be appended to the end of rules as comment "<arbitrary string>", and these will be preserved as-is in nft list output.

Nftables allows including additional files and directories. A directory, such as /etc/nftables.conf.d/ can be created which contains additional rulesets to be loaded.

Tip
Any of these files can be made executable, as long as the shebang #! /sbin/nft -f is included.

The following file creates a basic skeleton of a ruleset, which can be used with modules, loaded from /etc/nftables.conf.d/:

FILE /etc/nftables.rulesBasic router ruleset

#! /sbin/nft -fflush rulesettable netdev filter { # Basic filter chain, devices can be configued to jump here chain ingress_filter { # Drop all fragments. ip frag-off & 0x1fff!= 0 counter drop # Drop XMAS packets. tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop # Drop NULL packets. tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop # Drop uncommon MSS values. tcp flags syn tcp option maxseg size 1-535 counter drop }}table inet filter { chain input { type filter hook input priority 200; policy drop; counter jump input_hook counter jump base_filter log prefix "Dropped input traffic: " counter drop } chain input_hook { } chain base_filter { counter jump drop_filter ct state vmap { established: accept, related: accept, new: continue, invalid: drop } # Allow loopback traffic iifname lo counter accept oifname lo counter accept } chain drop_filter { } chain forward { type filter hook forward priority 200; policy drop; counter jump forward_hook counter jump base_filter log prefix "Dropped forwarded traffic: " counter drop } chain forward_hook { } chain output { type filter hook output priority 200; policy drop; counter jump output_hook counter jump base_filter log prefix "Dropped output traffic: " counter drop } chain output_hook { }}table inet nat { chain prerouting { type nat hook prerouting priority 0; } chain postrouting { type nat hook postrouting priority 500; }}include "/etc/nftables.rules.d/*.rules"

Note
This ruleset uses a common filter, base_filter, for input, output, and forwarded traffic. Each filter has an associated hook which can be used for addition of rules.

Example Modules

Important
These modules will be loaded in lexicographical order, which can drastically change the behavior of a ruleset.

Variable definitions

Important
Sets can be used to define IPs and ports, but cannot be used for interface names.

FILE /etc/nftables.rules.d/00-definitions.rulesDefine variables which can be used in other modules.

#! /sbin/nft -fdefine lan_interface = fib.landefine wifi_interface = ax1800define management_interface = fib.managementdefine dmz_interface = ethernet2define wan_interface = fib.wandefine wifi_network = 192.168.1.0/24define lan_network = 192.168.10.0/24define management_network = 192.168.255.0/24define dmz_network = 192.168.2.0/24table inet filter { set trusted_nets { type ipv4_addr flags interval elements = { $lan_network, $wifi_network } } set dmz_nets { type ipv4_addr flags interval elements = { $dmz_network } } set untrusted_nets { type ipv4_addr flags interval elements = { $dmz_network } }}

Jumping to the ingress filter

FILE /etc/nftables.rules.d/00-ingress.rulesHook the device ingress for fib1 and fib2, filtering with the defined ingress_filter chain.

#! /sbin/nft -ftable netdev filter { chain ingress { type filter hook ingress device fib1 priority -500; jump ingress_filter } chain ingress { type filter hook ingress device fib2 priority -500; jump ingress_filter }}

Basic drop filter

FILE /etc/nftables.rules.d/01-drop-policy.rulesPopulate the drop_filter chain to drop some spammy traffic found on the DMZ.

#! /sbin/nft -fdefine dmz_spam_udp = { 1234 }define dmz_spam_tcp = { 2350 }table inet filter { set spam_udp { type inet_service elements = { $dmz_spam_udp } } set spam_tcp { type inet_service elements = { $dmz_spam_tcp } } chain drop_filter { tcp dport @spam_tcp counter drop udp dport @spam_udp counter drop }}

Basic ICMP filter

Important
There is absolutely nothing wrong with allowing all ICMP, in fact, it's probably best.[1]

FILE /etc/nftables.rules.d/01-icmp.rulesAllow basic ICMP traffic

#! /sbin/nft -fdefine allowed_icmp_types = { echo-reply, echo-request }define trusted_icmp_types = { destination-unreachable, time-exceeded }define allowed_icmpv6_types = { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, echo-request, echo-reply }table inet filter { chain base_filter { ip protocol icmp jump icmp_filter ip6 nexthdr icmpv6 jump icmpv6_filter } chain icmp_filter { icmp type $allowed_icmp_types counter accept ip saddr @trusted_nets icmp type $trusted_icmp_types counter accept ip daddr @trusted_nets icmp type $trusted_icmp_types counter accept } chain icmpv6_filter { icmpv6 type $allowed_icmpv6_types counter accept }}

Allow DHCP traffic

FILE /etc/nftables.rules.d/05-dhcp.rulesAllow DHCP client and server traffic on appropriate interfaces.

#! /sbin/nft -fdefine dhcp_server_interfaces = { $lan_interface, $wifi_interface, $dmz_interface }define dhcp_client_interfaces = { $management_interface, $wan_interface }table inet filter { set dhcp_server { type inet_service; elements = { 67 } } set dhcp_client { type inet_service; elements = { 68 } } set dhcp6_server { type inet_service; elements = { 547 } } set dhcp6_client { type inet_service; elements = { 546 } } chain input_hook { iifname $dhcp_client_interfaces udp sport @dhcp_server udp dport @dhcp_client counter accept comment "Allow DHCP client input traffic" iifname $dhcp_client_interfaces udp sport @dhcp6_server udp dport @dhcp6_client counter accept comment "Allow DHCPv6 client input traffic" iifname $dhcp_server_interfaces udp dport @dhcp_server udp sport @dhcp_client counter accept comment "Allow DHCP server input traffic" iifname $dhcp_server_interfaces udp dport @dhcp6_server udp sport @dhcp6_client counter accept comment "Allow DHCPv6 server input traffic" } chain output_hook { oifname $dhcp_client_interfaces udp dport @dhcp_server udp sport @dhcp_client counter accept comment "Allow DHCP client output traffic" oifname $dhcp_client_interfaces udp dport @dhcp6_server udp sport @dhcp6_client counter accept comment "Allow DHCPv6 client output traffic" oifname $dhcp_server_interfaces udp sport @dhcp_server udp dport @dhcp_client counter accept comment "Allow DHCP server output traffic" oifname $dhcp_server_interfaces udp sport @dhcp6_server udp dport @dhcp6_client counter accept comment "Allow DHCPv6 server output traffic" }}

Allow inbound and forwarded SSH traffic

FILE /etc/nftables.rules.d/22-ssh.rulesAllow inbound and forwarded SSH from the $management_network; allow SSH to be forwarded to GitHub servers, from certain networks, and users on the router.

#! /sbin/nft -fdefine github_ssh_servers = { 140.82.112.3, 140.82.112.4, 140.82.114.3, 140.82.113.4, 140.82.114.4, 140.82.113.3 }table inet filter { set external_ssh_servers { type ipv4_addr elements = { $github_ssh_servers } } set external_ssh_clients { type ipv4_addr flags interval elements = { $lan_network } } set ssh_clients { type ipv4_addr flags interval elements = { $management_network } } set ssh_ports { type inet_service; elements = { 22 } } chain ssh_filter { ip saddr @external_ssh_clients ip daddr @external_ssh_servers counter accept comment "Allow these users to SSH to specified external servers" ip saddr @ssh_clients counter accept comment "Allow this set to SSH anywhere, including the router itself" skuid 1000 ip daddr @external_ssh_servers counter accept comment "Allow SSH traffic from UID 1000 to allowed external servers" } chain base_filter { tcp dport @ssh_ports counter jump ssh_filter }}

Allow outbound and forwarded NTP traffic

FILE /etc/nftables.rules.d/21-ntp.rulesAllow forwarded NTP traffic, outbound from the NTP user.

#! /sbin/nft -ftable inet filter { set ntp_ports { type inet_service elements = { 123 } } set ntp4_ports { type inet_service elements = { 4460 } } chain base_filter { tcp dport @ntp4_ports counter jump ntp_filter udp dport @ntp_ports counter jump ntp_filter } chain ntp_filter { ip saddr @trusted_nets counter accept skuid 123 counter accept }}

NAT LANs

FILE /etc/nftables.rules.d/05-lan-nat.rulesNAT some local networks.

#! /sbin/nft -ftable inet nat { set nat_nets { type ipv4_addr flags interval elements = { $lan_network, $wifi_network, $dmz_network } } chainpostrouting { oifname $wan_interface ip saddr @nat_nets counter masquerade }}

Masquerade Docker Traffic

FILE /etc/nftables.rules.d/10-docker.rulesMasquerade docker traffic

#! /sbin/nft -fdefine docker_default_net = 172.17.0.0/16define docker_server_net = 10.100.100.0/24define docker_nets = { $docker_default_net, $docker_server_net }table inet filter { set docker_nets { type ipv4_addr flags interval elements = { $docker_nets } } set dns_ports { type inet_service elements = { 53 } } set web_ports { type inet_service elements = { 443 } } chain docker_filter { udp dport @dns_ports counter accept oifname $wan_interface tcp dport @web_ports counter accept } chain forward_hook { ip saddr @docker_nets counter jump docker_filter }}table inet nat { set nat_nets { type ipv4_addr flags interval elements = { $docker_nets } }}

Logging

Log action

The log rule can be used to log traffic to the kernel log.

Tip
A prefix can be used to prefix the packet data.

Note
log rules do not need to target, and can use counters.

From the example configuration above, log prefix "Dropped input traffic: " counter drop results in:

CODE dmesg output

[228391.038768] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=0 DF PROTO=TCP SPT=61679 DPT=54728 WINDOW=65535 RES=0x00 SYN URGP=0 [228392.039028] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=0 DF PROTO=TCP SPT=61679 DPT=54728 WINDOW=65535 RES=0x00 SYN URGP=0 [228393.466640] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=44 TOS=0x00 PREC=0x00 TTL=37 ID=36042 PROTO=TCP SPT=22103 DPT=427 WINDOW=1024 RES=0x00 SYN URGP=0 [228394.239649] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=0 DF PROTO=TCP SPT=61679 DPT=54728 WINDOW=65535 RES=0x00 SYN URGP=0 [228396.088849] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=132 TOS=0x00 PREC=0x00 TTL=46 ID=47803 PROTO=UDP SPT=12306 DPT=54728 LEN=112 [228398.440759] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=0 DF PROTO=TCP SPT=61679 DPT=54728 WINDOW=65535 RES=0x00 SYN URGP=0 [228402.822458] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=132 TOS=0x04 PREC=0x00 TTL=42 ID=28841 PROTO=UDP SPT=57221 DPT=54728 LEN=112 [228405.338582] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=36 TOS=0x00 PREC=0xC0 TTL=1 ID=40280 PROTO=2 [228405.339550] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=36 TOS=0x00 PREC=0xC0 TTL=1 ID=40280 PROTO=2 [228405.779990] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=48 TOS=0x00 PREC=0x00 TTL=46 ID=49199 PROTO=UDP SPT=12306 DPT=54728 LEN=28 [228406.641443] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=60 TOS=0x00 PREC=0x00 TTL=49 ID=0 DF PROTO=TCP SPT=61679 DPT=54728 WINDOW=65535 RES=0x00 SYN URGP=0 [228409.477377] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=132 TOS=0x00 PREC=0x00 TTL=54 ID=49526 PROTO=UDP SPT=34989 DPT=62993 LEN=112 [228409.683232] Dropped input traffic: IN=fib.wan OUT= MAC=[macaddr] SRC=[srcip] DST=[dstip] LEN=132 TOS=0x00 PREC=0x00 TTL=54 ID=49656 PROTO=UDP

syslog-ng nftables configuration

Most logging daemons will log nftables traffic to the kernel log file, since it is logged to the kernel log. This can make it difficult to view dropped traffic, since it is mixed with non-firewall related traffic.

To configure syslog-ng to log certain nftables traffic to other files:

FILE /etc/syslog-ng/syslog-ng.confFilter fib.wan interface traffic to /var/log/nft/wan.log

source kernsrc { file("/proc/kmsg");};destination nft_WAN { file("/var/log/nft/wan.log"); };filter f_nft_WAN { program(kernel) and message("^.*IN=fib\.wan.*$"); };log { source(kernsrc); filter(f_nft_WAN); destination(nft_WAN); };

Tip
In this case, and not filter(f_nft_WAN) can be added to the f_messages and f_syslog filters to prevent traffic from being logged multiple times.

Examples

See the Nftables examples article.

Troubleshooting

Before loading new or edited rules check them with nft

user $nft -c -f ruleset

No such file or directory

If this error is printed for every chain of a table definition make sure, that the table's family is available through the kernel. This happens for example if the table uses family inet and the kernel configuration did not enable mixed IPv4 and IPv6 rules (CONFIG_NF_TABLES_INET).

Conflicting intervals

A set definition of IP ranges causes this error if ranges overlap. For example 224.0.0.0/3 and 240.0.0.0/5 overlap completely. Either add auto-merge to the set's options, drop the range that is fully included or change syntax to 224.0.0.0-255.255.255.255.

CODE Sample Set

table netdev filter { set blocked_ipv4 { 169.254.0.0/16, 224.0.0.0/3, 240.0.0.0/5 } # fix the last two IPs overlapping auto-merge}

Connections blocked after nftables restart or reboot

The default configuration of the save and restore functions uses numeric mode to store the rule set. The persisted rule set could have changed from the original upload from a manually written file. Such a transformation might break things. Therefore, ensure that:

  1. /etc/conf.d/nftables contains the parameter -n for the SAVE_OPTIONS
  2. Loading the rule set as root yields a working configuration
  3. The save and restore cycle of restarting nftables service causes the issue

If all three conditions are met, remove the -n parameter from SAVE_OPTIONS in /etc/conf.d/nftables. Then load the rule set again from the manually written file and restart the service. This cycles through save and restore and should create a fully working rule set.

Note
This affected at least version 0.9.9, see bug #819456.

Family netdev and ingress hook

Broken packets should be rejected early which requires an ingress hook for family netdev. This sets up a chain that acts for a dedicated network device before packets enter further processing – improved performance. The configuration looks like this:

CODE Family netdev and ingress chain

table netdev filter { chain ingress { type filter hook ingress device enp4s0 priority -500; # Drop all fragments. ip frag-off & 0x1fff!= 0 counter drop # Drop XMAS packets. tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop # Drop NULL packets. tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop # Drop uncommon MSS values. tcp flags syn tcp option maxseg size 1-535 counter drop }}

Mind the device name enp4s0. If this changes for example when changing hardware or an upgrade changed device naming this family is broken. In turn none of the rules will be loaded. The error looks like this (filename and line numbers differ depending on the host configuration):

CODE Error at chains instead of non-existing device

/etc/nftables.conf:94:9-15: Error: Could not... chain ingress { ^^^^^^^/etc/nftables.conf:94:9-15: Error: Could not... chain ingress { ^^^^^^^/etc/nftables.conf:94:9-15: Error: Could not... chain ingress { ^^^^^^^/etc/nftables.conf:94:9-15: Error: Could not... chain ingress { ^^^^^^^/etc/nftables.conf:94:9-15: Error: Could not... chain ingress { ^^^^^^^

Check that the device name is actually correct and exists, e.g. ip addr list.

See also

  • Iptables — a program used to configure and manage the kernel's netfilter modules. Contains a section about migration to nftables

External Resources

References

nftables - Gentoo wiki (2024)
Top Articles
Latest Posts
Article information

Author: Rev. Porsche Oberbrunner

Last Updated:

Views: 6632

Rating: 4.2 / 5 (73 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Rev. Porsche Oberbrunner

Birthday: 1994-06-25

Address: Suite 153 582 Lubowitz Walks, Port Alfredoborough, IN 72879-2838

Phone: +128413562823324

Job: IT Strategist

Hobby: Video gaming, Basketball, Web surfing, Book restoration, Jogging, Shooting, Fishing

Introduction: My name is Rev. Porsche Oberbrunner, I am a zany, graceful, talented, witty, determined, shiny, enchanting person who loves writing and wants to share my knowledge and understanding with you.