• Apacheのアクセスログから不審なエラーを選び
  • アクセス元を調べ
  • ログに出力する

というスクリプト。新サーバでも使っていましたが、終了の運びとなりました。

スクリプト内容

#!/bin/bash

# 変数定義
LOG_DIR="/var/log/bookstack"
ERROR_LOG="$LOG_DIR/bs_error.log"
COUNTRY_LIST="//home/hoge/script/config/country_list.csv"
OUTPUT_DIR="/home/hoge/script/log/blocked_list"
DATE=$(date +%Y%m%d)
LIST_FILE="$OUTPUT_DIR/ip.$DATE.csv"
RESULT_FILE="$OUTPUT_DIR/ip_list.$DATE.csv"
CRON_MODE=true  # cron処理の場合はtrue、標準出力に残す場合はfalse

cd $LOG_DIR

# error.logからIPアドレスだけを抜き出します
awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' $ERROR_LOG | sort > $LIST_FILE

# ip.YYYYMMDD.csvファイルがない場合にエラーを返します
if [ ! -f $LIST_FILE ]; then
echo "ファイル $LIST_FILE が存在しないので終了します。"
exit 1
fi

# 国コード,国の名前が書かれたcountry_list.csvがない場合にエラーを返します
if [ ! -f $COUNTRY_LIST ]; then
echo "ファイル $COUNTRY_LIST が存在しないので終了します。"
exit 1
fi

# IPアドレスに国名を付与したファイルを定義します。(ip_list.YYYYMMDD.csv)
> $RESULT_FILE

while read -r line; do
# IPアドレスを逆順に並び替えます。(例: 1.2.3.4 → 4.3.2.1)
ip_revers=$(echo "$line" | awk -F'.' '{print $4"."$3"."$2"."$1}')
# 並び替えたIPアドレスをcc.wariate.jpに並び替えて、国コードを抜き出します。(JP,CH,ESなど)
country_code=$(nslookup -type=TXT ${ip_revers}.cc.wariate.jp | grep '"' | awk -F'"' '{print $2}')
# 国コードをcountry_list.csvから参照して国名を抜き出します。
country_name=$(grep "$country_code" $COUNTRY_LIST | cut -d"," -f2)

# 標準出力に返す処理を行います。cron処理する場合はコメントアウトします。
if [ "$CRON_MODE" = false ]; then
echo "${line},${country_name}"
fi

# IPアドレス,国名の形式にして同ディレクトリのip_list.YYYYMMDD.csvに保存します
echo "${line},${country_name}" >> $RESULT_FILE
sleep 1
done < $LIST_FILE

# ip_list.csv.YYYYMMDDを読み込んで、IPアドレスをキー、国を値とする連想配列を作成します
declare -A countries
while read -r line; do
# CSVの1列目をIPアドレス、2列目を国とします
ip=$(echo $line | cut -d',' -f1)
country=$(echo $line | cut -d',' -f2)
# 連想配列に格納します
countries[$ip]=$country
done < $RESULT_FILE

# 結果を格納するための変数を定義します
result=""

# 連想配列を反復処理します
for ip in "${!countries[@]}"; do
# 各IPアドレスの件数を数えます
count=$(grep -c $ip $RESULT_FILE)
# 件数、IPアドレス、国をカンマ区切りで結合します
line="$count,$ip,${countries[$ip]}"
# 結果に追加します
result="$result\n$line"
done

# カウントした結果をcounted_ip.YYYYMMDD.csvに出力します
COUNTED_FILE="$OUTPUT_DIR/counted_ip.$DATE.csv"
echo -e $result > $COUNTED_FILE

# 最終結果をsorted_ip.$DATE.csvに出力します
SORTED_FILE="$OUTPUT_DIR/sorted_ip.$DATE.csv"
cat $COUNTED_FILE | LC_ALL=C sort -n -r > $SORTED_FILE

# 最終結果以外のログファイルを削除します
rm $LIST_FILE
rm $RESULT_FILE
rm $COUNTED_FILE

exit 0

このスクリプト、最初、それこそ日に10件もあればいい時代の頃に作ったモノで、Cron処理を行っていました。

しかし、アクセス数が(特にクローラーで)圧倒的になった今、このスクリプトは

  • for / whileの多様
  • 逐次nslookup
  • さらに連想配列による処理 

が重なり、ただのスワップ喰い虫となっていたのです。

  • 今は別手段により不審なアクセスを弾いていること
  • サーバの容量節約

のため、こちらは停止の運び。

2年以上にわたってよくぞここまで運用してくれたという感じです。