Last active
March 11, 2021 10:24
-
-
Save surfaceflinger/cadf92a1cb5dcf60c04cc5d9d8695950 to your computer and use it in GitHub Desktop.
nftables config that I use, from https://xdeb.org/post/2019/09/26/setting-up-a-server-firewall-with-nftables-that-support-wireguard-vpn/ so I have easy c+p access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/sbin/nft -f | |
# Hook order is: ingress -> prerouting -> input/output/forward -> postrouting | |
# Start by flushing all the rules. | |
flush ruleset | |
# Defining variables is easy in nftables scripts. | |
define wan = eth0 | |
define vpn = wg0 | |
define vpn_net = 192.168.69.0/24 | |
define vpn_address = 192.168.69.1 | |
# Setting up a table, simple firewalls will only need one table but there can be multiple. | |
# The "inet" say that this table will handle both ipv4 (ip) and ipv6 (ip6). | |
# The name is "firewall" you can name it anything you like. | |
table inet firewall { | |
# Sets are dictionaries and maps of ports, addresses etc. | |
# These can then easily be used in the rules. | |
# Sets can be named whatever you like. | |
# TCP ports to allow, here we add ssh, http and https. | |
set tcp_accepted { | |
# The "inet_service" are for tcp/udp ports and "flags interval" allows to set intervals, see the mosh ports below. | |
type inet_service; flags interval; | |
elements = { | |
80,443,1337,6969,25565 | |
} | |
} | |
# UDP ports to allow, here we add ports for WireGuard and mosh. | |
set udp_accepted { | |
type inet_service; flags interval; | |
elements = { | |
443,6969,46124,51820 | |
} | |
} | |
# The first chain, can be named anything you like. | |
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. | |
# Use a semicolon to separate multiple commands on one row. | |
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 | |
# OBS! Rules with "limit" need to be put before rules accepting "established" connections. | |
# Allow all incmming established and related traffic. | |
ct state established,related accept | |
# Allow loopback. | |
# Interfaces can by set with "iif" or "iifname" (oif/oifname). If the interface can come and go use "iifname", otherwise use "iif" since it performs better. | |
iif lo accept | |
# Allow certain inbound ICMP types (ping, traceroute). | |
# With these allowed you are a good network citizen. | |
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 | |
# Allow WireGuard clients to access DNS and services. | |
iifname $vpn udp dport 53 ct state new accept | |
iifname $vpn tcp dport @tcp_accepted ct state new accept | |
iifname $vpn udp dport @udp_accepted ct state new 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 peers to access other VPN peers. | |
iifname $vpn oifname $vpn ct state new accept | |
# Allow WAN to access internal VPN network through port forwarding. | |
# iifname $wan oifname $vpn ct state new accept | |
} | |
chain outgoing { | |
type filter hook output priority 0; policy drop; | |
# I believe settings "policy accept" would be the same but I prefer explicit rules. | |
# 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; | |
# dnat example to use for port forwarding wan -> vpn peer | |
# it's better to use specialized reverse proxies if possible. | |
# iifname $wan tcp dport 6969 dnat 192.168.69.3 | |
} | |
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 | |
# snat example to use for port forwarding wan -> vpn peer | |
# it's better to use specialized reverse proxies if possible. | |
# oifname $vpn ip daddr 192.168.69.3 tcp dport 6969 snat $vpn_address | |
} | |
} | |
# 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 = { | |
203.0.113.100,203.0.113.101 | |
} | |
} | |
chain ingress { | |
# For some reason the interface must be hardcoded here, variable do not work. | |
type filter hook ingress device eth0 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 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment