Scripting

From nftables wiki
Revision as of 14:13, 10 March 2018 by Arturo (talk | contribs) (→‎File formats: delete extra line which adds nothing to the example)
Jump to navigation Jump to search

Many people like to maintain their ruleset in shell scripts, this allows them to add comments and arrange rules in more human-friendly way. This is problematic though since shell scripts break atomicity when applying the ruleset, thus, the filtering policy is applied in an inconsistent way during the ruleset loading time.

Fortunately, nftables provides a native scripting environment to address these concerns which basically allows you to include other ruleset files, define variables and add comments. You have to restore the content of this native script through the nft -f my-ruleset.file command.

To create a nftables script, you have to add the following header to your script file:

#!/usr/sbin/nft -f

Adding comments

You can add comments to your file using the '#' character. Everything after the '#' will be ignored.

#!/usr/sbin/nft -f

#
# table declaration
#
add table filter

#
# chain declaration
#
add chain filter input { type filter hook input priority 0; policy drop; }

#
# rule declaration
#
add rule filter input ct state established,related counter accept

Including files

The example below shows how to include other ruleset files:

#!/usr/sbin/nft -f

include "ipv4-nat.ruleset"
include "ipv6-nat.ruleset"

Defining variables

You can use the define keyword to define variables, the following example shows a very simple ruleset to account the traffic that comes from 8.8.8.8 (the popular Google DNS server):

#!/usr/sbin/nft -f

define google_dns = 8.8.8.8

add table filter
add chain filter input { type filter hook input priority 0; }
add rule filter input ip saddr $google_dns counter

You can also define a variable for sets:

#!/usr/sbin/nft -f

define ntp_servers = { 84.77.40.132, 176.31.53.99, 81.19.96.148, 138.100.62.8 }

add table filter
add chain filter input { type filter hook input priority 0; }
add rule filter input ip saddr $ntp_servers counter

Don't forget that brackets have special semantics when used from rules, since they indicate that this variable represents a set. Therefore, avoid things like:

define google_dns = { 8.8.8.8 }

It is simply overkill to define a set that only stores one single element, instead use the singleton definition:

define google_dns = 8.8.8.8

File formats

nft -f <filename> accepts 2 formats, the first is the format seen in the output of nft list table. The second is using the same syntax of calling the nft binary several times, but in an atomic fashion.

Example of nftables output format:

#flush table nat
table ip nat {
	chain prerouting {
		type filter hook prerouting priority 0; policy accept;
	}

	chain postrouting {
		type filter hook postrouting priority 100; policy accept;
	}
}

Example of scripted config format:

#!/usr/sbin/nft -f

define ntp_servers = { 84.77.40.132, 176.31.53.99, 81.19.96.148, 138.100.62.8 }

add table filter
add chain filter input { type filter hook input priority 0; }
add rule filter input ip saddr $ntp_servers counter

You can freely translate between the two formats, as the syntax is mostly the same (only the organization differs). Depending on your use case, you may want to use one format or other when building your firewall.

See also

This related information is very useful when dealing with nftables scripts: