IIJ
システム技術部
小林直
2005年10月
1. はじめに
2. インストール
2.1. 使用プログラム
(a) sendmail
(b) milter
2.2. 必要環境
2.3. sendmailのコンパイル
2.4. sid-milterのコンパイル
2.5. dk-milterのコンパイル
2.6. dkim-milterのコンパイル
3. 設定
3.1. sendmail
3.2. sid-milter
3.3. dk-milter
3.4. dkim-milter
4. まとめ
1. はじめに
本稿は、MTAプログラム「sendmail」を用いて、送信ドメイン認証技術である「SPF」「Sender ID」「DomainKeys」「DKIM」を利用する方法について説明します。
今回使用するプログラムは、milterサーバとして実装されています。一般的なsendmailの使い方では使う機会が無いと思われるため、概要を以下に説明します。
Milter とは、「Mail Filter」の略称です。これはsendmail機能拡張のための実装で、APIとして提供されています。この機能を用いるとsendmailのソースコードに手を加えず、外部プログラムによって処理を追加することができます。あらゆることに対応できるわけではありませんが、このような分離された実装は保守性向上に役立ちます。
sendmailとmilterの関係は以下の図のようになります。
図1 sendmailとmilterの関係
2. インストール
本稿では、すでにMTAとしてsendmailが導入済みであるという前提で話を進めます。要求バージョンを満たしている場合、sendmail自体の再コンパイルは必要ありません。ですが、多くの環境ではmilterプログラムのコンパイルに必要となるmilterライブラリは用意されていないため、ソースコードからコンパイルする必要があります。
2.1. 使用プログラム
(a) sendmail
MTAプログラムです。MTA、milterクライアントとして動作します。バージョン8.13.0よりmilterの機能が標準で組み込まれるようになりました。
以下のコマンドによりコンパイルオプションが確認できます。 「MILTER」の記述があれば組み込まれています。
$ /usr/sbin/sendmail -d0 < /dev/null Version 8.13.4 Compiled with: DNSMAP LOG MATCHGECOS MILTER MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETUNIX NEWDB PIPELINING SCANF USERDB XDEBUG |
(b) milter
先述したとおり、sendmailのMilter APIを用いた外部プログラムです。このプログラムはmilterサーバとして動作します。milterクライアント(sendmail)との通信は、 UNIXドメインソケットまたはTCPを利用することができます。スレッドに依存しているため、一部のOSでは動きません(動作確認済みのOSについては後述します)。
今回解説する実装の一覧は以下の通りです。
表1 milterプログラム一覧
プログラム名 | 利用可能な機能 | 最新バージョン | 使用バージョン |
sid-milter | SenderID、SPF | 0.2.9 | 0.2.9 |
dk-milter | DomainKeys | 0.3.0 | 0.3.0 |
dkim-milter |
DKIM
|
0.1.1 | 0.1.1 |
2.2. 必要環境
milterサーバは、スレッドを使用しています。そのため、スレッドの使えないOSではsendmailとmilterサーバを同一ホストで実行させることができません。milterサーバのみスレッド使用可能なホストに分離すれば、問題なく使用できます。
基本的なOSの制約は上記の通りとなります。参考までに、私が動作確認をしている環境を以下に示します。本稿の例ではSolaris 9環境にて構築、設定をしています。
- FreeBSD 4系(一部動作不安定)
- Solaris 8 以降
- Linux Kernel 2.4 以降
2.3. sendmailのコンパイル
今回のmilterプログラムに必要とされるバージョンは、sendmail8.13.0.Beta3以降です。特に理由がなければ、本稿執筆時点での最新版である8.13.4の使用をお勧めします。
sendmailに関しては、MTAプログラムであるsendmail本体と、milterプログラム用のライブラリである「libmilter」をコンパイルします。使用しているsendmailが要求バージョンを満たしている場合は、libmilterのみのコンパイルで問題ありません。
以下のコマンドの実行によりmilterライブラリ(libmilter)が作成されます。
$ cd /tmp $ gzip -dc sendmail.8.13.4.tar.gz | tar -xf - $ cd sendmail-8.13.4/libmilter/ $ ./Build |
これにより、以下のファイルが生成されていれば成功です(注:Solaris9での場合)
/tmp/sendmail-8.13.4/obj.SunOS.5.9.sun4/libmilter/libmilter.a
必要な場合はsendmail本体もコンパイルします。
$ cd /tmp/sendmail-8.13.4/ $ ./Build |
各milterプログラムのコンパイルに必要となるパスは以下の通りです。
- milterライブラリパス
/tmp/sendmail-8.13.4/obj.SunOS.5.9.sun4/libmilter - includeパス
/tmp/sendmail-8.13.4/include
2.4. sid-milterのコンパイル
最新版は0.2.9です。このプログラムはまだバージョンアップが頻繁にされています。古いバージョンは致命的なバグが多くあるため、最新版の使用をお勧めします。
ソースコードを展開します。
$ cd /tmp $ gzip -dc sid-milter-0.2.9.tar.gz | tar -xf - |
先ほど作成したlibmilterを参照するように編集します。
##ファイル編集 sid-filter/Makefile.m4 (-行削除 +行追加) - dnl APPENDDEF(`confINCDIRS', `-I/usr/local/sendmail/include') - dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/sendmail/lib') + APPENDDEF(`confINCDIRS', `-I/tmp/sendmail-8.13.4/include') + APPENDDEF(`confLIBDIRS', `-L/tmp/sendmail-8.13.4/obj.SunOS.5.9.sun4/libmilter') |
コンパイルします。
$ ./Build |
これにより以下のファイルが生成されていれば成功です。
/tmp/sid-milter-0.2.9/obj.SunOS.5.9.sun4/sid-filter/sid-filter
問題がなければインストールします。
$ ./Build install |
非同期リゾルバに関係したエラーが発生する場合は以下を書き換えて再度Buildします。
##ファイル libar/Makefile.m4 (-行削除 +行追加) - dnl APPENDDEF(`confENVDEF', `-DNONSTANDARD_RES_STRUCTURE') + APPENDDEF(`confENVDEF', `-DNONSTANDARD_RES_STRUCTURE') |
2.5. dk-milterのコンパイル
DomainKeysはIIMと統合されDKIMになりました。共に電子署名型の送信ドメイン認証技術であり、これらを統合したDKIMには DomainKeysの特徴が多く引き継がれています。DKIMはリリースされて間もない事もあり、現状ではDomainKeysの方が多く使用されているため、これについても説明します。こちらはsid-milterと異なり、署名を検証するためOpenSSLが必要になります。OpenSSLのインストールされている場所はOSによって異なりますので、適宜読み替えてください。
ソースコードを展開します。
$ cd /tmp $ gzip -dc dk-milter-0.3.0.tar.gz | tar -xf - |
sid-milter同様にlibmilterを使用するためMakefile.m4を編集します。
##ファイル編集 dk-filter/Makefile.m4 (-行削除 +行追加) #milterライブラリパスを設定します。 - dnl APPENDDEF(`confINCDIRS', `-I/usr/local/sendmail/include') - dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/sendmail/lib') + APPENDDEF(`confINCDIRS', `-I/tmp/sendmail-8.13.4/include') + APPENDDEF(`confLIBDIRS', `-L/tmp/sendmail-8.13.4/obj.SunOS.5.9.sun4/libmilter') #非同期リゾルバを有効にします。 - dnl bldPUSH_SMLIB(`ar') + bldPUSH_SMLIB(`ar') #OpenSSLのパスを指定します。 - dnl APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ') - dnl APPENDDEF(`confLIBDIRS', `-L/usr/local/ssl/lib ') + APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ') + APPENDDEF(`confLIBDIRS', `-L/usr/local/ssl/lib ') ##ファイル編集 libdk/Makefile.m4 #非同期リゾルバを有効にします。 - dnl bldPUSH_SMLIB(`ar') - dnl APPENDDEF(`confENVDEF', `-DUSE_ARLIB ') - dnl APPENDDEF(`confINCDIRS', `-I../libar/ ') + bldPUSH_SMLIB(`ar') + APPENDDEF(`confENVDEF', `-DUSE_ARLIB ') + APPENDDEF(`confINCDIRS', `-I../libar/ ') #OpenSSLのパスを指定します。 - dnl APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ') + APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ') |
コンパイルします。
$ ./Build |
これにより以下のファイルが生成されていれば成功です。
/tmp/dk-milter-0.3.0/obj.SunOS.5.9.sun4/dk-filter/dk-filter
問題がなければインストールします。
$ ./Build install |
2.6. dkim-milterのコンパイル
DKIMの実装です。多くの部分はdk-milterを元としているためコンパイルにおける設定はほぼ同じになります。dk-milterの手順から以下の部分を読み替えてください。
dk-milter-0.3.0 ⇒ dkim-milter-0.1.1
dk-filter ⇒ dkim-filter
libdk ⇒ libdkim
非同期リゾルバに関係したエラーが発生する場合は以下を書き換えます。
##ファイル libar/Makefile.m4 (-行削除 +行追加) - dnl APPENDDEF(`confENVDEF', `-DNONSTANDARD_RES_STRUCTURE') + APPENDDEF(`confENVDEF', `-DNONSTANDARD_RES_STRUCTURE') |
3. 設定
3.1. sendmail
sendmailのm4マクロ定義INPUT_MAIL_FILTERを用いて、milterサーバと通信する方法を指定します。詳細はsendmail付属のcf/READMEに記述があります。
milterの動作不良、異常終了によるバウンスメールの発生を避けるため、問題発生時に一時的エラー(4xx)を返す設定を推奨します。 複数のmilterを使用する場合は、INPUT_MAIL_FILTERを複数記述します。
milterのアドレス指定の書式は以下のようになります。
- TCPの場合
inet:port@address - UNIXドメインソケットの場合
unix:/socket_path
例) INPUT_MAIL_FILTER(`filter1′, `S=inet:10000@127.0.0.1, F=T, T=R:1m’)dnl
この例では以下の通りの設定になります
表2 INPUT_MAIL_FILTER引数一覧
例の値 | 説明 |
filter1 | フィルタ識別名称。任意の文字列が使用可能 |
S=inet:10000@127.0.0.1 | milterサーバ指定。このアドレスに接続 |
F=T | milter接続失敗時の動作。R(5xxエラー)、T(4xxエラー)が指定可能 |
T=R:1m | milterの読み込みタイムアウト値。未指定時は10秒なため延長 |
3.2. sid-milter
このプログラムによって提供されるのは「Sender ID」「SPF」に基づいて送信者のメールアドレスを検証する部分のみです。インストールされたプログラム名は「sid-filter」となります。現状では、検証結果に基づいた受信拒否はトラブルの原因となる可能性があります。そのため、受信拒否はせずに結果をヘッダに追加する設定をお勧めします。
例) sid-filter -l -p inet:10000@127.0.0.1 -t -T 10 -A
表3 sid-filterコマンドラインオプション一覧
例の値 | 説明 |
-p inet:10000@127.0.0.1 | milterアドレスの指定。このアドレスで接続を受け付ける |
-l | syslog経由でログを記録 |
-t | ヘッダに検証結果を追加するのみの動作となる |
-T 10 | SPFレコード検証の際に発生するDNS問い合わせの待ち時間を制限 |
-A | milterプロセスが異常終了した場合自動起動 |
3.3. dk-milter
このプログラムは「DomainKeys」の署名と検証両方の機能を提供します。インストールされたプログラム名は「dk-filter」となります。今回の説明で使用するコマンドラインオプションは以下の通りです。
表4 dk-filterコマンドラインオプション一覧
例の値 | 説明 |
-p inet:10001@127.0.0.1 | milterアドレスの指定。このアドレスで接続を受け付ける |
-l | syslog経由でログを記録 |
-c nofws | 署名時における本文の正規化方法を指定 |
-b s | 署名のみの動作 |
-b v | 検証のみの動作 |
-i /tmp/hostlist | 署名対象とするクライアントのIPアドレスを指定(未指定時は127.0.0.1のみ) |
-T 10 | DNS問い合わせの待ち時間を制限 |
-s /tmp/keypath | 署名時に使用する秘密鍵のファイルを指定 |
-d example.com | 署名対象とするFromヘッダのドメインを指定 |
-S key1 | 署名時に使用するセレクタを指定 |
-H | 署名対象としたヘッダの一覧を明示的に記述 |
-A | milterプロセスが異常終了した場合自動起動 |
(a) 署名
dk-filterの設定の他にDNSのゾーンへ公開鍵を登録する作業が必要になります。署名対象となるのは以下の条件を共に満たす場合です。
- Fromヘッダのメールアドレスが -d オプションで指定するドメイン
- MTAに接続したアクセス元IPが -i オプションに指定されたファイルに記述されている
DNSに登録の必要があるものは以下の2つです。
- _domainkey.ドメイン名 ドメイン全体のポリシーを記述
- <key1>._domainkey.ドメイン名 検証に使用される公開鍵を記述
鍵は付属するツール gentxt.csh で生成することができます。 生成と同時にDNSのゾーンに記述するレコードも出力されます。
$ cd /tmp/dk-milter-0.3.0/dk-filter $ ./gentxt.csh <key1> example.com <key1>._domainkey IN TXT "g=; k=rsa; t=y; p=MFwwDQYJKoZIhvcN..." ; …… DomainKey <key1> for example.com |
ゾーンに登録、レコードが参照可能であることを確認します。
$ dig <key1>._domainkey.example.com. txt <key1>._domainkey.example.com 1H IN TXT "g=; k=rsa; t=y; pMFwwDQYJKoZIhvcN..." |
_domainkey.example.com. のレコードを記述していない場合はこれも追加します。
$ dig _domainkey.example.com. txt _domainkey.example.com. 1H IN TXT "t=y; o=~" |
上記スクリプトの実行により同一ディレクトリに鍵が生成されます。 生成された秘密鍵 key1.private が -s オプションの引数で指定するファイルです。
$ ls <key1>.p* <key1>.private <key1>.public |
例) dk-filter -l -p inet:10001@127.0.0.1 -c nofws -b s -s /path/key -i /path/hostlist -d example.com -S <key1> -H -A
署名は、以下のようなヘッダとして追加されます。
DomainKey-Signature: a=rsa-sha1; s=<key1>; d=example.com; c=nofws; q=dns; h=to:from:subject; b=SNJf5……..==
(b) 検証
検証のみの場合はDNSレコードの登録、鍵の生成は必要ありません。 標準設定で検証結果によるバウンスメールは発生しません。
例) dk-filter -l -p inet:10002@127.0.0.1 -A -T 10 -b v
検証結果は以下の様なヘッダとして追加されます。
Authentication-Results: mx.example.com; domainkeys=pass
3.4. dkim-milter
このプログラムは「DKIM」の署名と検証両方の機能を提供します。 インストールされたプログラム名は「dkim-filter」となります。
大半のコマンドラインオプションはdk-filterと同じですが、以下の点が変更されています。
- -c オプションで使用可能な値が変更された
- -H オプションが標準で有効になった(DKIMの仕様)
(a) 署名
DomainKeys同様にDNSへのレコード登録、鍵の生成が必要です。 互換性があるためDomainKeys用に生成したレコード、鍵をそのまま使えます。
例) dkim-filter -l -p inet:10003@127.0.0.1 -c nowsp -b s -s /path/key -i /path/hostlist -d example.com -S key1 -A
署名結果は以下のようなヘッダとして追加されます。
DKIM-Signature: a=rsa-sha1; c=nowsp; d=example.com; s=key1; t=1123140900; h=To:From; b=YwFxKqMur……==
(b) 検証
検証のみの場合はDNSレコードの登録、鍵の生成は必要ありません。 標準設定で検証結果によるバウンスメールは発生しません。
例)dkim-filter -l -p inet:10004@127.0.0.1 -A -T 10 -b v
検証結果は以下のようなヘッダとして追加されます。
Authentication-Results: mx.example.com header.From=sender@example.com; dkim=pass
4. まとめ
sendmailに関してはmilterという外部拡張のための機能があるため、比較的容易に実装を利用することができます。milterを用いた送信ドメイン認証の実装を問わず、多くの実装は発展途上であり、バグや不安定な点が存在します。
現状で恒久的エラーを返すのは、ソフトウェアの安定性、実装の普及の点からリスクが高い行為となります。そのため、バウンスメールを発生させず、ヘッダに Authentication-Resultsとして結果を挿入する設定をお勧めします。この設定の場合、送信ドメインの偽装されたメールを受け取ってしまいますが、ヘッダを見て検証結果を判断することができます。