gemini://://perso.pw/blog/articles/nftables.gmi
View on Gemini
#

Introduction to nftables on Linux

  • Author: Solène
  • Date: 06 February 2023
  • Tags: linux firewall nftables

#

Introduction

Linux kernel has an integrated firewall named netfilter, but you manipulate it through command lines such as the good old iptables, or nftables which will eventually superseed iptables.

Today, I'll share my experience in using nftables to manage my Linux home router, and my workstation.

I won't explain much in this blog post because I just want to introduce nftables and show what it looks like, and how to get started.

I added comments in my configuration files, I hope it's enough to get a grasp and make you curious to learn about nftables if you use Linux.

#

Configurations

nftables works by creating a file running `nft -f` in the shebang, this allows atomic replacement of the ruleset if it's valid.

Depending on your system, you may need to run the script at boot, but for instance on Gentoo, a systemd service is provided to save rules upon shutdown and restore them at boot.

##

Router

```
#!/sbin/nft -f
```
flush ruleset
```
```
table inet filter {
```
```
    # defines a list of networks for further reference
```
    set safe_local {
```
	type ipv4_addr
```
	flags interval
```
```
	elements = { 10.42.42.0/24 }
```
    }
```
```
    chain input {
```
        # drop by default
```
        type filter hook input priority 0; policy drop;
```
        ct state invalid drop comment "early drop of invalid packets"
```
```
        # allow connections to work when initiated from this system
```
        ct state {established, related} accept comment "accept all connections related to connections made by us"
```
```
        # allow loopback
```
        iif lo accept comment "accept loopback"
```
```
        # remove weird packets
```
        iif != lo ip daddr 127.0.0.1/8 drop comment "drop connections to loopback not coming from loopback"
```
        iif != lo ip6 daddr ::1/128    drop comment "drop connections to loopback not coming from loopback"
```
```
        # make ICMP work
```
        ip protocol icmp accept comment "accept all ICMP types"
```
        ip6 nexthdr icmpv6 accept comment "accept all ICMP types"
```
```
        # only for known local networks
```
        ip saddr @safe_local tcp dport {22, 53, 80, 2222, 19999, 12344, 12345, 12346} accept
```
        ip saddr @safe_local udp dport {53} accept
```
```
        # allow on WAN
```
        iif eth0 tcp dport {80} accept
```
        iif eth0 udp dport {7495} accept
```
    }
```
```
    # allow NAT to get outside
```
    chain lan_masquerade {
```
        type nat hook postrouting priority srcnat;
```
        meta nfproto ipv4 oifname "eth0" masquerade
```
    }
```
```
    # port forwarding
```
    chain lan_nat {
```
        type nat hook prerouting priority dstnat;
```
        iif eth0 tcp dport 80 dnat ip to 10.42.42.102:8080
```
    }
```
```
}

##

Workstation

```
#!/sbin/nft -f
```
```
flush ruleset
```
```
table inet filter {
```
```
    set safe_local {
```
	type ipv4_addr
```
	flags interval
```
```
	elements = { 10.42.42.0/24, 10.43.43.1/32 }
```
    }
```
```
    chain input {
```
        # drop by default
```
        type filter hook input priority 0; policy drop;
```
        ct state invalid drop comment "early drop of invalid packets"
```
```
        # allow connections to work when initiated from this system
```
        ct state {established, related} accept comment "accept all connections related to connections made by us"
```
```
        # allow loopback
```
        iif lo accept comment "accept loopback"
```
```
        # remove weird packets
```
        iif != lo ip daddr 127.0.0.1/8 drop comment "drop connections to loopback not coming from loopback"
```
        iif != lo ip6 daddr ::1/128    drop comment "drop connections to loopback not coming from loopback"
```
```
        # make ICMP work
```
        ip protocol icmp accept comment "accept all ICMP types"
```
        ip6 nexthdr icmpv6 accept comment "accept all ICMP types"
```
```
        # only for known local networks
```
        ip saddr @safe_local tcp dport 22 accept comment "accept SSH"
```
        ip saddr @safe_local tcp dport {7905, 7906} accept comment "accept musikcube"
```
        ip saddr @safe_local tcp dport 8080 accept comment "accept nginx"
```
        ip saddr @safe_local tcp dport 1714-1764 accept comment "accept kdeconnect TCP"
```
        ip saddr @safe_local udp dport 1714-1764 accept comment "accept kdeconnect UDP"
```
        ip saddr @safe_local tcp dport 22000 accept comment "accept syncthing"
```
        ip saddr @safe_local udp dport 22000 accept comment "accept syncthing"
```
        ip saddr @safe_local tcp dport {139, 775, 445} accept comment "accept samba"
```
        ip saddr @safe_local tcp dport {111, 775, 2049} accept comment "accept NFS TCP"
```
        ip saddr @safe_local udp dport 111 accept comment "accept NFS UDP"
```
```
        # for my public IP over VPN
```
        ip daddr 78.224.46.36 udp dport 57500-57600 accept comment "accept mosh"
```
        ip6 daddr 2a00:5854:2151::1 udp dport 57500-57600 accept comment "accept mosh"
```
```
    }
```
```
    # drop anything that looks forwarded
```
    chain forward {
```
        type filter hook forward priority 0; policy drop;
```
    }
```
```
}

#

Some commands

If you need to operate a firewall using nftables, you may use `nft` to add/remove rules on the go instead of using the script with the ruleset.

However, let me share a small cheatsheet of useful commands:

##

List rules

If you need to display the current rules in use:

```
nft list ruleset

##

Flush rules

If you want to delete all the rules, just use:

```
nft flush ruleset

#

Going further

If you want to learn more about nftables, there is the excellent man page of the command `nft`.

I used some resources from Arch Linux and Gentoo that you may also enjoy: