Future iptables : nftables

Quick introduction

NFTables is the successor of iptables and it has a new easier syntax. Multiple iptables command can be merged into one nftables command. Here is a short review:-

  • nftables project aims to replace iptables, along with {ip6,arp,eb}tables, using them as foundation.
  • BPF friendly
  • better performance
  • runs in userspace, which means no kernel upgrade for adding new features
  • works well on linux 3.15+
  • said to work fine along with iptables, except for nat & mangle
  • one can create own table, chain
  • one can use multiple matches and actions in a single command

Further down

Here is a good howto on installation and basics, that you must read.
I felt that the existing wikis are confusing, cause they were trying to reuse iptable's table and chain names. Here is something which I hope to ease things. The below diagram is a summary of nftables, covering the basics.

nftables overview

So, when creating tables you need family name. While creating chain you need to mention chain type and hook type, which is were it resembles iptables. Also while creating chain, you need to mention priority, which is used when there are multiple chains in the same hook type. One command can have multiple combinations of matches followed by multiple actions.

nft is the command name and here are some of the options list.
nft command overview

Common Operations

# add a new table named hostfirewall
nft add table inet hostfirewall 

# list all tables within family inet (ip and ip6)
nft list tables inet 



# add chain 
nft add chain inet hostfirewall ingress { type filter hook input priority 100 \; } 



# list all chains and rules within a table 
nft list inet  hostfirewall 



# add rule to block inboud http from specific ip 
# nft [operation] [family] [table-name] [chain-name] [match1] [match2] [action] 
nft add   rule   inet    hostfirewall   ingress   tcp dport 80    ip daddr 1.1.1.1    drop   




# insert a rule below above 
nft insert rule inet hostfirewall ingress tcp dport 80 ip daddr 1.1.1.2 accept 

# insert a rule between the two above rules
## first list rule 
nft -nna list chain  inet hostfirewall ingress  
table inet hostfirewall {
	chain ingress {
		 type filter hook input priority 100;
		 tcp dport 80 ip daddr 1.1.1.2 accept # handle 3
		 tcp dport 80 ip daddr 1.1.1.1 drop # handle 2
	}
}
## note the handle numbers, equivalent to iptables  --line-numbers 
## insert rule in position 2 
nft insert rule inet hostfirewall  ingress  position 2  tcp dport 80 ip daddr  1.1.1.3 accept
nft -nna list chain  inet hostfirewall ingress   
table inet hostfirewall {
	chain ingress {
		 type filter hook input priority 100;
		 tcp dport 80 ip daddr 1.1.1.2 accept # handle 3
		 tcp dport 80 ip daddr 1.1.1.3 accept # handle 4
		 tcp dport 80 ip daddr 1.1.1.1 drop # handle 2
	}
}




Save/Restore tables

# Save/restore rules using a file 
nft list table inet hostfirewall    > /tmp/hostfirewall.fw  
## delete table for test
nft delete table  inet hostfirewall   
## restore table 
nft -f /tmp/hostfirewall.fw   
## list table 
nft list table inet hostfirewall  
table inet hostfirewall {
	chain ingress {
		 type filter hook input priority 100;
		 tcp dport http ip daddr 1.1.1.2 accept
		 tcp dport http ip daddr 1.1.1.3 accept
		 tcp dport http ip daddr 1.1.1.1 drop
	}
}

Using expressions in rule

nft provides with the following expressions working with numbers.

ne - Not equal to 
lt - Less than 
gt - Greater than 
le - Less than equal to 
ge - Greater than equal to 
nft insert rule  inet hostfirewall  ingress  tcp dport ne 22  ip daddr  1.1.1.4  drop

Using sets

There are 2 ways of using multiple values in a set, like multiple ip list or port list. One way is to mention it inline the rule command (called anonymous set), which cannot be modified.

# Anonymous set 
nft add rule inet hostfirewall ingress   tcp dport { 21, 443, 8080 , 8000 } drop

The other way is by using named sets which can be constantly updated.

# Named set 
## create a named set 
nft add set inet hostfirewall  blacklist { type ipv4_addr \; }

## use set to block specific port
nft add rule  inet hostfirewall   ingress  tcp dport  443 ip daddr @blacklist drop

## adding ips in blacklist set 
nft add  element  inet hostfirewall  blacklist  { 1.2.1.3,  1.1.3.2 }
 
 

The following types can be used in set and dictionary:-

ipv4_addr   - IPv4 address 
ether_addr  - Physicall address
inet_proto  - Inet protocol type  
inet_service- Service name/port number 
mark 	    - mark type  

Using dictionary

A very interesting feature, which lets you match and take action at the same time. Again, you can create anonymous and named dictionaries.

# anonymous dictionary (self explanatory) 
 nft add rule inet hostfirewall ingress  tcp  dport 22  ip daddr  vmap { 1.1.3.1 : accept ,  1.5.6.3: drop  } 


# named dictionary 
nft add map  inet  hostfirewall  white_blacklist  { type  ipv4_addr : verdict \; }  
## adding rule to use named dictionary 
nft add  rule inet hostfirewall  ingress tcp dport 22  ip daddr vmap @white_blacklist
## add element to dictionary 
nft add  element  inet hostfirewall   white_blacklist { 1.2.3.2: drop , 1.1.3.2: accept }

~~Dictionary can be used efficiently in cases like dnat, redirect, snat. ~~

Rate limit

Commonly used rate limiting feature in iptables, to log dropped requests, can be replicated by the following:-

nft add rule inet hostfirewall  ingress   limit rate 5/second  log prefix \" **ingress** \" drop 

Match on socket username or user id

Another good feature of nftables is to write rules based on user running a socket. Works with ip family.

## Block inbound request from a specific user to all sockets run by user id 1000 
nft add table   fw
nft add chain fw ingress { type filter  hook input   priorit 100 \; }  
nft add rule fw ingress   meta skuid 1000 ip daddr 1.1.1.1 drop 

Using ranges

Ranges can be specified by using "-".

nft add rule  fw  ingress  ip daddr 1.1.1.1-1.1.1.100 accept 
nft add rule fw ingress   tcp sport  8000-9000 accept 

List all ruleset

To use list of all rules, equivalent to iptables -L.

nft list ruleset 

Setting up router

Using nft to manage routing, with masquerade.

nft  add table   rfw 
nft add chain rfw  pass { type filter     hook forward priority 100 \; }


# add a chain within table, like iptables -X chain_name 
nft add chain rfw infranet
nft add rule   rfw infranet   ip daddr 2.1.1.1 tcp dport  443 accept   
nft add rule   rfw infranet   ip daddr 2.1.1.10 tcp dport   993 accept   
nft add rule   rfw infranet   ip daddr 2.1.1.50 tcp dport   576 accept   
nft add rule   rfw infranet   drop  
nft add rule rfw  pass ip daddr  2.1.1.0/24  meta iifname eth0  goto infranet 

# masquerade rule 
nft add chain  rfw masq { type  nat hook postrouting priority 100 \; }
nft add rule  rfw masq meta iifname eth0 meta oifname  eth4  masquerade


DNAT rule

nft add chain rfw  preroute  { type  nat hook prerouting priority 100 \; }
nft add rule  rfw preroute  meta iifname  eth04 tcp dport 4000-5000  dnat  192.168.24.6

Flushing rules


## Flush all rules within table 
nft flush table rfw 

## Flush rules and not delete , within chain 
nft flush chain rfw masq 

## Flush all ruleset DANGEROUS
nft flush ruleset 

Summary

Note:-

  • In nft command, if family is not mentioned, family type is set to ip by default. You can skip family type in the commands. It is used only to stress the fact, there can be same table names under different family
  • In nft command, most operations use table name to reference to rules or chains or named sets or named dictionaries
  • When using mutliple matches like tcp port 22 ip daddr 1.1.1.1, the point to note is that the execution is done from left to right
  • Better to avoid using iptables and nftables
  • What makes nftables so good is simplicity in options. Once you get the hang of it, you will love it
  • In chain priority, the higher the value, higher the priority
Dinesh Gunasekar - | Tags : nftables, firewall
comments powered by Disqus