From b10c77936256989ecd50887edbbd8325131878b0 Mon Sep 17 00:00:00 2001 From: Simon Cornet Date: Mon, 16 Feb 2026 17:33:01 +0100 Subject: [PATCH] feat: nftables > iptables --- handlers/main.yaml | 6 ++-- tasks/firewall.yaml | 44 ++++------------------------- tasks/routing.yaml | 6 ++-- templates/nftables.conf.j2 | 57 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 templates/nftables.conf.j2 diff --git a/handlers/main.yaml b/handlers/main.yaml index dee2aa5..bc8bff4 100644 --- a/handlers/main.yaml +++ b/handlers/main.yaml @@ -1,9 +1,9 @@ --- -# restart iptables -- name: "restart iptables" +# restart nftables +- name: "restart nftables" ansible.builtin.service: - name: "iptables" + name: "nftables" state: "restarted" # apply local routes diff --git a/tasks/firewall.yaml b/tasks/firewall.yaml index e51fe87..7e9b697 100644 --- a/tasks/firewall.yaml +++ b/tasks/firewall.yaml @@ -1,46 +1,14 @@ --- -# deploy ipv4 iptable rules -- name: "firewall - ipv4 rules" - ansible.builtin.copy: - dest: "/etc/iptables/rules-save" +# deploy nftables rules +- name: "firewall - nftables rules" + ansible.builtin.template: + src: "nftables.conf.j2" + dest: "/etc/nftables.conf" mode: "0600" owner: "root" group: "root" - content: | - *nat - :PREROUTING ACCEPT [0:0] - :INPUT ACCEPT [0:0] - :OUTPUT ACCEPT [0:0] - :POSTROUTING ACCEPT [0:0] - # NAT masquerade from LAN to WAN - -A POSTROUTING -o {{ wan_interface }} -j MASQUERADE - {% for forward in nat_port_forwards %} - # {{ forward.name }} - -A PREROUTING -i {{ wan_interface }} -p {{ forward.protocol | default('tcp') }} --dport {{ forward.port }} -j DNAT --to-destination {{ forward.dst }}:{{ forward.port }} - {% endfor %} - COMMIT - - *filter - :INPUT DROP [0:0] - :FORWARD DROP [0:0] - :OUTPUT ACCEPT [0:0] - # Allow established/related - -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT - -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT - # Allow loopback - -A INPUT -i lo -j ACCEPT - # Allow LAN management access - -A INPUT -i {{ lan_interface }} -j ACCEPT - # Allow forwarding from LAN to anywhere - -A FORWARD -i {{ lan_interface }} -o {{ wan_interface }} -j ACCEPT - {% for forward in nat_port_forwards %} - # {{ forward.name }} - -A FORWARD -i {{ wan_interface }} -o {{ lan_interface }} -d {{ forward.dst }} -p {{ forward.protocol | default('tcp') }} --dport {{ forward.port }} -j ACCEPT - {% endfor %} - COMMIT - notify: "restart iptables" - + notify: "restart nftables" # load nf_conntrack module - name: "firewall - load nf_conntrack module" diff --git a/tasks/routing.yaml b/tasks/routing.yaml index be2a0fe..390c45c 100644 --- a/tasks/routing.yaml +++ b/tasks/routing.yaml @@ -1,10 +1,10 @@ --- -# install iptables -- name: "routing - install ptables" +# install nftables +- name: "routing - install nftables" community.general.apk: name: - - "iptables" + - "nftables" state: "present" update_cache: true diff --git a/templates/nftables.conf.j2 b/templates/nftables.conf.j2 new file mode 100644 index 0000000..ec6e04f --- /dev/null +++ b/templates/nftables.conf.j2 @@ -0,0 +1,57 @@ +#!/usr/sbin/nft -f + +flush ruleset + +table inet filter { + chain input { + type filter hook input priority 0; policy drop; + + # Allow established/related + ct state established,related accept + + # Allow loopback + iif lo accept + + # Allow LAN management access + iif {{ lan_interface }} accept + + # Allow ICMP + ip protocol icmp accept + ip6 nexthdr ipv6-icmp accept + } + + chain forward { + type filter hook forward priority 0; policy drop; + + # Allow established/related + ct state established,related accept + + # Allow forwarding from LAN to anywhere + iif {{ lan_interface }} oif {{ wan_interface }} accept +{% for forward in nat_port_forwards %} + # {{ forward.name }} + iif {{ wan_interface }} oif {{ lan_interface }} ip daddr {{ forward.dst }} {{ forward.protocol | default('tcp') }} dport {{ forward.port }} accept +{% endfor %} + } + + chain output { + type filter hook output priority 0; policy accept; + } +} + +table ip nat { + chain postrouting { + type nat hook postrouting priority 100; policy accept; + + # NAT masquerade from LAN to WAN + oif {{ wan_interface }} masquerade + } + + chain prerouting { + type nat hook prerouting priority -100; policy accept; +{% for forward in nat_port_forwards %} + # {{ forward.name }} + iif {{ wan_interface }} {{ forward.protocol | default('tcp') }} dport {{ forward.port }} dnat to {{ forward.dst }}:{{ forward.port }} +{% endfor %} + } +}