[FrontPage] [TitleIndex] [WordIndex

This is a read-only archived version of wiki.centos.org

Amavisd-new、 ClamAV 及 SpamAssassin

<<TableOfContents: execution failed [Argument "maxdepth" must be an integer value, not "[1]"] (see also the log)>>

敬请注意:

/!\ 注意:本文档是为 CentOS 5 而撰写的。它的内容对 CentOS 6 或较后版本也许并不准确。

1. 引言

Amavisd-new 是个位于邮件服务器(MTA)和病毒扫描器(ClamAV)及/或 SpamAssassin 等内容检查器之间,可靠而高性能的界面。Amavisd-new 支持以 (E)SMTP 和 LMTP 协议,或以 UNIX 通讯端与 MTA 及内容检查器沟通。此外,它也可运用专用的辅助程序如 Mail::SpamAssassin 的 Perl 模块。

Amavisd-new 支持数个 MTA。但一如 Amavisd-new 的文档所指,Amavisd-new 「与 Postfix 有最佳配搭,亦可配合双 sendmail 的设置及 Exim v4,也能配合 sendmail/milter,或任何采用 MTA 的 SMTP 转发站」。这份指南是针对 Postfix 及在其上测试的,它亦补充这份基本的 Postfix 指南。日后其它 MTA 或许会被加入。

我们将会设置 Amavisd-new 的守护程序 amavisd,让它接纳来自我们的 MTA 的邮件,把它们传给 ClamAV 及 SpamAssassin 来检查内容,然后还给我们的 MTA 来发放。Amavisd 会利用 lmtp 在 TCP 端口 10024 上聆听及接收来自我们的 MTA 的邮件,然后通过本地的 UNIX 通讯端把它传给 ClamAV,和利用 Mail::SpamAssassin 的 Perl 模块传送给 SpamAssassin。经过扫描的邮件将会通过 smtp 在 TCP 端口 10025 上还给我们的 MTA 来发放。

Amavisd-new 不须与 MTA 处于同一台实体服务器上,在高流量的环境下,Amavisd-new、ClamAV 与 SpamAssassin 往往都与 MTA 身处不同的服务器。

2. 安装

Amavisd-new 及 ClamAV 可从 RPMForge 软件库安装。要启用 RPMForge 软件库,请参阅 RPMForge 的指引。

SpamAssassin 属于 CentOS 的 base 软件库,但 RPMForge 收录了一个更新的版本。你应该考虑用 RPMForge 的版本。要这样做(尤其假如你已采用 yum 的 priorities 插件),请在你的 etc/yum.repos.d/CentOS-Base.repo 档内的 [base] 及 [updates] 部份加入以下内容:

[base]
exclude=spamassass*
...
[updates]
exclude=spamassass*
...

首先,安装 amavisd-new、clamv 及 spamassassin 组件:

yum --enablerepo=rpmforge,rpmforge-extras install amavisd-new clamav clamav-devel clamd spamassassin

这样多数亦会安装一大堆依赖性组件,包括不同的 perl 模块及压缩组件。一切顺利的话,amavis 及 clamav 这两位新用户应该已被安装在系统上:

# cat /etc/passwd | grep "amavis\|clamav"
clamav:x:101:102:Clam Anti Virus Checker:/var/clamav:/sbin/nologin
amavis:x:102:103:Amavis email scan user:/var/amavis:/bin/sh

除此之外,clamav 这个用户应该已经自动被加进 amavis 这个群组:

# groups clamav
clamav : clamav amavis

要不然,你可手动地把 clamav 加进 amavis 这个群组:

gpasswd -a clamav amavis

最后,三个新的服务应服已被加进系统内

# chkconfig --list | grep "amavisd\|clamd\|spamassassin"
amavisd         0:off   1:off   2:on    3:on    4:on    5:on    6:off
clamd           0:off   1:off   2:on    3:on    4:on    5:on    6:off
spamassassin    0:off   1:off   2:off   3:off   4:off   5:off   6:off

spamassassin 这个引导 spamd 的服务可以被停用,因为 Amavisd-new 不会应用 spamassassin 的守护程序(spamd),却会直接装入 spamassassin 作为一个模块。

3. 设置

事实上 SpamAssassin 并不须要特别的设置便可配合 Amavisd-new,它可即装即用。这并不等于你不能通过 /etc/mail/spamassassin/local.cf 或该目录内的自定 cf 档来设置它。

3.1. ClamAV

ClamAV 的设置存放在 /etc/clamd.conf 内。我们必须编辑 /etc/clamd.conf 让 ClamAV 知道 Amavisd-new 将会利用本地的 UNIX 通讯端而不是 tcp 端口来与它沟通,以及该通讯端在那里。请如下编辑 LocalSocket 的设置并备注掉 TCPSocket:

### /etc/clamd.conf
#
# 设置 clam 的 LocalSocket
# 留意它 *必须* 吻合 /etc/amavisd.conf 内的设置
#
LocalSocket /var/run/clamav/clamd.sock
#
# 备注掉 TCPSocket 这个设置:
# TCPSocket 3310

3.2. Amavisd-new

Amavisd-new 把它的设置放在 /etc/amavisd.conf 之内。

由于 Amavisd-new 功能强大及灵活性高,当中确实有很多东西可查阅,因此我们不开每次看数个比较重要的设置。

首先,我们可会通过解除以下数行的注释来停止检查病毒或垃圾邮件(由于下面数行是被注释掉的,因此病毒及垃圾邮件在缺省中是被启用的):

### /etc/amavisd.conf:
#
# To disable virus or spam checks, uncomment the following:
#
# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders & dearchivers

接着,请留意以下数行,纵使它们无须被修改:

$max_servers = 2;                   # num of pre-forked children (2..30 is common), -m
$daemon_user  = "amavis";           # (no default;  customary: vscan or amavis), -u
$daemon_group = "amavis";           # (no default;  customary: vscan or amavis), -g
...
$inet_socket_port = 10024;          # listen on this local TCP port(s)
...
# $notify_method  = 'smtp:[127.0.0.1]:10025';
# $forward_method = 'smtp:[127.0.0.1]:10025';  # set to undef with milter!

$max_servers 设置同步执行的 Amavisd-new 进程数量,而且必须与 /etc/postfix/master.cf 内的 amavisfeed 服务的 maxproc 栏吻合(请参阅下面的 Postfix 设置)。

$daemon_user$daemon_group 应该吻合用来执行 Amavisd-new 的用户及群组。

$inet_socket_port 定义 Amavisd-new 将会在那一个 tcp 端口接纳来自 Postfix 的连接。

$notify_method$forward_method 定义 Amavisd-new 把邮件重新注入 Postfix 的途径。

以下设置必须被修改(涉及 $mydomain 和 $myhostname 时)及解除注释(删除行首的 # 号):

$mydomain = 'example.com';                  # 编辑:a convenient default for other settings
$MYHOME = '/var/amavis';                    # 解除注释:a convenient default for other settings, -H
$helpers_home = "$MYHOME/var";              # 解除注释:working directory for SpamAssassin, -S
$lock_file = "$MYHOME/var/amavisd.lock";    # 解除注释, -L
$pid_file  = "$MYHOME/var/amavisd.pid";     # 解除注释, -P
$myhostname = 'mail.example.com';           # 解除注释及编辑:must be a fully-qualified domain name!

接着是一些 SpamAssassin 设置来交换区缺省的 SpamAssassin 设置:

$sa_tag_level_deflt  = 2.0;                 # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.2;                 # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.9;                 # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10;                  # spam level beyond which a DSN is not sent
# $sa_quarantine_cutoff_level = 25;         # spam level beyond which quarantine is off
$penpals_bonus_score = 8;                   # (no effect without a @storage_sql_dsn database)
$penpals_threshold_high = $sa_kill_level_deflt;         # don't waste time on hi spam
$sa_mail_body_size_limit = 400*1024;        # don't waste time on SA if mail is larger
$sa_local_tests_only = 0;                   # only tests which do not require internet access?

不一定要修改它们,但是你值得知道它们的存在,因为这里是最方便修改垃圾邮件限制的地方。

$sa_tag_level_deflt 指定 Amavisd-new 由那一个级别开始写入 X-Spam-Flag、X-Spma-Score、X-Spam-Status 等垃圾邮件信息标头。假如你想为所有邮件加入信息标头,请把此值设为 -999。

$sa_tag2_level_deflt 指定由那一个级别开始在垃圾邮件的标题上标签它们。

$sa_kill_level_deflt 指定 Amavisd-new 由那一个级别开始拦截和扣留邮件。这个用途很大,因为 SpamAssassin 在缺省情况下不会这样做。

$sa_dsn_cutoff_level 指定由那一个级别开始寄件失败通告不会被发送给寄件人。由于多数垃圾邮件寄件者的地址都是伪造的,不为明显的垃圾邮件发送寄件失败通告是最合理的,要不然你只会加剧反向散寄的问题。

$sa_quarantine_cutoff_level 指定那一个级别开始不必扣留垃圾邮件。这个选项缺省是被注释掉的,意思就是所有邮件都会被扣留。

接下来是发送通告的电邮地址:

$virus_admin               = "virusalert\@$mydomain";   # notifications recip.
$mailfrom_notify_admin     = "virusalert\@$mydomain";   # notifications sender
$mailfrom_notify_recip     = "virusalert\@$mydomain";   # notifications sender
$mailfrom_notify_spamadmin = "spam.police\@$mydomain";  # notifications sender

你大概会将它们设置为 postmaster\@$mydomain 或其它你想收到垃圾邮件通告的电邮地址。

最后,我们须要如下为 ClamAV 的部份解除注释:

### http://www.clamav.net/
['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"],
  qr/\bOK$/, qr/\bFOUND$/,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
# # NOTE: run clamd under the same user as amavisd, or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer socket "$MYHOME/clamd".

请留意 /var/run/clamav/clamd.sock 这个设置必须与我们先前在 /etc/clamd.conf 内输入的 LocalSocket /var/run/clamav/clamd.sock 设置吻合。

3.3. Postfix

然后我们须要设置 Postfix 内的服务(/etc/postfix/master.cf)好让邮件会被传给 Amavisd-new 进行过滤及再次注入 Postfix。

首先我们会设置 Amavisd-new 这个服务要接受来自 Postfix 的邮件。Amavisd-new 同时支持 lmtp 及 smtp,而在这个实例中我们选用 lmtp 协议。(FIXME: 我未知有任何理由要特定选用某个协议,因此我选择 lmtp 纯綷由于用 lmtp 置标本地派给 Amavisd-new 的邮件有助阅读日志)。

打开 /etc/postfix/master.cf 并加入以下名为 amavisfeed 的服务:

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
amavisfeed unix    -       -       n        -      2     lmtp
    -o lmtp_data_done_timeout=1200
    -o lmtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20

请留意在 maxproc 栏内的数值(2)必须与 /etc/amavisd.conf 内的 $max_servers 设置吻合。有关各选项的详细解释请参阅 Amavisd-new 的文档(/usr/share/doc/amavisd-new-2.5.4/README.postfix.html)。

然后我们定义一个专用的服务把邮件重新注入 Postfix。我们为此在 /etc/postfix/master.cf 内加入一个在 localhost(127.0.0.1)的 tcp 10025 端口(/etc/amavisd.conf 的缺省值)上聆听的 smtp 服务:

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
127.0.0.1:10025 inet n    -       n       -       -     smtpd
    -o content_filter=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=reject_unauth_pipelining
    -o smtpd_end_of_data_restrictions=
    -o smtpd_restriction_classes=
    -o mynetworks=127.0.0.0/8
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
    -o local_header_rewrite_clients=
    -o smtpd_milters=
    -o local_recipient_maps=
    -o relay_recipient_maps=

有关各选项的详细解释请参阅 Amavisd-new 的文档(/usr/share/doc/amavisd-new-2.5.4/README.postfix.html)。

在 /etc/postfix/master.cfg 作出改动后,我们必须重新装入 postfix,好让这些改动能生效:

postfix reload

这个时候,你也许应该测试 Amavisd-new 及 Postfix 的常注程序是否在正确地聆听(参阅下面「测试」部份)。

当一切已准备就绪,最后一步就是通过在 /etc/postfix/main.cf 加入以下设置来启用邮件过滤:

content_filter=amavisfeed:[127.0.0.1]:10024

然后重新装入 postfix 让这些改动生效:

postfix reload

接着查看你的邮件日志。

tail -f /var/log/maillog

3.4. 其它 MTA

除了 Postfix 外,Amavisd-new 也可以设置供其它 MTA 使用。有关其它 MTA 的 README 档可以在这里找到:

http://www.ijs.si/software/amavisd/#doc

有兴趣撰写关于如何为其它 MTA 进行设置的人仕,请参阅「如何参予」这一页:

http://wiki.centos.org/zh/HowToContribute

4. 测试

现在是个好时机来测试我们所定义的服务能如常运作。

首先,引导 clamd 及 amavisd 服务:

# service clamd start
Starting Clam AntiVirus Daemon:                            [  OK  ]
# service amavisd start
Starting Mail Virus Scanner (amavisd):                     [  OK  ]

现在利用 telnet 测试 amavisd 这个服务正在 127.0.0.1:10024 上耹听:

$ telnet localhost 10024
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready
ehlo localhost
250-[127.0.0.1]
250-VRFY
250-PIPELINING
250-SIZE
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 XFORWARD NAME ADDR PROTO HELO
quit
221 2.0.0 [127.0.0.1] amavisd-new closing transmission channel
Connection closed by foreign host.

假若一切正常的话,你应该如上看见成功的连接。

接下来测试 Postfix 的 smtpd 正在 127.0.0.1:10025 上聆听:

$ telnet localhost 10025
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
220 mail.example.com ESMTP Postfix
ehlo localhost
250-mail.example.com
250-PIPELINING
250-SIZE 20480000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.

同样地我们应该如上看见成功的连接。现在我们可以通过发送特别的符串来测试扫描能否正常运作。

测试 SpamAssassinGTUBE(Generic Test for Unsolicited Bulk Email)符串。

测试 ClamAV 的 EICAR 符串。

请进入 /usr/share/doc/amavisd-new-2.5.4/test-messages 这个目录,然后执行:

perl -pe 's/./chr(ord($&)^255)/sge' <sample.tar.gz.compl | zcat | tar xvf -

把测试的样本邮件解压出来。请利用这两个指命来发送一个垃圾邮件样本及一封有毒的邮件:

$ sendmail -i your-address@example.com < sample-virus-simple.txt
$ sendmail -i your-address@example.com < sample-spam-GTUBE-junk.txt

请以你的实际电邮地址取代 your-address@example.com 。在你的邮件日志(即 /var/log/maillog)内查阅来自 amavis 的扫描结果,而你应该看见 Passed SPAMMY 或 Blocked INFECTED (Eicar-Test-Signature)。现在你应该检查你的设置乎合你的期望。

5. SELinux

/!\ 解决 SELinux 问题的其中一个权宜之计就是在  /etc/selinux/config  内临时以 permissive 替换 enforcing。这个做法还有一个好处,就是所须的信息将会收录在位于 /var/log/audit/ 的 SELinux 日志内。详情请参阅这篇有关 SELinux 的文章。

当 SELinux 已被启用并在 enforcing 模式下,amavisd 及 ClamAV 须要一些额外的政策。下面的 SELinux 政策模块是这样制定的:在(已完整地更新)CentOS 5 上设置 SELinux 为 permissive 模式,然后按上面指引设置 amavisd/ClamAV/SpamAssassin,接着遵照 SELinux 教学文档内的描述把 AVC 的错误日志传给 audit2allow。

我们将会为 amavisd 及 ClamAV 创建两个自定的 SELinux 政策模块,它们分别是 amavisdlocal 及 clamlocal(SpamAssassin 并不须要一个自定的 SELinux 政策)。请把以下内容分别剪贴到 amavisdlocal.te 及 clamlocal.te:

module amavisdlocal 1.0;

require {
        type traceroute_port_t;
        type pgpkeyserver_port_t;
        type amavis_var_lib_t;
        type amavis_t;
        type clockspeed_port_t;
        class udp_socket name_bind;
        class lnk_file { read create unlink getattr };
}

#============= amavis_t ==============
allow amavis_t clockspeed_port_t:udp_socket name_bind;
allow amavis_t pgpkeyserver_port_t:udp_socket name_bind;
allow amavis_t traceroute_port_t:udp_socket name_bind;
allow amavis_t amavis_var_lib_t:lnk_file { read create unlink getattr };

module clamlocal 1.0;

require {
        type proc_t;
        type var_t;
        type sysctl_kernel_t;
        type clamd_t;
        class file { read getattr };
        class dir { read search };
}

#============= clamd_t ==============
allow clamd_t proc_t:file { read getattr };
allow clamd_t sysctl_kernel_t:dir search;
allow clamd_t sysctl_kernel_t:file read;
allow clamd_t var_t:dir read;
allow clamd_t var_t:file { read getattr };

现在创建及装入 amavisdlocal 模块:

# checkmodule -M -m -o amavisdlocal.mod amavisdlocal.te
checkmodule:  loading policy configuration from amavisdlocal.te
checkmodule:  policy configuration loaded
checkmodule:  writing binary representation (version 6) to amavisdlocal.mod
# semodule_package -o amavisdlocal.pp -m amavisdlocal.mod
# semodule -i amavisdlocal.pp

然后为 clamlocal 重复一次:

# checkmodule -M -m -o clamlocal.mod clamlocal.te
checkmodule:  loading policy configuration from clamlocal.te
checkmodule:  policy configuration loaded
checkmodule:  writing binary representation (version 6) to clamlocal.mod
# semodule_package -o clamlocal.pp -m clamlocal.mod
# semodule -i clamlocal.pp

最后,检查我们自定的本地 SELinux 模块已被装入:

# semodule -l
amavis  1.1.0
amavisdlocal    1.0
ccs     1.0.0
clamav  1.1.0
clamlocal       1.0
dcc     1.1.0
evolution       1.1.0
iscsid  1.0.0
mozilla 1.1.0
mplayer 1.1.0
nagios  1.1.0
oddjob  1.0.1
pcscd   1.0.0
postgrey        1.0
pyzor   1.1.0
razor   1.1.0
ricci   1.0.0
smartmon        1.1.0

5.1. CentOS 6

CentOS 6 须要额外的步骤。多谢 http://lists.centos.org/pipermail/centos-docs/2012-October/004994.html 中的 Harald Oehlmann。

Amavis 把所有邮件内容及附件(子目录「部件」)放进 /var/amavis/tmp 下的子目录内。病毒扫描器会扫描这些文件及把结果写进这个目录内。

SELinux 会阻止病毒扫描器访问这个目录,导致 /var/log/mail 内出现 (!)run_av (ClamAV-clamscan) FAILED 等错误。

请完成以下步骤来容许 clam-av 使用此界面:

--se_clamav_amavis.te--
# ***HaO 2012-09-30: 新增规则容让 clamav 访问 amavis 文件
# 和写出 ok 档,与及创建临时数据夹
module clamscanamavis 1.0;
require {
        type clamscan_t;
        type amavis_var_lib_t;
        class file {getattr read open write create unlink};
        class dir {search read getattr open write add_name create
setattr remove_name rmdir};
}
allow clamscan_t amavis_var_lib_t:file {getattr read open write create
unlink};
allow clamscan_t amavis_var_lib_t:dir {search read getattr open write
add_name create setattr remove_name rmdir};

接着

checkmodule -M -m -o se_clamav_amavis.mod se_clamav_amavis.te
semodule_package -o se_clamav_amavis.pp -m se_clamav_amavis.mod
semodule -i se_clamav_amavis.pp

6. 更新

6.1. SpamAssassin

垃圾邮件正在迅速地改变,新规则亦回应此时常被撰写出来。通过 sa-update,这些规则可以非常快捷地(有可能在数分钟内)被发行,并逮捕新的垃圾邮件。请先阅读关于 sa-update 然后才继续。要启用自动更新,请利用你喜欢的编辑打开 /etc/cron.d/sa-update 并解除内有项目的注释,令它变为:

10 4 * * * root /usr/share/spamassassin/sa-update.cron 2>&1 | tee -a /var/log/sa-update.log

存储并离开。这个 cron 项目将会在每日上午 4 时 10 分被执行。

6.2. ClamAV

ClamAV 利用 freshclam 来更新病毒的定义。它们是通过 /etc/cron.daily/freshclam 这个 cron 脚本进行自动更新的。你不必做任何事情。你可以查阅你的 /var/log/clamav/freshclam.log 日志档来确定你的更新是否成功。

7. 连结

Amavisd-new 的安装在 /usr/share/doc/amavisd-new-2.5.4/ 内包括大量的文档,而读者尤其可参考 /usr/share/doc/amavisd-new-2.5.4/README.postfix.html。它的网上版本位于:http://www.ijs.si/software/amavisd/README.postfix.html

http://www.linuxjournal.com/article/7778

http://www200.pair.com/mecham/spam/clamav-redhat-amavis.html

http://www200.pair.com/mecham/spam/clamav-amavisd-new.html

...

Translation of revision 35~


2023-09-11 07:23