iptablesのパケットログをPostgreSQLに保存したい。何を唐突に変な事を言い出すかと思うなかれ。絶対に需要はあるはずだ(無いかも)。

ちらっとぐぐってみるとCentOS6のiptables 1.4.7にはNFLOGという仕組みがあって、さらにnetfilter.orgで提供しているulogdなるものを使うとiptablesからのログを受け取ってPostgreSQLに吐き出せるらしい。
さっそく試してみる。なお、以下の例では全て/usr/localに入るので/usr以下にあるのが良い場合はconfigureの引数を適時変更されたい。

# wget ftp://ftp.netfilter.org/pub/ulogd/ulogd-1.24.tar.bz2
# wget ftp://ftp.netfilter.org/pub/ulogd/ulogd-2.0.2.tar.bz2
# wget ftp://ftp.netfilter.org/pub/libmnl/libmnl-1.0.3.tar.bz2
# wget ftp://ftp.netfilter.org/pub/libnetfilter_acct/libnetfilter_acct-1.0.2.tar.bz2
# wget ftp://ftp.netfilter.org/pub/libnetfilter_conntrack/libnetfilter_conntrack-1.0.3.tar.bz2
# wget ftp://ftp.netfilter.org/pub/libnetfilter_log/libnetfilter_log-1.0.1.tar.bz2
# wget ftp://ftp.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.1.tar.bz2

とりあえず以上のものが要るっぽい。上のFTPサイトにはlibnetfilter_queueとかもあったけどulogd-2.0.2のビルド時に要求されなかったため取ってこなかった。ulogd-1.24は、initスクリプトの雛形が2.0.2に無かったのでここから取るために取ってきた。無くても良い。

# tar xjf libmnl-1.0.3.tar.bz2 -C /usr/local/src
# tar xjf libnetfilter_acct-1.0.2.tar.bz2 -C /usr/local/src
# tar xjf libnetfilter_conntrack-1.0.3.tar.bz2 -C /usr/local/src
# tar xjf libnetfilter_log-1.0.1.tar.bz2 -C /usr/local/src
# tar xjf libnfnetlink-1.0.1.tar.bz2 -C /usr/local/src
# tar xjf ulogd-1.24.tar.bz2 -C /usr/local/src
# tar xjf ulogd-2.0.2.tar.bz2 -C /usr/local/src

構築環境はx86_64なのでソースからビルドするライブラリ達は/usr/local/lib64に入って欲しい。configureオプションをつける。i686環境の場合または別にlibに入ってもいい場合はこのオプションは不要。

# export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig
# cd /usr/local/src/libnfnetlink-1.0.1
# ./configure --libdir=/usr/local/lib64
# make install

ライブラリは全部上のような感じ。libnfnetlinkが色々依存されてるので最初にビルドする。ところで、CentOS6提供のmysqlパッケージがある状態でulogd-2.0.2をconfigureするとMySQL plugin: yesとなるくせにmakeするとエラーになりやがる。configureのオプションに–without-mysqlを指定する。MySQLプラグインを使う場合はmysql-develを入れるとmakeも通るようになるようだ。後、PostgreSQLを使うのでpostgresql-develとpostgresql-serverをyumで入れる。

# yum postgresql-devel postgresql-server
# cd /usr/local/src/ulogd-2.0.2
# ./configure --libdir=/usr/local/lib64 --without-mysql
# make install

さて、お次は設定ファイルをコピーして手直しする。/usr/local/etcに生ファイルを置きたくないので/etcに置いてリンクを張ることにする。

# cp ulogd.conf /etc
# cd /usr/local/etc
# ln -s /etc/ulogd.conf .

もちろんconfigureで–sysconfdir=/etcとして/etc/ulogd.confを参照するようにしても良い。そっちの方がすっきりするかも知れない。ulogd.confは

#plugin="/usr/local/lib64/ulogd/ulogd_output_PGSQL.so"

#stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,mac2str1:HWHDR,pgsql1:PGSQL

という2行のコメントを外すととりあえずは動く。下の方の

[pgsql1]
db="nulog"
host="localhost"
user="nupik"
table="ulog"
#schema="public"
pass="changeme"
procedure="INSERT_PACKET_FULL"

というところに合わせてPostgreSQLの環境を直す。pg_hba.confでlocalhost(IPv6が有効になっている場合は::1のnulog)への接続を有効にした後、nupikユーザを作り、そやつをオーナーにnulogデータベースを作成する。
nulogデータベースでcreate language plpgsqlを実行した後で/usr/local/src/ulogd-2.0.2/doc/pgsql-ulogd2.sqlを流す。これで準備はOK。動作テストは

# /usr/local/sbin/ulogd -v

で動かせるのでここでstartingの状態になればとりあえずは動いている事になる。先ほど有効にしたstack=log2は[log2]セクションでグループが1という事になっているので、iptablesでは以下のように設定する。

# iptables -t nat -I POSTGROUTING -s 192.168.1.0/24 -j NFLOG --nflog-group 1

これで、POSTROUTINGチェインを通り配送元が192.168.1.0/24であるパケットがPostgreSQLのnlog2というテーブルとtcpなどのテーブルに入る。今回はnlog2テーブルの内容だけ欲しいのでINSERT_PACKET_FULLというプロシージャーでINSERT_TCP_FULLなどを呼び出しているところを削ってしまった。

以上で、iptablesのログを時刻とともにデータベースに保存する事ができるようになった。後はinitスクリプトである。ulogd-1.24のulogd.initを/etc/init.d/ulogdとしてコピーし、ちょっと手直し。スクリプトの先頭でLD_LIBRARY_PATH=/usr/local/lib64するのと、実行ファイルが/usr/sbin/ulogdになっているので/usr/local/sbin/ulogdに変更する。LD_LIBRARY_PATHは/etc/ld.so.conf.d/に/usr/local/lib64という行が入ったlocal.confなどを作ってldconfigしても良い。
もちろん、POSTROUTINGのためにはipv4転送とかの設定も要るのでそちらも適切に設定を。ついでに、先ほどのulogd.confでは/var/log/ulogd.logというファイルが出力されるので、logrotateの設定も行っておくと良い。