理想未来ってなんやねん

娘可愛い。お父さん頑張る。

postfixで送信元毎の同時送信数を制限する方法

名探偵コナンじゃないですが、


犯人はこの中にいる!』


みたいな事件が社内で起こってしまいました。


今回の犯人はT.M.君。
犯した罪はメールボムを使用したサーバー攻撃です。


どうもプログラムのデバッグでメールを送信するようにしていたようですが、そのプログラムを走らせたまま帰ってしまいました。


おかげでメールのキューが溜まってしまった結果、業務のメールが送信できなくなり他部署から思いっきり怒られてしまう始末。トホホです。


一度間違いを犯した人は間違いを犯さなくなると思いますが、他の人がやってしまう可能性もあるわけで、善良な社員をゲリラ的テロリストにさせない為にも、きちんと制限を行っておいた方が良いでしょう。


という訳でpostfixで送信元毎の同時送信数を制限する方法について調べて設定してみました。

postfixで使用できるパラメータ

postfixのパフォーマンスチューニングに関するマニュアルは下記のページに書かれています。
Postfixパフォーマンスチューニング


今回のケースでは過剰に接続するクライアントに対する測定に書かれた設定が参考になりそうです。

パラメータ名 デフォルト値 説明
smtpd_client_connection_count_limit 50 1つのSMTPクライアントからの同時最大接続数
smtpd_client_message_rate_limit 制限なし 1つのSMTPクライアントからの単位時間あたりのメッセージ配送要求数
smtpd_client_recipient_rate_limit 制限なし 1つのSMTPクライアントからの単位時間あたりの送信先アドレス数
smtpd_client_connection_rate_limit 制限なし 1つのSMTPクライアントからの単位時間あたりの同時最大接続数
anvil_rate_time_unit 60s 上記制限を行う単位時間
smtpd_client_event_limit_exceptions $mynetworks 上記制限を掛けないSMTPクライアント


『1つのSMTPクライアントからの』と書かれていますが、IPで制限されますので、『1サーバー』とか『1拠点』と考えた方が良いでしょう。


上記の設定をmain.cfとmaster.cfの適切な箇所に記載します。

/etc/postfix/main.cf

main.cfで設定を行うと全体的な設定になります。
今回は下記の通り設定しました。

anvil_rate_time_unit=60s
smtpd_client_message_rate_limit=120
smtpd_client_event_limit_exceptions=127.0.0.0/8
  • anvil_rate_time_unitはデフォルトと同じ60sです。今回の場合、ここは特に変更しなくて良いでしょう。
  • smtpd_client_message_rate_limitを120に制限します。
  • smtpd_client_event_limit_exceptionsを127.0.0.0/8に変更します。こちらを指定しないと$mynetworksの値が使用されますが、mynetworksにはローカルネットワークのサーバーも含んでおり、今回のトラブルはローカルネットワークのサーバーからのメール送信で発生したためローカルホストのみに制限します。

/etc/postfix/master.cf

master.cfで設定を行うと個別のサービスに対しての設定になります。
今回は下記の通り設定しました。

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
smtp      inet  n       -       n       -       50       smtpd
    -o smtpd_client_connection_count_limit=10
    -o smtpd_client_connection_rate_limit=30
submission inet n       -       n       -       -       smtpd
    -o smtpd_client_connection_count_limit=50
    -o smtpd_client_connection_rate_limit=200
    -o smtpd_etrn_restrictions=reject
    -o smtpd_client_restrictions=permit_sasl_authenticated,reject

smtpは社外もしくは内部のサーバーからの送信制限です。

  • maxproc(最大プロセス数)を50
  • smtpd_client_connection_count_limit(1 IPからの同時接続数)を10
  • smtpd_client_connection_rate_limit(単位時間(anvil_rate_time_unit=60s)辺りの接続数)を30

に設定しています。


submissionはSubmission Port(587)を通して送られる社内からのユーザーからのメールで制限を掛けるとお叱りを受けるので軽めにしておきました。


設定が終わったらpostfix reloadで設定を反映します。

テスト

実際に送信して試してみます。
メールサーバーとは別のサーバーからメールを送信して試します。
アドレスは実際に使用できるアドレスに変更してください。

<?php

$senders[] = 'foo@example.com';
$senders[] = 'bar@example.com';
$recipients[] = 'foo@example.com';
$recipients[] = 'bar@example.com';

for($i = 0; $i < 10000; $i++)
{
    foreach($senders as $s)
    {
        foreach($recipients as $r)
        {
            mail($r, 'Test', 'Test', NULL, "-f$s");
        }
    }        
}


上記スクリプトをtest_mail.phpという名前で保存したとして、

php test_mail.php

で実行します。


受信側サーバーのメールキューをmailqコマンドで確認し、キュー内のメールが一定まで増えた後、減っていく状況が確認できるかと思います。
又、送信側サーバーのメールキューもmailqコマンドで確認し、溜まっている状況が確認できればOKです。


キューに溜まったメールは『postfixでキューに溜まった特定の送信元、送信先のメールを一括削除する方法』に記載した方法で一括削除できます。