{ pkgs, lib, name, ... }: let inherit (lib) concatStringsSep length replicate splitString ; inherit (lib.lists) map; c4 = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"; mkV4' = p: concatStringsSep "\\." (p ++ (replicate (4 - (length p)) c4)); mkV4 = s: mkV4' (splitString "." s); nft = s: [ "nft" ] ++ [ s ]; streams' = import ./streams.nix; in { # Switch to nftables networking.nftables.enable = true; services.reaction = { enable = true; extraPackages = [ pkgs.nftables ]; runAsRoot = true; logLevel = "WARN"; settings = { patterns = { ip = { regex = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"; ignoreregex = map mkV4 [ "10" # Legacy wireguard "129.199" # ENS "100.80" # Netbird internal ]; ignore = [ "127.0.0.1" "::1" ]; }; }; start = [ (nft '' table inet reaction { set ipv4bans { type ipv4_addr flags interval auto-merge } set ipv6bans { type ipv6_addr flags interval auto-merge } chain input { type filter hook input priority 0 policy accept ip saddr @ipv4bans drop ip6 saddr @ipv6bans drop } } '') ]; stop = [ (nft "delete table inet reaction") ]; streams = streams'.default // (streams'.${name} or { }); }; }; }