経緯
自前プログラムで特定のポートを開いて待ち受けている仕掛けを稼働させているのですが、今度はこのポートがきちんと開いているかどうかを確認したくなりました。
そこで以下の内容を考えました。
- 10分おきに
cron
でシェルスクリプトを実行。lsof
コマンドで特定ポート (今回は3102
) が開いているかをチェック。- ポートが開いていない場合は警告メールを送信する。
- 上述とは別に一定時間おき( 3:10 と 10:02 )に同じシェルスクリプトを実行。
- 正常の場合に定期レポートを送信する。
- とりあえず動けば良いので日本語(文字コードやマルチバイト文字)の問題は考えないものとする。
成果物
早速ですが成果物を。
#!/bin/sh
# constants: port number
THREE=3
A=10
TWO=2
## 3102
PORT="$THREE$A$TWO"
# variables: time
HOUR=`TZ='Asia/Tokyo' date '+%-H'`
MINUTES=`TZ='Asia/Tokyo' date '+%-M'`
# constants: mail
FROM=johndoe@example.jp
TO=janedoe@example.jp
# main process
if [[ "$(uname -n):$PORT" == "$(lsof -i:$PORT|awk '{print $NF}'|grep "$PORT")" ]];then
if [ "$THREE" = "$HOUR" -a "$A" = "$MINUTES" ] || [ "$A" = "$HOUR" -a "$TWO" = "$MINUTES" ] ;then
sendmail -f $FROM -t <<EOL
From: <$FROM>
To: <$TO>
Subject: [SATORI] Regular Report
This email is a regular report.
EOL
fi
else
sendmail -f $FROM -t <<EOL
From: <$FROM>
To: <$TO>
Subject: [KOISHI] REQUIRE ACTION TO OPEN PORT
PLEASE TAKE ACTION TO OPEN PORT:$PORT ASAP!
EOL
fi
本当に最小限を最短で実装するため愚直な書き方をしています。ベッタベタにハードコーディングしていますし。
if [[ "$(uname -n):$PORT" == "$(lsof -i:$PORT|awk '{print $NF}'|grep "$PORT")" ]];then
肝はこの if
文ですね。
- 右辺を
lsof -i:{ポート番号}
にawk
やgrep
で絞り込みをして、{ホスト名}:{ポート番号}
の文字列のみになるように調整 - これと左辺の
uname -n
で出力されるホスト名にコロンとポート番号を繋いだ文字列が - 同値になるかどうか
で判定しています。
メール送信は sendmail -f $FROM -t ...
と、 sendmail
コマンドで Envelope From を -f
オプションで書き換えて送信しています。
他は細々と条件や時・分のみを現在時刻から抽出して比較したりして定期レポートを送信するかどうか判定する、という感じです。
やや古めの環境想定なのであえて -a
を使っています。
参考
lsof
sendmail
- シェルスクリプトでメール送信、「さようならnkf」編 #ShellScript – Qiita
- ヘタレログ: sendmailコマンドでEnvelope Fromを変更する方法
- テストメールの送信方法 #Linux – Qiita