AAtsushi's Blog
Infrastructure

nftables: The Successor to iptables

→ 日本語版を読む

nftables is a packet filtering tool and the successor to iptables, ip6tables, and others.

For simple use cases, firewalld is used, but for complex cases or configurations across the entire network, nftables is used. Going forward, the use of nftables is recommended in place of iptables.

Configuration Structure

The entire nftables configuration is called a ruleset. The ruleset has tables configured per address family. Tables have chains, and chains contain rules.

  • Ruleset
    • Table A
      • Chain i
        • Rule 1
        • Rule 2
      • Chain ii
        • Rule 1
        • Rule 2
    • Table B
      • Chain i
        • Rule 1
        • Rule 2

Tables are created per address family (= protocol).

Address Family Types

Address families include the following types:

  • ip: IPv4
  • ip6: IPv6
  • inet: IPv4 and IPv6
  • arp: ARP
  • bridge:
    • Network bridge (essentially an L2 switch. See here for details)
  • netdev:
    • Network interface.
    • Can be configured to target all network traffic entering a network device.
    • Used for packet dropping, load balancing, etc.

nftables can be installed with dnf install nftables (of course [yum](<https://d.hatena.ne.jp/keyword/yum>) install nftables also works).

# dnf install nftables
# systemctl start nftables
# dnf list installed | grep nftables
nftables.x86_64                      1:1.0.4-11.el9              @anaconda
# rpm -qa | grep nftables
nftables-1.0.4-11.el9.x86_64

nftables is configured with the nft command. To create a table named "table01" with address family "ip", the command is as follows:

# nft create table ip table01 # Create table "table01" with address family "ip"
# nft list ruleset
table ip table01 {
}

Next, create a chain. (Details described later)

# nft create chain ip table01 chain01 { type filter hook input priority 1 \; policy accept \; } # Create a chain with type "filter", hook "input", priority "1", policy "drop"
# nft list ruleset
table ip table01 {
        chain chain01 {
                type filter hook input priority filter + 1; policy drop;
        }
}

Add a rule to the chain. (Details described later)

# nft add rule ip table01 chain01 ip saddr 59.138.xxx.xxx accept
# nft -a list ruleset
table ip table01 { # handle 1
        chain chain01 { # handle 1
                type filter hook input priority filter + 1; policy accept;
                ip saddr 59.138.xxx.xxx accept # handle 2
        }
}

Deletion works like this. You can also disable a created table with { flags dormant \; }.

# nft delete rule ip table01 chain01 handle 2
# nft -a list ruleset
table ip table01 { # handle 1
        chain chain01 { # handle 1
                type filter hook input priority filter + 1; policy accept;
        }
}
#
# nft delete chain ip table01 chain01 # Delete the chain
# nft list ruleset
table ip table01 {
}
# nft add table ip table01 { flags dormant \; } # Disable the table
# nft list ruleset
table ip table01 {
        flags dormant
}
# nft delete table ip table01 # Delete the table
# nft list ruleset
#

Tables

To create a table, use nft create table [address family] [table name].

Chains

To create a chain, use nft create chain [address family] [table name] [chain name] { type [type] hook [hook] priority [priority] ; policy [policy] ; }.

Types

Three types exist:

  • filter
    • Used for filtering
  • nat
    • Used for NAT
    • Only available for ip and ip6
  • route
    • Used for packet routing
    • Only available for ip and ip6

Hooks

Six types exist:

  • prerouting
    • Executed when a packet is received, before routing
    • Supported by ip, ip6, inet, bridge
  • input
    • When a packet destined for the local host is received
    • Supported by ip, ip6, inet, bridge, arp
  • forward
    • Executed when forwarding
    • Supported by ip, ip6, inet, bridge
  • output
    • Executed when a local process generates a packet
    • Supported by ip, ip6, inet, bridge, arp
  • postrouting
    • Executed when a packet is sent
    • Supported by ip, ip6, inet, bridge
  • ingress
    • Executed when a packet is received
    • Supported by netdev

Priority

  • Priority order among chains (= determines which chain runs first when multiple chains with the same hook are defined)
  • Chains are executed in order from the smallest value

Policy

  • Specifies whether to allow (accept) or discard (drop) packets that do not match any rule in the chain
  • If omitted, defaults to accept

Rules

Rules are added with nft insert rule or nft add rule. With insert, the rule is added before the specified handle number; with add, it is added after the specified handle number. If no handle number is specified, insert adds the rule at the top and add adds it at the bottom.

nft add rule ip table01 chain01 handle [handle number] [expression] [action]

Rules in a chain are evaluated in order. Once all rules have been evaluated, or when the evaluation cannot continue (e.g., the packet is dropped), evaluation of that chain completes and evaluation of the next chain begins.

In the following example, two rules are added: packets from source IP 59.138.xxx.xxx are accepted, and all others are dropped.

# nft add rule ip table01 chain01 ip saddr 59.138.xxx.xxx accept
# nft add rule ip table01 chain01 drop
# nft -a list ruleset
table ip table01 { # handle 1
        chain chain01 { # handle 1
                type filter hook input priority filter + 1; policy accept;
                ip saddr 59.138.xxx.xxx accept # handle 2
                drop # handle 3
        }
}

In the following example, a rule is inserted before handle number 3.

# nft insert rule ip table01 chain01 handle 3 ip saddr 59.139.xxx.xxx accept
# nft -a list ruleset
table ip table01 { # handle 1
        chain chain01 { # handle 1
                type filter hook input priority filter + 1; policy accept;
                ip saddr 59.138.xxx.xxx accept # handle 2
                ip saddr 59.139.xxx.xxx accept # handle 4
                drop # handle 3
        }
}

Rules can be modified with replace and deleted with delete.

Common actions include:

  • accept
  • drop
  • reject
    • Rejects the packet and sends a notification back to the source. The with keyword can be used to specify what to send back.
  • log
    • Logs packet information
  • snat, dnat

Probably the most common use case is specifying source/destination IP and destination port.

ip saddr 100.122.34.10 ip daddr 22.31.33.44 tcp dport 443 accept

In the example above, the source IP is specified with ip saddr, the destination with ip daddr, and the destination port with tcp dport.

Commonly used keywords include:

  • IP address specification
    • ip saddr [IP address], ip daddr [IP address] (for IPv6, use ip6 saddr; for ICMP, use icmp saddr, etc.)
  • Protocol specification
    • ip protocol [protocol specification]
  • Port number specification
    • tcp sport [port number], tcp dport [port number] (for UDP, use udp sport, etc.)

There are many other keywords for connection state, byte count, and more, making it possible to handle complex cases.

Saving and Deleting Rulesets

A ruleset can be restored by loading the text output of nft list ruleset. Therefore, you can save rules with nft list ruleset > ruleset.txt. Delete a ruleset with nft flush ruleset, and restore it with nft -f ruleset.txt.

# nft list ruleset
table ip table01 {
}
# nft list ruleset > ruleset.txt # Save the ruleset
# nft flush ruleset # Delete the ruleset
# nft list ruleset
# nft -f ruleset.txt # Load the ruleset
# nft list ruleset
table ip table01 {
}

Auto-Loading Rulesets

Settings made with nftables commands are lost when the system is powered off or rebooted. In RHEL, you can automatically load nftables rules at system startup using the following method. This ensures rules are always applied to the system.

In RHEL, write the file to load at system startup using an include statement in the /etc/sysconfig/nftables.conf file.

/etc/sysconfig/nftables.conf

include "/etc/nftables/_example_.nft"

With this setting, the configuration is loaded from /etc/nftables/_example_.nft.

systemctl restart nftables loads the configuration without a full reboot.

References

nftables

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/securing_networks/getting-started-with-nftables_securing-networks

https://linuc.org/study/knowledge/1118/

https://knowledge.sakura.ad.jp/22636/

iptables

https://tech-blog.rakus.co.jp/entry/20220301/iptables

https://www.designet.co.jp/faq/term/?id=aXB0YWJsZXM#

https://knowledge.sakura.ad.jp/4048/

https://www.unix-power.net/networking/post-631