B.2. NEWステートでありながらSYNビットの立っていないパケット

iptables の仕様のうち、充分な説明がなく、多くの人 (正直、僕もそのひとりだった) が見落としている部分がひとつある。 NEW ステートを使用した時、SYN ビットの立っていないパケットでもファイヤーウォールを通過してしまうのだ。この仕様が存在するのは、場合によっては、あるパケットが、別のファイヤーウォールなどで ESTABLISHED 状態であるコネクションに、属している可能性を検討したいことがあるからだ。これのおかげで、複数のファイヤーウォールの併設が可能となり、うち 1つのファイヤーウォールではデータを一切損失することなく受けるということが可能となる。こうすれば、副ファイヤーウォールにサブネットのファイヤーウォール処理を引き継がせることができる。とはいえ、この仕様が、NEW ステートを用いると、それが接続開始時の 3 ウェイハンドシェークであろうとなかろうと、あらゆる種類の TCP コネクションを許してしまう結果をもたらしているのは事実だ。この問題に対処するには、以下のルールを INPUTOUTPUTFORWARD チェーンに追加する:

$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j LOG \
     --log-prefix "New not syn:"
$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
    

Caution

上記のルールはこの問題を処置してくれる。この動作は Netfilter/iptables プロジェクトでろくに説明されていない。本来ならば絶対に特記されてしかるべき事柄だ。言い換えれば、ファイヤーウォールの構築時には、こうした動作に対して厳重な注意を払っていなくてはならないということだ。

認識しておかなくてはならないのは、このルールが、マイクロソフトによる間違った TCP/IP 実装との間で少々問題を起こすという点だ。上記のルールでは、時として、マイクロソフト製品が発したパケットが NEW ステートと見なされ、故にログおよび破棄されることがある。とはいえ、僕の知る限りでは、それでコネクションが絶たれてしまうことはないようだ。これが発生するのはコネクションがクローズされる時で、最後の FIN/ACK が送られ、Netfilter のステート機構がコネクションを閉じ、この接続が conntrack テーブルから消された際に起こる。マイクロソフトの異常な実装は、この時期になって、さらにパケットを送ってくるのだ。そのパケットは、NEW ステートと判断されるが、SYN ビットを欠いているので上記のルールにマッチしてしまう。つまるところ、このルールについてあれこれ悩む必要はない。どうしても気になるなら、このルールに --log-tcp-options オプションを付けてヘッダもログするようにすれば、パケットの中身がもう少し詳しく調べられるだろう。

このルールにはもうひとつ問題がある。PPP 接続時に起動されるよう仕組んであるスクリプトがあり、その時、例えば LAN 内から、誰かが既にファイヤーウォールへコネクションを張っていた場合だ。この場合、PPP 接続が開始すると、LAN からの既存のコネクションは事実上抹殺される。この現象が起こるのは、スクリプトコード上で conntracknat をモジュールとして扱っており、そのスクリプトが走る度にモジュールのロード/アンロードが行われる場合に限られる。また、ファイヤーウォール以外のホストから telnet 経由で rc.firewall.txt スクリプトを走らせた場合にも発現する。話を単純化するため、今あなたは telnet などのストリームコネクションでファイヤーウォールに接続するとしよう。あなたはコネクション追跡モジュールをロードし、それから "NEW であるが SYN でない " ルールをロードする。そこで、telnet クライアントあるいはデーモンが何か送ろうとする。しかしこの時、コネクション追跡コードにとって、現コネクション上では双方向のパケットは未検出で、しかも、そのパケットはコネクションにおける最初のパケットではないので SYN ビットは立っていない。そのため、コネクション追跡機構はこれを正規のコネクションとは認めない。その結果、そのパケットは例のルールに合致してログされ、床に投げ捨てられてしまうのだ。