とあるサーバから、あるサーバに接続したとき、あるサーバに残るアクセスログの接続元 IP アドレスをラウンドロビン的に変更することが必要になったので調査してみた。そうすると、iptables を使うとできるというまさにぴったりの記事を発見した。
さっそく、CentOS で試してみると、iptables の libipt_statistic モジュールがないというエラーになってしまった。次に RedHat のページを調べていると、Bug 215361 – iptables is missing /lib/iptables/libipt_statistic.so というまさにぴったりな情報が見つかった。その情報では、iptables バージョン 1.3.6 から追加されたとあったので、さっそく netfilter iptables バージョン 1.3.6 のページの変更点を調べてみると、たしかに次のような記載があった。
- Add support for statistic match (needs kernel >= 2.6.18)
[ Patrick McHardy ]
CentOS 5.3 x86_64 の iptables のバージョンは、iptables-1.3.5-4.el5 なので一つバージョンが古いのが原因のようだ。Linux カーネル 2.6.18 が必須とのことなので、CentOS でもおそらく使えるそうだ。
さっそく、iptables バージョン 1.3.6 を導入するために、RPM を作成にとりかかった。
まず、iptables-1.3.5-4.el5 の SRPM をダウンロードして、このバージョンの iptables.spec ファイルをパッチなどはすべて正しくあてるように、かつ libipt_statistic をビルドして組み込むように RPM を作成した。
libipt_statistic は、iptables バージョン 1.4.0 以降から標準で組み込まれるようになっているが、バージョン 1.3.6 では標準では組み込まれない。ちょうど、該当のコミットログがあったので、コミットログを参照しながら RPM を作成した。
作成した RPM は、ここにアップロードしてある。あわせて、SRPM もアップロードした。他に作った人がいないかも調べてみたが、見つからなかった。
iptables を現時点での最新版であるバージョン 1.4.6 ではなく、バージョン 1.3.6 にしようとした理由は RPM のおそらくメジャーアップグレードになるので RPM の作成が大変であること、安定性の面で経験がまったくないのでなるべる標準にインストールされるバージョンに近いものにしたいと思ったからだ。
作成した RPM で、CentOS にインストールされている既存の iptables をバージョンアップして、さっそく試してみた。
まず、外側のネットワークのデバイスに IP エイリアスを設定する。次の例は、ifconfig eth0 の出力結果だが、不要な情報は省いてある。
eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.161.125 Bcast:192.168.161.255 Mask:255.255.255.0
eth0:0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.161.124 Bcast:192.168.161.255 Mask:255.255.255.0
eth0:1 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.161.123 Bcast:192.168.161.255 Mask:255.255.255.0
eth0:2 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.161.122 Bcast:192.168.161.255 Mask:255.255.255.0
次の iptables の設定で NAT チェインを、次のように設定する。(スマイルアイコン対策のため、PREGROUTING と POSTROUTING の前のセミコロンは省いてある)
*nat
PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 4 -j SNAT –to-source 192.168.161.125
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 4 -j SNAT –to-source 192.168.161.124
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 4 -j SNAT –to-source 192.168.161.123
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 4 -j SNAT –to-source 192.168.161.122
COMMIT
iptables を再起動して、さっそく接続先のサーバに Apache HTTPD を起動して、アクセスログを確認してみると、次のような結果になった。
192.168.161.125 – - [11/Feb/2010:23:17:07 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.124 – - [11/Feb/2010:23:17:08 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.123 – - [11/Feb/2010:23:17:09 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.122 – - [11/Feb/2010:23:17:09 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:17:10 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:17:11 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.124 – - [11/Feb/2010:23:17:12 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:17:13 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:17:14 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.123 – - [11/Feb/2010:23:17:14 +0900] “GET / HTTP/1.1″ 200 44
完全にはラウンドロビンにはなっていないが、リクエストごとにアクセス元の IP アドレスが毎回変更されている。
最後に libipt_statistic のモジュールとはどんなモジュールかソースコードを読んでみた。libipt_statistic モジュールとは、ある状態になっているかを調べることができるモジュールのようである。
設定内容は、次のような設定が可能。
–mode mode: マッチモード (random あるいは nth)
–probability p: 確立
–everyn: n 番目のパケットに毎回マッチする
–packet p: 初期値のカウント値(p は、0 以上 p – 1 以下)、デフォルトは 0
どうやらこのモジュールは、ある状態ごとに iptables の設定を変更できるモジュールのようだ。
いろいろと試した結果、完全なラウンドロビンにするには、次のような設定でいけるようだ。(スマイルアイコン対策のため、PREGROUTING と POSTROUTING の前のセミコロンは省いてある)
*nat
PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 4 -j SNAT –to-source 192.168.161.125
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 3 -j SNAT –to-source 192.168.161.124
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 2 -j SNAT –to-source 192.168.161.123
-A POSTROUTING -o eth0 -p tcp –dport 80 -m statistic –mode nth –every 1 -j SNAT –to-source 192.168.161.122
COMMIT
上の設定のときの Apache アクセスログは、次のようになった。
192.168.161.122 – - [11/Feb/2010:23:27:29 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:27:30 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.124 – - [11/Feb/2010:23:27:31 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.123 – - [11/Feb/2010:23:27:32 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.122 – - [11/Feb/2010:23:27:32 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:27:33 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.124 – - [11/Feb/2010:23:27:34 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.123 – - [11/Feb/2010:23:27:34 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.122 – - [11/Feb/2010:23:27:35 +0900] “GET / HTTP/1.1″ 200 44
192.168.161.125 – - [11/Feb/2010:23:27:36 +0900] “GET / HTTP/1.1″ 200 44
どうして、この設定だと、完全にラウンドロビンになるのか、よく分かっていない。。。
iptables には、こんなこともできるのかと感動した。
# 2010.04.01: 追記
iptables の設定ファイルの例は、ここに置いた。
Tags: linux iptables