フィルタ

fml8 チュートリアル (バージョン 7.99.1-20180910)
Prev |  | Next

# Chapter 21. フィルタ

# レシピ’s

1. フィルタシステムを使わない独自のフィルタを設定したい
2. 特定のメールアドレスを拒否したい
3. message/partial をフィルタしたい。
4. 危ない添付ファイルがついてきたメールは拒否する HOOK
5. フィルタで弾いた時に、エラーメールをどこへ返す
6. spamassassin で SPAM メールを無視する。
7. spamassassin で SPAM メールと判定したら、 ヘッダに X-Spam-Status: Yes をつける。
8. SPAM 対策として、To: および Cc: に ML 名を必須としたい
9. ＭＬ独自の Message-ID: をつけて矯正したい

1. フィルタシステムを使わない独自のフィルタを設定したい

fml8 のフィルタシステムで利用可能なフィルタは

    /usr/local/etc/fml//defaults/$VERSION/default_config.cf.ja

を読むと分かります。

この内蔵フィルタで実装されていない内容のフィルタは article_post_verify_request_end_hook article_filter_start_hook article_filter_end_hook article_post_run_start_hook のいづれかの HOOK でおこなえばよいでしょう。

    $article_filter_start_hook = q{
    	my $header = $curproc->incoming_message_header();
    	my $body   = $curproc->incoming_message_body();

    	if (条件) {
    		$curproc->policy_reject_this_message();
    	}
    };

のように書けば良いとおもいます。 フィルタの書き方についてはソースコード本体や、 以下のレシピも参照して下さい。

2. 特定のメールアドレスを拒否したい

たとえば特定のドメイン(\S+\@example.co.jp)は全部はじきたいといった フィルタのことです。 内蔵フィルタの一部として実装しようと考えていますが、 残念ながら未実装です _o_

3. message/partial をフィルタしたい。

mime component filter で「message/partial * reject」を設定して下さい。

    [/usr/local/etc/fml/mime_component_filter]

    # allow only text/plain messages.
    message/partial *		reject
    text/plain	*		permit
    text/html	*		reject
    multipart/*	!text/plain	reject

注意: このフィルタは全ＭＬに反映されます。

4. 危ない添付ファイルがついてきたメールは拒否する HOOK

fml8 は、あらかじめ入力されたメッセージを解析し、メモリ上に鎖状の Mail::Message オブジェクトの形で持っています。そこで、MIME/Multipart の各部分のヘッダを取り出して、正規表現で順に確認すればよいだけです。

HOOK でなんとかする/ごまかす例は次の通りです。 どちらの例でも、マッチした場合、stop_this_process() 命令で、 それ以上の処理を止めています。 また、この例では何もエラーメッセージを返そうとしていないため、 結果として、このメッセージは無視されて終りになっています。

返事をしてあげたいなら、 reply_message() で、何か返事を返してあげてく ださい…が、たぶんウィルスとかなので返事をしないほうが良いでしょう。

.exe など特定のファイル拡張子にマッチするか？を調べる例。 昔の fml8 (2004/12/08 以前)なら、こんな感じ。

    $distribute_verify_request_start_hook = q{
        my $msg = $curproc->incoming_message() || undef;
        for (my $m = $msg; $m ; $m = $m->{ next } ) {
    	my $hs = $m->message_fields() || '';
    	if ($hs =~ /filename=.*\.(com|vbs|vbe|wsh|wse|js|exe|doc|rtf)/o) {
    	    $curproc->log("attachment \.$1 found");
    	    $curproc->stop_this_process();
    	}
        }
    };

2004/12/08 以降の fml8 なら、こんなかんじ。

    $distribute_verify_request_start_hook = q{
        my $msg  = $curproc->incoming_message() || undef;
        my $list = $msg->message_chain_as_array_ref();
        for my $m (@$list) {
    	my $hs = $m->message_fields() || '';
    	if ($hs =~ /filename=.*\.(com|vbs|vbe|wsh|wse|js|exe|doc|rtf)/o) {
    	    $curproc->log("[new] attachment \.$1 found");
    	    $curproc->stop_this_process();
    	}
        }
    };

別解としては、

    Content-Disposition: attachment;

という表示になることを前提に、これを引っかけるという案もあります。

    $distribute_verify_request_start_hook = q{
        my $msg = $curproc->incoming_message() || undef;
        for (my $m = $msg; $m ; $m = $m->{ next } ) {
    	my $hs = $m->message_fields() || '';
    	if ($hs =~ /Content-Disposition:.*attachment;/o) {
    	    $curproc->log("attachment \.$1 found");
    	    $curproc->stop_this_process();
    	}
        }
    };

2004/12/08 の fml8 以降なら、こんなかんじ。

    $distribute_verify_request_start_hook = q{
        my $msg  = $curproc->incoming_message() || undef;
        my $list = $msg->message_chain_as_array_ref();
        for my $m (@$list) {
    	my $hs = $m->message_fields() || '';
    	if ($hs =~ /Content-Disposition:.*attachment;/o) {
    	    $curproc->log("[new] attachment \.$1 found");
    	    $curproc->stop_this_process();
    	}
        }
    };

5. フィルタで弾いた時に、エラーメールをどこへ返す

デフォルトでは

    use_article_filter_reject_notice	=	yes
    article_filter_reject_notice_recipient	=	maintainer sender

となっています。 つまり、 (1) エラーメールを返し(yes)、 (2) 返す先はＭＬの管理者と送信者の両方(maintainer sender) です。

返送する先を送信者( From: のアドレス )にするには

    article_filter_reject_notice_recipient	=	sender

としてください。

ＭＬの管理者と送信者( From: のアドレス )の両方に返すには

    article_filter_reject_notice_recipient	=	maintainer sender

としてください。

そもそもエラーメールを返さないようにするには、

    use_article_filter_reject_notice	=	no

としてください。

6. spamassassin で SPAM メールを無視する。

Caution
そもそも spamassassin をよびだす内蔵フィルタがあるのですが、 それをあえて使わない例です。

1. 内蔵フィルタの方の設定です。

    use_article_spam_filter         =       yes
    article_spam_filter_drivers     =       spamassassin

2. HOOK でなんとかする/ごまかす例は次の通りです。

    $distribute_verify_request_end_hook = q{
            my $spamassassin = '/usr/pkg/bin/spamc -c';

            use FileHandle;
            my $wh  = new FileHandle "| $spamassassin";

            if (defined $wh) {
                    $wh->autoflush(1);
                    my $msg = $curproc->incoming_message();
                    $msg->print($wh);
                    $wh->close();
                    if ($?) {
                            $curproc->log("spam: (code = $?)");
                            $curproc->stop_this_process();
                    }
            }
    };

7. spamassassin で SPAM メールと判定したら、 ヘッダに X-Spam-Status: Yes をつける。

    $distribute_verify_request_end_hook = q{
    	my $spamassassin = '/usr/pkg/bin/spamc -c';

    	use FileHandle;
    	my $wh  = new FileHandle "| $spamassassin";

    	if (defined $wh) {
    		$wh->autoflush(1);
    		my $msg = $curproc->incoming_message();
    		$msg->print($wh);
    		$wh->close();
    		if ($?) {
    			$curproc->log("spam: (code = $?)");
    			my $hdr = $curproc->incoming_message_header();
    			$hdr->add('X-Spam-Status', 'Yes');
    		}
    	}
    };

ちょっとトリッキーですが、動きます。

8. SPAM 対策として、To: および Cc: に ML 名を必須としたい

HOOK で行なうなら次のようになります。

    $article_filter_end_hook = q{
    	my $header = $curproc->incoming_message_header();
    	my $addr   = $config->{ article_post_address };
    	my $to     = $header->get('To') || '';
    	my $cc     = $header->get('Cc') || '';
    	my $to_cc  = "$to, $cc";
    	my $found  = 0;

    	use Mail::Address;
    	my (@addrlist) = Mail::Address->parse($to_cc);
    	for my $a (@addrlist) {
    		my $_addr = $a->address();
    		if ($_addr =~ /^$addr$/i) {
    			$found = 1;
    		}
    	}

    	if ($found) {
    		$curproc->log("article_post_address found in header");
    	}
    	else {
    		$curproc->log("article_post_address not found in header");
    		$curproc->policy_reject_this_message();
    	}
    };

9. ＭＬ独自の Message-ID: をつけて矯正したい

未実装です。

HOOK でなんとかすることは出来ます。 「記事に ML 独自の Message-ID: をつけたい」というレシピを参照して下さい。

fml4 では「In-Reply-To: や References: をつけてくれない MUA があるた めにスレッドがうまく扱えない」という問題を解決するために、ＭＬ独自の Message-ID: をつけて矯正するという機能がありました。現代では、そういっ た MUA も死に絶えたでしょうから fml8 では考慮しないことにします。

Prev | Home | Next
レシピ’s | Up | メッセージの拡張

fml 8.0 (fml-devel) project homepage is www.fml.org/software/fml8/.
fml 4.0 project homepage is www.fml.org/software/fml4/.
about one floppy bsd routers, see www.bsdrouter.org/.
other free softwares are found at www.fml.org/software/.

author's homepage is www.fml.org/home/fukachan/.
Also, visit nuinui's world :) at www.nuinui.net.

For questions about FML, e-mail <fml-bugs@fml.org>.