mail-server/rspamd.nix

277 lines
7.9 KiB
Nix

{ config, lib, pkgs, ... }:
# TODO: use blacklists
with lib;
let
cfg = config.fudo.mail.rspamd;
mailCfg = config.fudo.mail;
in {
options.fudo.mail.rspamd = with types; {
enable = mkEnableOption "Enable rspamd spam test server.";
ports = {
metrics = mkOption {
type = port;
default = 7573;
};
controller = mkOption {
type = port;
default = 11334;
};
milter = mkOption {
type = port;
default = 11335;
};
};
antivirus = {
host = mkOption {
type = str;
description = "Host of the ClamAV server.";
};
port = mkOption {
type = port;
description = "Port at which to reach ClamAV";
};
};
redis = {
host = mkOption {
type = str;
default = "redis";
};
port = mkOption {
type = port;
default = 6379;
};
password = mkOption {
type = str;
description = "Password with which to connect to Redis.";
};
};
};
config = mkIf cfg.enable {
networking.firewall = {
enable = true;
allowedTCPPorts = with cfg.ports; [ metrics controller milter ];
allowedUDPPorts = with cfg.ports; [ controller milter ];
};
services = {
prometheus.exporters.rspamd = {
enable = true;
listenAddress = "127.0.0.1";
port = cfg.ports.metrics;
};
rspamd = {
enable = true;
locals = {
"milter_headers.conf".text = "extended_spam_headers = yes;";
"redis.conf".text = ''
servers = "${cfg.redis.host}:${toString cfg.redis.port}";
password = "${cfg.redis.password}";
'';
"antivirus.conf".text = ''
clamav {
action = "reject";
symbol = "CLAM_VIRUS";
type = "clamav";
log_clean = true;
servers = "${cfg.antivirus.host}:${toString cfg.antivirus.port}";
scan_mime_parts = false; # scan mail as a whole unit, not parts. seems to be needed to work at all
}
'';
"neural.conf".text = ''
symbols = {
"NEURAL_SPAM" = {
weight = 3.0;
description = "Neural network spam";
}
"NEURAL_HAM" = {
weight = -3.0;
description = "Neural network ham";
}
}
'';
"mx_check.conf".text = ''
enabled = true;
timeout = 10.0;
exclude_domains = [
"https://maps.rspamd.com/freemail/disposable.txt.zst",
"https://maps.rspamd.com/freemail/free.txt.zst",
];
'';
"reputation.conf".text = ''
rules {
ip_reputation = {
selector "ip" {
}
symbol = "IP_REPUTATION";
}
spf_reputation = {
selector "spf" {
}
symbol = "SPF_REPUTATION";
}
dkim_reputation = {
selector "dkim" {
}
symbol = "DKIM_REPUTATION"; # Also adjusts scores for DKIM_ALLOW, DKIM_REJECT
}
generic_reputation = {
selector "generic" {
selector = "ip"; # see https://rspamd.com/doc/configuration/selectors.html
}
symbol = "GENERIC_REPUTATION";
}
}
'';
# SURBL checks URLs in emails against known-bad urls
"rbl.conf".text = ''
surbl {
rules {
"SURBL_MULTI" {
ignore_defaults = true; # for compatibility with old defaults
rbl = "multi.surbl.org";
checks = ['emails', 'dkim', 'urls'];
emails_domainonly = true;
urls = true;
returnbits = {
CRACKED_SURBL = 128; # From February 2016
ABUSE_SURBL = 64;
MW_SURBL_MULTI = 16;
PH_SURBL_MULTI = 8;
SURBL_BLOCKED = 1;
}
}
"URIBL_MULTI" {
ignore_defaults = true; # for compatibility with old defaults
rbl = "multi.uribl.com";
checks = ['emails', 'dkim', 'urls'];
emails_domainonly = true;
returnbits = {
URIBL_BLOCKED = 1;
URIBL_BLACK = 2;
URIBL_GREY = 4;
URIBL_RED = 8;
}
}
"RSPAMD_URIBL" {
ignore_defaults = true; # for compatibility with old defaults
rbl = "uribl.rspamd.com";
checks = ['emails', 'dkim', 'urls'];
# Also check images
images = true;
# Check emails for URLs
emails_domainonly = true;
# Hashed BL
hash = 'blake2';
hash_len = 32;
hash_format = 'base32';
returncodes = {
RSPAMD_URIBL = [
"127.0.0.2",
];
}
}
"DBL" {
ignore_defaults = true; # for compatibility with old defaults
rbl = "dbl.spamhaus.org";
no_ip = true;
checks = ['emails', 'dkim', 'urls'];
emails_domainonly = true;
returncodes = {
# spam domain
DBL_SPAM = "127.0.1.2";
# phish domain
DBL_PHISH = "127.0.1.4";
# malware domain
DBL_MALWARE = "127.0.1.5";
# botnet C&C domain
DBL_BOTNET = "127.0.1.6";
# abused legit spam
DBL_ABUSE = "127.0.1.102";
# abused spammed redirector domain
DBL_ABUSE_REDIR = "127.0.1.103";
# abused legit phish
DBL_ABUSE_PHISH = "127.0.1.104";
# abused legit malware
DBL_ABUSE_MALWARE = "127.0.1.105";
# abused legit botnet C&C
DBL_ABUSE_BOTNET = "127.0.1.106";
# error - IP queries prohibited!
DBL_PROHIBIT = "127.0.1.255";
# issue #3074
DBL_BLOCKED_OPENRESOLVER = "127.255.255.254";
DBL_BLOCKED = "127.255.255.255";
}
}
"SEM_URIBL_UNKNOWN" {
ignore_defaults = true; # for compatibility with old defaults
rbl = "uribl.spameatingmonkey.net";
no_ip = true;
checks = ['emails', 'dkim', 'urls'];
emails_domainonly = true;
returnbits {
SEM_URIBL = 2;
}
}
}
}
'';
};
overrides."milter_headers.conf".text = "extended_spam_headers = true;";
workers = {
rspamd_proxy = {
type = "rspamd_proxy";
bindSockets = [ "*:${toString cfg.ports.milter}" ];
count = 4;
extraConfig = ''
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
'';
};
controller = {
type = "controller";
count = 4;
bindSockets = [ "*:${toString cfg.ports.controller}" ];
includes = [ ];
};
};
};
};
};
}