このドキュメントは Postfix バージョン 2.1 以降を要求します。
通常、Postfix はメールを受け取り、それをメールキューに入れてから 配送します。ここで述べる外部コンテンツフィルタを使うと、メールはキューに 入った「後で」フィルタリングされます。このアプローチはメールフィルタリング プロセスからメール受信プロセスを切り離し、並列に走らせるフィルタリング プロセスの数を最大限にします。
キューに入った後のコンテンツフィルタは次のように使われることを意図して います:
ネットワーク
または
ローカルユーザ-> Postfix
キュー-> コンテンツ
フィルタ-> Postfix
キュー-> ネットワークまたは
ローカルメールボックス
このドキュメントは一つの Postfix インスタンスを以下の全てに使っている 実装を記述しています: メールの受信やフィルタリング、配送。2つの別々の Postfix インスタンスを使う応用はこのドキュメントの後のバージョンでカバー される予定です。
キューに入った後のコンテンツフィルタと、入ってくる SMTP メールが Postfix キューに入れられる「前に」フィルタリングされる SMTPD_PROXY_README ドキュメントに 記述されたアプローチを混同しないでください。
このドキュメントは全てのEメールをフィルタリングする2つのアプローチと、 選択的にメールをフィルタリングするいくつかのオプションを記述しています:
外部コンテンツフィルタは Postfix からフィルタリングされていないメールを 受け取り (ずっと下に記述されています)、以下のいずれかをおこないます:
Postfix にメールを差し戻します。これはコンテンツや配送先を変更した 後かもしれません。
(Postfix に適切な状態コードを送り返すことで) メールを拒否します。 Postfix はメールを送信者に返します。
注意: メールワームや詐称された spam が多い中、送信者アドレスがほとんどの場合は 元々のものではないため、送信者アドレスにウィルスを送り返すのは「とても悪い 考え」です。既知のウィルスは破棄し、疑わしいものは人が処理を決められるように 検疫するほうがよいでしょう。
最初の例は構築が単純です。Postfix はネットワークから smtpd(8) サーバでフィルタリングされていない メールを受け取り、フィルタを Postfix pipe(8) 配送エージェントでコンテンツフィルタに配送します。コンテンツフィルタは フィルタリングされたメールを Postfix に Postfix sendmail(1) コマンドで差し挟み、Postfix が 最終的な配送先に配送できるようにします。
これは Postfix sendmail(1) コマンドを 使って投函されたメールはコンテンツフィルタリングできないことを意味します。
以下の図で、数字が続く名前は Postfix コマンドまたはデーモンプログラムを 表しています。Postfix アーキテクチャの概要は OVERVIEW ドキュメントを参照してください。
フィルタ
リング前
->
smtpd(8)
pickup(8)>- cleanup(8) -> qmgr(8)
Postfix
キュー-< local(8)
smtp(8)
pipe(8)->
->
フィルタ後
フィルタ後
^
||
vmaildrop
キュー<- Postfix
postdrop(1)<- Postfix
sendmail(1)<- コンテンツ
フィルタ
コンテンツフィルタは以下のような簡単なシェルスクリプトでも構いません:
1 #!/bin/sh 2 3 # Simple shell-based filter. It is meant to be invoked as follows: 4 # /path/to/script -f sender recipients... 5 6 # Localize these. 7 INSPECT_DIR=/var/spool/filter 8 SENDMAIL="/usr/sbin/sendmail -i" 9 10 # Exit codes from <sysexits.h> 11 EX_TEMPFAIL=75 12 EX_UNAVAILABLE=69 13 14 # Clean up when done or when aborting. 15 trap "rm -f in.$$" 0 1 2 3 15 16 17 # Start processing. 18 cd $INSPECT_DIR || { 19 echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } 20 21 cat >in.$$ || { 22 echo Cannot save mail to file; exit $EX_TEMPFAIL; } 23 24 # Specify your content filter here. 25 # filter <in.$$ || { 26 # echo Message content rejected; exit $EX_UNAVAILABLE; } 27 28 $SENDMAIL "$@" <in.$$ 29 30 exit $?
解説:
21行目: まずメッセージをファイルにキャプチャし、コンテンツを サードパーティコンテンツフィルタプログラムに通すという考え方です。
22行目: メールをファイルにキャプチャできない場合は、終了ステータス 75 (EX_TEMPFAIL) で終了してメール配送を遅延させます。Postfix はメッセージを deferred メールキューに置き、後で再び試行します。
25行目: ここに実際に標準入力でコンテンツを受け取るコンテンツフィルタ プログラムプログラムを指定する必要があります。
26行目: コンテンツフィルタプログラムが問題を見つけた場合、終了 ステータス 69 (EX_UNAVAILABLE) で終了することでメールをバウンスさせます。 Postfix はメッセージを配送できないとして送信者に返します。
注意: メールワームや spam が多い中、送信者アドレスが詐称されて いるかもしれないため、送信者アドレスに既知のウィルスや spam を送り返すのは 「とても悪い考え」です。悪いことが既知のコンテンツは破棄し、疑わしい コンテンツは人が検査できるように検疫するのが安全です。
28行目: コンテンツに問題がない場合には Postfix sendmail コマンドへの 入力として与えられ、フィルタコマンドの終了ステータスは Postfix sendmail コマンドが生成する終了ステータスとなります。
30行目: Postfix は Postfix sendmail コマンドの終了ステータスを 返します。
結果に満足するまで、まずはしばらくこのスクリプトを手で動かすことを 推奨します。実際のメッセージ (ヘッダ+本体) を入力として走らせます:
% /path/to/script -f sender recipient... <message-file
コンテンツフィルタスクリプトに満足したら:
"filter" という専用のローカルユーザアカウントを作ります。このユーザは 潜在的に危険な全てのメールのコンテンツを扱います - これが別のアカウントに すべき理由です。"nobody"、ましてや "root" や "postfix" を使っては いけません。
"filter" ユーザだけがアクセスできる /var/spool/filter ディレクトリを 作成します。これはコンテンツフィルタリングスクリプトがテンポラリファイルを 置くことが想定された場所です。
Postfix が pipe(8) 配送エージェントで コンテンツフィルタにメールを配送するように設定します。
/etc/postfix/master.cf: # ============================================================= # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ============================================================= filter unix - n n - 10 pipe flags=Rq user=filter argv=/path/to/script -f ${sender} -- ${recipient}
これは同時に最大 10 までのコンテンツフィルタを動かします。10 という並列 プロセス数制限の代わりに、あなたのマシンに適したプロセス制限数を使って ください。コンテンツ検査ソフトウェアはシステムリソースをむさぼり食うかも しれないため、同時に膨大な数は走らせない方がよいでしょう。
SMTP で到達したメールのみにコンテンツフィルタを使うには、Postfix SMTP サーバを定義している master.cf エントリに "-o content_filter=filter:dummy" を加えます:
/etc/postfix/master.cf: # ============================================================= # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ============================================================= smtp inet ...other stuff here, do not change... smtpd -o content_filter=filter:dummy
"content_filter" 行は 入ってくるメールメッセージそれぞれに "filter:dummy" というコンテンツフィルタを 要求するレコードを Postfix に加えさせます。このレコードは通常のメール ルーティングを上書きし、メールをコンテンツフィルタに与えるようにします。
content_filter 設定 パラメータは Postfix transport テーブルの右側部分と同様な文法を 受け付けます。
変更を完了するために "postfix reload" を実行してください。
コンテンツフィルタリングを無効にするには、master.cf ファイルを編集し、 "-o content_filter=filter:dummy" テキストを Postfix SMTP サーバを定義したエントリから取り除き、もう一度 "postfix reload" を実行します。
上に示したようなシェルスクリプトで、SMTP で到着してから出て行くまでの 通過にかかる Postfix のパフォーマンスが4倍ほど落ちます。コンテンツ フィルタリングのプロセスでさらにテンポラリファイルを作成したり削除したり するたびごとに、さらに通過のパフォーマンスが悪くなるでしょう。ローカルで 投函されたり、ローカルに配送されるメールはすでに SMTP で通過するメール よりも遅いため、パフォーマンスの影響は少ないです。
上のようなコンテンツフィルタの問題は、あまり堅牢ではないということです。 それは、ソフトウェアがしっかり定義されたプロトコルで Postfix と話をしない ためです。シェルがなんらかのメモリアロケーション問題でフィルタシェル スクリプトが止まった場合、スクリプトは /usr/include/sysexits.h にあるような 正しい終了ステータスを生成しません。メールは deferred キューに行くのでは なく、バウンスされます。同様にコンテンツフィルタ自身がリソース問題に当たった 場合も堅牢性がなくなる可能性があります。
単純なコンテンツフィルタの方式は header_checks や body_checks パターンで 呼び出されるコンテンツフィルタアクションに対しては適切ではありません。 これらのパターンは Postfix sendmail コマンドでメールが差し挟まれる際に 再び適用され、その結果メールフィルタリングループに入ってしまいます。 高度なコンテンツフィルタリングの手法 (以下参照) では、フィルタリング されたメールに対して header_checks や body_checks パターンを無効に することが可能となります。
2つ目の例はかなり複雑ですが、よいパフォーマンスを出し、マシンがリソース 問題に当たったときもメールをバウンスする可能性が低くなります。この コンテンツフィルタはフィルタリングされていないメールを localhost ポート 10025 で SMTP を使って受け取り、フィルタリングされたメールを localhost ポート 10026 で SMTP を使って Postfix に差し戻します。
SMTP が使えないコンテンツフィルタソフトウェアに対しては、Bennett Todd の SMTP プロキシがよい PERL/SMTP コンテンツフィルタリングフレームワークを実装して います。参照: http://bent.latency.net/smtpprox/。
以下の図で、数字が続く名前は Postfix コマンドまたはデーモンプログラムを 表しています。Postfix アーキテクチャの概要は OVERVIEW ドキュメントを参照してください。
フィルタリング前
フィルタリング前->
->smtpd(8)
pickup(8)>- cleanup(8) -> qmgr(8)
Postfix
キュー-< smtp(8)
local(8)->
->フィルタ後
フィルタ後^
||
vsmtpd(8)
10026smtp(8)
^
||
vコンテンツフィルタ 10025
ここで上げる例では、SMTP で到達したメールや Postfix sendmail コマンドを 使ってローカルで投かんされたメールを含めて、全てのメールをフィルタリング します。ローカルユーザをフィルタリングから除外する方法や、配送先に依存する コンテンツフィルタの設定方法は、このドキュメントの最後の方にある例を 参照してください。
テンポラリファイルを作らないのであれば、SMTP で到着してから出て行く までの通過にかかる Postfix のパフォーマンスが2倍ほど落ちることが想定 されます。テンポラリファイルを作るごとに数倍パフォーマンスが失われます。
全てのメールに対して高度なコンテンツフィルタ方式を有効にするには、 次のように main.cf に指定します:
/etc/postfix/main.cf: content_filter = scan:localhost:10025 receive_override_options = no_address_mappings
"content_filter" 行は 入ってくるメールメッセージそれぞれに "scan:localhost:10025" という コンテンツフィルタを要求するレコードを Postfix に加えさせます。コンテンツ フィルタ要求レコードは smtpd(8) および pickup(8) サーバ (と、サービスを有効にしている 場合は qmqpd(8) によって加えられます。
コンテンツフィルタリング要求はキューファイルに保管されます; このようにして Postfix はフィルタリングを必要とするメールを管理します。 キューファイルがコンテンツフィルタリング要求を含んでいると、キュー マネージャは最終配送先に関わらず、メールを指定されたコンテンツフィルタに 配送します。
"receive_override_options" 行はコンテンツフィルタリングの前にアドレスを操作できないようにし、 コンテンツフィルタがバーチャルエイリアス展開やカノニカルマッピング、 自動 bcc、アドレスマスカレードなどの結果ではなく、元のメールアドレスを 見られるようにします。
コンテンツフィルタリングを無効にするには、main.cf の上の2行を削除 またはコメントアウトします。高度なコンテンツフィルタリングに対するその他 全ての変更はコンテンツフィルタリングが無効になっている時には効果が ありません。
この例で、"scan" は少し異なる設定パラメータを持つ Postfix SMTP クライアントのインスタンスです。このように Postfix master.cf ファイルで サービスを設定します:
/etc/postfix/master.cf: # ============================================================= # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ============================================================= scan unix - - n - 10 smtp -o smtp_send_xforward_command=yes
これは同時に最大 10 までのコンテンツフィルタを動かします。10 という 並列プロセス数制限の代わりに、あなたのマシンに適したプロセス制限数を使って ください。コンテンツ検査ソフトウェアはシステムリソースをむさぼり食うかも しれないため、同時に膨大な数は走らせない方がよいでしょう。
"-o smtp_send_xforward_command=yes" を付けると、scan transport はフィルタ後の smtpd プロセスに元のクライアント 名や IP アドレスを転送して、フィルタリングされたメールが実際のクライアント 名や IP アドレス付きでログに記録されるようにしようとします。それ以上の 情報は smtp(8) や XFORWARD_README を参照してください。
コンテンツフィルタは Postfix の inetd と同等な Postfix spawn サービスを 使って、設定することができます。例えば、localhost ポート 10025 で待つ、最大 10 のコンテンツフィルタリングプロセスは次のようになります:
/etc/postfix/master.cf: # =================================================================== # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # =================================================================== localhost:10025 inet n n n - 10 spawn user=filter argv=/path/to/filter localhost 10026
"filter" は専用のローカルユーザアカウントです。ユーザはログインせず、 "*" パスワード、存在しないシェルとホームディレクトリが与えられます。 このユーザは全ての潜在的に危険なメールの内容を扱います - これが別の アカウントであるべき理由です。
Postfix のかわりにあなたのフィルタで localhost:10025 ポートを listen したいのであれば、あなたのフィルタをスタンドアロンプログラムとして起動 しなければならず、また Postfix spawn サービスを使ってはいけません。
適切な診断でメールをバウンスするか、ローカルホストの 10026 ポートで 待っている専用のリスナを通してメールを Postfix に返すことがコンテンツ フィルタの仕事です。
最も単純なコンテンツフィルタは、単に入力と出力の間で SMTP コマンドや データをコピーするものです。問題があった場合にやらねばならないのは、 Postfix からの `.' の入力に対して `550 content rejected' と応答し、 Postfix にメールを差し戻す接続で `.' を送らずに切断することだけです。
/etc/postfix/master.cf: # =================================================================== # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # =================================================================== localhost:10026 inet n - n - 10 smtpd -o content_filter= -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks -o smtpd_helo_restrictions= -o smtpd_client_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o mynetworks=127.0.0.0/8 -o smtpd_authorized_xforward_hosts=127.0.0.0/8
注意: "=" や "," 文字の前後に空白を使わないでください。
注意: SMTP サーバは "filter" master.cf エントリのプロセス制限よりも 小さくしてはいけません。
"-o content_filter=" は main.cf の設定を上書きし、コンテンツフィルタからのメールにはコンテンツ フィルタリングを要求しません。これは必須で、そうしないとコンテンツ フィルタリングのループにメールがとどまってしまいます。
"-o receive_override_options" は main.cf の設定を上書きします。これは main.cf で指定されるオプションと 相互補完します:
受信者を知らないかどうか調べようとするのを止め、またヘッダ/本体 チェックを無効にします。この仕事はコンテンツフィルタの前にすでに おこなわれており、繰り返すのは無駄です。
バーチャルエイリアス展開やカノニカルマッピング、アドレス マスカレード、その他のアドレスマッピングを有効にします。
これらの receive override options は SMTP サーバ自身によって実装され、 cleanup サーバに渡されます。
"-o smtpd_xxx_restrictions" および "-o mynetworks=127.0.0.0/8" は main.cf の設定を上書きします。これらはここでの時間を無駄にするだけの ジャンクメール制御を無効にします。
"-o smtpd_authorized_xforward_hosts=127.0.0.0/8" で、 フィルタリングされたメールに実際のクライアント名や IP アドレスを付けて ログに記録できるように、scan transport は元のクライアント名や IP アドレスを フィルタリング後の smtpd プロセスに転送しようとします。 XFORWARD_README や smtpd(8) を参照してください。
ここで述べたコンテンツフィルタリングの "サンドイッチ" アプローチでは、 利用可能な CPU やメモリ、I/O リソースに対してフィルタの並列度がマッチ していることが重要です。コンテンツフィルタリングプロセスが少なすぎると、 流量が少なくても active キュー にメールがたまってしまいます; 並列数が大きすぎると、リソースが不十分で プロセスが落ちてしまい、コンテンツフィルタ宛のメールが遅延することに なってしまいます。
今のところ、コンテンツフィルタのパフォーマンスチューニングは試行錯誤です; フィルタリングされたメッセージとフィルタリングされていないメッセージで 同じキューを共有しているため、分析するには不都合です。このドキュメントの 概要で触れたように、複数の Postfix インスタンスを使ったコンテンツ フィルタリングが将来のバージョンでカバーされます。
最も簡単な方法は、master.cf で複数の SMTP サーバ IP アドレスを使う 「1つの」Postfix インスタンスを設定することです:
内部ユーザからのみのメール用に2つの SMTP サーバ IP アドレスを用意し、 コンテンツフィルタリングを無効にします。
/etc/postfix.master.cf: # ================================================================== # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ================================================================== 1.2.3.4:smtp inet n - n - - smtpd -o smtpd_client_restrictions=permit_mynetworks,reject 127.0.0.1:smtp inet n - n - - smtpd -o smtpd_client_restrictions=permit_mynetworks,reject
外部ユーザからのメール用に1つの SMTP サーバアドレスを用意し、 コンテンツフィルタリングを有効にします。
/etc/postfix.master.cf: # ================================================================= # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ================================================================= 1.2.3.5:smtp inet n - n - - smtpd -o content_filter=foo:bar -o receive_override_options=no_address_mappings
この後は、main.cf ファイルで "content_filter" や "receive_override_options" を指定してはいけないことを除いて、上に概要が示された "高度な" または "単純な" コンテンツフィルタリングの例と同じ手順に従うことができます。
あなたが MX サービスを提供していて、ドメインごとに異なるコンテンツ フィルタを適用したいのであれば、master.cf で複数の SMTP サーバ IP アドレスを持つ「1つの」Postfix インスタンスを設定することができます。 それぞれのアドレスは異なるコンテンツフィルタサービスを提供します。
/etc/postfix.master.cf: # ================================================================= # service type private unpriv chroot wakeup maxproc command # (yes) (yes) (yes) (never) (100) # ================================================================= # SMTP service for domains that are content filtered with foo:bar 1.2.3.4:smtp inet n - n - - smtpd -o content_filter=foo:bar -o receive_override_options=no_address_mappings # SMTP service for domains that are content filtered with xxx:yyy 1.2.3.5:smtp inet n - n - - smtpd -o content_filter=xxx:yyy -o receive_override_options=no_address_mappings
この後は、main.cf ファイルで "content_filter" や "receive_override_options" を指定してはいけないことを除いて、上に概要が示された "高度な" または "単純な" コンテンツフィルタリングの例と同じ手順に従うことができます。
それぞれのドメインを適切な SMTP サーバインスタンスに向けるように、DNS の MX レコードを設定します。
上のフィルタリング設定は静的なものです。決められた道筋に従うと、 メールは常にフィルタリングされるか全くされないかのどちらかです。 Postfix 2.0 では動的にもコンテンツフィルタリングを有効にできるように なりました。
access(5) テーブルのルールでコンテンツフィルタリングを有効にするには:
/etc/postfix/access: whatever FILTER foo:bar
header_checks(5) または body_checks(5) テーブルのパターンで コンテンツフィルタリングを有効にするには:
/etc/postfix/header_checks: /whatever/ FILTER foo:bar
cleanup サーバのヘッダ/本体チェックと同様に、smtpd access マップでも これをおこなうことができます。この機能は細心の注意を払って使わなければ いけません: フィルタリング後の smtpd や cleanup デーモンで全ての UCE 機能を無効にしなければいけません。そうしないとコンテンツフィルタリング ループを起こしてしまいます。
制限:
smtpd access マップや header/body_checks の FILTER アクションは main.cf のcontent_filter パラメータで指定されるフィルタに優先します。
メッセージが2つ以上のフィルタアクションを引き起こす場合は、最後の ものが有効になります。
同じコンテンツフィルタが与えられたメッセージの全ての受信者に 適用されます。