| Title: Introduction to nftables on Linux | |
| Author: Solène | |
| Date: 06 February 2023 | |
| Tags: linux firewall nftables | |
| Description: In this article, I'll share my simple setup using 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 | |
| ```nftables | |
| #!/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 … | |
| # 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 loopba… | |
| iif != lo ip6 daddr ::1/128 drop comment "drop connections to loopba… | |
| # 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, … | |
| 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 | |
| ```nftables | |
| #!/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 … | |
| # 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 loopba… | |
| iif != lo ip6 daddr ::1/128 drop comment "drop connections to loopba… | |
| # 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 musi… | |
| ip saddr @safe_local tcp dport 8080 accept comment "accept nginx" | |
| ip saddr @safe_local tcp dport 1714-1764 accept comment "accept kdeconn… | |
| ip saddr @safe_local udp dport 1714-1764 accept comment "accept kdeconn… | |
| 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 s… | |
| ip saddr @safe_local tcp dport {111, 775, 2049} accept comment "accept … | |
| 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 "accep… | |
| } | |
| # 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: | |
| ```shell | |
| nft list ruleset | |
| ``` | |
| ## Flush rules | |
| If you want to delete all the rules, just use: | |
| ```shell | |
| 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: | |
| Gentoo Wiki: Nftables | |
| Gentoo Wiki: Nftables examples | |
| Arch Linux Wiki: Nftables |