Table of Contents

, , ,

NFTables Configuration

The best reference for nftables is at the dedicated wiki wiki nftables. Some other references I found nftables router. The reference at stosb is good, but not for a router Explaining My Configs: nftables.

After a lot of experimenting the following is my NFTables router configuration file. Create the following file called: “router.nft”.

Dont forget to ensure the router is allowed to forward packets:

Sample NFTables configuration

sudo vim /etc/nftables.conf

Router NFtable Setup - ''/etc/nftables.conf''

mail server ports:

Some configuration notes

Refer to nftables wiki Matching packets by interface name. The use of interface index of the interface name causes an error on boot of the nftables.service, probably because the interface has not been brought up and indexed. Yet the name index of lo does work, perhaps it is predefined. Using the network interface name works. Use of name indexes is said to be faster than names. One possible way around this would be to have a basic nftables.service script for boot, dropping all connectivity, except local ssh ports and have a separate end of boot script with the full nftables script.

:!: It is important to remember that the order of the commands in a chain is very important. An earlier accept, drop or reject action will terminate further processing of a packet within that chain.
:!: My setup is based upon a static wan ip address. Dynamic ip wan address would require additional configuration and would not be as stable.

Some key related commands:

There seem to be a number of way to to allow port forwarding from WAN to LAN.

Using type filter hook forward priority 0; policy drop; for forwarding and type nat hook prerouting priority 0; for prerouting.

Prerouting: iif $external tcp dport { http, https } dnat home_srv, where “home_srv” host DNS resolves to IP address

  1. ip daddr home_srv ct status dnat accept
  2. ip daddr home_srv tcp dport {http, https} accept (not checked, taken from IPTables -A FORWARD -p tcp -d 192.168.99.100 –dport 80 -j ACCEPT)
  3. tcp dport {http, https} ct state new accept

Hairpin NAT

After setting up and getting my router to function I found that I could not access my local http pages. This is a NAT problem*. The solution is hairpin NAT also known as NAT loopback or NAT reflection.

The following are some resources that discuss this:

The following commands provide a complete ipv4 NAT solution, including hairpin NAT using NFTables firewall:

  1. prerouting (standard)
    1. sudo nft add rule ip nat prerouting ip daddr 2.3.4.5/32 tcp dport {http, https} dnat 192.168.3.11
  2. postrouting (standard)
    1. Using masquerade: sudo nft add rule ip nat postrouting ip saddr 192.168.3.0/24 ip oifname ppp1 masquerade
    2. Using snat: sudo nft add rule ip nat postrouting ip saddr 192.168.3.0/24 ip oifname ppp1 snat 2.3.4.5/32
  3. postrouting (hairpin)
    1. Using snat to external ip: sudo nft add rule ip nat postrouting ip saddr 192.168.3.0/24 ip daddr 192.168.3.11/32 tcp dport {http, https} counter snat 2.3.4.5/32
    2. Using snat to internal ip: sudo nft add rule ip nat postrouting ip saddr 192.168.3.0/24 ip daddr 192.168.3.11/32 tcp dport {http, https} counter snat 192.168.3.1/32
    3. Using masquerade (to internal ip): sudo nft add rule ip nat postrouting ip saddr 192.168.3.0/24 ip daddr 192.168.3.11/32 tcp dport {http, https} counter masquerade

Notes:

  1. Where options for snat or masquerade are given, either snat or masquerade can be used, not both.
  2. Hairpin snat to the router/gateway external address is expected to function correctly.
  3. masquerade versus snat:
    1. Masquerade operates directly with dynamic wan ip.
    2. Dynamic wan ip does not operate with snat reliably.
    3. Masquerade requires more router resources than snat

This only affects local networks that use NAT which is basically mandatory for IPv4 and not required for IPv6, hence unless NAT is used in a IPv6 local network hairpin.

* Whilst investigating this matter's commentary it was often stated that this problem is better solved using DNS. I was some what confused by SSL certificate DNS verification, and local DNS resolution. Then there was all the talk about dual horizon or split DNS. Basically the certificate authority may use WAN DNS to verify ownership of web site. I need to program my domain name suppliers DNS with the certificate info and this is used to verify my control and ownership of the domain and allow issue of certificate to me. My LAN DNS is effectively a split horizon in that LAN DNS server resolves my LAN addresses, all external address are ultimately passed to the WAN for resolution, although the results may be temporarily store locally to speed up subsequent DNS queries. If my LAN servers have valid certificates and the LAN DNS addresses used are valid then it serves the secure service reliably off the LAN. Presumably it still needs to perform CA verification of the WAN, not sure about this. The local DNS server cannot be directly addressed from the WAN. If a WAN incoming service passes my WAN router firewall and is correctly directed directed to the LAN server and this server has a valid certificate then this will also function using the WAN address. A LAN DNS is definitely a more elegant method to serve local content than hairpin NAT!. This also explains why my NFTables hairpin NAT has always been showing no usage since I first experimented. The LAN DNS makes it unnecessary. I have recently been using Traefik in a Docker container to act as my back-end server proxy and manager of certificates main and sub-domain wildcard.

Diagram 1
DNAT, Simple, Hairpin, not working and Hairpin working
(Where the gateway (router) is on the network WAN device)

Some additional hand NFtables commands to adjust online:

A good reference for this is in wiki.nftables.org Quick reference-nftables in 10 minutes

IPv6 NFTables Setup (For Hurricane Electric Tunnel)

sudo nft add rule inet firewall forward iifname “he-ipv6” counter jump base_checks

sudo nft add rule inet firewall forward iifname “br0” oifname “he-ipv6” counter accept

The following rule did not work: sudo nft add rule inet firewall forward iifname “he-ipv6” oifname “br0” counter jump base_checks

Some info on NAT with NFTables and be seen in the following references: wiki.nftables.org - Performing Network Address Translation (NAT), Ars Technica SNAT vs. DNAT vs. Masquerading and wiki.gentoo.org Nftables/Examples. It is interesting to see that the nftables wiki states that iptables NAT must be turned off with sudo rmmod iptable_nat.

How to make NFTables configuration permanent / restore on boot

The systemd service nftables can be used to auto start nftables and is setup to load the nftable configuration file at /etc/nftables.conf. Use sudo systemctl status/start/stop/reload/enable/disable nftables.

Start and reload basically run /usr/sbin/nft -f /etc/nftables.conf, whereas stop runs /usr/sbin/nft flush ruleset

The command systemctl show -p FragmentPath nftables shows where the systemctl script is located; /lib/systemd/system/nftables.service, in my case.

See nftables-systemd on github.com