diff options
| -rw-r--r-- | hosts/surtr/email/default.nix | 58 | ||||
| -rw-r--r-- | hosts/surtr/ruleset.nft | 31 |
2 files changed, 82 insertions, 7 deletions
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix index 057e29f3..23ac8aa1 100644 --- a/hosts/surtr/email/default.nix +++ b/hosts/surtr/email/default.nix | |||
| @@ -32,9 +32,47 @@ let | |||
| 32 | }); | 32 | }); |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | nftables-nologin-script = pkgs.writeScript "nftables-mail-nologin" '' | ||
| 36 | #!${pkgs.zsh}/bin/zsh | ||
| 37 | |||
| 38 | set -e | ||
| 39 | export PATH="${lib.makeBinPath (with pkgs; [inetutils nftables])}:$PATH" | ||
| 40 | |||
| 41 | typeset -a as_sets route route6 | ||
| 42 | as_sets=(${lib.escapeShellArgs config.services.email.nologinASSets}) | ||
| 43 | |||
| 44 | for as_set in $as_sets; do | ||
| 45 | while IFS=$'\n' read line; do | ||
| 46 | if [[ "''${line}" =~ "^route:\s+(.+)$" ]]; then | ||
| 47 | route+=($match[1]) | ||
| 48 | elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then | ||
| 49 | route6+=($match[1]) | ||
| 50 | fi | ||
| 51 | done < <(whois -h whois.radb.net "!i''${as_set},1" | egrep -o 'AS[0-9]+' | xargs -- whois -h whois.radb.net -- -i origin) | ||
| 52 | done | ||
| 53 | |||
| 54 | printf -v elements4 '%s,' "''${route[@]}" | ||
| 55 | elements4=''${elements4%,} | ||
| 56 | printf -v elements6 '%s,' "''${route6[@]}" | ||
| 57 | elements6=''${elements6%,} | ||
| 58 | nft -f - <<EOF | ||
| 59 | flush set inet filter mail_nologin4 | ||
| 60 | flush set inet filter mail_nologin6 | ||
| 61 | add element inet filter mail_nologin4 {''${elements4}} | ||
| 62 | add element inet filter mail_nologin6 {''${elements6}} | ||
| 63 | EOF | ||
| 64 | ''; | ||
| 65 | |||
| 35 | spmDomains = ["bouncy.email"]; | 66 | spmDomains = ["bouncy.email"]; |
| 36 | emailDomains = spmDomains ++ ["kleen.consulting"]; | 67 | emailDomains = spmDomains ++ ["kleen.consulting"]; |
| 37 | in { | 68 | in { |
| 69 | options = { | ||
| 70 | services.email.nologinASSets = mkOption { | ||
| 71 | type = types.listOf types.str; | ||
| 72 | default = []; | ||
| 73 | }; | ||
| 74 | }; | ||
| 75 | |||
| 38 | config = { | 76 | config = { |
| 39 | nixpkgs.overlays = [ | 77 | nixpkgs.overlays = [ |
| 40 | (final: prev: { | 78 | (final: prev: { |
| @@ -918,5 +956,25 @@ in { | |||
| 918 | id=REJECT_RL; action=450 4.7.1 Exceeding maximum of $$HIT_RATELIMIT_LIMIT recipients per $$HIT_RATELIMIT_INTERVAL seconds [$$HIT_RATECOUNT] | 956 | id=REJECT_RL; action=450 4.7.1 Exceeding maximum of $$HIT_RATELIMIT_LIMIT recipients per $$HIT_RATELIMIT_INTERVAL seconds [$$HIT_RATECOUNT] |
| 919 | ''; | 957 | ''; |
| 920 | }; | 958 | }; |
| 959 | |||
| 960 | services.email.nologinASSets = ["AS-MICROSOFT"]; | ||
| 961 | systemd.services.nftables.serviceConfig = { | ||
| 962 | ExecStart = lib.mkAfter [ nftables-nologin-script ]; | ||
| 963 | ExecReload = lib.mkAfter [ nftables-nologin-script ]; | ||
| 964 | }; | ||
| 965 | systemd.services."nftables-mail-nologin" = { | ||
| 966 | serviceConfig = { | ||
| 967 | Type = "oneshot"; | ||
| 968 | ExecStart = nftables-nologin-script; | ||
| 969 | }; | ||
| 970 | }; | ||
| 971 | systemd.timers."nftables-mail-nologin" = { | ||
| 972 | wantedBy = [ "nftables.service" ]; | ||
| 973 | |||
| 974 | timerConfig = { | ||
| 975 | OnActiveSec = "20h"; | ||
| 976 | RandomizedDelaySec = "8h"; | ||
| 977 | }; | ||
| 978 | }; | ||
| 921 | }; | 979 | }; |
| 922 | } | 980 | } |
diff --git a/hosts/surtr/ruleset.nft b/hosts/surtr/ruleset.nft index 14fc9b79..5c2bba7c 100644 --- a/hosts/surtr/ruleset.nft +++ b/hosts/surtr/ruleset.nft | |||
| @@ -86,6 +86,7 @@ table inet filter { | |||
| 86 | 86 | ||
| 87 | counter established-rx {} | 87 | counter established-rx {} |
| 88 | 88 | ||
| 89 | counter reject-mail-nologin {} | ||
| 89 | counter reject-ratelimit-rx {} | 90 | counter reject-ratelimit-rx {} |
| 90 | counter reject-rx {} | 91 | counter reject-rx {} |
| 91 | counter reject-tcp-rx {} | 92 | counter reject-tcp-rx {} |
| @@ -114,6 +115,17 @@ table inet filter { | |||
| 114 | 115 | ||
| 115 | counter tx {} | 116 | counter tx {} |
| 116 | 117 | ||
| 118 | set mail_nologin4 { | ||
| 119 | type ipv4_addr | ||
| 120 | flags interval | ||
| 121 | auto-merge | ||
| 122 | } | ||
| 123 | set mail_nologin6 { | ||
| 124 | type ipv6_addr | ||
| 125 | flags interval | ||
| 126 | auto-merge | ||
| 127 | } | ||
| 128 | |||
| 117 | chain forward { | 129 | chain forward { |
| 118 | type filter hook forward priority filter | 130 | type filter hook forward priority filter |
| 119 | policy drop | 131 | policy drop |
| @@ -145,6 +157,14 @@ table inet filter { | |||
| 145 | counter name drop-fw | 157 | counter name drop-fw |
| 146 | } | 158 | } |
| 147 | 159 | ||
| 160 | chain reject_input { | ||
| 161 | limit name lim_reject log level debug prefix "drop input: " counter name reject-ratelimit-rx drop | ||
| 162 | log level debug prefix "reject input: " counter name reject-rx | ||
| 163 | meta l4proto tcp ct state new counter name reject-tcp-rx reject with tcp reset | ||
| 164 | ct state new counter name reject-icmp-rx reject | ||
| 165 | |||
| 166 | counter name drop-rx | ||
| 167 | } | ||
| 148 | chain input { | 168 | chain input { |
| 149 | type filter hook input priority filter | 169 | type filter hook input priority filter |
| 150 | policy drop | 170 | policy drop |
| @@ -177,6 +197,9 @@ table inet filter { | |||
| 177 | udp dport {3478, 5349} counter name stun-rx accept | 197 | udp dport {3478, 5349} counter name stun-rx accept |
| 178 | udp dport 49000-50000 counter name turn-rx accept | 198 | udp dport 49000-50000 counter name turn-rx accept |
| 179 | 199 | ||
| 200 | tcp dport {465,466,993,4190} ip saddr @mail_nologin4 log prefix "mail nologin: " counter name reject-mail-nologin jump reject_input | ||
| 201 | tcp dport {465,466,993,4190} ip6 saddr @mail_nologin6 log prefix "mail nologin: " counter name reject-mail-nologin jump reject_input | ||
| 202 | |||
| 180 | tcp dport 25 counter name smtp-rx accept | 203 | tcp dport 25 counter name smtp-rx accept |
| 181 | tcp dport {465, 466} counter name submissions-rx accept | 204 | tcp dport {465, 466} counter name submissions-rx accept |
| 182 | tcp dport 993 counter name imaps-rx accept | 205 | tcp dport 993 counter name imaps-rx accept |
| @@ -186,13 +209,7 @@ table inet filter { | |||
| 186 | ct state {established, related} counter name established-rx accept | 209 | ct state {established, related} counter name established-rx accept |
| 187 | 210 | ||
| 188 | 211 | ||
| 189 | limit name lim_reject log level debug prefix "drop input: " counter name reject-ratelimit-rx drop | 212 | jump reject_input |
| 190 | log level debug prefix "reject input: " counter name reject-rx | ||
| 191 | meta l4proto tcp ct state new counter name reject-tcp-rx reject with tcp reset | ||
| 192 | ct state new counter name reject-icmp-rx reject | ||
| 193 | |||
| 194 | |||
| 195 | counter name drop-rx | ||
| 196 | } | 213 | } |
| 197 | 214 | ||
| 198 | chain output { | 215 | chain output { |
