ご注意下さい
この記事は3年以上前に書かれた記事ですので、内容が古い可能性があります。
前回は受信側としての設定の紹介をしました。受信したメールに添付されている電子署名を相手のDNSに登録されている公開鍵を使って複合し、確かに本物であることの確認をする設定を行いました。
今回はDomainkeys/DKIMという電子署名の仕組みを使って、自分が送信するメールに対して電子署名してみましょう。メールに添付した電子署名とこちらのDNSに登録した公開鍵から、確かにこちらから送付した正当なメールかどうかを受信側でチェックすることが可能になります。
この記事のもくじ
まずはもう一度qmailを綺麗に作る
qmailは1.03が安定版かつ最終版ですが、いろいろと問題もありさまざまなパッチがリリースされています。代表的なもので、
- qmail-103-dns.patch:DNSにて512バイトを超えるUDPパケットが来た場合に処理できなくなる問題の修正パッチ。
- qmail-date-localtime.patch:Receivedなどの時刻をローカルタイムにするパッチ
- qmail-smtpd-newline.patch:qmail-smtpdが\nで終了する行を受け付けるパッチ
- qmail-smtpd-relay-reject.patch:Mailアドレスのユーザ名部分に"@"、"!"、"%"が含まれているメールを拒否するパッチ
- qmail-smtp-auth:SMTP認証に対応するパッチ
- qmail-spf-rc5.patch:SPFに対応するパッチ
これぐらいは対応しなければならないと思いますが、ひとつひとつ適用するには面倒ですしパッチ間の競合があってうまく適用できない場合もあります。
最近はこの辺のパッチをまとめたジャンボパッチがありますのでそのパッチを素のqmail-1.03に適用してしまうのが良いでしょう。
ジャンボパッチの適用
qmail-1.03-jms1-7.10.patchというのがありますのでこれをダウンロードします。
なお、このパッチには上記のパッチのうちnewlineパッチが含まれていませんのでこれは個別にパッチを適用します
# wget https://qmail.jms1.net/patches/qmail-1.03-jms1-7.10.patch
# wget http://notes.sagredo.eu/sites/notes.sagredo.eu/files/qmail/patches/qmail-smtpd-newline.patch
# tar zxvf qmail-1.03.tar.gz
# cd qmail-1.03
# patch < ../qmail-1.03-jms1-7.10.patch # patch < ../qmail-smtpd-newline.patch
今回は上記に加えてDomainkeys/DKIMに対応するためのパッチを追加で適用します。
その前にlibdomainkeysとlibdkimの2つのライブラリのインストールが必要となります。
libdomainkeysのインストール
まずはlibdomainkeysのインストールを行います。
# tar zxzf libdomainkeys-0.69.tar.gz
# cd libdomainkeys-0.69
# make
# install -m 644 libdomainkeys.a /usr/local/lib
# install -m 644 domainkeys.h dktrace.h /usr/local/include
# install -m 755 dknewkey /usr/local/bin
ですが場合によってはmakeエラーとなる可能性があります。
gcc -DBIND_8_COMPAT -O2 -o dktest dktest.o -L. -ldomainkeys -lcrypto `cat dns.lib` `cat socket.lib`
./libdomainkeys.a(dns_txt.o): In function `dns_text':
dns_txt.c:(.text+0x55): undefined reference to `__res_query'
dns_txt.c:(.text+0xd3): undefined reference to `__dn_expand'
dns_txt.c:(.text+0x19d): undefined reference to `__dn_expand'
collect2: ld はステータス 1 で終了しました
make: *** [dktest] エラー 1
#
上記のようなエラーが出てきた場合には
# make
とすることで回避可能です。
libdkimのインストール
次にlibdkimのインストールを行います。
# wget http://www.bltweb.net/qmail/libdkim-1.0.19-linux.patch
# wget http://www.bltweb.net/qmail/libdkim-1.0.19-extra-options.patch
# unzip libdkim-1.0.19.zip
# cd libdkim/src
# patch -p2 < ../../libdkim-1.0.19-linux.patch # patch -p2 < ../../libdkim-1.0.19-extra-options.patch # make # make install
Domainkeys/DKIMパッチの適用
いよいよ準備が整ったところでqmailにパッチを適用し、コンパイルを行っています。
# cd qmail-1.03
# patch -p1 < ../qmail-1.03-jms1.7.08-dkim-r1.patch # sed -ie '1s/$/ -DDKIM/' conf-cc
# make
# make man
# make setup check
蛇足ですが、上記sed文の意味ですが、conf-ccの1行目の行末に「 -DDKIM」と付けることを意味していますので手で修正してもOKです。
cc -O2 -DTLS -DEXTERNAL_TODO -I/usr/local/ssl/include -I/usr/kerberos/include -DDKIM This will be used to compile .c files.
さらに蛇足ですが、manファイルは/var/qmail/man配下にインストールされますが、このままではman qmail-smtpdとしてもmanを参照できません。/etc/man.configにパスを追加してあげる必要があります。
# MANBIN /usr/local/bin/man # # Every automatically generated MANPATH includes these fields # MANPATH /usr/man MANPATH /usr/share/man MANPATH /usr/local/man MANPATH /usr/local/share/man MANPATH /usr/X11R6/man MANPATH /var/qmail/man MANPATH /usr/lib/courier-imap/man #
Domainkeys/DKIM認証ヘッダ(Authentication-Results:)付与
tcpserverの設定でDKVERYFYを付ければDomainkeys/DKIMのチェックをしAuthentication-Resultsヘッダをつけてくれるようになります。
:allow,DKVERIFY="",AUTH_UNSET_DKVERIFY="",QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl"
以下のようなメールヘッダが付与されていることを確認しましょう。
Authentication-Results: kamata-net.com; domainkeys=pass (ok); dkim=pass (ok)
Domainkeys/DKIM署名設定
送信メールに対する電子署名設定は簡単です。
# cd /etc/domainkeys/kamata-net.com
# dknewkey default 1024 > default.pub
# chown -R root:root /etc/domainkeys
# chmod 640 /etc/domainkeys/kamata-net.com/default
# chown root:qmail /etc/domainkeys/kamata-net.com/default
/etc/domainkeys/kamata-net.com/default.pubの内容はDNSに登録します。
IN A 218.45.184.224 IN NS ns.kamata-net.com. IN MX 10 mail.kamata-net.com. IN TXT "v=spf1 mx include:spf-01.asahi-net.or.jp -all" default._domainkey IN TXT "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDg3AnIBiD9aNjBhyEPojxvHqYNvEaTm8sHNwywBTBjBzHruf94ij8T50zsUs1Pw8gfVbSXIUQ7myVUSDiLFvenc6H3mJSXs+KlXrA2ZzskNNO5VyDO1zYBgs4+aOupuXyFDLfwDNVI3YzwMv9av6X3ixer+395i2/0croIshcAkwIDAQAB" _adsp._domainkey IN TXT "dkim=all"
6行目はspamassassinをデバッグモードで動作させている際に以下のようなエラーを発見して調べて分かりました。
Mar 8 02:43:08 kamataxxx spamd[32226]: dkim: signature verification result: none
Mar 8 02:43:08 kamataxxx spamd[32226]: dkim: adsp: performing lookup on _adsp._domainkey.kamata-net.com
Mar 8 02:43:08 kamataxxx spamd[32226]: dkim: adsp result: U/unknown (dns: unknown), author domain 'kamata-net.com'
ADSPレコードの公開をしてdkim=allとすることで、このドメイン名がついているメールには全て電子署名がついています。と宣言することになります。つまり電子署名が無いメールは全て成りすましである、ということを宣言している訳です。
DKIM (Domainkeys Identified Mail) : 迷惑メール対策委員会
SPFレコードにおける-allと同じような意味ですね。
次に /var/qmail/control/dksignというファイルを作って以下のように記述します。
/etc/domainkeys/%/default
%はメールアドレスの@マークより右側のドメイン部分に相当します。
テストしてみる
では早速テストしてみます。yahooメールかgmailにアカウントを作ってテストメールを送付するのが手っ取り早いと思います。
Yahoo!メールの場合
Received-SPF: pass (mail1.asahi-net.or.jp: domain of test@kamata-net.com designates 202.224.39.197 as permitted sender) receiver=mail1.asahi-net.or.jp; client-ip=202.224.39.197; envelope-from=test@kamata-net.com; Authentication-Results: mta585.mail.kks.yahoo.co.jp from=kamata-net.com; domainkeys=pass (ok); dkim=pass (ok); header.i=@kamata-net.com
Gmailの場合
Received-SPF: pass (google.com: domain of test@kamata-net.com designates 202.224.39.197 as permitted sender) client-ip=202.224.39.197; Authentication-Results: mx.google.com; spf=pass (google.com: domain of test@kamata-net.com designates 202.224.39.197 as permitted sender) smtp.mail=test@kamata-net.com; dkim=pass header.i=@kamata-net.com
上記のようにdkim、domainkeysもpassとなっていることを確認しましょう。もちろんSPFもですよ。
追加でやっておいた方がいいかもしれない作業
Domainkeys/DKIM認証には直接関係ないのですが、RELAYCLIENT環境変数で気になることがあったので追記しておきます。
ここで細かいことは省きざっくりとqmailの動きを見ておきましょう。
外部ネットワークからのアクセス(主にメール受信)か、内部ネットワークからのアクセス(主にメール送信)によって動きが異なります。
Internal Network External Network (主に送信メール) (主に受信メール) | | +-----------+------------+ | Internal Net +-----+-----+・tcp.smtp.cdb からの場合は | tcpserver | RELAYCLIENT +-----+-----+ 環境変数を付加 | +-----+-----+・rcpthosts |qmail-smtpd|・SPFチェックヘッダ付与(Received-SPF) | |・domainkeys/DKIMチェックヘッダ付与(Authentication-Results) +-----+-----+・SMTP認証 | +-----------+------------+ |RELAYCLIENTあり | RELAYCLIENTなし | +------+------+ | |qmail-scanner| | | -queue.pl | | +------+------+ | | | +------+------+ | | F-Prot |・ウィルスチェック | | (fpscan) | | +------+------+ | | | +------+------+・local.cf | |spam assassin|・SPFチェック | | (SA/spamd) |・Domainkeys/DKIM認証 | +------+------+・スパム判定 | | +-----------+------------+ | +-----+-----+ |qmail-queue| +-----+-----+ | +-----+-----+ | qmail-send|・locals +-----+-----+ | +-----------+------------+ | | +------+------+・.qmail +------+------+・smtproutes | qmail-local | | qmail-remote|・Domainkeys/DKIM署名 +------+------+ +------+------+ | | ローカル配信 外部配信
tcpserverでは192.168.a,b,cの内部セグメントについてはRELAYCLIENT環境変数をセットし、QMAILQUEUE環境変数でキュープログラムの指定をしています。外部セグメントからのアクセスの場合は5行目のアクセスになりますのでRELAYCLIENT環境変数はセットせず、キュープログラムもqmail-scanner-queue.plを指定しており、ウィルスチェックとスパム判定を行うことになります。
192.168.a.:allow,RELAYCLIENT="",RBLSMTPD="",QMAILQUEUE="/var/qmail/bin/qmail-queue",TCPLOCALHOST="localhost",TCPLOCALIP="127.0.0.1" 192.168.b.:allow,RELAYCLIENT="",RBLSMTPD="",QMAILQUEUE="/var/qmail/bin/qmail-queue",TCPLOCALHOST="localhost",TCPLOCALIP="127.0.0.1" 192.168.c.:allow,RELAYCLIENT="",RBLSMTPD="",QMAILQUEUE="/var/qmail/bin/qmail-queue",TCPLOCALHOST="localhost",TCPLOCALIP="127.0.0.1" 127.0.0.1:allow,QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl" :allow,QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl"
ところがiPhoneやスマホなど、外出先などからメール送信する際には右側のルートを通ってくることになります。すると自身がメール送信したいにも関わらずウィルスチェックやSPFチェック、Domainkeys/DKIM認証など無駄な処理をしてしまいますし、理由が分かりませんが(散々調べましたが結局分からず)、なぜかSPF_FAILとなってしまうなど散々なことになってしまいました。
以下は/var/log/maillogの抜粋ですが、外部からアクセスした際のログです。
Mar 8 02:43:08 kamataxxx spamd[32226]: spf: checking HELO (helo=?10.95.245.230?, ip=49.98.162.242)
Mar 8 02:43:08 kamataxxx spamd[32226]: dns: providing a callback for id: 53152/?10.95.245.230?/TXT/IN
Mar 8 02:43:08 kamataxxx spamd[32226]: spf: query for /49.98.162.242/?10.95.245.230?: result: none, comment: , text: No applicable sender policy available
Mar 8 02:43:08 kamataxxx spamd[32226]: dkim: author test@kamata-net.com, not in any dkim whitelist
Mar 8 02:43:08 kamataxxx spamd[32226]: spf: already checked for Received-SPF headers, proceeding with DNS based checks
Mar 8 02:43:08 kamataxxx spamd[32226]: spf: checking EnvelopeFrom (helo=?10.95.245.230?, ip=49.98.162.242, envfrom=test@kamata-net.com)
Mar 8 02:43:08 kamataxxx spamd[32226]: dns: providing a callback for id: 24882/kamata-net.com/TXT/IN
Mar 8 02:43:08 kamataxxx spamd[32226]: dns: providing a callback for id: 55341/kamata-net.com/MX/IN
Mar 8 02:43:08 kamataxxx spamd[32226]: dns: providing a callback for id: 18745/mail.kamata-net.com/A/IN
Mar 8 02:43:08 kamataxxx spamd[32226]: dns: providing a callback for id: 13130/spf-01.asahi-net.or.jp/TXT/IN
Mar 8 02:43:08 kamataxxx spamd[32226]: spf: query for test@kamata-net.com/49.98.162.242/?10.95.245.230?: result: fail, comment: Please see http://www.openspf.org/Why?s=mfrom;id=test%40kamata-net.com;ip=49.98.162.242;r=kamataxxx, text: Mechanism '-all' matched
Mar 8 02:43:08 kamataxxx spamd[32226]: FreeMail: RULE (__freemail_reply) check_freemail_replyto
~
Mar 8 02:43:10 kamataxxx spamd[32226]: spamd: clean message (7.5/10.0) for qscand:601 in 2.4 seconds, 1122 bytes.
Mar 8 02:43:10 kamataxxx spamd[32226]: spamd: result: . 7 - BAYES_50,CONTENT_TYPE_PRESENT,DIRECTUNKNOWN,HTML_MESSAGE,MIMEQENC,MULTIPART_ALTERNATIVE,ONLY1HOPDIRECT,QENCPTR1,QENCPTR2,RDNS_NONE,SPF_FAIL,TO_EQ_FM_DOM_SPF_FAIL scantime=2.4,size=1122,user=qscand,uid=601,required_score=10.0,rhost=kamataxxx,raddr=127.0.0.1,rport=60198,mid=<6C77C138C80E436C91AD068447F85AB7@kamata-net.com>,bayes=0.500004,autolearn=no
コメントに書いてあるサイトを見てもkamata-net.comドメインのSPFレコードはspmodeを通して送ることを宣言していないよ。とあり…。
kamataxxx, rejected a message that claimed an envelope sender address of test@kamata-net.com.
kamataxxx, received a message from s662242.xgsspn.imtp.tachikawa.spmode.ne.jp (49.98.162.242) that claimed an envelope sender address of test@kamata-net.com.
However, the domain kamata-net.com has declared using SPF that it does not send mail through s662242.xgsspn.imtp.tachikawa.spmode.ne.jp (49.98.162.242). That is why the message was rejected.
仕様がよくわからない部分があるのですが、
3月 08 18:02:04.103 [14187] dbg: diag: [...] module installed: Mail::SPF, version v2.009
3月 08 18:02:04.818 [14187] dbg: plugin: loading Mail::SpamAssassin::Plugin::SPF from @INC
3月 08 18:02:05.755 [14187] dbg: config: fixed relative path: /var/lib/spamassassin/3.003001/updates_spamassassin_org/25_spf.cf
3月 08 18:02:05.755 [14187] dbg: config: using "/var/lib/spamassassin/3.003001/updates_spamassassin_org/25_spf.cf" for included file
3月 08 18:02:05.756 [14187] dbg: config: read file /var/lib/spamassassin/3.003001/updates_spamassassin_org/25_spf.cf
3月 08 18:02:05.831 [14187] dbg: config: fixed relative path: /var/lib/spamassassin/3.003001/updates_spamassassin_org/60_whitelist_spf.cf
3月 08 18:02:05.831 [14187] dbg: config: using "/var/lib/spamassassin/3.003001/updates_spamassassin_org/60_whitelist_spf.cf" for included file
3月 08 18:02:05.832 [14187] dbg: config: read file /var/lib/spamassassin/3.003001/updates_spamassassin_org/60_whitelist_spf.cf
3月 08 18:02:17.566 [14187] dbg: spf: cannot get Envelope-From, cannot use SPF
3月 08 18:02:17.566 [14187] dbg: spf: def_spf_whitelist_from: could not find useable envelope sender
3月 08 18:02:17.567 [14187] dbg: spf: spf_whitelist_from: could not find useable envelope sender
3月 08 18:02:17.803 [14187] info: rules: meta test TO_EQ_FM_SPF_FAIL has dependency 'ALL_TRUSTED' with a zero score
3月 08 18:02:17.822 [14187] info: rules: meta test TO_EQ_FM_DOM_SPF_FAIL has dependency 'ALL_TRUSTED' with a zero score
#
上記のエラーと関係していそうですのでこれはまた別の機会に解決してみようと思います。
いずれにせよ、外部ネットワークから直接メールサーバに接続してメールを配信しようとした際にSPF_FAILとなり最悪自身のメールがスパムメールと判定されてしまう可能性があります。
外部からメールを送る可能性のあるメールアドレスをspamassassinのlocal.cfに
whitelist_from test@kamata-net.com
にしてしまうのもいいのですが、SPF_FAILだろうが、DKIM認証に失敗しようがスパムメールの送信元がtest@kamata-net.comを騙っていた場合に素通しとなってしまいますのでwhitelist_fromに書いてしまうのは少々危険です。
ではどうするか?ということですが、左のルートを通るようにすればいいと考えています。そもそもman qmail-smtpdの仕様として、SMTP認証が通ったら環境変数RELAYCLIENTとTCPREMOTEINFOが設定される、とありますし。
~
qmail-smtpd can accept LOGIN, PLAIN, and optionally CRAM-MD5 AUTH types. It invokes checkpro-
gram, which reads on file descriptor 3 the username, a 0 byte, the password or CRAM-MD5 response
derived from hostname, another 0 byte, a CRAM-MD5 challenge (if applicable to the AUTH type), and
a final 0 byte. checkprogram invokes subprogram upon successful authentication, which should in
turn return 0 to qmail-smtpd, effectively setting the environment variables RELAYCLIENT and
TCPREMOTEINFO (any supplied value replaced with the authenticated username). qmail-smtpd will
reject the authentication attempt if it receives a nonzero return value from checkprogram or sub-
program.
ところがqmail-1.03-jms1-7.10.patchはqmail-smtpd-authパッチを含んでいるのですがRELAYCLIENTでgrepしても上記manページしかヒットしない…。もしかしてqmail-smtpd-auth-0.31ベース(一番有名なバージョン)の古いパッチが問題でそれをジャンボパッチに含んでいる?ということで調べてみると、最新はqmail-smtpd-auth-0.5.10な模様。こちらのパッチを見てみると
+ switch (authcmds[i].fun(arg)) { + case 0: + seenauth = 1; + protocol = "ESMTPA"; + relayclient = ""; + remoteinfo = user.s; + if (!env_unset("TCPREMOTEINFO")) die_read(); + if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem(); + if (!env_put2("RELAYCLIENT",relayclient)) die_nomem(); + out("235 ok, go ahead (#2.0.0)\r\n"); + break; + case 1: + err_authfail(user.s,authcmds[i].text); + }
としっかりRELAYCLIENTを設定しています。
ということでqmail-smtpd-auth-0.5.10を適用すればいいのですが、当然qmail-1.03-jms1-7.10.patchと競合してしまいますので、ここはqmail-smtpd.cを手で編集することにします。
switch (authcmds[i].fun(arg)) { case 0: authd = 1; relayclient = ""; auth_fixenv(); readenv(); remoteinfo = user.s; if (!env_unset("TCPREMOTEINFO")) die_read(); if (!env_put2("TCPREMOTEINFO",remoteinfo)) die_nomem(); if (!env_unset("SMTP_AUTH_USER")) die_read(); if (!env_put2("SMTP_AUTH_USER",remoteinfo)) die_nomem(); if (!env_put2("RELAYCLIENT",relayclient)) die_nomem(); out("235 ok, go ahead (#2.0.0)\r\n"); break; case 1: out("535 authorization failed (#5.7.0)\r\n"); }
再度make setup check をしてインストールしましょう。これでSMTP認証を通った場合には左のルートを通ることになりますので不要なチェックは飛ばしてメールをqmail-queue経由で外部に送信することになります。
(参考にさせて頂いたサイト)
DKIM and DomainKeys patch for qmail | Brandon's Blog
記事はここまで。