Postfix SMTP アクセスポリシー委任


Postfix SMTP アクセスポリシー委任の目的

Postfix SMTP サーバは、特定の SMTP プロトコルの段階で、メールをブロッ クまたは受け入れるための多くの組み込みの仕組みを持つ。バージョン 2.1 から、Postfix は Postfix の外側で実行している外部サーバにポリシー判定 を委任できるようになった。

このポリシー判定の仕組みは、単純な greylist ポリシーなら、1ダース行程度の Perl で実装できる。他のポリシー委任の例 は、http://spf.pobox.com/ の Meng Wong による SPF ポリシーサーバである。両方のポリシーの例は、Postfix の ソースコード中のディレクトリ examples/smtpd-policy に見つけられる。

ポリシー委任は現在、Postfix にポリシーを追加する好ましい方法である。 数行の Perl で新しい機能を、C コードで同じことを試みるよりもとても簡単 に開発できる。性能の違いは、もっとも厳しい環境を除けば、無視される。

このドキュメントは次の話題をカバーする:

プロトコル解説

Postfix ポリシー委任プロトコルは本当に簡単である。クライアント要求 は改行で区切られた name=value 属性のリストで、空行で終了される。サーバ の応答は1つの name=value 属性で、空行で終了される。

これは、Postfix SMTP サーバが 委任されたSMTPD アクセスポリシー要求 で送るすべての属性の例である:

request=smtpd_access_policy
protocol_state=RCPT
protocol_name=SMTP
helo_name=some.domain.tld
queue_id=8045F2AB23
sender=foo@bar.tld
recipient=bar@foo.tld
client_address=1.2.3.4
client_name=another.domain.tld
instance=123.456.7
sasl_method=plain
sasl_username=you
sasl_sender=
size=12345
[empty line]

Notes:

次は SMTPD 委任ポリシー要求の使用である:

ポリシーサーバは Postfix SMTPD access(5) テーブルに許される任意のアクション で応答する。例:

action=defer_if_permit Service temporarily unavailable
[empty line]

これは、Postfix SMTP サーバが要求を永久に拒否する理由を見つけない場 合に、Postfix SMTP サーバが 450 一時エラーコードとテキスト "Service temporarily unavailable" で要求を拒否する。

ポリシーサーバが応答を返さないというトラブルの場合、サーバは警告を ログし、切断する。Postfix はしばらく後で要求を再試行する。

ポリシークライアント/サーバ構成

ポリシークライアントに委任された Postfix は TCP ソケットまたは UNIX ドメインソケットに接続できる。例:

inet:127.0.0.1:9998
unix:/some/where/policy
unix:private/policy

最初の例は、ポリシーサーバが TCP ソケット 127.0.0.1 ポート 9998 で listen することを示す。2番目の例は、UNIX ドメインソケットの絶対パスを 示す。3番目の例は、Postfix キューディレクトリからの相対パスを示す; Postfix master デーモンから起動されるポリシーサーバにはこれを使用する。

UNIX ドメインソケットで listen する "policy" という名前のポリシーサー ビスを生成し、Postfix spawn(8) デーモンの制 御下でそれを実行するには、次のようなものを使用する:

 1 /etc/postfix/master.cf:
 2     policy  unix  -       n       n       -       -       spawn
 3       user=nobody argv=/some/where/policy-server
 4 
 5 /etc/postfix/main.cf:
 6     smtpd_recipient_restrictions =
 7         ... 
 8         reject_unauth_destination 
 9         check_policy_service unix:private/policy 
10         ...
11     policy_time_limit = 3600

NOTES:

 1 /etc/postfix/master.cf:
 2     127.0.0.1:9998  inet  -       n       n       -       -       spawn
 3       user=nobody argv=/some/where/policy-server
 4 
 5 /etc/postfix/main.cf:
 6     smtpd_recipient_restrictions =
 7         ... 
 8         reject_unauth_destination 
 9         check_policy_service inet:127.0.0.1:9998
10         ...
11     127.0.0.1:9998_time_limit = 3600

ポリシー委任プロトコルのクライアント側を制御する他の構成パラメータ:

例: グレイリストポリシーサーバ

グレイリストは、http://www.greylisting.org/ で述べられているゴミメールの防衛策である。アイデアは postfix-users メー リングリストで、 それが普及する一年前に議論された。

Postfix ソースツリー内のファイル examples/smtpd-policy/greylist.pl は簡単なグレイリストポリシーサーバを実装している。このサーバはすべての (client, sender, recipient) triple について、時刻を格納する。デフォル トでは、時刻が 60秒以上古くなるまで受け付けられない。これは、ランダム に選択された送信者アドレスのゴミメールと、ランダムに選択されたオープン プロキシーを通ったメールを停止する。これは IP アドレスを頻繁に変更する スパマーからのゴミメールも停止する。

examples/smtpd-policy/greylist.pl を /usr/libexec/postfix またはあ なたのシステムに適切な場所にコピーする。

greylist.pl Perl スクリプト中に、グレイリストデータベースファイルの 場所と、受け付けられるまでの遅延時間を指定する必要がある。デフォルト設 定は:

$database_name="/var/mta/greylist.db";
$greylist_delay=60;

/var/mta ディレクトリ(またはあなたの選んだ場所)は "nobody" またはポ リシーサービス用に master.cf に設定したユーザ名で書き込めるようにすべ きである。

例:

# mkdir /var/mta
# chown nobody /var/mta

Note: グレイリストデータベースは、/tmp や /var/tmp のような全員に書 き込み可能なディレクトリに生成してはいけない。そして、空き領域が無くな りそうなファイルシステムにグレイリストデータベースを生成してはいけない。 Postfix はメールキューとメールボックス格納では、"領域不足" 状態で生き られるが、壊れたグレイリストデータベースは生きられない。ファイが壊れる と、あなたが手でファイルを削除するまでメールが受信できなくなる。

greylist.pl Perl スクリプトは Postfix master デーモンの制御下で実行 できる。たとえば、"nobody" ユーザで、Postfix プロセスだけにアクセスで きる UNIX ドメインソケットを使用してスクリプトを実行するには:

1 /etc/postfix/master.cf:
2     policy  unix  -       n       n       -       -       spawn
3       user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
4 
5 /etc/postfix/main.cf:
6      policy_time_limit = 3600

Notes:

上述の "Policy client/server configuration" 節で説明したように、Solaris では unix: スタイルの代 わりに inet: スタイルソケットを使用する必要がある。

1 /etc/postfix/master.cf:
2     127.0.0.1:9998  inet  -       n       n       -       -       spawn
3       user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
4 
5 /etc/postfix/main.cf:
6      127.0.0.1:9998_time_limit = 3600

このサービスを呼び出すには、 "check_policy_service inet:127.0.0.1:9998" を指定する。

頻繁に偽造されるドメインからのメールのグレイリスト

頻繁に偽造メールが現れる特定のドメインに対してグレイリストを有効に するのは、比較的安全である。頻繁に偽造される MAIL FROM ドメインのリス トは http://www.monkeys.com/anti-spam/filtering/sender-domain-validate.in で見つけられる。

 1 /etc/postfix/main.cf:
 2     smtpd_recipient_restrictions =
 3         reject_unlisted_recipient
 4         ...
 5         reject_unauth_destination 
 6         check_sender_access hash:/etc/postfix/sender_access
 7         ...
 8     restriction_classes = greylist
 9     greylist = check_policy_service unix:private/policy
10 
11 /etc/postfix/sender_access:
12     aol.com     greylist
13     hotmail.com greylist
14     bigfoot.com greylist
15     ... etcetera ...

NOTES:

すべてのメールのグレイリスト

すべてのメールについてグレイリストを有効にする場合、ワンタイム送信 者アドレスを使用するメーリングリストを例外にしたいだろう。そのようなメー リングリストは比較的すぐにあなたのグレイリストデータベースを汚染するか らである。

 1 /etc/postfix/main.cf:
 2     smtpd_recipient_restrictions =
 3         reject_unlisted_recipient
 4         ...
 5         reject_unauth_destination 
 6         check_sender_access hash:/etc/postfix/sender_access
 7         check_policy_service unix:private/policy
 8         ...
 9 
10 /etc/postfix/sender_access:
11     securityfocus.com OK
12     ...

NOTES:

グレイリスト保守ルーチン

グレイリストデータベースは時間が経つと大きくなる。グレイリストサー バはデータベースエントリを削除しないからである。注意しないと、グレイリ ストデータベースは最終的にあなたのファイルシステムの空き領域を使いきる。

状態ファイルサイズがある閾値を超えた時、悪影響なしに単純にファイル をリネームまたは削除できる; Postfix は自動的に新しいファイルを生成する。 最悪の場合、新しいメールが1時間以上遅延する。影響を小さくするには、週 末の始まりの夜中にファイルをリネームまたは削除する。

Perl グレイリストサーバの例

これは、グレイリストポリシーの実装例 Perl サブルーチンである。 examples/smtpd-policy/greylist.pl として Postfix ソースとともに配布さ れる一般的な目的のサンプルポリシーサーバの一部である。

#
# greylist status database and greylist time interval. DO NOT create the
# greylist status database in a world-writable directory such as /tmp
# or /var/tmp. DO NOT create the greylist database in a file system
# that can run out of space.
#
$database_name="/var/mta/greylist.db";
$greylist_delay=60;

#
# Demo SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# table.  Request attributes are available via the %attr hash.
#
sub smtpd_access_policy {
    my($key, $time_stamp, $now);

    # Open the database on the fly.
    open_database() unless $database_obj;

    # Lookup the time stamp for this client/sender/recipient.
    $key =
        lc $attr{"client_address"}."/".$attr{"sender"}."/".$attr{"recipient"};
    $time_stamp = read_database($key);
    $now = time();

    # If new request, add this client/sender/recipient to the database.
    if ($time_stamp == 0) {
        $time_stamp = $now;
        update_database($key, $time_stamp);
    }

    # The result can be any action that is allowed in a Postfix access(5) map.
    #
    # To label the mail, return ``PREPEND headername: headertext''
    #
    # In case of success, return ``DUNNO'' instead of ``OK'', so that the
    # check_policy_service restriction can be followed by other restrictions.
    #
    # In case of failure, return ``DEFER_IF_PERMIT optional text...'',
    # so that mail can still be blocked by other access restrictions.
    #
    syslog $syslog_priority, "request age %d", $now - $time_stamp if $verbose;
    if ($now - $time_stamp > $greylist_delay) {
        return "dunno";
    } else {
        return "defer_if_permit Service temporarily unavailable";
    }
}