{ pkgs, lib, config, machines, ... }: let inherit (builtins) hasAttr readFile; inherit (pkgs.lib) unlinesAttrs; inherit (config) networking; inherit (config.users) users groups; in { networking.firewall.enable = false; security.lockKernelModules = false; systemd.services.disable-kernel-module-loading.after = [ "nftables.service" ]; systemd.services.nftables.serviceConfig.TimeoutStartSec = "20"; networking.nftables = { enable = true; ruleset = lib.mkBefore '' table inet filter { set lograte4 { type ipv4_addr; size 65535; flags dynamic; } set lograte6 { type ipv6_addr; size 65535; flags dynamic; } chain block { add @lograte4 { ip saddr limit rate 1/minute } log level warn prefix "block: " add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "block: " counter drop } chain ping-flood { add @lograte4 { ip saddr limit rate 1/minute } log level warn prefix "ping-flood: " add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "ping-flood: " counter drop } chain smurf { add @lograte4 { ip saddr limit rate 1/minute } log level warn prefix "smurf: " add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "smurf: " counter drop } chain bogus-tcp { add @lograte4 { ip saddr limit rate 1/minute } log level warn prefix "bogus-tcp: " add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "bogus-tcp: " counter drop } chain syn-flood { add @lograte4 { ip saddr limit rate 1/minute } log level warn prefix "syn-flood: " add @lograte6 { ip6 saddr limit rate 1/minute } log level warn prefix "syn-flood: " counter drop } chain check-tcp { tcp flags syn tcp option maxseg size != 536-65535 counter goto bogus-tcp tcp flags & (ack|fin) == fin counter goto bogus-tcp tcp flags & (ack|psh) == psh counter goto bogus-tcp tcp flags & (ack|urg) == urg counter goto bogus-tcp tcp flags & (fin|ack) == fin counter goto bogus-tcp tcp flags & (fin|rst) == (fin|rst) counter goto bogus-tcp tcp flags & (fin|psh|ack) == (fin|psh) counter goto bogus-tcp tcp flags & (syn|fin) == (syn|fin) counter goto bogus-tcp comment "SYN-FIN scan" tcp flags & (syn|rst) == (syn|rst) counter goto bogus-tcp comment "SYN-RST scan" tcp flags == (fin|syn|rst|psh|ack|urg) counter goto bogus-tcp comment "XMAS scan" tcp flags == 0x0 counter goto bogus-tcp comment "NULL scan" tcp flags == (fin|urg|psh) counter goto bogus-tcp tcp flags == (fin|urg|psh|syn) counter goto bogus-tcp comment "NMAP-ID" tcp flags == (fin|urg|syn|rst|ack) counter goto bogus-tcp ct state new tcp flags != syn counter goto bogus-tcp tcp sport 0 tcp flags & (fin|syn|rst|ack) == syn counter goto bogus-tcp tcp flags & (fin|syn|rst|ack) == syn counter limit rate over 30/second burst 60 packets goto syn-flood } chain net2fw { #udp dport mdns ip6 daddr ff02::fb counter accept comment "Accept mDNS" #udp dport mdns ip daddr 224.0.0.251 counter accept comment "Accept mDNS" #jump non-internet #ct state new add @connlimit { ip saddr ct count over 20 } counter tcp reject with tcp reset # Some .nix append rules here with: add rule inet filter net2fw ... } chain fw2net { tcp dport { 80, 443 } counter accept comment "HTTP" udp dport 123 skuid ${users.systemd-timesync.name} counter accept comment "NTP" tcp dport 9418 counter accept comment "Git" # Some .nix append rules here with: add rule inet filter fw2net ... } chain intra2fw { # Some .nix append rules here with: add rule inet filter intra2fw ... } chain fw2intra { # Some .nix append rules here with: add rule inet filter fw2intra ... } chain fwd-intra { # Some .nix append rules here with: add rule inet filter fwd-intra ... } chain extra2fw { # Some .nix append rules here with: add rule inet filter extra2fw ... } chain accept-icmpv6 { # Traffic That Must Not Be Dropped # https://tools.ietf.org/html/rfc4890#section-4.4.1 icmpv6 type destination-unreachable counter accept icmpv6 type packet-too-big counter accept icmpv6 type time-exceeded counter accept icmpv6 type parameter-problem counter accept # Address Configuration and Router Selection messages # (must be received with hop limit = 255) icmpv6 type nd-router-solicit ip6 hoplimit 255 counter accept ip6 nexthdr ipv6-icmp icmpv6 type nd-router-advert ip6 hoplimit 255 counter accept icmpv6 type nd-neighbor-solicit ip6 hoplimit 255 counter accept icmpv6 type nd-neighbor-advert ip6 hoplimit 255 counter accept icmpv6 type nd-redirect ip6 hoplimit 255 log level warn prefix "icmpv6: nd-redirect: " counter drop icmpv6 type ind-neighbor-solicit ip6 hoplimit 255 counter accept icmpv6 type ind-neighbor-advert ip6 hoplimit 255 counter accept # Link-local multicast receiver notification messages # (must have link-local source address) icmpv6 type mld-listener-query ip6 saddr fe80::/10 counter accept icmpv6 type mld-listener-report ip6 saddr fe80::/10 counter accept icmpv6 type mld-listener-done ip6 saddr fe80::/10 counter accept # https://tools.ietf.org/html/rfc3810 Multicast Listener Discovery Version 2 (MLDv2) for IPv6 icmpv6 type mld2-listener-report ip6 saddr fe80::/10 counter accept # SEND Certificate Path notification messages # (must be received with hop limit = 255) icmpv6 type 148 ip6 hoplimit 255 counter accept comment "certificate-path-solicitation" icmpv6 type 149 ip6 hoplimit 255 counter accept comment "certificate-path-advertisement" # Multicast Router Discovery messages # (must have link-local source address and hop limit = 1) icmpv6 type 151 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-advertisement" icmpv6 type 152 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-solicitation" icmpv6 type 153 ip6 saddr fe80::/10 ip6 hoplimit 1 counter accept comment "multicast-router-termination" } chain input { type filter hook input priority filter policy drop iifname lo accept jump check-tcp ct state { established, related } accept # Connectivity checking messages # (multicast) ping ip protocol icmp icmp type echo-reply counter accept ${lib.optionalString networking.enableIPv6 '' # drop packets with rh0 headers rt type 0 jump block rt type 0 jump block rt type 0 jump block # (multicast) ping ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept #ip6 daddr fe80::/64 udp dport 546 counter accept comment "DHCPv6" ''} ct state invalid counter drop ip protocol icmp icmp type destination-unreachable counter accept ip protocol icmp icmp type time-exceeded counter accept ip protocol icmp icmp type parameter-problem counter accept ip protocol icmp icmp type echo-request limit rate over 10/second burst 20 packets goto ping-flood ip protocol icmp icmp type echo-request counter accept # echo-reply is handled before invalid packets to allow multicast ping # which do not have an associated connection. #ip daddr 224.0.0.251 udp dport 5353 counter accept comment "mDNS" #ip daddr 239.255.255.250 udp dport 1900 counter accept comment "UPnP" #ip saddr 0.0.0.0/32 counter accept comment "DHCP" #ip udp sport 67 udp dport 68 counter accept comment "DHCP" ${lib.optionalString networking.enableIPv6 '' ip6 nexthdr ipv6-icmp jump accept-icmpv6 # Connectivity checking messages icmpv6 type echo-request counter accept # echo-reply is handled before invalid because of multicast ip6 nexthdr ipv6-icmp log level err prefix "net2fw: icmpv6: catch all: " counter reject ip6 daddr ff02::fb udp dport 5353 counter accept comment "mDNS" ip6 daddr ff02::f udp dport 1900 counter accept comment "UPnP" ''} ip saddr 224.0.0.0/4 counter goto smurf fib saddr type broadcast counter goto smurf # admin services tcp dport 22 counter accept comment "SSH" udp dport 60000-61000 counter accept comment "Mosh" # Some .nix append gotos here with: add rule inet filter input iffname ... goto ... } chain forward { type filter hook forward priority filter policy drop ct state { related, established } accept ip protocol icmp icmp type destination-unreachable counter accept ip protocol icmp icmp type time-exceeded counter accept ip protocol icmp icmp type parameter-problem counter accept ip protocol icmp icmp type echo-request counter accept ${lib.optionalString networking.enableIPv6 '' # Traffic That Must Not Be Dropped # https://tools.ietf.org/html/rfc4890#section-4.3.1 ip6 nexthdr ipv6-icmp icmpv6 type destination-unreachable counter accept ip6 nexthdr ipv6-icmp icmpv6 type packet-too-big counter accept ip6 nexthdr ipv6-icmp icmpv6 type time-exceeded counter accept ip6 nexthdr ipv6-icmp icmpv6 type parameter-problem counter accept # Connectivity checking messages ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept # Traffic That Normally Should Not Be Dropped # https://tools.ietf.org/html/rfc4890#section-4.3.2 ip6 nexthdr ipv6-icmp icmpv6 type 144 counter accept comment "home-agent-address-discovery-request" ip6 nexthdr ipv6-icmp icmpv6 type 145 counter accept comment "home-agent-address-discovery-reply" ip6 nexthdr ipv6-icmp icmpv6 type 146 counter accept comment "mobile-prefix-solicitation" ip6 nexthdr ipv6-icmp icmpv6 type 147 counter accept comment "mobile-prefix-advertisement" ''} } chain output { type filter hook output priority filter policy drop oifname lo accept ct state { related, established } accept ip protocol icmp counter accept ip daddr 224.0.0.0/4 udp dport 1900 counter accept comment "UPnP" meta skuid 0 udp dport 33434-33523 counter accept comment "traceroute" ${lib.optionalString networking.enableIPv6 '' ip6 nexthdr ipv6-icmp jump accept-icmpv6 # Connectivity checking messages ip6 nexthdr ipv6-icmp icmpv6 type echo-request counter accept ip6 nexthdr ipv6-icmp icmpv6 type echo-reply counter accept ip6 nexthdr ipv6-icmp log level err prefix "fw2net: icmpv6: catch all: " counter reject ip6 daddr ff02::1:2/64 udp dport 547 counter accept comment "DHCPv6" ''} ct state invalid log level warn prefix "fw2net: invalid: " counter drop tcp dport 22 counter accept comment "SSH" # Some .nix append gotos here with: add rule inet filter output oifname ... goto ... } } table inet nat { chain prerouting { type nat hook prerouting priority filter policy accept } chain postrouting { type nat hook postrouting priority srcnat policy accept } } ''; }; }