メールが配信されない!!~2~(procmailの解析)

Linuxで遊ぶ

どうも、自称Linuxサーバ評論家の瀬古草夫です。

で、前回の続きなんですが、メール振り分けプログラムのprocmailの設定ファイルprocmailrcを見てみます。ちなみに、この設定ファイルの :0 から始まる部分は、レシピと呼ばれているそうです。たぶん、自分で自由にメールの振り分け方法を作れるので、レシピと呼ばれているのだと思いますが・・・。

設定ファイルprocmailrcを確認する

# vi /etc/procmailrc
SHELL=/bin/bash
PATH=/usr/bin:/bin
DROPPRIVS=yes
MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/
SPAM=$MAILDIR/.Spam/
LOGFILE=$HOME/.procmail.log # ログ出力先
#VERBOSE=ON # 詳細ログ出力

# Clam AntiVirusによるウィルスチェック
AV_REPORT=`/usr/bin/clamdscan  --no-summary - 2>&1| awk -F\n -v ORS=' ' '{print}'|awk '{print $NF}'`
VIRUS=`if [ "$AV_REPORT" != "OK" ]; then echo Yes; else echo No;fi`
:0fw
| formail -i "X-Virus: $VIRUS"

# Clam AntiVirusがウィルス判定したメールは削除
:0
* ^X-Virus: Yes
/dev/null

# SpamAssassinによるスパムチェック
:0fw
|/usr/bin/spamc

# SpamAssassinにより判定されたSpam-Levelが一定値(ここでは20)以上の場合は削除
# ※必要なメールが削除されてしまう可能性があることに留意すること
:0
* ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
/dev/null
# SpamAssassinがスパム判定したメールはスパム専用メールボックスへ配送
:0
*^X-Spam-Flag: YES
$SPAM

この設定ファイルをググってみたら、結構な数、ひっかかりますわな。
瀬古も、かな~り昔に、このファイルをどこかのサイトから拾ってきてそのまま自分のサーバに適用していた訳です。
そりゃ、人の作ったものを何も考えずそのままコピペしてたら、いざトラブった時に神頼みしかできないのも当然ですわ。

という事で、上の設定ファイルを順番に確かめていきます。

1行目~8行目までは、環境変数の定義、10行目からClam AntiVirusでウイルスチェックをしている事がわかります。
11行目を見ると

AV_REPORT=/usr/bin/clamdscan  --no-summary - 2>&1| awk -F\n -v ORS=' ' '{print}'|awk '{print $NF}'

とあります。

こりゃ、なんじゃらほいですな。
まあ、clamdscan のコマンドを実行して、その結果をawkコマンドで整形して変数AV_REPORTに代入している事は、なんとか理解できます。

わし、awkコマンドなんぞ使ったことないし、どんな処理をしているのかいまいちピンときませんわ。

とりあえずは、 clamdscan – 2>&1 の出力結果がどのようになるかを確かめてみました。

clamdscan – 2>&1 の出力結果 (ウイルスなしメールの場合)

stream: OK

----------- SCAN SUMMARY -----------
Infected files: 0
Time: 0.010 sec (0 m 0 s)

clamdscan – 2>&1 の出力結果 (ウイルスありメールの場合)

stream: Win.Test.EICAR_HDB-1 FOUND

----------- SCAN SUMMARY -----------
Infected files: 1
Time: 0.006 sec (0 m 0 s)

clamdscan --no-summary - 2>&1

stream: OK
stream: Win.Test.EICAR_HDB-1 FOUND


次に、オプション –no-summary を追加した
clamdscan –no-summary – 2>&1の出力結果を確かめます。

clamdscan –no-summary – 2>&1の出力結果 (ウイルスなしメールの場合)

stream: OK

clamdscan –no-summary – 2>&1の出力結果 (ウイルスありメールの場合)

stream: Win.Test.EICAR_HDB-1 FOUND

きれいにサマリー(要約)が消えていますね。

次に、2>&1の意味なのですが、これは、標準エラー出力(2)を標準出力(1)にリダイレクト(>)しています。
なので、clamdscan -でウイルスチェック完了後に出力されるメッセージと、エラーが発生した時に出力されるメッセージの両方が、標準出力される訳です。

そもそも、clamdscanコマンドは、clamdが起動していないと利用できません。
という事は、 clamd を停止させれば、 clamdscanを実行した際、何らかのエラーが出力される事になります。


そこで、 clamd を停止させた時に、clamdscan –no-summary – 2>&1を実行した時の出力結果と、 clamdscan –no-summary – を実行した時の出力結果を見比べる事にします。

clamd を停止させた時に、clamdscan –no-summary – 2>&1を実行した時の出力結果

ERROR: Could not connect to clamd on LocalSocket /var/run/clamav/clamd.sock: No such file or directory
ERROR: Could not lookup 127.0.0.1: Servname not supported for ai_socktype

clamd を停止させた時に、clamdscan –no-summary -を実行した時の出力結果

 

clamdscan –no-summary -を実行した場合は、何も出力されない事がわかりました。
次に、clamdを起動中に、clamdscan –no-summary -を実行した時の出力結果 を見てみます。

clamd 起動中に、clamdscan –no-summary -を実行した時の出力結果 (ウイルスなし)

stream: OK

clamd 起動中に、clamdscan –no-summary -を実行した時の出力結果 (ウイルスあり)

stream: Win.Test.EICAR_HDB-1 FOUND

非常にくどい実験をしましたが、clamdscanの出力結果は必要な情報です。

そして、awkを、ちょこっとだけお勉強させてもらいましたよ。

-F 指定の区切り文字
-v 変数の定義
ORS(出力レコード区切り文字)組み込み変数


との事なので、
awk -F\n -v ORS= ‘ ‘ ‘{print}’

は、どうやら改行コード(\n)をスペースの文字列に変換して複数行の内容を一行にしているようです。そして、
awk ‘{print $NF}’
は、スペースで区切られた最後のフィールドのみを出力しているようです。

つまり、clamdが起動時、 ウイルスありメールの場合、”FOUND”、ウイルスなしのメールの場合、”OK”、そして clamdの停止時は、”ai_socktype”が 変数AV_REPORTに代入される訳です。

そして、設定ファイルの12行目には、

VIRUS=`if [ "$AV_REPORT" != "OK" ]; then echo Yes; else echo No;fi`

とあります。これは条件文です。変数AV_REPORTの値がOKじゃない場合は、Yes、OKの場合は、Noを変数VIRUSに代入しています。

そして、設定ファイルの14行目

:0fw
| formail -i "X-Virus: $VIRUS"

このレシピはメールのヘッダに追加する情報です。

ウイルスありメールの場合、X-Virus: Yes
ウイルスなしメールの場合、 X-Virus: No
がメールのヘッダに追加されます。

そして、設定ファイルの17行目

:0
* ^X-Virus: Yes
/dev/null

このレシピは、メールヘッダの行頭がX-Virus: Yesとマッチしていれば、メールは、/dev/nullによって、永遠に消し去られる悲しい運命にあるのでした。

めでたしめでたし。
・・・じゃなかった。

メールが届かなかった原因

ここまで解析したら、メールが届かなかった理由がわかっちゃいますよね?

はい、単に何らかの原因で、clamdが停止していただけなのですわ。

VIRUS=`if [ "$AV_REPORT" != "OK" ]; then echo Yes; else echo No;fi`

問題はこの条件文です。
clamdが停止していたら、”ai_socktype”が 変数AV_REPORTに代入される訳ですやん。
という事は、AV_REPORTは、当然”OK”ではないので、ウイルスメールと判定されて、そのメールは、誰も目にも触れずに永遠の眠りにつく訳ですわ。

問題の解決

とにかく、 clamdが停止 していてもメールは受信したいし、 AV_REPORT=/usr/bin/clamdscan --no-summary - 2>&1| awk -F\n -v ORS=' ' '{print}'|awk '{print $NF}'
って、結構無駄な事をやっているようなので、下記のように書き換えました。
ついでに変数名も変えちゃいました。

CLAM_CHECK=`clamdscan --no-summary -|awk '{printf $NF}'`
VIRUS=`if [ "$CLAM_CHECK" != "FOUND" ]; then echo No; else echo YES;fi`

たったこの2行の為に、長々と書いちゃいましたね。
でも原因がわかって、ほっとしております。

SHELL=/bin/bash
PATH=/usr/bin:/bin
DROPPRIVS=yes
MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/
LOGFILE=$HOME/.procmail.log # ログ出力先
#VERBOSE=ON # 詳細ログ出力

### Clam AntiVirusでメールチェック
CLAM_CHECK=`clamdscan --no-summary -|awk '{printf $NF}'`
VIRUS=`if [ "$CLAM_CHECK" != "FOUND" ]; then echo No; else echo YES;fi`

###出力確認用
#:0c
#|echo "$CLAM_CHECK" >> /home/XXX/check.txt

###メールヘッダの追加
:0fw
| formail -i "X-Virus: $VIRUS"

### ウイルスメールを削除
:0
* ^X-Virus: Yes
/dev/null

コメント

タイトルとURLをコピーしました