ものすごく以前の記事で、Postfix が吐き出すメールログ ( mail.log ) に、”cannot find your hostname.” というログが残ることがある、と書いたことがあります。
Cannot find your hostname という病
このログの意味するところは、送信元のメール送信サーバー (MTA) の IPアドレスをの DNS の逆引きで名前解決できない場合に、接続要求を出してきた MTA に Reject (接続拒否) を返した時に残されるログです。
これは、Postfix の設定ファイル、/etc/postfix/main.cf
の smtpd_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'
に渡しています。
zgrep
は gzip
や compress
で圧縮されたファイルから正規表現等を使って検索します。ただ、このコマンドは圧縮されていない通常のファイル にも使用できる便利なコマンドです。
結果
ここまでで、過去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!
-
ワンライナーとは、特定の処理を一行のプログラムだけで実現するものです。 ↩
0件のコメント