文書一覧に戻る | GreetPause | milter-greylist | milter-regex | milter-blockdomain 最終更新日:2021/02/13

S25R スパム対策方式( Selective SMTP Rejection:選択的SMTP拒絶)
http://www.gabacho-net.jp/anti-spam/

  1. はじめに
  2. milter-regex の設定ファイルの分割管理と milter-regex.conf の生成
  3. 必須のホワイトリスト
  4. サイト・ローカルのホワイトリストやブラックリスト
  5. SMTP の HELO をチェックする設定
  6. SMTP の エンベロープFROM に関する設定
  7. S25R の公開ホワイトリストを milter-regex の様式に変換して取り込む
  8. S25R の公開ブラックリストを milter-regex の様式に変換して取り込む(削除)
  9. milter-regexで、SMTPのRCPTが来た時に、S25Rのチェックを実施する設定ファイル

1. はじめに

スパム対策は、メールの運営者や利用者の要件によって異なり、万能・唯一といった方式があるわけではなく、
複数の方式を組み合わせることにより、より効果的な結果が得られます。
ここでは、以下の要件や受容条件で、実用的な方法を紹介します。

実用的な方法としては、以下の2つを組み合わせて利用します。

  1. sendmail で、日本以外からの接続に対してグリートポーズ(タールピット)を適用する。

    sendmail によるグリートポーズは、以下をご参照下さい。
    http://www.bea.hi-ho.ne.jp/abetakao/ja/documents/sendmail-greetpause.html

  2. milter-regex で、S25R を適用する。

    次章以降で紹介します。
    ただし、milter-regex は、メール・ログを監視して受信したいホストが S25R のルールに該当した場合、
    手動でホワイト・リストに追加しなければならず、「なるべく、メンテナンス・フリー。なるべく、無人運用。」という
    要件の実現が十分ではありません。要件の実現には、付録 A で述べたとおり、milter-greylist の利用をおすすめします。


2. milter-regex の設定ファイルの分割管理と milter-regex.conf の生成

milter-regex の設定ファイル milter-regex.conf は、設定内容を別ファイルの参照にできないので、
設定の変更の頻度や設定の種類によって、いくつかのファイルに分割しておき、それらを統合して
milter-regex の設定ファイル milter-regex.conf を生成するようにすると、S25R の公開ホワイトリストの
自動取り込みが行いやすくなります。

設定ファイルは、どのような分割でも自由ですが、意図したとおりの順番でファイルを統合できるように、
ファイル名の先頭を番号にしておきます。

ファイル名想定変更頻度設定内容
10-whitelist.conf必須のホワイトリスト
11-whitelist.conf手作業で保守するサイト・ローカルのホワイトリスト
20-blacklist.conf手作業で保守するサイト・ローカルのブラックリスト
61-helo.conf無効なHELOのルールなど
62-envfrom.confSMTP の エンベロープFROM に関する設定
71-whitelist.conf高(定期的)S25Rの公開ホワイトリストをmilter-regexの様式に変換したホワイトリスト
72-blacklist.conf廃止S25Rの公開ブラックリストをmilter-regexの様式に変換したブラックリスト
90-s25r.confS25Rの基本ルールなど

分割した設定ファイルを milter-regex の設定ファイル milter-regex.conf に統合するスクリプト

#!/bin/bash

DATADIR=/var/lib/milter-regex     ・・・ 上記の分割した設定ファイルの保管パス(任意のパス)
CONF=milter-regex.conf

rm $DATADIR/$CONF

for FILE in `ls $DATADIR/*.conf | sort`
do

    if [ `basename $FILE` = $CONF ] ; then
        continue
    fi

    cat $FILE >> $DATADIR/$CONF

done

3. 必須のホワイトリスト

ループバック・アドレスとローカル・ネットワークは、必須のホワイトリストです。

####################################################################################################
#####
#####     10-whitelist.conf
#####
####################################################################################################

# ループバック・アドレスとローカル・ネットワークの無条件送信許可

accept

connect // /^127\.[0-9]*\.[0-9]*\.[0-9]*$/

connect // /^10\.[0-9]*\.[0-9]*\.[0-9]*$/
connect // /^169\.254\.[0-9]*\.[0-9]*$/
connect // /^172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]*\.[0-9]*$/e
connect // /^192\.168\.[0-9]*\.[0-9]*$/

connect // /^192\.0\.2\.[0-9]*$/     ・・・ メール・サーバー自身や自サイトのグローバル・アドレスを指定する。

4. サイト・ローカルのホワイトリストやブラックリスト

サイト・ローカルのホワイトリストやブラックリストですが、中には長期(過去数年)にわたり有効なものもあります。
ご参考になさって下さい。
http://www.bea.hi-ho.ne.jp/abetakao/black-and-white/


5. SMTPのHELOをチェックする設定

不正なHELOに適用するルールです。

####################################################################################################
#####
#####     61-helo.conf
#####
####################################################################################################

# HELOにピリオドがない(FQDNでない)

tempfail "Refused connection temporarily. Be patient. ( Non FQDN HELO )"

helo /\./n and envrcpt /^<.*>$/

# HELOでこちらのサーバー名やIPアドレスを名乗る

reject "Refused connection by site policy. ( Malformed HELO )"

helo /^foobar\.example\.jp$/i and connect // /^127\.0\.0\.1$/n and connect // /^192\.0\.2\.1$/n
helo /^192\.0\.2\.1$/         and connect // /^127\.0\.0\.1$/n and connect // /^192\.0\.2\.1$/n
helo /^localhost$/i           and connect // /^127\.0\.0\.1$/n and connect // /^192\.0\.2\.1$/n
helo /^127\.0\.0\.1$/         and connect // /^127\.0\.0\.1$/n and connect // /^192\.0\.2\.1$/n

# HELOがピリオドだけ

reject "Refused connection by site policy. ( Invalid HELO )"

helo /^\.$/

192.0.2.1 は、メール・サーバーのグローバル・アドレスを設定します。

foobar.example.jp は、メール・サーバーのホスト名を設定します。

HELOにピリオドがない場合に一時拒否を応答するルールは、S25R と同様に、
必ず、メールのログを監視し、有効な再送を検知した場合は、このルールの前に
HELOにピリオドがないホストに対するホワイトリストを追加して、受信するように運用する必要があります。


6. SMTP の エンベロープFROM に関する設定

エンベロープFROMは、空白で送られる場合があります。RFCでは、次のように述べられています。

RFC 3464   Section 2. Format of a Delivery Status Notification (抜粋)

Whenever an SMTP transaction is used to send a DSN, the MAIL FROM command MUST use a NULL return address, i.e., "MAIL FROM:<>".

RFC 5321   Section 3.6.3. Message Submission Servers as Relays (抜粋)

One way to prevent loops in error reporting is to specify a null reverse-path in the MAIL command of a notification message.
When such a message is transmitted, the reverse-path MUST be set to null (see Section 4.5.5 for additional discussion).
A MAIL command with a null reverse-path appears as follows:

      MAIL FROM:<>

エンベロープFROMが空白で無効な宛先アドレスに送ろうとするメールも多く見られ、
エンベロープFROMが空白の場合に一時拒否を適用するルールです。

####################################################################################################
#####
#####     62-envfrom.conf
#####
####################################################################################################

# エンベロープFromが空白なら、一時拒否を返す。

tempfail "Refused connection temporarily. Be patient. ( NULL return address )"

envfrom /^<>$/ and envrcpt /^<.*>$/

エンベロープFROMが空白の場合に一時拒否を応答するルールは、S25R と同様に、
必ず、メールのログを監視し、有効な再送を検知した場合は、このルールの前に
エンベロープFromの空白に対するホワイトリストを追加して、受信するように運用する必要があります。


7. S25R の公開ホワイトリストを milter-regex の様式に変換して取り込む

公開されているホワイトリストを、以下のように connect 文に変換します。

/^192\.0\.2\.1$/ OK

/^192-0-2-2\.example\.jp$/ OK

↓ ↓ ↓

connect // /^192\.0\.2\.1$/e

connect /^192-0-2-2\.example\.jp$/e //

sedコマンドは、s の直後に指定した文字を区切り文字として認識し、一般的には、区切り文字はに / を使用することが多いと思います。
ここでは、判定対象や置換対象に / があり、/ をエスケープするとコマンドが読みにくくなるため、区切り文字に % を使用しています。

sed 's%^ */\(.*[a-z].*\)\$/.*%connect /\1\$/e //%g' white-list.txt | sed 's%^ */\([^a-z]*\)/.*%connect // /\1/e%g' > 71-whitelist.conf

ホワイトリストによる受信許可も、SMTPのRCPTが来た時に判定する場合は、
変換結果の connect 文に and envrcpt /^<.*>$/ を条件に加えるように、次のコマンドで変換します。

sed 's%^ */\(.*[a-z].*\)\$/.*%connect /\1\$/e // and envrcpt /^<\.\*>\$/%g' white-list.txt | sed 's%^ */\([^a-z]*\)/.*%connect // /\1/e and envrcpt /^<\.\*>\$/%g' > 71-whitelist.conf

変換漏れがないか確認するコマンドです。変換できない行数がゼロならば、OKです。

grep -v '^ *#' 71-whitelist.conf | grep -v '^ *$' | egrep -c -v '^(connect|macro /_/) '

公開ホワイトリストをダウンロードして milter-regex の様式に変換するまでを自動化するスクリプト
SMTPのRCPTが来た時に判定するように変換する sed コマンドになっています。

#!/bin/bash

DATADIR=/var/lib/milter-regex     ・・・ 分割した設定ファイルの保管パス

NEW_WHITELIST=$DATADIR/white-list.txt
OLD_WHITELIST=$DATADIR/white-list.old
WGET_LOG=$DATADIR/wget.log

MILTER_REGEX_S25R_WHITELIST=$DATADIR/71-whitelist.conf

# 現在の公開ホワイトリストを退避する

if [ -f $NEW_WHITELIST ] ; then
    if [ -s $NEW_WHITELIST ] ; then
        # 以前に取得した公開ホワイトリストを更新確認用に退避する
        cp -p $NEW_WHITELIST $OLD_WHITELIST
    fi
    # 以前に取得した公開ホワイトリストを削除する
    rm $NEW_WHITELIST
fi

# 公開ホワイトリストをwgetで取得する

wget -P $DATADIR http://www.gabacho-net.jp/anti-spam/white-list.txt > $WGET_LOG 2>&1
if [ $? -ne 0 ] ; then
    # wgetの戻りコードがゼロ以外なら中止
    exit 1
fi

if [ ! -s $NEW_WHITELIST ] ; then
    # wgetで取得したファイルの大きさがゼロなら中止
    exit 1
fi

LINE1=`head -1 $NEW_WHITELIST`
if [ "$LINE1" != '# *** PUBLISHED S25R WHITE LIST ***' ] ; then
    # 1行目が想定文字列でなければ中止
    exit 1
fi

LINE2=`sed -n '2,2p' $NEW_WHITELIST | cut -c 1-14`
if [ "$LINE2" != '# Last update:' ] ; then
    # 2行目が想定文字列でなければ中止
    exit 1
fi

# 公開ホワイトリストが更新されているか調べ、更新されていなければここで終了する

if [ -f $OLD_WHITELIST ] ; then
    diff $OLD_WHITELIST $NEW_WHITELIST > /dev/null 2>&1
    if [ $? -eq 0 ] ; then
        # 公開ホワイトリストの更新確認用に退避した古いファイルを削除する
        rm $OLD_WHITELIST
        # 公開ホワイトリストが更新されていなければ終了
        exit 0
    fi
    # 公開ホワイトリストの更新確認用に退避した古いファイルを削除する
    rm $OLD_WHITELIST
fi

# 公開ホワイトリストを milter-regex の様式に変換する

echo '####################################################################################################'  > $MILTER_REGEX_S25R_WHITELIST
echo '#####'                                                                                                >> $MILTER_REGEX_S25R_WHITELIST
echo '#####     '`basename $MILTER_REGEX_S25R_WHITELIST`                                                    >> $MILTER_REGEX_S25R_WHITELIST
echo '#####'                                                                                                >> $MILTER_REGEX_S25R_WHITELIST
echo '####################################################################################################' >> $MILTER_REGEX_S25R_WHITELIST
echo >> $MILTER_REGEX_S25R_WHITELIST
echo 'accept' >> $MILTER_REGEX_S25R_WHITELIST
echo >> $MILTER_REGEX_S25R_WHITELIST

sed 's%^ */\(.*[a-z].*\)\$/.*%connect /\1\$/e // and envrcpt /^<\.\*>\$/%g' $NEW_WHITELIST | sed 's%^ */\([^a-z]*\)/.*%connect // /\1/e and envrcpt /^<\.\*>\$/%g' >> $MILTER_REGEX_S25R_WHITELIST

COUNT=`grep -v '^ *#' $MILTER_REGEX_S25R_WHITELIST | grep -v '^ *$' | egrep -c -v '^(accept|connect |macro /_/ )'`
if [ $COUNT -ne 0 ] ; then
    # 変換できない行数がゼロ以外なら中止
    exit 1
fi

8. S25R の公開ブラックリストを milter-regex の様式に変換して取り込む(削除)

公開されているブラックリストは、2021年2月時点で4年近く更新されていないので、
milter-regex の connect 文に変換して取り込む処理は削除しました。


9. milter-regexで、SMTPのRCPTが来た時に、S25Rのチェックを実施する設定ファイル

S25R によるチェックにおける逆引きのホスト名は、パラノイド検査の合格で逆引きのホスト名とし、
パラノイド検査の不合格は逆引きできないとすることで良い効果が得られます。

パラノイド検査のDNSルックアップ自体は、sendmail が行いますが、パラノイド検査の合否結果を考慮するか/しないかによって、
milter-regex の設定キーワードが異なります。

注:
下記の設定ファイルは、S25Rの原典にない追加ルール付きです。
S25Rの原典の6つのルールだけをご希望の方は、『 # 追加ルール 』以降を全て削除してご活用下さい。

milter-regex-s25r.conf

付録 A: S25R の運用における milter-regex と milter-greylist の特徴比較

S25Rは、milter-regex および milter-greylist の何れでも実現できます。
S25Rの milter-greylist の設定ファイルは、こちらです。

運用上の主な要件や特徴は、以下のとおりです。

milter-regexmilter-greylist
再送の監視 手動、もしくは、外部スクリプトによる自動化 自動(milter-greylist自身)
ホワイトリストの保守 手動、もしくは、外部スクリプトによる自動化 自動(milter-greylist自身によるオート・ホワイトリスト)
S25Rの公開ホワイトリストの活用 定期的に取り込んだほうが良い
理由:
S25R のルールに該当するホストでも、
受信した方が良いと思われる既知のホストについて、
一時拒否せずに受信できる。
定期的に取り込んだほうが良い
理由:
S25R のルールに該当するホストでも、
受信した方が良いと思われる既知のホストについて、
一時拒否せずに受信できる。
S25Rのルールに該当するホストでも、
milter-greylistのオート・ホワイトリストによる
許可を待たずに、初回時の遅延を回避できる。
SMTP認証を通過したアクセスの
アクセス制限の緩和
追加の許可ルール設定が必要 デフォルト設定で、SMTP認証を通過したアクセスは許可

付録 B: milter-regex のための sendmail の設定
  1. milter-regex で利用するパスを決める。

    任意のパスに設定することができます。
    また、それぞれのパスは、別々のパスに設定しても問題ありません。

    /var/run/milter/milter-regex.sock

    milter-regex のソケット・ファイル
    後述の sendmail.mc の INPUT_MAIL_FILTER で、このパスを指定します。

    /var/lib/milter-regex

    分割管理する設定ファイルのパス
    「 2. milter-regex の設定ファイルの分割管理と milter-regex.conf の生成 」、
    「 7. S25R の公開ホワイトリストを milter-regex の様式に変換して取り込む の
    2つのサンプル・スクリプト中の変数 DATADIR で、このパスを指定します。

    ディレクトリを作成します。
    ディレクトリの所有者は、実行ユーザー milter に設定します。

    mkdir /var/lib/milter-regex
    
    chown milter:milter /var/lib/milter-regex
    
  2. sendmail の設定

    sendmail.mc に milter-regex の指定を追加します。

    INPUT_MAIL_FILTER(`milter-regex',`S=local:/var/run/milter/milter-regex.sock, F=, T=S:1m;R:1m')dnl
    

    sendmail.mc から sendmail.cf を生成します。 その際、sendmail.mc に「 include(`../m4/cf.m4') 」のようなカレント・ディレクトリを基点とした指定がある場合は、 カレント・ディレクトリを生成用のディレクトリに移動します。(下記の例では、/usr/share/sendmail/cf/cf )

    # 現在の sendmail.cf のバックアップ・コピーを取得する
    cp -p /etc/mail/sendmail.cf /etc/mail/sendmail.cf-yyyymmdd-hhmm
    
    # 生成用のパスに移動する
    cd /usr/share/sendmail/cf/cf
    
    # sendmail.mc から sendmail.cf を生成する
    m4 /etc/mail/sendmail.mc | cat -s > /etc/mail/sendmail.cf
    
  3. milter-regex の起動
    MILTER_REGEX=/usr/local/sbin/milter-regex
    MILTER_REGEX_CONF=/var/lib/milter-regex/milter-regex.conf
    MILTER_REGEX_SOCK=/var/run/milter/milter-regex.sock
    MILTER_REGEX_PID=/var/run/milter/milter-regex.pid
    MILTER_REGEX_UID=milter
    MILTER_REGEX_GID=milter
    
    MILTER_RUN=`dirname $MILTER_REGEX_SOCK`
    
    if [ ! -d $MILTER_RUN ] ; then
        mkdir -p $MILTER_RUN
        chown $MILTER_REGEX_UID $MILTER_RUN
        chmod o-rwx $MILTER_RUN
    fi
    
    $MILTER_REGEX -c $MILTER_REGEX_CONF -u $MILTER_REGEX_UID -U $MILTER_REGEX_UID -G $MILTER_REGEX_GID -p $MILTER_REGEX_SOCK -r $MILTER_REGEX_PID
    

付録 C: S25R の公開ホワイトリストや公開ブラックリストへの登録依頼方法

下記の連絡先に情報を送付すると、掲載基準に適合していれば、登録していただけます。
ギブ・アンド・テイクの精神で情報提供し、S25R の導入サイトで情報共有を図りましょう。

http://www.gabacho-net.jp/anti-spam/contact.html


付録 D: 平易な表現の(正規表現でない)多数のドメインを扱う milter-blockdomain

アクセス元を逆引きしたホスト名が S25R の6つのルールに該当しなかったり、アクセス元のIPアドレスを逆引きできない場合や、 S25R の6つのルールに該当する場合でも、再送信により milter-greylist のオート・ホワイトリストで、若干のスパム・メールは通過して着信してしまいます。

汎用的/一般的なルールを通過するドメインをブラックリスト/グレイリストで管理しようとすると多数になりがちですが、 milter-blockdomain は正規表現ではない平易な表現でドメインを指定でき、かつ、ひとつの指定で逆引きしたホスト名、HELO、エンベロープFROMを検査できます。

http://www.bea.hi-ho.ne.jp/abetakao/milter-blockdomain/


最終更新日:2018/02/04 Another HTML-lint W3C Validation LogCounter
Copyright(C) 2012, Takao Abe

改訂履歴
2021/02/13 内容を整理
S25Rの公開ブラックリストの取り込みを削除
2018/02/04 サイト・ローカルのホワイトリストやブラックリストを分離。
http://www.bea.hi-ho.ne.jp/abetakao/black-and-white/
2016/06/19 追加: 付録 D: 平易な表現の(正規表現でない)多数のドメインを扱う milter-blockdomain
http://www.bea.hi-ho.ne.jp/abetakao/milter-blockdomain/
2015/07/26 以下を追加。
付録 B: milter-regext のための sendmail の設定
付録 C: S25R の公開ホワイトリストや公開ブラックリストへの登録依頼方法
2015/06/14 S25Rの公開ホワイトリストを取り込むスクリプトに、accept文を生成するように変更。
S25Rの公開ブラックリストの取り込むファイルを追加。 ( 72-blacklist.conf )
2015/02/08 S25Rの公開ホワイトリストの変換で、macro /_/ 文を生成しないようにsedコマンドの指定を変更。
S25Rの公開ホワイトリストを milter-regex の様式に変換して取り込むサンプル・スクリプトに、
wgetでダウンロードした公開ホワイトリストの1行目と2行目が想定文字列かどうかのチェックを追加。
逆引きホスト名の判定は、パラノイド検査のパスで判定することを推奨し、milter-regex の判定文を変更。 ( 90-s25r.conf )
2014/05/04 逆引きホスト名に . (ドット)を返す DNS が見つかり、一時拒否ルールを追加。 ( 90-s25r.conf )
2013/12/15 公開ホワイトリストをダウンロードして milter-regex の様式に変換するスクリプトを追記。
2013/09/21 付録A S25Rの公開ホワイトリストの活用の理由を修正。
2013/09/08 Envelope From が空白だった場合に一時拒否ルールを追加。 ( 62-envfrom.conf )
2013/07/27 設定ファイルの分割管理と基本的な設定などの設定ファイル全体を記述。
2013/06/11 改訂
2013/05/30 改訂
2013/05/26 改訂
2012/12/15 公開