{ config, lib, ... }: let openTCP = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openTCP; openUDP = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openUDP; openTCPVPN = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openTCPVPN; openUDPVPN = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openUDPVPN; deviceAddress = interface: device: config.architect.networks.${interface}.devices.${device}.address; gdevices = [ (deviceAddress "tailscale" "architect") (deviceAddress "tailscale" "dodino") (deviceAddress "tailscale" "manduria") (deviceAddress "tailscale" "kmerr") (deviceAddress "tailscale" "chuck") ]; in { networking = { # needed to use nftables firewall.enable = false; nat.enable = false; nftables = { enable = true; ruleset = with config.architect.networks; '' table ip raw { chain PREROUTING { type filter hook prerouting priority raw; policy accept; } chain OUTPUT { type filter hook output priority raw; policy accept; } } table ip nat { chain DOCKER { type nat hook prerouting priority dstnat; policy accept; } chain PREROUTING { type nat hook prerouting priority dstnat; policy accept; } chain INPUT { type nat hook input priority 100; policy accept; } chain OUTPUT { type nat hook output priority -100; policy accept; } chain POSTROUTING { type nat hook postrouting priority srcnat; policy accept; oifname ${lan.interface} ip saddr ${tailscale.net} masquerade } } table ip mangle { chain PREROUTING { type filter hook prerouting priority mangle; policy drop; ct state invalid,untracked drop comment "drop invalid" ip daddr 255.255.255.255 accept comment "allow broadcast traffic" ip daddr 224.0.0.0/4 accept comment "allow multicast traffic" iifname ${lan.interface} ip saddr 127.0.0.0/8 drop comment "bind any ip to intf ${lan.interface}" iifname ${lan.interface} accept comment "bind any ip to intf ${lan.interface}" iifname ${tailscale.interface} ip saddr ${tailscale.net} accept iifname ${tailscale.interface} ip saddr 100.100.100.100/32 accept iifname "lo" accept comment "bind any ip to intf lo" jump mangle_drop } chain INPUT { type filter hook input priority mangle; policy accept; } chain FORWARD { type filter hook forward priority mangle; policy accept; } chain OUTPUT { type route hook output priority mangle; policy accept; } chain POSTROUTING { type filter hook postrouting priority mangle; policy accept; } chain mangle_drop { ip protocol icmp jump mangle_drop_icmp ip protocol udp jump mangle_drop_udp ip protocol tcp jump mangle_drop_tcp log prefix "MANGLE-DROP-UNK " drop } chain mangle_drop_icmp { log prefix "MANGLE-DROP-ICMP " drop } chain mangle_drop_tcp { log prefix "MANGLE-DROP-TCP " drop } chain mangle_drop_udp { log prefix "MANGLE-DROP-UDP " drop } } table ip filter { chain INPUT { type filter hook input priority filter; policy drop; ct state established,related accept iifname "lo" accept comment "loopback" ip daddr 255.255.255.255 accept comment "allow broadcast traffic" ip daddr 224.0.0.0/4 accept comment "allow multicast traffic" ip saddr ${lan.net} accept comment "lan > local" ip saddr ${tailscale.net} accept comment "tailscale > local" ip saddr {${lib.concatStringsSep "," gdevices}} accept comment "vpn > local" iifname ${lan.interface} tcp dport {${openTCP}} accept iifname ${lan.interface} udp dport {${openUDP}} accept jump filter_drop } chain FORWARD { type filter hook forward priority filter; policy drop; ct state established,related accept oifname ${lan.interface} ip saddr ${tailscale.net} accept jump filter_drop } chain OUTPUT { type filter hook output priority filter; policy drop; ct state established,related accept accept comment "local > *" jump filter_drop } chain filter_drop { ip protocol icmp jump filter_drop_icmp ip protocol udp jump filter_drop_udp ip protocol tcp jump filter_drop_tcp log prefix "DROP-UNK " drop } chain filter_drop_icmp { log prefix "DROP-icmp " drop } chain filter_drop_tcp { log prefix "DROP-tcp " drop } chain filter_drop_udp { log prefix "DROP-udp " drop } } ''; }; }; }