delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

31 Dec 2023

用 rspamd 来实现反垃圾邮件

我搞邮件服务器有二十多年了,最开始是在学校做社团的邮件服务, 后来有几年和 老房东 在某领先网络媒体公司做了多年针对公众提供的邮件服务,因此前同事群的名字也是「老邮条」。 我个人的域名是2002年注册的,自从那时起我就一直在自己运行邮件服务。

在过去二十年中的大部分时间,我采用的是 amavisd-new, 与直接使用 SpamAssassin 相比, 它还增加了病毒扫描等一系列功能和 milter 接口,这让它与 MTA 更容易集成。

最近我发现 FreeBSD.org 把反垃圾系统替换成了 rspamd, 所以在11月初把我的邮件系统也换成了 rspamd,经过两个月的使用,总体的感觉是「我tm早干嘛去了」。

FreeBSD 的 rspamd port 是 Vsevolod Stakhov (vsevolod@) 维护的,和 amavisd-new 相比, 最肉眼可见的好处就是 CPU 开销的大幅下降,除了由于它是 C 写的之外,这也得益于其 事件驱动的异步架构设计

在 FreeBSD 上使用 rspamd 可以直接用 pkg 来安装(此处同时安装 redis 作为后端存储):

pkg install redis rspamd

需要注意,redis 默认会绑到 127.0.0.1,如果在 jail 中运行 redis 的话,这可能会导致 redis 暴露给整个 Internet, 这很危险。解决方法是把 redis 绑到某个安全的内网,或是只使用 Unix domain socket。

例如,redis 可以如此配置:

# 禁止 TCP 监听
port 0

# 启用 Unix domain socket
unixsocket /var/run/redis/rspamd.sock
unixsocketperm 660

requirepass <某个随机密码>

maxmemory 512mb
maxmemory-policy volatile-ttl

注意上述权限配置中使用的权限是 660,因此需要把 rspamd 的角色用户加入 redis 用户组。

与之对应地,在 /usr/local/etc/rspamd/local.d/redis.conf 中如此配置:

servers = "/var/run/redis/rspamd.sock";
password = "<某个随机密码>";

与 amavisd-new 类似,rspamd 的 milter 服务也可以添加信头来方便其他 MUA 或是 sieve 来进行拣选。 很明显,其他系统添加的此类信头应该删掉,为了便于迁移,我采用了如下的配置 (/usr/local/etc/rspamd/local.d/milter_headers.conf):

use = ["x-spamd-bar", "authentication-results", "x-spamd-result", "x-spam-level"];
authenticated_headers = ["authentication-results"];

routines {
  authentication-results {
    header = "Authentication-Results";
    remove = 1;
  }
  x-spamd-result {
    header = 'X-Spamd-Result';
    remove = 1;
  }
  x-spamd-level {
    header = "X-Spam-Level";
    char = "*";
    remove = 1;
  }
}

其他配置方面我没有做特别多的改动。

postfix 集成部分,基本上只是把 smtpd_milter 换成 rspamd。

与 sieve 集成的部分,可以用 rspamc 去连接 rspamd 的 controller 来完成 learn_spamlearn_ham

我之前的系统中长期使用了 clamav,而该系统最后一次抓到病毒是 2006 年的事情。 clamav 本身依赖许多解压缩程序,尽管它是丢掉特权运行的,但考虑到现实情况,对于我这样的食古不化型 (邮件客户端关闭了全部附件预览等一系列功能) 的邮件用户来说,反病毒的价值确实不大,因此这次顺手暂时先拆掉了。

rspamd 的控制面板可以罩在 zero trust 代理 后面,方便访问。