[olug] switching from iptables to nftables

Lou Duchez lou at paprikash.com
Sun Jun 30 10:01:27 CDT 2019

... one interesting thing I learned about nftables: it takes a little 
jiggering to get nftables and fail2ban to get along.  Not much, though.

So with nftables, you set up your chains and rules and etc to operate on 
one of a few families, such as "ip", "ip6", or "inet" (which encompasses 
"ip" and "ip6").  "inet" seems like a natural choice, but if you want to 
do NAT, you can't; you have to use "ip" or "ip6".

fail2ban, on the other hand, defaults to "inet".  So if you want to do 
NAT and you also want to use fail2ban, you need to teach fail2ban to use 
"ip" (or "ip6" I suppose).  Here's what to do:

- Create a file called /etc/fail2ban/action.d/nftables-common.local, 
that consists of:

    nftables_family = ip

- And when you're setting up your actions in /etc/fail2ban/jail.local, 
they'll be "nftables-multiport" rather than "iptables" or 
"iptables-multiport".  (This applies whether or not you're doing NAT.)

> I finally decided to bite the bullet and start playing with nftables.  
> In theory it'll do all the things iptables will do, but offers 
> efficiencies that iptables does not.  It also incorporates 
> functionality that, under the iptables paradigm, required using the 
> ipset utility.
> One caution: I had more trouble getting my nftables configuration to 
> actually take effect.  Turns out there was some remnant or other of 
> iptables still lurking in the system, and I decided to cope with that 
> by uninstalling iptables altogether.  So if nftables simply refuses to 
> work for you, it might be iptables.
> Here is a simple firewall config, to open only specific ports to the 
> world, and to open up some ports only to trusted IPs.  First I open 
> traffic to the world-accessible ports, then I drop any traffic that 
> doesn't come from a trusted IP, and then finally I open ports that 
> only trusted IPs should get at.
> table ip filter {
>         # my set of trusted IPs
>         set MY_TRUSTED_IPS {
>                 type ipv4_addr
>                 flags interval
>                 elements = {,,
>                    , }
>         }
>         # my inbound traffic chain -- note that I specify it hooks 
> into the "input" process
>         chain MY_INBOUND_TRAFFIC {
>                 type filter hook input priority 0; policy drop;
>                # the two most basic rules: keep allowing existing 
> connections, and also allow loopback traffic
>                 ct state established,related accept
>                 iifname "lo" accept
>                # allow Web traffic, and pings (no more than 2 per second)
>                 tcp dport http accept
>                 icmp type echo-request limit rate 2/second accept
>                # check if the incoming IP is a trusted IP, and if it's 
> not, drop whatever traffic
>                 jump untrustedbans
>                # now that we've weeded out untrusted sources, we can 
> open up the SSH port
>                 tcp dport 22 accept
>         }
>         # my outbound traffic chain -- note that I specify it hooks 
> into the "output" process
>         #
>         # it doesn't do much other than "accept" outbound traffic; 
> it's there for future use and my love of symmetry
>         chain MY_OUTBOUND_TRAFFIC {
>                 type filter hook output priority 0; policy accept;
>         }
>        # my chain for dealing with untrusted IPs: if the source 
> address is in the trusted list, return out of this chain,
>        # otherwise drop the traffic
>        chain untrustedbans {
>                 ip saddr @MY_TRUSTED_IPS return
>                 drop
>         }
> }

More information about the OLUG mailing list