![CentOSicon](https://stat.ameba.jp/user_images/20130817/09/yukisku/4a/ee/p/t00630060_0063006012650754789.png?caw=800)
(H26.6.15追記)その後まだ問題があったので、新しくスクリプトを書き直しました。その記事はこちら。
以前swatch_action.shを改造したものの、まだ動作に問題があるようだったので再度改造に取り組んだ。ざっくり症状を言うと、IPアドレスをうまく取得してくれない、というもの。
問題があったのは以下の例、maillog中の認証失敗ログ。
warning: 11.22.aaa.com[111.111.22.11]: SASL LOGIN authentication failed: authentication failure
「authentication failed」の文字列で監視設定していた場合、上記のログが記述されるとswatch_action.shが実行される。
swatch_action.shのスクリプトでは、ログからIPアドレス部分だけを抜き出すようになっている。しかし上記のような記述があった場合、抜き出したいIPは本来「111.111.22.11」だが、「11.22.aaa.com[111.111.22.11」の部分が抜き出されてその後の処理がされてしまい、目的とするIPにブロックがかからない。今まではIPを抜き出すスクリプトは以下のもので行っていた。
# ログからIPアドレスを抽出
IPADDR=`echo $LOG|cut -d " " -f $1`
echo "$IPADDR"|grep "^[0-9]*\." > /dev/null 2>&1
if [ $? -eq 0 ]; then
# IPアドレスから始まる場合
IPADDR=`echo "$IPADDR"|sed -e 's/\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' -e d`
else
# IPアドレス以外から始まる場合
IPADDR=`echo "$IPADDR"|sed -e 's/.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' -e d`
fi
IPADDR=`echo $LOG|cut -d " " -f $1`
echo "$IPADDR"|grep "^[0-9]*\." > /dev/null 2>&1
if [ $? -eq 0 ]; then
# IPアドレスから始まる場合
IPADDR=`echo "$IPADDR"|sed -e 's/\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' -e d`
else
# IPアドレス以外から始まる場合
IPADDR=`echo "$IPADDR"|sed -e 's/.*[^0-9]\([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*\).*/\1/p' -e d`
fi
上記のスクリプトでは、数値から始まる単語をIPアドレスとして処理するため、数値の後に文字列が入る単語、今回の例のようなログからはIPアドレスが取得できない。そこで取得方法を以下のように変更した。
# ログからIPアドレスを抽出
IPADDR=`echo $LOG | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
IPADDR=`echo $LOG | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
grepのoオプションはマッチした部分だけを取り出すので、ログ中の4つの1~3ケタの数字がドット3つで区切られている文字列が取り出される。
ただし、この方法でも問題は残る。たとえば「567.789.123.456」といった明らかにIPアドレスではないものもマッチしてしまう。今のところ問題ないので、しばらくこれで様子を見ることにする。
今回記述したswatch_action.sh全文は以下。メール通知機能はメール件数がとんでもない事になるので削除している。
#!/bin/bash
PATH=/bin:/sbin:/usr/bin
LANG=C
# ログを標準入力から取得
read LOG
# ログからIPアドレスを抽出
IPADDR=`echo $LOG | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
# IPアドレスが取得できなかった場合は誤一致したログを出力して終了
if [ "$IPADDR" = "" ]; then
echo "$LOG" >> /var/log/swatch/IPerr.log
exit
else
# IPアドレスが取得できた場合の処理はここから
# IPアドレスをピリオドで分割
addr1=`echo $IPADDR|cut -d . -f 1`
addr2=`echo $IPADDR|cut -d . -f 2`
addr3=`echo $IPADDR|cut -d . -f 3`
addr4=`echo $IPADDR|cut -d . -f 4`
# IPアドレスがプライベートIPアドレスの場合は終了
if [ "$IPADDR" = "127.0.0.1" ]; then
exit
elif [ "$addr1" = "10" ]; then
exit
elif [ "$addr1" = "172" ] && [ $addr2 -ge 16 ] && [ $addr2 -le 31 ]; then
exit
elif [ "$addr1" = "192" ] && [ "$addr2" = "168" ]; then
exit
fi
# 不正アクセスログメッセージをIPアドレス別ログファイルに記録
echo "$LOG" >> /var/log/swatch/"$IPADDR"
# IPアドレス別ログファイルから累積不正アクセス数(ログ行数)取得
cnt=`cat /var/log/swatch/$IPADDR | wc -l`
# 該当IPアドレスからの累積不正アクセス数が3以上の場合または
# 引数でlockと指定された場合アクセス規制
if [ $cnt -ge 3 ] || [ $# -eq 2 -a "$2" = "lock" ]; then
# 該当IPアドレスからのアクセスを拒否するルールを挿入
iptables -I INPUT -s $IPADDR -j DROP
# 上記ルールを24時間後に削除するスケジュールを登録
echo "iptables -D INPUT -s $IPADDR -j DROP > /dev/null 2>&1" | \
at now+24hour > /dev/null 2>&1
echo "`date` $IPADDR $cnt lock!"
else
echo "`date` $IPADDR $cnt"
fi
fi
PATH=/bin:/sbin:/usr/bin
LANG=C
# ログを標準入力から取得
read LOG
# ログからIPアドレスを抽出
IPADDR=`echo $LOG | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
# IPアドレスが取得できなかった場合は誤一致したログを出力して終了
if [ "$IPADDR" = "" ]; then
echo "$LOG" >> /var/log/swatch/IPerr.log
exit
else
# IPアドレスが取得できた場合の処理はここから
# IPアドレスをピリオドで分割
addr1=`echo $IPADDR|cut -d . -f 1`
addr2=`echo $IPADDR|cut -d . -f 2`
addr3=`echo $IPADDR|cut -d . -f 3`
addr4=`echo $IPADDR|cut -d . -f 4`
# IPアドレスがプライベートIPアドレスの場合は終了
if [ "$IPADDR" = "127.0.0.1" ]; then
exit
elif [ "$addr1" = "10" ]; then
exit
elif [ "$addr1" = "172" ] && [ $addr2 -ge 16 ] && [ $addr2 -le 31 ]; then
exit
elif [ "$addr1" = "192" ] && [ "$addr2" = "168" ]; then
exit
fi
# 不正アクセスログメッセージをIPアドレス別ログファイルに記録
echo "$LOG" >> /var/log/swatch/"$IPADDR"
# IPアドレス別ログファイルから累積不正アクセス数(ログ行数)取得
cnt=`cat /var/log/swatch/$IPADDR | wc -l`
# 該当IPアドレスからの累積不正アクセス数が3以上の場合または
# 引数でlockと指定された場合アクセス規制
if [ $cnt -ge 3 ] || [ $# -eq 2 -a "$2" = "lock" ]; then
# 該当IPアドレスからのアクセスを拒否するルールを挿入
iptables -I INPUT -s $IPADDR -j DROP
# 上記ルールを24時間後に削除するスケジュールを登録
echo "iptables -D INPUT -s $IPADDR -j DROP > /dev/null 2>&1" | \
at now+24hour > /dev/null 2>&1
echo "`date` $IPADDR $cnt lock!"
else
echo "`date` $IPADDR $cnt"
fi
fi