#!/usr/sbin/nft -f #--- Hook order is: ingress -> prerouting -> input/output/forward -> postrouting #--- Flush previous rules flush ruleset #--- Definitions define wan = eth0 define vpn = wg0 define vpn_net = 10.16.76.1/22 #---VPN_NETWORK #define ipsec_remote = 10.0.0.0/24 #--- "inet" say that this table will handle both ipv4 (ip) and ipv6 (ip6). table inet firewall { #--- TCP ports to allow (ssh, http and https). set tcp_accepted { #--- "inet_service" are for tcp/udp ports, "flags interval" allows to set intervals. type inet_service; flags interval; elements = {80,443,10760} #---OpenTCPports/ } #--- UDP ports to allow WireGuard. set udp_accepted { type inet_service; flags interval; elements = {53,500,4500,25237} #---OpenUDPports } chain incoming { type filter hook input priority 0; policy drop; # Drop invalid packets. ct state invalid drop # Drop none SYN packets. tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop # Limit ping requests. ip protocol icmp icmp type echo-request limit rate over 1/second burst 5 packets drop ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 1/second burst 5 packets drop # Allow all incmming established and related traffic. ct state established,related accept # Allow loopback. iif lo accept # Allow certain inbound ICMP types (ping, traceroute). ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept # Without the nd-* ones ipv6 will not work. ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept # Allow needed tcp and udp ports. iifname $wan tcp dport @tcp_accepted ct state new accept iifname $wan udp dport @udp_accepted ct state new accept #iifname $vpn tcp dport @tcp_accepted ct state new accept #iifname $vpn udp dport @udp_accepted ct state new accept # Allow all incoming traffic from vpn iifname $vpn ct state new accept # Allow WireGuard clients to access DNS and services. iifname $vpn udp dport 53 ct state new accept # Allow VPN clients to communicate with each other. iifname $vpn oifname $vpn ct state new accept # Allows IPSEC StrongSwan trafic. ip protocol { ah, esp } accept meta ipsec exists accept #ipsec in ip saddr $ipsec_remote accept } chain forwarding { type filter hook forward priority 0; policy drop; # Drop invalid packets. ct state invalid drop # Forward all established and related traffic. ct state established,related accept # Forward WireGuard traffic. # Allow WireGuard traffic to access the internet via wan. iifname $vpn oifname $wan ct state new accept # Allow VPN clients to communicate with each other. iifname $vpn oifname $vpn accept } chain outgoing { type filter hook output priority 0; policy drop; # Drop invalid packets. ct state invalid drop # Allow all other outgoing traffic. # For some reason ipv6 ICMP needs to be explicitly allowed here. ip6 nexthdr ipv6-icmp accept ct state new,established,related accept } } # Separate table for hook pre- and postrouting. # If using kernel 5.2 or later you can replace "ip" with "inet" to also filter IPv6 traffic. table ip router { # With kernel 4.17 or earlier both need to be set even when one is empty. chain prerouting { type nat hook prerouting priority -100; } chain postrouting { type nat hook postrouting priority 100; # Masquerade WireGuard traffic. # All WireGuard traffic will look like it comes from the servers IP address. oifname $wan ip saddr $vpn_net masquerade } } # Separate table for hook ingress to filter bad packets early. table netdev filter { # List of ipv4 addresses to block. set blocklist_v4 { # The "ipv4_addr" are for ipv4 addresses and "flags interval" allows to set intervals. type ipv4_addr; flags interval; elements = {172.16.254.1,172.16.254.2} #---BloquedIPs } chain ingress { # For some reason the interface must be hardcoded here, variable do not work. type filter hook ingress device $wan priority -500; # Drop all fragments. ip frag-off & 0x1fff != 0 counter drop # Drop bad addresses. ip saddr @blocklist_v4 counter drop # Drop XMAS packets. tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop # Drop NULL packets. tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop # Drop uncommon MSS values. tcp flags syn tcp option maxseg size 1-535 counter drop } }