exim+SpamAssassinでspam撃退かつTLS認証対応

今まではeximのフィルタ機能を使って,.forwardファイルにパイプでspamassassinコマンドを通してspam判定をしていたのですが,KDDI DIONがメールサーバ仕様を勝手に変えたのを機会にSpamAssassinデーモン版に変えてみました.

exim-4.69から最新のexim-4.80にバージョンアップしました.

ソースから入れる場合,TLS対応のためにLocal/Makefilesを編集します.

# This setting is required for any TLS support (either OpenSSL or GnuTLS)
SUPPORT_TLS=yes

eximのconfigureは結構カスタマイズします.
まずTLS対応.

# spamd_address = 127.0.0.1 783

# SpamAssassinデーモンは別のマシンや複数マシンで走らせることもできますが,とりあえずeximと同居させます
spamd_address = 127.0.0.1 783

# tls_advertise_hosts = *

# TLSが使えることを全ての相手マシンにアピールします
tls_advertise_hosts = *

# tls_certificate = /etc/ssl/exim.crt
# tls_privatekey = /etc/ssl/exim.pem

# 別にファイル名は同じでもいいのですが,opensslで作ります
tls_certificate = /usr/local/exim/exim-private.crt
tls_privatekey = /usr/local/exim/exim-private.pem


# daemon_smtp_ports = 25 : 465 : 587
# tls_on_connect_ports = 465

# 通常のSMTP25以外も見張ります
daemon_smtp_ports = 25 : 465 : 587
tls_on_connect_ports = 465

local_delivery:
driver = appendfile
file = /var/mail/$local_part
delivery_date_add
envelope_to_add
return_path_add

# 本命SpamAssassinクライアントを使うことを宣言
local_delivery:
driver = appendfile
file = /var/mail/$local_part
delivery_date_add
envelope_to_add
return_path_add
transport_filter = /usr/local/bin/spamc

opensslを使った認証ファイルは,フツーにapacheやなんかで使う場合と同じです.

# openssl req -new -x509 -key /usr/local/exim/exim-private.pem -out /usr/local/exim/exim-private.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.

        • -

Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) :
Organization Name (eg, company) [Internet Widgits Pty Ltd]: d.hatena.ne.jp/tullio
Organizational Unit Name (eg, section)
:
Common Name (eg, YOUR name) : (重要)
Email Address
:

(重要)ですが,ドメインのMXフィールドを記述すれば良いと思います.メールサーバなので.



ACLもちょっと工夫します.
まずこちらの設定をいれます.
阻止率99%のスパム対策方式の研究報告 | スパム対策技術

warn hosts = ^[^\.]*[0-9][^0-9\.]+[0-9]
message = spam not permitted [rule 1]
add_header = X-Warning: $sender_host_address is in EXIMED_WARN lists

warn hosts = ^[^\.]*[0-9]{5}
message = spam not permitted [rule 2]
add_header = X-Warning: $sender_host_address is in EXIMED_WARN lists

# warn hosts = ^[^\.]*[0-9]\.[^\.]*[0-9]\.[^\.]+\..+\.
# message = spam not permitted [rule 3]
# add_header = X-Warning: $sender_host_address is in EXIMED_WARN lists

warn hosts = ^[^\.]*[0-9]\.[^\.]*[0-9]-[0-9]
message = spam not permitted [rule 4]
add_header = X-Warning: $sender_host_address is in EXIMED_WARN lists

rule3は,誤検知があったので一時的にコメントにしてます.
DNSブラックリスト設定もいれます.

#############################################################################
# There are no default checks on DNS black lists because the domains that
# contain these lists are changing all the time. However, here are two
# examples of how you can get Exim to perform a DNS black list lookup at this
# point. The first one denies, whereas the second just warns.
#
# deny message = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
# dnslists = black.list.example
#
deny dnslists = truncate.gbudb.net:bl.spamcop.net:all.rbl.jp
message = rejected because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
add_header = X-Warning: $sender_host_address is in a black list at $dnslist_domain
log_message = found in $dnslist_domain
#############################################################################

まぁ,DNSブラックリストSpamAssassinでもチェックしてくれるので冗長なのですが,ACLで弾いておくとSpamAssassinを通らないので,負荷が減る可能性があります.

SpamAssassin用のACL設定はこちら.

acl_check_data:

# Deny if the message contains a virus. Before enabling this check, you
# must install a virus scanner and set the av_scanner option above.
#
# deny malware = *
# message = This message contains a virus ($malware_name).

# Add headers to a message if it is judged to be spam. Before enabling this,
# you must install SpamAssassin. You may also need to set the spamd_address
# option above.
#
deny spam = joe
add_header = X-Spam_score: $spam_score\n\
X-Spam_score_int: $spam_score_int\n\
X-Spam_bar: $spam_bar\n\
X-Spam_report: $spam_report
log_message = X-Spam_score: [SPAM] ($spam_score) $header_message-id
# Accept the message.

spam=joeというのは,ユーザjoeのホームディレクトリ以下の.spamassassinを使うということで,ユーザがたくさんいるマシンならサイトグローバルな場所を作って,もしくは自分ユーザくらいしかなければ自分ユーザ名を指定すれば良いと思います.
log_messageは,自分で誤検知検知(?)スクリプトなんかを作る時のために,好きなようにカスタマイズして下さい.

TLSのチェックは,opensslコマンドである程度できます.

openssl s_client -connect localhost:25 -starttls smtp
CONNECTED(00000003)
depth=0 /C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)
verify error:num=18:self signed certificate
verify return:1
depth=0 /C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)
verify return:1

    • -

Certificate chain
0 s:/C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)
i:/C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)

    • -

Server certificate
 -----BEGIN CERTIFICATE-----
MIICajCCAhSgAwIBAgIJAPMbRr7sFhxsMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV
(snip)
 -----END CERTIFICATE-----
subject=/C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)
issuer=/C=JP/ST=Tokyo/O=d.hatena.ne.jp/tullio/CN=(重要)

    • -

No client certificate CA names sent

    • -

SSL handshake has read 1851 bytes and written 500 bytes

    • -

New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 512 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
(snip)

    • -

250 HELP

もし設定がうまくいっていない場合は,次のようになると思います.

openssl s_client -connect localhost:25 -starttls smtp
CONNECTED(00000003)
95211:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:/usr/src/secure/lib/libssl/../../../crypto/openssl/ssl/s23_clnt.c:602:

凄く良い感じです.一日に2000通以上の迷惑メールが弾かれてます.快適です.