hotshot# portinstall security/swatch [Gathering depends for security/swatch ................ done] ---> Installing 'swatch-3.2.3' from a port (security/swatch) ---> Building '/usr/ports/security/swatch'
/etc/rc.conf http://www.hodogaya.org/home-server/swatch-ipfw.html
swatch_enable="YES" swatch_rules="1" swatch_1_flags="--tail-file=/var/log/auth.log --awk-field-syntax --config-file=/usr/local/etc/swatchrc -r 00:01 --daemon" swatch_1_user="root" swatch_1_pidfile="/var/run/swatch1.pid"
↓
swatch_enable="YES" swatch_rules="1" swatch_1_flags="--tail-file=/var/log/maillog --awk-field-syntax --config-file=/usr/local/etc/swatchrc -r 00:01 --daemon" swatch_1_user="root" swatch_1_pidfile="/var/run/swatch1.pid"
/usr/local/etc/swatchrc
watchfor /Failed password for root from/ exec /sbin/ipfw add 1 deny all from $11:255.255.255.255 to any mail=root,subject=Failed_password_for_root_from
↓
watchfor /_DIE: Suicide in child_init_hook/ exec amavisd reload mail=root,subject=Amavisd-new reloaded!
swatch --tail-file=/var/log/maillog --awk-field-syntax --config-file=/usr/local/etc/swatchrc -r 00:01 --daemon
Apr 3 11:06:00 hotshot amavis[19297]: (!!)TROUBLE in child_init_hook: BDB no dbS: Lock table is out of available locker entries, . at (eval 97) line 27. Apr 3 11:06:00 hotshot amavis[19297]: (!)_DIE: Suicide in child_init_hook: BDB no dbS: Lock table is out of available locker entries, . at (eval 97) line 27. Apr 3 11:06:00 hotshot amavis[17631]: (17631-08) (!)TempDir removal: tempdir is to be PRESERVED: /var/amavis/tmp/amavis-20100403T080159-17631 Apr 3 11:06:05 hotshot postfix/smtp[19229]: 332485642D: to=<root@smb.net>, orig_to=<root>, relay=none, delay=0.05, delays=0.05/0/0/0, dsn=4.4.1, status=deferred (connect to 127.0.0.1[127.0.0.1]:10024: Connection refused) Apr 3 11:06:06 hotshot amavis[19207]: starting. /usr/local/sbin/amavisd at hotshot.smb.net amavisd-new-2.6.4 (20090625), Unicode aware Apr 3 11:06:06 hotshot amavis[19207]: Perl version 5.008009 Apr 3 11:06:06 hotshot postfix/pickup[19084]: 2F9C656428: uid=0 from=<root> Apr 3 11:06:06 hotshot postfix/cleanup[19202]: 2F9C656428: message-id=<20100403020606.2F9C656428@hotshot.smb.net> Apr 3 11:06:06 hotshot postfix/qmgr[1324]: 2F9C656428: from=<root@smb.net>, size=455, nrcpt=1 (queue active) Apr 3 11:06:06 hotshot postfix/smtp[19233]: connect to 127.0.0.1[127.0.0.1]:10024: Connection refused Apr 3 11:06:06 hotshot postfix/smtp[19233]: 2F9C656428: to=<root@smb.net>, orig_to=<root>, relay=none, delay=0.07, delays=0.07/0/0/0, dsn=4.4.1, status=deferred (connect to 127.0.0.1[127.0.0.1]:10024: Connection refused) Apr 3 11:06:06 hotshot amavis[19226]: starting. /usr/local/sbin/amavisd at hotshot.smb.net amavisd-new-2.6.4 (20090625), Unicode aware Apr 3 11:06:06 hotshot amavis[19226]: Perl version 5.008009 Apr 3 11:06:06 hotshot postfix/pickup[19084]: 8CEC056430: uid=0 from=<root> Apr 3 11:06:06 hotshot postfix/cleanup[19202]: 8CEC056430: message-id=<20100403020606.8CEC056430@hotshot.smb.net> Apr 3 11:06:06 hotshot postfix/qmgr[1324]: 8CEC056430: from=<root@smb.net>, size=455, nrcpt=1 (queue active) Apr 3 11:06:06 hotshot postfix/smtp[19241]: connect to 127.0.0.1[127.0.0.1]:10024: Connection refused Apr 3 11:06:06 hotshot postfix/smtp[19241]: 8CEC056430: to=<root@smb.net>, orig_to=<root>, relay=none, delay=0.09, delays=0.09/0/0/0, dsn=4.4.1, status=deferred (connect to 127.0.0.1[127.0.0.1]:10024: Connection refused) Apr 3 11:06:07 hotshot postfix/pickup[19084]: B440856424: uid=0 from=<root> Apr 3 11:06:07 hotshot postfix/cleanup[19202]: B440856424: message-id=<20100403020607.B440856424@hotshot.smb.net> Apr 3 11:06:07 hotshot postfix/qmgr[1324]: B440856424: from=<root@smb.net>, size=455, nrcpt=1 (queue active) Apr 3 11:06:07 hotshot postfix/smtp[19203]: connect to 127.0.0.1[127.0.0.1]:10024: Connection refused Apr 3 11:06:07 hotshot postfix/smtp[19203]: B440856424: to=<root@smb.net>, orig_to=<root>, relay=none, delay=0.55, delays=0.55/0/0/0, dsn=4.4.1, status=deferred (connect to 127.0.0.1[127.0.0.1]:10024: Connection refused)
!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
html lang="ja">
head>
<meta http-equiv="Content-Type" content="text/html;CHARSET=Shift_JIS"> <meta http-equiv="Content-Style-Type" content="text/css"> <meta http-equiv="Content-Script-Type" content="text/javascript"> <meta name="Author" content="Takeo Hashimoto"> <meta name="GENERATOR" content="nvi-m17n"> <link rel="shortcut icon" type="image/png" href="../../image/note.png"> <link rel="STYLESHEET" type="text/css" href="../../base.css"> <link rel="START PREFETCH" href="http://www5f.biglobe.ne.jp/~sempreff/index.html"> <link rev="MADE" href="mailto:sempreff@anet.ne.jp"> <title> -- Junky's Dive -- :: note :: FreeBSD :: ログトラップの仕込み</title>/head>
body>
div id="content">
div id="header">
div id="pagetitle">-- Junky's Dive -- 2nd movement.</div>
div id="houses" class="houseitem">
a href="http://www5f.biglobe.ne.jp/~sempreff/">本館</a> |
a href="http://d.hatena.ne.jp/sempreff/">別邸</a> |
a href="http://www2.tok2.com/home/takeo/">物置</a> |
a href="http://fortessimo.blogspot.com/">別荘</a> |
a href="http://my.opera.com/sempreff/albums/">画像</a>
/div> <!-- swell the height of header block. --></div>
div id="main"><div id="innermain"><!-- main contents starts here -->
h1>ログトラップの仕込み</h1>
p> あるログファイルに特定のパターンや特定の文言が出たら それをトラップして対応するアクションを行わせたい… というような仕組みを、 一般にそう言うかどうか知らないが、ログトラップと呼ぶことにする。
/p>
p> 出来合いのツールとしては swatch が定番である。 余裕があれば|面倒クサければ、自作してもよい。
/p>
p> どのようなツールを使うとしても、決めておくことは以下の通り。
/p>
ul>
li>監視対象ファイル
li>引っかけたい文字列
li>引っかけたあとの挙動
li>どのユーザで処理するか
/ul>
h2><a name="SWATCH" id="SWATCH">swatch の設定</a></h2>
p> 導入は依存モジュールの判断が面倒なので、ports から入れると楽だ。
/p>
pre class="sample">
# cd /usr/ports/security/swatch
# make install clean
/pre>
p> あとは上述の4項目を仕込んでいく。 「監視対象ファイル」と「どのユーザで処理するか」は /etc/rc.conf にて設定する。 ユーザは指定しなければ root となる。 指定する場合は、$HOME に .swatch_script.nnnnn というファイルができるので、 実在する HOME を持っているユーザを指定する必要がある。 つまり、nobody みたいな HOME が /nonexistent になっているユーザでは ちゃんと動かすことができない。 また、いちいち書かなくてもわかるだろうが、 対象ログファイルは該当ユーザが読み込める必要がある。 ログファイルの位置やユーザ (プロセス) によっては chroot してもよいだろう。 その他 rc の仕組みで動かすためのオプションを追加して、 /etc/rc.conf への仕込みは最終的に以下のようになる。
/p>
pre class="sample"> swatch_enable="YES" swatch_rules="1" swatch_1_flags="--config-file=/usr/local/etc/swatch1.conf --tail-file=/var/log/ messages --daemon --pid-file=/var/run/swatch1.pid" swatch_1_pidfile="/var/run/swatch1.pid"
#swatch_1_user="nobody"
#swatch_1_chdir="/var/tmp"
/pre>
p> 複数の監視を行う場合は、swatch_rules を増やしてあげて、 対応する flags や pidfile を定義してあげればよい。
/p>
p> 残った二つの項目「引っかけたい文字列」と「引っかけたあとの挙動」は それぞれ別のファイルで指定する。 それは --config-file にて指定する。 上記例の場合は /usr/local/etc/swatch1.conf である。 このファイルは、以下のようにパターンと挙動を定義する。
/p>
pre class="sample"> watchfor /PATTERN TO PICK/ exec "/usr/local/bin/counterAction.sh $_"
/pre>
p> watchfor でパターンを、exec でアクションを指定するわけだ。 アクションの引数となっている「$_」には引っかかった行がそのまま渡されるので 「(」やその他の シェル構文にとって特殊な文字はまともに渡せないので注意するべし。
/p>
p> ここまで設定できれば あとは /usr/local/etc/rc.d/swatch.sh で起動してやればよい。 だが、困ったことに swatch は停止時にちゃんと停止できないケースがある。 これを回避するには (乱暴だが) sig_stop を SIGKILL で上書きしてしまえばよい。 どう乱暴かと言うと、該当ユーザの HOME にできる .swatch_script.nnnnn が 停止時に消されずに残ってしまうのだ。これは溜ったら日付を見て手動で消すしかない。
/p>
pre class="sample"> : load_rc_config ${name}
sig_stop=SIGKILL
if [ -n "${swatch_rules}" ]; then :
/pre>
p> 起動されるアクションは実行できれば何でもよい。 メイルを送るなり設定ファイルを書き換えてサービスを再起動するなり 何でも好きなように書けばよい。
/p>
p> まとめると、以下のように指定することになる。
/p>
ul>
li>監視対象ファイル → /etc/rc.conf の swatch_n_flags の --tail-file
li>引っかけたい文字列 → config ファイルの watchfor 行
li>引っかけたあとの挙動 → config ファイルの exec 行
li>どのユーザで処理するか → /etc/rc.conf の swatch_n_user
/ul>
h2><a name="SCRIPT" id="SCRIPT">スクリプトで自作する場合</a></h2>
p> swatch のような出来合いのツールは確かに便利だが、 仕掛けが大きいので、ちょっと躊躇するかもしれない。そういう場合は、 /usr/bin/tail や GNU tail などを用いてスクリプトを自作してしまえばよい。
/p>
p> FreeBSD の /usr/bin/tail は -F filename を指定することで ファイルの名前変更やローテートを追跡することができる。
/p>
p> スクリプトの例は以下の通り。
/p>
pre class="sample">
#!/bin/sh
#
# tail を用いた簡易ログトラップスクリプト。
#
# http://moko.cry.jp:3232/~keiji/linux/doc/easylogview.rhtml
# を元に改変したもの
#
PATH="/bin:/usr/bin:/usr/local/bin" # その他必要な PATH を指定するべし export PATH
LOGFILE="/var/log/messages" # 監視対象ログファイル PATTERN="pattern" # grep 抽出のパターン ACTION="/usr/local/bin/counterAction.sh" # ヒット時のアクション
# tail -n 1 --follow=name $FILE | while read INPUT; do # GNU tail の場合 tail -n 0 -F $LOGFILE | while read line; do
if echo "$line" | egrep -e "$PATTERN" > /dev/null 2>&1; then $ACTION "$line" fi
done
/pre>
p> 見て判る通り、 単純に tail の出力を while で受けて一行づつ grep しているだけである。 起動時にはこのスクリプトをバックグラウンドで実行させればよいし、 停止させるには tail を kill すれば止まる。
/p>
p> 「どのユーザで処理するか」は実行時のユーザに依存するよう逃げてしまっているので 設定は「監視対象ファイル」「パターン」「アクション」の三つだけである。 このサンプルスクリプトではそこまで踏み込んでいないが、 この三つの設定を別ファイルにして引数で指定するようにすれば、 複数のログファイル監視も簡単に実現できる。
/p>
h2><a name="TEST" id="TEST">挙動の確認</a></h2>
p> swatch を用いるにしろ自作スクリプトを用いるにしろ、 ログトラップのような運用にかかる仕込みはテストが大事である。 少なくとも以下の点を注意してテストする。
/p>
ul>
li>正しく起動・停止できるか。人間系が絡む場合はちゃんと文書化されているか。
li>パターンに正規表現を用いる場合、マッチに過不足がないか。
li>ログファイルがローテートされる場合、ちゃんと追跡されるか。
li>ログファイルが cat /dev/null などでクリアされる場合、ちゃんと追跡されるか。
/ul>
hr>
p> 参考サイト:
/p>
ul>
li><a class="outgoing" href="http://www.hijiki.net/archives/000102.html"> 自宅サーバ雑記帳: FreeBSD on swatchでログ監視</a>
li><a class="outgoing" href="http://d-net.robata.org/IDS/log_check.html"> (IDS)ログ解析方法</a>
li><a class="outgoing" href="http://d.hatena.ne.jp/stereocat/searchdiary?word=*%5Bsoft%5D"> 猫が逃げ惑う日記</a>
li><a class="outgoing" href="http://safe-linux.homeip.net/security/linux-swatch-02.html"> ログ自動監視ツールSwatchの設定</a>
li><a class="outgoing" href="http://moko.cry.jp:3232/~keiji/linux/doc/easylogview.rhtml"> シェルスクリプトで作る簡単なログ監視スクリプト</a>
/ul>
!-- main contents ends here --></div></div>
div id="side"><div class="innerside">
div class="sideitem"><ul class="menu">
li><a href="../../index.html">歓迎</a></li>
li><a href="../../ThinkPad/">交際</a></li>
li class="selected"><a href="../">メモ</a></li>
li><a href="../../script/">小物</a></li>
li><a href="../../link/">外海</a></li>
/ul>
/div></div>
div class="innerside">
div class="sideitem"><ul class="menu">
li class="selected"><a href="../FreeBSD/">FreeBSD</a></li>
li><a href="../AIX/">AIX</a></li>
li><a href="../X11/">X11</a></li>
li><a href="../Palm/">Palm</a></li>
li><a href="../Zaurus/">Zaurus</a></li>
li><a href="../Java/">Java</a></li>
li><a href="../Windows/">Windows</a></li>
/ul>
/div>
/div></div>
div id="footer1">[$Revision: 1.2 $ $Date: 2009.02.17 12:11:57 $]</div>
div id="footer2">[EOF]</div>
/div><!-- end of footer -->
/body>
/html>