ものすごく以前の記事で、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. ワンライナーとは、特定の処理を一行のプログラムだけで実現するものです。 


 
記事を共有する

0件のコメント

コメントを残す

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