Netfilter new school with NFTABLES

Warning

on Debian 10 you’ve got an older version of nftables which requires priorities to be written by numbers instead of names. so here’s a few for reference

   0        filter
-100        dstnat
 100        srcnat

Requirements

zcat /proc/config.gz | grep NF_TABLES

Ubuntu

apt install nftables
systemctl status nftables
mv -i /etc/nftables.conf /etc/nftables.conf.dist

Slackware

slackpkg install nftables iptables libnftnl libpcap libnl3 dbus-1
mv /etc/nftables/ /etc/nftables.dist/

Make sure you have no interfering rules there (could be caused by Docker for example)

iptables -nvL
iptables -nvL -t nat
iptables -nvL -t mangle
nft list ruleset

Defaults

just for the record, the default ruleset looks like this

   flush ruleset

   table inet filter {
           chain input {
                   type filter hook input priority 0;
           }
           chain forward {
                   type filter hook forward priority 0;
           }
           chain output {
                   type filter hook output priority 0;
           }
   }

Block-all policy setup

we’re going for a very specific setup – we want TCP REJECT and ICMP HOST UNREACHABLE, not just DROP. the default policy can only be accept or drop. But reject can still be defined as last and ipso-facto default rule nevertheless.

vi /etc/nftables.conf

table inet filter
table ip nat

flush table inet filter
flush table ip nat

table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;

        iifname lo accept
        iifname != lo ip daddr 127.0.0.0/8 reject
        iifname != lo ip6 daddr ::1 reject

        ip protocol icmp accept
        ip6 nexthdr ipv6-icmp accept

        #tcp dport 2222 accept

        ct state established,related accept
        reject
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        reject
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

        # established,related,invalid

Block only the front-facing NIC

an alternative is to policy ACCEPT and filter only front-facing interface

with DROP

define nic=xenbr0

table inet filter
flush table inet filter
table inet filter {
    chain input {
        type filter hook input priority filter; policy accept;

        ip protocol icmp accept
        ip6 nexthdr ipv6-icmp accept
        ip protocol vrrp ip daddr 224.0.0.0/8 accept

        iif $nic tcp dport 2222 accept

        iif $nic ct state established,related accept
        iif $nic drop
    }
}

or with REJECT

        iif $nic ct state established,related accept
        iif $nic reject with tcp reset
        iif $nic reject with icmp type host-unreachable
        iif $nic reject

which in the end results in

                    iif eth0 ct state established,related accept
                    iif eth0 meta l4proto tcp reject with tcp reset
                    iif eth0 reject

and for a workstation e.g.

table inet filter
flush table inet filter
table inet filter {
    chain input {
        type filter hook input priority filter; policy accept;

        ip protocol icmp accept
        ip6 nexthdr ipv6-icmp accept

        # torrent on wired network only
        iif eth0 tcp dport 32002 accept

        iif eth0 ct state established,related accept
        iif eth0 drop

        iif wlan0 ct state established,related accept
        iif wlan0 drop
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
    }

    chain output {
        type filter hook output priority filter; policy accept;
    }
}

or with REJECT (same as above but twice)

SNAT

in case you got firewalling rules in place from above, you first need to allow forwarding

    # NAT --> accept
    chain forward {
            type filter hook forward priority 0; policy accept;
    }

static front-facing address

table ip nat
flush table ip nat
table ip nat {
    # SNAT
    chain postrouting {
        type nat hook postrouting priority 100;
        ip saddr INTERNAL-CIDR oif FACING-INTERFACE snat FACING-IP;
    }
}

–or– dynamic front-facing address

table ip nat {
        chain postrouting {
                type nat hook postrouting priority srcnat;
        oif eth0 masquerade
        oif wlan0 masquerade
        }
}

you can also define the subnets you wanna SNAT more precisely while masquerading

                ip saddr 192.168.122.0/24 oif wlan0 masquerade

DNAT

    # DNAT
        chain prerouting {
                type nat hook prerouting priority dstnat;
                iif $nic tcp dport 80 dnat x.x.x.x;
            #iif $nic tcp dport 80 dnat x.x.x.x:ALTERNATE-PORT;
        }

Ready to go

apply on Ubuntu

    systemctl status nftables
    systemctl start nftables
    systemctl enable nftables
    systemctl reload nftables

or on Slackware at boot time

vi /etc/rc.d/rc.inet1

# self-verbose
sysctl -w net.ipv4.ip_forward=1

echo -n FIREWALL AND SNAT...
nft -f /etc/nftables.conf && echo done || echo FAIL

Acceptance

nft list ruleset

Additional notes

flush a single table

nft flush table inet filter

If you want to be more precise on what kind of ICMP traffic you’re letting pass through, here are some hints

#icmp type echo-request accept
#icmpv6 type {echo-request,nd-neighbor-solicit} accept

also something for IPv6 here

# accept neighbour discovery otherwise connectivity breaks
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, echo-request, nd-router-advert, nd-neighbor-advert } accept

Testing

during testing phases on a remote server, avoid shooting yourself in the pants

crontab -l > /var/tmp/crontab.dist
crontab -e

*/15 * * * * nft flush ruleset

proceed (and cross fingers)

date
nft -f /etc/nftables.conf
nft list ruleset

then DO NOT FORGET TO GET RID OF THAT CRON JOB

Resources

https://wiki.nftables.org/wiki-nftables/index.php/Main_Page

https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes

https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_server

https://wiki.gentoo.org/wiki/Nftables

https://wiki.gentoo.org/wiki/Nftables/Examples

https://wiki.archlinux.org/index.php/nftables

https://wiki.archlinux.org/title/nftables

https://wiki.debian.org/nftables

https://cryptsus.com/blog/setting-up-nftables-firewall.html

https://gist.github.com/kravietz/e527895020da22cb20281d5fdee0b1da

https://linux-audit.com/nftables-beginners-guide-to-traffic-filtering/

tips & tricks

https://serverfault.com/questions/1018300/how-to-use-defined-variables-in-nftables-though-terminal-not-in-script

https://serverfault.com/questions/818323/how-to-define-port-range-in-nftables

icmp

http://shouldiblockicmp.com/

snat

https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)

[FR] https://www.it-connect.fr/chapitres/configurer-le-nat-sous-nftables/

https://superuser.com/questions/985800/complete-masquerading-nat-example-using-nftables-on-linux

https://unix.stackexchange.com/questions/283275/how-to-do-masquerading-with-nftables

dnat

https://serverfault.com/questions/895611/nftables-dnat-forwarding-is-not-working-properly

return-rst

https://wiki.archlinux.org/title/nftables

https://wiki.nftables.org/wiki-nftables/index.php/Quick_reference-nftables_in_10_minutes

https://serverfault.com/questions/157375/reject-vs-drop-when-using-iptables

Nftables opening gmabit https://discourse.pi-hole.net/t/nftables-opening-gmabit/28830

Rejecting traffic https://wiki.nftables.org/wiki-nftables/index.php/Rejecting_traffic

ops

https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains

https://wiki.nftables.org/wiki-nftables/index.php/Operations_at_ruleset_level

https://wiki.nftables.org/wiki-nftables/index.php/Simple_rule_management

https://wiki.archlinux.org/title/nftables#Flush_table

troubles

https://wiki.nftables.org/wiki-nftables/index.php/Ruleset_debug/tracing

priorities

https://unix.stackexchange.com/questions/419851/when-and-how-to-use-chain-priorities-in-nftables

ip-based acls

https://unix.stackexchange.com/questions/558581/nftables-allow-redis-only-from-specific-ip-addresses


HOME | GUIDES | LECTURES | LAB | SMTP HEALTH | HTML5
Copyright © 2022 Pierre-Philipp Braun