パケットをキャプチャした結果を日付別に分類・圧縮するシェルスクリプト
書いた。初めてシェルスクリプトを1から書いた。割と大変だった。要tcpdump。
2009/6/16 23:55 追記
ブクマが付いてて驚いた。自分用だからいいやとてきとーに書いたのを後悔。いくつかバグを修正しました。あとちょっとした説明を書いてみた。
ディレクトリ構成
.
-- capture.sh (シェルスクリプト) |
-- filter.txt (パケットフィルタリングの条件を書いて置く) |
-- nohup.out (シェルスクリプトの標準出力が保存される。自動的に生成される) |
こんな感じでログが保存されていきます。毎日日付が変わると,その日のログ用のディレクトリが作成され,新しいログはそこに保存されるようになります。
上の図は,6/17になった直後のディレクトリ構造を表していて,このあと20090616.tar.bz2が自動的に生成され,ディレクトリ20090616は削除されます。この圧縮処理ですが,1日分のログが数GBあるので結構時間がかかります。本当は日付が変わった直後じゃなくて人気が無くなる午前4時くらいにやった方がよいのかも。
ちなみにパケットのログは同じ文字列の繰り返しが多いためか,圧縮すると結構容量は小さくなります (1.5GB→431MB, 2.4GB→601MBで大体4倍の圧縮率)。
ソースコード
#!/bin/bash message() { echo "$(date +'%Y-%m-%d %T') " $@ } touch_dir() { if [ ! -d $1 ] then message "create_dir $1" mkdir $1 fi } log_dir="packet" touch_dir $log_dir set_dir() { dir_name="$(date +%Y%m%d)" dir_path="$log_dir/$dir_name" } kill_proc() { message "kill process [$prev_ps]" if [ $1 != -1 ] && kill -0 $1 2> /dev/null then kill -s TERM $1 wait $1 message "terminate process [$1]" else message "process [$1] is already terminated" fi } when_term() { kill_proc $prev_ps kill_proc $running_ps message "exit" } running_ps=-1 running_dir="" running_path="" trap 'when_term' CHLD INT TERM while : do set_dir # wait until dir_name is change until [ $dir_name != "$running_dir" ] do sleep 1m set_dir done # start new process with new dir_name prev_ps=$running_ps prev_dir=$running_dir prev_path=$running_path touch_dir $dir_path rename .log .old.log $dir_path/* message "start new process [dir: $dir_name]" /usr/sbin/tcpdump -F"filter.txt" -X -s 200 -i eth0 2> $dir_path/packet_message.log | split -C 10485760 -a 3 -d - $dir_path/packet.log. & running_ps=$! running_dir=$dir_name running_path=$dir_path message "running [$running_ps]" # kill previous process if it exists if [ $prev_ps -ne -1 ] then kill_proc $prev_ps # archive previous logs message "archive old [$prev_dir]" tar jcf "$log_dir/$prev_dir.tar.bz2" $prev_path # delete previous logs rm -rf "$prev_path" fi done
以下のように実行する。
# nohup ./capture.sh &
このシェルスクリプトは意図的に終了させない限り動き続けます。終了させるときはプロセス番号を探してきて,kill $process_number してください。
バグとか
TERMのシグナルを受け取ると,子プロセスを終了し,メッセージを出力してからスクリプト本体が終了する,なんて風に書いたつもりなんですが,メッセージがなぜか出力されません。子プロセスはきちんと終了できているみたいです。nohupをつかって起動させている関係なのかもしれませんがよくわかりません。つかデバッグが難しくて原因が特定できません。まあ基本的に連続稼働させるものでkillするのはスクリプトを書き換えた時ぐらいなのであまり問題にはならないかと思います。