From 20dd97aafaa028aa76a51573211007068a1e034d Mon Sep 17 00:00:00 2001 From: Maurice Date: Mon, 29 Sep 2025 15:52:06 +0200 Subject: [PATCH] Getting started with NFTables - long way to go --- installation/basic.sh | 4 +- services/caddy/config/Caddyfile | 1 + services/firewall/firewall.nft | 58 ++++++++++++++++++++++ services/firewall/global.policy.json | 5 +- services/firewall/reset-firewall.sh | 14 ++++++ services/wireguard/install.sh | 4 +- services/wireguard/vpn_traffic.policy.json | 1 - todo.txt | 11 +++- 8 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 services/firewall/firewall.nft create mode 100644 services/firewall/reset-firewall.sh diff --git a/installation/basic.sh b/installation/basic.sh index 77d3d55..5f0d4e4 100644 --- a/installation/basic.sh +++ b/installation/basic.sh @@ -14,4 +14,6 @@ EOF # Allow local.d services rc-update add local default -rc-service local start \ No newline at end of file +rc-service local start + +rc-update add sysctl \ No newline at end of file diff --git a/services/caddy/config/Caddyfile b/services/caddy/config/Caddyfile index a220c7a..c755c7c 100644 --- a/services/caddy/config/Caddyfile +++ b/services/caddy/config/Caddyfile @@ -56,6 +56,7 @@ Content-Security-Policy default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; Referrer-Policy: same-origin -Server + -X-Powered-By } } diff --git a/services/firewall/firewall.nft b/services/firewall/firewall.nft new file mode 100644 index 0000000..f2dda96 --- /dev/null +++ b/services/firewall/firewall.nft @@ -0,0 +1,58 @@ +flush ruleset + +define wan = eth0 +define vpn = wg0 +define vpn_net = 10.0.0.0/24 +define lan_net = 192.168.2.0/24 + +# Without the nd-* ones ipv6 will not work. +define allowed_icmpv6 = { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } +define allowed_icmp = { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } + +table inet firewall { + chain postrouting { + type nat hook postrouting priority 100; + + # Masquerade WireGuard VPN traffic to LAN subnet + oifname $wan ip saddr $vpn_net masquerade + } + + chain incoming { + # This line set what traffic the chain will handle, the priority and default policy. + # The priority comes in when you in another table have a chain set to "hook input" and want to specify in what order they should run. + type filter hook input priority 0; policy drop; + + ct state invalid drop # early drop of invalid packets + ct state {established, related} accept # allow established/related connections + + iif lo accept # allow traffic from loopback interface + + # Limit and accept ICMP packets + ip protocol icmp icmp type @allowed_icmp limit rate 1/second burst 5 packets accept + ip6 nexthdr icmpv6 icmpv6 type @allowed_icmpv6 limit rate 1/second burst 5 packets accept + + # Rules for all interfaces + tcp dport { 80, 443 } accept # Allow http and https for all interfaces + udp dport 443 accept # Allow quic (http/3) for all interfaces + + # Rules for WAN interface only + iifname $wan tcp dport 22 limit rate 10/minute accept # Rate limit SSH (port 22) to 10 connections per minute + iifname $wan udp dport 51820 accept # Allow Wireguard incoming from WAN + + # Rules for VPN interface only + iifname $vpn udp dport 53 accept # Allow DNS traffic from VPN + } + + chain forward { + type filter hook forward priority 0; policy drop; + + ct state invalid drop # early drop of invalid packets + ct state {established, related} accept # allow established/related connections + + iifname $vpn oifname $wan accept # Allow VPN traffic to access WAN + } + + chain outgoing { + type filter hook output priority 0; policy accept; + } +} \ No newline at end of file diff --git a/services/firewall/global.policy.json b/services/firewall/global.policy.json index 8a06e2c..beadb53 100644 --- a/services/firewall/global.policy.json +++ b/services/firewall/global.policy.json @@ -5,9 +5,12 @@ "VPN": { "iface": "wg0" } }, "policy": [ - { "in": "VPN", "action": "accept" }, { "out": "VPN", "action": "accept" }, + { "in": "VPN", "action": "drop" }, { "in": "WAN", "action": "drop" }, { "action": "reject" } + ], + "snat": [ + { "out": "WAN", "src": "10.0.0.1/24" } ] } \ No newline at end of file diff --git a/services/firewall/reset-firewall.sh b/services/firewall/reset-firewall.sh new file mode 100644 index 0000000..71618cf --- /dev/null +++ b/services/firewall/reset-firewall.sh @@ -0,0 +1,14 @@ +#!/bin/sh +iptables -F +iptables -X +iptables -t nat -F +iptables -t nat -X +iptables -t mangle -F +iptables -t mangle -X +iptables -P INPUT ACCEPT +iptables -P FORWARD ACCEPT +iptables -P OUTPUT ACCEPT + +# Wireguard +# iptables -A FORWARD -i wg0 -j ACCEPT +# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE \ No newline at end of file diff --git a/services/wireguard/install.sh b/services/wireguard/install.sh index 0a2a615..920ecb6 100644 --- a/services/wireguard/install.sh +++ b/services/wireguard/install.sh @@ -12,8 +12,8 @@ cat < /etc/wireguard/wg0.conf PrivateKey = $(cat /etc/wireguard/server_priv.key) Address = 10.0.0.1/24 # Server has IP in the wg network ListenPort = 51820 -PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE -PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE +#PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +#PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE EOF # Enable IP forwarding, persistent diff --git a/services/wireguard/vpn_traffic.policy.json b/services/wireguard/vpn_traffic.policy.json index f275d8a..73e3512 100644 --- a/services/wireguard/vpn_traffic.policy.json +++ b/services/wireguard/vpn_traffic.policy.json @@ -3,7 +3,6 @@ "filter": [ { "in": "VPN", - "out": "_fw", "service": [ "ssh", "dns", "ping", "http", "https" ], "action": "accept", "src": "10.0.0.1/24" diff --git a/todo.txt b/todo.txt index 2026455..e2a4622 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,12 @@ backup(), restore() -Volume labels (label) \ No newline at end of file +Volume labels (label) + +Switch to NFTables or UFW. + +Firewall: +- Block all traffic by default +- Allow outgoing (wan) http,https,dns,ssh,ntp,ping +- Allow incoming (wan) http,https,ssh,wireguard +- Allow wireguard traffic to lan (so access for instance 192.168.2.x) and wan (access the internet), +BUT only http,https,ping,dns \ No newline at end of file