ものすごく以前の記事で、Postfix が吐き出すメールログ ( mail.log ) に、”cannot find your hostname.” というログが残ることがある、と書いたことがあります。

 

 

Cannot find your hostname という病

このログの意味するところは、送信元のメール送信サーバー (MTA) の IPアドレスをの DNS の逆引きで名前解決できない場合に、接続要求を出してきた MTA に Reject (接続拒否) を返した時に残されるログです。

これは、Postfix の設定ファイル、/etc/postfix/main.cfsmtpd_client_restrictions というパラメータに、 reject_unknown_client を追加することでその機能を有効にしているためです。

何故そんな設定をしているかというと、MTA に接続要求をしてくるクライアントを制限して、スパムや迷惑メール等に対しての対策、としているわけですが、そういった身元の怪しい (と思われる) MTA の中に、結構大手のプロバイダさんや、企業のアドレスが紛れ込んでくることがあります。それもそんなに低い確率ではないんですよね。

これは以前の記事にも書いたとおりです。

よって、本来は受信してほしいのにも関わらず、上記の設定で Reject されている アドレスを受信させるために、手っ取り早く一覧を取得できるコマンドライン上の ワンライナー 1を作りました。

・・いや、厳密に言えば作っていました。

で、久しぶりに使おうと思ったところ、

あれ、このコマンドの意味やんやったっけ

となってしまったので、それぞれのコマンドの意味をしっかりと把握しておかねば、という意味合いでこの覚書を書いた次第です。

すべての同じような Postfix の設定で同様の処理が可能かどうかは保証できませんが、もし参考になれば幸いです。

また、UNIX系のシェルからであれば、こんなふうなことも一発で出来てしまう、ということを Linux 初学者、もしくは Linux (UNIX) に興味のある Windows ユーザー の方に知ってもらえると嬉しいです。

 

ワンライナー

下がその肝心のワンライナーです。

find /var/log/ -mtime -90 -name 'mail.log*' | xargs zgrep 'cannot find' | cut -d':' -f9 | sed -e 's/cannot find your hostname, \|\[\|\]\|;\|<\|>//g;s/=/:/g' | sort | perl -anle 'print "$F[0]\t$F[2]\t\t$F[1]"' | uniq -c| sort -t$'\t' -k1nr | less

この一行の結果で得られる結果はこのようになります。

    260 xxx.xxx.203.39  to:xxxx@mydomain.jp             from:lsn_no_reply@linkshare.com
    174 xxx.xxx.203.40  to:xxxx@mydomain.jp             from:lsn_no_reply@linkshare.com
    107 xxx.xxx.196.181 to:xxxx@mydomain.jp             from:lsn_no_reply@linkshare.com
     30 xxx.xxx.203.38  to:xxxx@mydomain.jp             from:lsn_no_reply@linkshare.com
     11 xxx.xxx.73.102  to:xxxx@mydomain.jp             from:info@vpcmail2.lifecard.co.jp
      3 xxx.xxx.62.40   to:spameri@tiscali.it           from:spameri@tiscali.it
      3 xxx.xxx.228.56  to:xxxx@mydomain.jp             from:itrcjc@uehg.com
      3 xxx.xxx.102.106 to:xxxx@mydomain.jp             from:ejrffb@pyaa.com
      3 xxx.xxx.186.173 to:xxxx@mydomain.jp             from:rtgvt@tphq.com
      3 xxx.xxx.235.233 to:spameri@tiscali.it           from:spameri@tiscali.it
      2 xxx.xxx.149.65  to:xxxx@mydomain.jp             from:ostt@vybj.com

内容は、左から、件数、送信元 MTA の IPアドレス、宛先メールアドレス、差出人メールアドレス となっています。

この場合、linkshare さんの MTA が逆引きエラーで Reject されており、件数も多いのがわかります。

こういった場合には、アクセス許可リスト に linkshare さんのドメイン名かIPアドレスを追加しなければいけません。

 

ワンライナーの説明

ここからはこのワンライナーの説明をしていきたいと思います。

 


find /var/log/ -mtime -90 -name 'mail.log*'

 

説明

まず、find コマンドで、/var/log ディレクトリから mail.log で始まるファイル名を取得させます。

条件としては、かこ90日以内に更新のあったログファイルということにしています。

 

オプション
-mtime -90
90日前から現在までに更新されたファイル。
オプション 意味
-mtime -3 3日前 ( 72時間前 → 現在 ) から現在まで
-mtime 3 3日前の24時間 ( 96時間前 → 72時間前 ) の間
-mtime +3 4日前 ( 過去 → 96時間前 ) まで

 

-name
取得したいファイル名。ワイルドカードが使用できます。* : 任意の0文字以上、? : 任意の一文字。正規表現を使いたい場合は、-regex でできる。

 


xargs zgrep 'cannot find

説明

xargs は、標準入力を読み取って、それを引数として指定されたコマンドに渡すためのコマンドです。

要するに、前の find コマンドの結果、渡されてくるファイル名を、zgrep 'cannnot find' に渡しています。

zgrepgzipcompress で圧縮されたファイルから正規表現等を使って検索します。ただ、このコマンドは圧縮されていない通常のファイル にも使用できる便利なコマンドです。

結果

ここまでで、過去90日以内に変更、更新された cannot find your hostname という文字列を含んだログの一覧が取得できます。

下は、そのうちの一行を取り出したものです。こんな感じでログが記録されています。

/var/log/mail.log.2.gz:Nov 23 12:25:10 myhost postfix/smtpd[4271]: NOQUEUE: reject: RCPT from unknown[xxx.xxx.148.89]: 450 4.7.25 Client host rejected: cannot find your hostname, [xxx.xxx.148.89]; from=<ipjsmb@cjsl.com> to=<xxxxx@mydomain.jp> proto=ESMTP helo=<maux.com>

 


cut -d':' -f9

説明

: を区切り文字として、9番目のフィールドだけ取り出す。

オプション
-d
デリミタ (区切り文字) を指定します。
-f
区切られた範囲をフィールドとして、何番目のフィールドを取得するか、フィールド番号を指定します。
例: -f2, -f2,9, -f2,4-9,12,15
結果

これで先程のログから、: で区切って 9番目のフィールドを取り出します。

 cannot find your hostname, [xxx.xxx.148.89]; from=<ipjsmb@cjsl.com> to=<xxxxx@mydomain.jp> proto=ESMTP helo=<maux.com>

 


sed -e 's/cannot find your hostname, \|\[\|\]\|;\|<\|>//g;s/=/:/g'

説明

sed を使って、文字列を加工します。

cannot find your hostname, [];<> を文字列から削除し、=: に置換。

オプション
-e script
実行するコマンドとして、script を追加する。
s/置換前/置換後/g で、文字列を置き換えています。; で区切ると複数のコマンドを指定出来ます。
結果
 xxx.xxx.148.89 from:ipjsmb@cjsl.com to:xxxxx@mydomain.jp proto:ESMTP helo:maux.com

 


sort

説明

ここでログのデータを一旦ソートします。グループ化するための準備なので、並び順は特に指定しません。

 


perl -anle 'print "$F[0]\t$F[2]\t\t$F[1]"'

説明

ソートされたログを perl で、IPアドレス to:アドレス from:アドレス のフィールドのみにする。

結果
xxx.xxx.148.89  to:xxxxx@mydomain.jp             from:ipjsmb@cjsl.com

 


uniq -c

説明

IPアドレス to:アドレス from:アドレス でグループ化してその行数をカウントし、列の最初に合計を付して返します。

オプション
-c
行の先頭に、重複していた行数を表示します。
結果

これは、この組み合わせが合計20行あったものが一行にまとめられて、行頭に合計が付されています。

20     xxx.xxx.148.89  to:xxxxx@mydomain.jp             from:ipjsmb@cjsl.com

 


sort -t$'\t' -k1nr

説明

最終的に、行数をキーにして降順 (多いもの順) で並べ替える。

オプション
-t$'\t'
区切り文字をタブとする
-k1
並べ替えのキーとなるフィールドは1番目のフィールド
-n
数値として並べ替えする
-r
降順で並べ替え

 


less

説明

最終結果をページャーで表示する。

この、less コマンドはあくまでも参考です。 | less の代わりに > filename.txt としてもいいですし、そのまま root 宛にメール送信しても構いません。

 

まとめ

このようにして、UNIX コマンドをいくつも組み合わせてワンライナーで処理をかけるのが、UNIXシェルの醍醐味だと思います。これをもしもWindowsでやろうと思えば、、と考えると嫌な気分になってきますね。

もしかすると、Windows の コマンドプロンプト (CMD) でも同じようなことが出来るかもしれませんし、Power Shell を使うともっと高度な事ができるのかもしれませんが、UNIXシェルほど気楽ではないでしょう。

UNIXシェルには先人の知恵がつまっている のです。

もしかすると同じ処理を全く別の方法で書けるかもしれません。

例えば、perl の代わりに awk を使うとか・・

あるいは全然別の組み合わせや、もしかすると perl だけで全て書けるかも・・。とにかく、UNIXシェルは 自由 なんです。

Let's enjoy UNIX!

 

 


  1. ワンライナーとは、特定の処理を一行のプログラムだけで実現するものです。 


 

 
Share this...

zaturendo

中小企業社内SE。

0件のコメント

コメントを残す

Avatar placeholder

メールアドレスが公開されることはありません。