![]() |
VOOZH | about |
nftables comes with a built-in generic set infrastructure that allows you to use any supported selector to build sets. This infrastructure makes possible the representation of maps and verdict maps.
The set elements are internally represented using performance data structures such as hashtables and red-black trees.
Anonymous sets are those that are:
The following example shows how to create a simple set.
%nftaddruleipfilteroutputtcpdport{22,23}counter
This rule above catches all traffic going to TCP ports 22 and 23, in case of matching the counters are updated.
Eric Leblond in his Why you will love nftables article shows a very simple example to compare iptables with nftables:
ip6tables-AINPUT-ptcp-mmultiport--dports23,80,443-jACCEPT
ip6tables-AINPUT-picmpv6--icmpv6-typeneighbor-solicitation-jACCEPT
ip6tables-AINPUT-picmpv6--icmpv6-typeecho-request-jACCEPT
ip6tables-AINPUT-picmpv6--icmpv6-typerouter-advertisement-jACCEPT
ip6tables-AINPUT-picmpv6--icmpv6-typeneighbor-advertisement-jACCEPT
Which can be expressed in nftables with a couple of rules that provide a set:
%nftaddruleip6filterinputtcpdport{telnet,http,https}accept %nftaddruleip6filterinputicmpv6type{nd-neighbor-solicit,echo-request,nd-router-advert,nd-neighbor-advert}accept
You can use nft add set to create a named set. For example:
%nftaddsetipfilterblackhole{typeipv4_addr\;comment\"dropallpacketsfromthesehosts\"\;}
creates a set named blackhole. Set names must be 16 characters or less. The optional set comment attribute requires at least nftables 0.9.7 and kernel 5.10. The type keyword indicates the data type of elements to be stored in the set. In this case blackhole stores IPv4 addresses, which you can add using nft add element:
%nftaddelementipfilterblackhole{192.168.3.4} %nftaddelementipfilterblackhole{192.168.1.4,192.168.1.5}
You can use named sets from rules, as for example:
%nftaddruleipfilterinputipsaddr@blackholedrop
%nftaddruleipfilteroutputipdaddr!=@blackholeaccept
Named sets can be updated anytime.
When working with nftables.conf, you can define sets in a number of ways. You can then reference those sets later on using $VARIABLE_NAME notation.
Here are some examples showing sets defined in one line, spanning multiple lines, and sets referencing other sets. The set is then used in a rule to allow incoming traffic from certain IP ranges.
defineSIMPLE_SET={192.168.1.1,192.168.1.2} defineCDN_EDGE={ 192.168.1.1, 192.168.1.2, 192.168.1.3, 10.0.0.0/8 } defineCDN_MONITORS={ 192.168.1.10, 192.168.1.20 } defineCDN={ $CDN_EDGE, $CDN_MONITORS } # Allow HTTP(S) from approved IP ranges only tcpdport{http,https}ipsaddr$CDNaccept udpdport{http,https}ipsaddr$CDNaccept
Sets specifications are:
Supported data types if using the type keyword are:
The typeof keyword is available since 0.9.4 and allows you to use a high level expression, then let nftables resolve the base type for you:
tableinetmytable{ sets1{ typeofosfname elements={"Linux"} } sets2{ typeofvlanid elements={2,3,103} } sets3{ typeofipdaddr elements={1.1.1.1} } }
%nftaddtableipfilter %nftaddsetipfilterports{typeinet_service\;timeout3h45s\;}
These commands create a table named filter and add a set named ports to it, where elements are deleted after 3 hours and 45 seconds of being added.
Multiple flags should be separated by comma:
%nftaddsetipfilterflags_set{typeipv4_addr\;flagsconstant,interval\;}
%nftaddsetipfilterdaddrs{typeipv4_addr\;flagstimeout\;elements={192.168.1.1timeout10s,192.168.1.2timeout30s}\;}
This command creates a set name daddrs with elements 192.168.1.1, which stays in it for 10s, and 192.168.1.2, which stays for 30s.
%nftaddsetipfiltersaddrs{typeipv4_addr\;size2\;}
tableinetmytable{ sets{ typeofipsaddr counter elements={1.1.1.1counterpackets0bytes0,1.1.1.2counterpackets0bytes0, 1.1.1.3counterpackets0bytes0,1.1.1.4counterpackets0bytes0} } }
For example, this origin set configuration will collapse the elements into the CIDR:
tableinetmytable{ setmyset{ typeofipsaddr flagsinterval auto-merge elements={10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.0/8, } } }
Resulting in this when you list back the ruleset, because the CIDR already contains the individual elements:
tableinetmytable{ setmyset{ typeofipsaddr flagsinterval auto-merge elements={10.0.0.0/8, } } }
Also, note that not using auto-merge will make such ruleset fail to load with something like:
/etc/nftables/ruleset.nft:38:21-29: Error: conflicting intervals specified 10.0.0.1 , ~~~~~~~^^^^^^^^^
You can list the content of a named set via:
%nftlistsetipfiltermyset
You can also check if an element exists in the set from its key:
%nftgetelementipfiltermyset{1.1.1.1}
The example above checks if the IPv4 address 1.1.1.1 exists in the myset set.