ルールの保存とリストア

iptables には、構築したルール群 (以降 「ルールセット」と呼ぶ) を保存/リストアするためのユーティリティが付属している。保存は iptables-save、リストアは iptables-resotre というプログラムで行う。どちらも、単体では、ファイルではなく stdout, stdin との間で出力/読み込みをするので、ファイルに保存したりファイルから読み取ったりするには、シェルのリダイレクト機能 ( > ) などを併用する必要がある。

実は、RedHat系Linuxでは、iptables の rc スクリプト自体、中で iptables-saveiptables-restore を使っている。 /etc/rc.d/init.d/iptalbes スクリプトは、start) 関数の中では、 /etc/sysconfig/iptables ファイルからルールセットを読み取って iptables-restore でロードしている。 また、save 引数を付けて iptables rcスクリプトを呼んだ時には、iptables-save コマンドが呼ばれて /etc/sysconfig/iptables ファイルに現在のルールセットを保存するようになっている。ただし、save 引数で iptables rcスクリプトを呼ぶことに実用性があるのか? それなら直接 iptables-saveコマンドを呼んだほうが、明快だし応用も利く。

iptables rcスクリプトは、start や stop に伴って、これ以外にも、モジュールのロードやアンロード、テーブルのフラッシングなど様々なことをやっている。iptables-save, iptables-restore や、こうした rcスクリプトからの iptables 操作自体を嫌う声も聞こえるが、これはこれでなかなかよくできていると筆者は思う。ただし、LANインターフェースの IPがコロコロ変わる環境、例えば、ルータを挟まずに PPPoE で直接インターネット接続しているLinuxマシンをファイヤーウォールに仕立て上げる場合には、標準の rcスクリプトは不向き。現時点でのIPアドレスを調べる関数を新たに作成して環境変数に設定したり、それを読み取ってルールを動的に作成する仕組みを作ったりと大改造が必要で、かえって手間がかかりそうだ。

/etc/rc.d/init.d/iptables スクリプトを読んでみれば分かるが、このスクリプトは、数種類のオプション設定を /etc/sysconfig/iptables-config ファイルから拾っている。例えば、$IPTABLES_MODULESという変数は、通常では読み込まれない追加モジュールを能動的・強制的に読み込ませるために使う。iptables を有効にすると、そのままでは FTP ができなくなってしまうので ip_conntrack_ftpモジュールが必須となるが、iptables-config ファイルに

 IPTABLES_MODULES="ip_conntrack_ftp"

と記述しておくと、"service iptables start" 時にこのモジュールも読み込まれるようになる。

ルールファイルの書式

ここからの説明では、ルールセット自体をシェルスクリプトとして書く世の中の主流に逆らって、iptables を rcスクリプトによってロードすることを前提にする。シェルスクリプト式のルール設定ファイルでは:

#!/bin/sh
iptables -A INPUT -p tcp ACCEPT
.
.

のような記述になるが、ここからの iptables 設定ファイルは iptables-restore で読み込むことを前提とするので:

-A INPUT -p tcp ACCEPT
.
. 

という具合に、インタープリタの指定行も iptables コマンドも無しの記述になる。以下に、この方式の設定ファイルで使う特別な書式を挙げる。とにかくドキュメントが不足しているので、以下は実地に実験した結果「こうだろう」と言える項目。これ以外にもあるかもしれないが、少なくとも、これだけは間違いないはず。

特別な意味を持つ表記
# This is a comment line # で始まる行はコメントとして無視される。行頭に # がある場合だけであって、
-A INPUT some_rule # This is a comment
という記述はエラーとなる
:chain (policy|-) チェーンの名称とそのポリシーを宣言する。ユーザ定義チェーンの場合はポリシーは設定できないので、 ":sample_chain -" という風に、ポリシーの代わりに "-" を書いておく必要がある
*table 上記のチェーン作成やルールの作成は、それがどのテーブルに属するものか示すために、必ず "*filter" などという風にテーブル名を先頭行に付けてひとまとめにしなくてはならない。具体例は 「iptables 設定例」 を見れば分かるはず
COMMIT そこまでの設定を実行する。テーブル毎にコミットするのが普通のようだ

もうひとつ悲しいのは、ルール記述で改行のエスケープ (\) が効かないこと。実際の運用では支障はないが、こうして html 上で設定を見せる際には、ちょっと扱いにくい。

iptables-save

iptables-save ユーティリティは、現在ロードされているルールセットを stdout に出力する。リダイレクトしなければコンソールに出力されるだけなので、単に、自分の設定したルールが実際どう解釈されているかを確認したり、iptablesの正しい文法を見るため使ったりもできる。

コマンド書式:
iptables-save [-c] [-t table]

オプション:

-c ヒットパケット/ヒットバイトのカウンタも付けて出力する
-t table table で指定したテーブルのルールだけを出力する

-c オプション付きで使った場合の出力の一部を抜粋して挙げておく。

*filter
:OUTPUT DROP [0:0]
[33676:4535404] -A OUTPUT -s 127.0.0.1 -j ACCEPT

このように、チェーン毎、ルール毎に、ヒットしたパケットのカウンタが [ ] に囲まれて表示される。一番下の例では、「パケット数では33676個、バイト数で勘定すると4535404バイトのパケットが、このルールにヒットした」 ということを意味している。ルールセットをファイルに書き出すにはこんな風にリダイレクトすればいい:

iptables-save > /etc/sysconfig/iptables

iptables-restore

iptables-save で出力した形式のルールセット記述を、stdin から読み取ってリストアする。

コマンド書式:
iptables-restore [-c] [-n]

オプション:

-c 読み込む記述にパケット/バイトカウンタがあれば、それも含めてリストアする。つまり、iptables-save した時とまったく同じ状態に戻るわけだ。このオプションを使わなければ、パケット/バイトカウンタはすべて [0:0] にリセットされる
-n -n を付けない時は、リストアに先立ってすべてのテーブルがクリーンナップされるが、これを付けるとフラッシングを行わない

iptables-restore にファイルを読み取らせてリストアを行うには:

cat /etc/sysconfig/iptables | iptables-restore

のようにパイプ渡しするか、

iptables-restore < /etc/sysconfig/iptables

という風にリダイレクトで渡せばいい。

解せない事実がある。iptables に付属しているmanを読んでも、Netfilter のホームページ にあるドキュメントを見ても、Iptables チュートリアル を読んでも、iptables-restore は stdin からしか設定を読み込めないとされている。だから上記のような方法を採っているわけだが、実際には (少なくとも Fedora Core 用として rpm で配布されている iptables-1.2.9 では) "iptables-restore /etc/sysconfig/iptables" が、ちゃんと機能してしまう。つまり、ファイルから直接読み込むことができるのだ。悪いことではないにしろ、仕様が変わったなら man やドキュメントでちゃんと説明してほしいものだ。それとも、この iptables 自体が、RedHat によって改造されたバージョンなのだろうか。

実のところ、rcスクリプトを使う通常の運用では、iptables-restore は滅多に使わない。"service iptables start" すれば、どうせ /etc/rc.d/init.d/iptables スクリプトが /etc/sysconfig/iptables ファイルを読み、勝手に iptables-restore を使ってリストアしてくれるからだ。この際にちょっと不便なのは、 "service iptables start" では、オプションをその都度指定することができない点。オプション設定ファイル /etc/sysconfig/iptables-config に:

IPTABLES_SAVE_COUNTER="yes"

を書いておけば、service iptables save 時にはカウンタは必ず保存され、service iptables start の際にもカウンタも含めてリストアされるが、たまたま今回だけはリセットしたいと思った時に手立てがない。といっても、 iptables-config には上記設定を書いておいて、カウンタをリセットしたい時には別途 "iptables -Z" コマンドを発行すればいいだけの話だ。

設定の作り込みに不可欠なツール

tcpdump

テキストベースのネットワークトラフィック分析ツール。これを起動している間、インターフェースに「触れた」パケットの種別、ヘッダ情報、送信元、宛先などが stdout に出力される。どういう条件下でどんなパケットが流れてくるか調べるのに便利。普通に使うだけなら、オプションも引数も必要ない。

主なオプション (どれも省略可能) :

-i interface 「聞く」インターフェースを指定する。このオプションを特に指定しない場合には、ifconofig -a でループバックインターフェースの次に挙がるインターフェースが検出の対象となる
-e リンク層のヘッダを出力する
-n ホストのアドレスをリゾルブしない。つまりDNSを牽かずに数字のまま表示する
-nn 上記プラス、プロトコルナンバーも数字のまま表示する
-p 聞くインターフェースを無差別 (promiscuous) モードにしない 。このオプションを付けない場合、tcpdumpは当該のインターフェースを無差別モードに移行させる。無差別モードでは、そのインターフェース宛てのパケットでなくても、とにかくそのインターフェースに触れたパケットなら何でも拾われる。目的によって使い分けると効果的
-l 標準出力のバッファリングを有効にする。 tcpdump の man には、ログファイルに書き出させながらリアルタイムでモニタするには `tcpdump -l | tee file ' のようにすると良いと書かれている
-v 各パケットについて詳しい情報を出力する。さらに詳細にする -vv や、さらにもっと詳細な -vvv というオプションもある

この他、オプションに続いて、パケットの素性によって出力を絞り込む様々な表現が使用できる。例えば `tcp and dst port 80' を指定すると、TCPのパケットでなお且つ宛先ポートが 80 であるパケットだけを表示させることができる。

ethereal

同じくトラフィック分析ツールだが、こちらはグラフィカルインターフェースを持つ。capture メニューの start をクリックすると設定画面が出るので、最低限、聞くインターフェースを指定する。同じ画面で tcpdump と同じように無差別モードにするかどうか選べるので、必要に応じて選択。capture メニューの capture filter を使うと、拾うパケットをプロトコルやポートナンバーなど様々な条件で絞り込むこともできる。