Concatenations
Since Linux kernel 4.1, nftables supports concatenations.
This new feature allows you to put two or more selectors together to perform very fast lookups by combining them with sets, dictionaries, maps and meters.
Literal sets
% nft add rule ip filter input ip saddr . ip daddr . ip protocol { 1.1.1.1 . 2.2.2.2 . tcp, 1.1.1.1 . 3.3.3.3 . udp} counter accept
So if the packet is source IP address AND destination IP address AND TCP destination port match:
- 1.1.1.1 and 2.2.2.2 and TCP.
or
- 1.1.1.1 and 3.3.3.3 and UDP.
nftables updates the counter for this rule and then accepts the packet.
Dictionary declarations
The following example creates the whitelist dictionary using a concatenation of two selectors:
% nft add map filter whitelist { type ipv4_addr . inet_service : verdict \; }
Once you create the dictionary, you can use it from a rule that creates the following concatenation:
% nft add rule filter input ip saddr . tcp dport vmap @whitelist
Thus, the rule above looks up for a verdict based on the source IP address AND the TCP destination port.
Since the dictionary is initially empty, you can dynamically populate this dictionary with elements through:
% nft add element filter whitelist { 1.2.3.4 . 22 : accept}
Literal maps
The rule below determines the destination IP address that is used to perform DNAT to the packet based on:
- the source IP address
AND
- the destination TCP port
% nft add rule ip nat prerouting dnat ip saddr . tcp dport map { 1.1.1.1 . 80 : 192.168.1.100, 2.2.2.2 . 8888 : 192.168.1.101 }
Examples
Some concrete example concatenations so you get an idea on how powerful this new feature is.
Network addresses
The example below implements a dictionary using network masks as matching element.
% nft add rule tablename chainname ip saddr and 255.255.255.0 . ip daddr and 255.255.255.0 vmap { 10.10.10.0 . 10.10.20.0 : accept }
Note that this is not an interval, this is masking the ip saddr and ip daddr, then concate both results. This concatenation is used to lookup for a matching of this the result in the map. This syntax may be compacted in future releases to support CIDR notation.
This could be easily implemented using a named map as well:
% nft add map tablename myMap { type ipv4_addr . ipv4_addr : verdict \; }
% nft add rule tablename chainname ip saddr and 255.255.255.0 . ip saddr and 255.255.255.0 vmap @myMap
% nft add element tablename myMap { 10.10.10.0 . 10.10.20.0 : accept }
Interfaces
The example below checks both input and output interfaces of a forwarded packet.
% nft add rule tablename chainname iif . oif vmap { eth0 . eth1 : accept }
Please note that using strings (for example iifname and oifname) and other variable sized data types is not supported yet.
Some ipset types
These ipset types can be implemented in nftables using concatenations. Probably more equivalences exists, it just a matter of combining data types. Of course, you could implement these as named maps/sets as well.
hash:net,net
% nft add rule tablename chainname ip saddr and 255.255.255.0 . ip daddr and 255.255.255.0 vmap { 10.10.10.0 . 10.10.20.0 : accept }
hash:net,port,net
% nft add rule tablename chainname ip saddr and 255.255.255.0 . tcp dport . ip daddr and 255.255.255.0 vmap { 10.10.10.0 . 80 . 10.10.20.0 : accept }
hash:net,iface
% nft add rule tablename chainname ip saddr and 255.255.255.0 . iif vmap { 10.10.10.0 . eth0 : accept }