IPフィルタが何であるかをよく理解しておくのは重要なことだ。 iptables は IPフィルタである。このことをよく理解しておかないと、今後自分のファイヤーウォールを設計する時に暗礁に乗り上げることになる。
IP フィルタは TCP/IP 参照スタックのうち、主にレイヤー 2 で働く。現代の IPフィルタのほとんどがそうであるように、 iptables も、レイヤー 3 で作用することもできる。しかし、定義上では、 IPフィルタは第 2 層で働くものとされている。
IPフィルタの実装定義に厳格に従うのならば、 IPフィルタは IP ヘッダ (送信元/宛先アドレス, TOS/DSCP/ECN, TTL, プロトコル など、本当の意味で IP ヘッダ内に存在する情報のみ) に基づいてしかパケットをフィルタリングできないことになる。しかし iptables は IPフィルタの定義に対して 100% 厳格ではないので、パケットの奥深くに埋め込まれているヘッダ (TCP, UDP など) や、もっとローレベルのヘッダ (MACソースアドレス) に基づくフィルタリングも行える。
しかしここでひとつ問題がある。 iptables は最近になって、より厳格になってきているということだ。 iptables はストリームを「追いかけること (follow)」はしないし、データ同士を合体させたりもしない。そういった処理はプロセッサやメモリを喰いすぎるのだ。これが何を意味するかは後でじっくりと説明することにしよう。 iptables は TCP/IP スタックそのものがやるのと全く同じように、パケットそれぞれの身元を調べて記憶し、それらが同一のストリームに属しているかどうかを (シーケンスナンバー やポートナンバー などに基づいて) 判断する。これはコネクション追跡 (connection tracking) と呼ばれ、それがあるからこそ、パケットの宛先/送信元ネットワークアドレス変換 (一般的に DNAT, SNAT と呼ばれる) やステートマッチが行えるのだ。
上で明言を控えた点だが、 iptables は別々のパケットから読み取ったデータ同士を (デフォルトでは) くっつけることはできない。そのため、あなたが目にしているのが常にそのデータの全体とは限らない。僕がわざわざこの点に触れるのは、 netfilter/iptables に関係したメーリングリストの幾つかで、根本的に間違ったアイデアについての「どうやったらできるか」という質問が散見されるからだ。例えば、新たな Windows ベースのウイルスが現れる度に、特定の文字列を含むストリームを破棄する方法を質問する輩が現れる。たちが悪いのは、これが実に簡単にやれるという点だ。例えば:
cmd.exe
のような文字列でマッチを行えば、一応はできてしまう。
しかしここで、もしウイルスなりクラッキングプログラムなりのライターが非常にずる賢くて、パケットサイズを非常に小さくして cmd をひとつのパケットに入れ、次のパケットに .exe を乗せるようにしていたらどうなるか。あるいは、経路途中で、そんな小さなサイズのパケットしか通れないようなネットワークを通らざるを得ないとしたら。その通り。文字列マッチ (string match) はパケットの境界線を越えて作用することはできないので、問題のパケットは擦り抜けてしまう。
「どうして、パケットを跨っても作用するように文字列マッチや何かを作り替えないのさ」という疑問の浮かんだ人もいるだろう。答えは単純。 CPU時間 (processor time) を喰ってしまうからだ。コネクション追跡は既に、 CPU時間 を気にせずにいられるぎりぎりの所まで来ている。そこへ更なるレイヤー、例えば前記の機能を加えれば、おそらく想像を絶する数のファイヤーウォールが使用不能となるだろう。その 1個の機能のメモリ消費量の問題を度外視したとしてもだ。
こうした機能に手をつけないのには他にも理由がある。世の中にはプロキシというテクノロジが存在する。プロキシは IP フィルタよりも上層のレイヤーでトラフィックを扱うために開発されたものであり、この要望を達成するにはそちらのほうが適しているのだ。プロキシの開発目的は、速度の遅いインターネット接続でもダウンロードやページ閲覧をできるだけ効率よく行うことだった。例えば WEBプロキシのひとつに Squid がある。誰かが今、或るページのダウンロード要求を出したとすると、プロキシがその要求を横取り、あるいは受信し、WEB ブラウザとのコネクションを開く。次にプロキシは WEB サーバに接続して当該のファイルをダウンロード。ファイル (あるいはページ) のダウンロードが完了したら、それをクライアントへと送る。今度、別のブラウザがさっきと同じページを要求してきたら、ファイル (あるいはページ) は既にプロキシの懐に存在するため、それを直に送ればいいので、帯域の節約になるというわけだ。
知っている人もいるだろうが、プロキシは、ダウンロードするファイルにもっと踏み込んで、内容を読み取る機能も備えている。だから、ストリームやファイル、ページの中身を検査するのなら、こちらにほうがずっと適しているのだ。
既に iptables 及び netfilter でレイヤー7 フィルタリングを行うことの問題点を警告したところで、実は、その問題の解決に挑む一連のパッチも存在する。これは http://l7-filter.sourceforge.net/ と呼ばれるもので、かなり多くのレイヤー7 プロトコルに対してマッチを行うことができる。ただし、l7-filter は、純粋なフィルタリングに使用できなくもないが、メインの用途は QoS や トラフィック・アカウンティング との併用だ。 l7-filter はまだカーネルや netfilterコアチームとは別のところで試験と開発が進められいるところで、それ故、当文書でこれ以上触れるつもりはない。