[前に戻る: ネットワークアドレス変換 (NAT)] [目次] [次に進む: ルールセット作成の近道]
ここで例を見てみましょう。
rdr on tl0 proto tcp from any to any port 80 -> 192.168.1.20
この行は、ポート 80 (web サーバ) へのトラフィックをネットワークの内側の 192.168.1.20 のマシンにリダイレクトしています。ですので、192.168.1.20 はゲートウェイの背後で ネットワークの内部であるにも関わらず、このマシンに対して外部からアクセス可能です。
上記 rdr 行の from any to any の部分は実に役に立ちます。 たとえば、もし、どこかのアドレスかサブネットから、ポート 80 の web サーバに アクセスをさせなければならないことがわかっている場合には、以下のようにして それらを限定することができます。
rdr on tl0 proto tcp from 27.146.49.0/24 to any port 80 -> \
192.168.1.20
これは指定されたサブネットだけをリダイレクトします。これは、異なるアクセス元の ホストから、ゲートウェイの背後の異なるマシンへのリダイレクトが可能であることを 意味します。これは実に役に立ちます。たとえば、リモートサイトのユーザに、彼ら自身の デスクトップコンピュータへアクセスさせるのに、彼らのアクセス元の IP アドレスさえ わかっていれば、以下のように、ゲートウェイの IP アドレスと同じポート番号を使用して アクセスさせることもできるのです。
rdr on tl0 proto tcp from 27.146.49.14 to any port 80 -> \
192.168.1.20
rdr on tl0 proto tcp from 16.114.4.89 to any port 80 -> \
192.168.1.22
rdr on tl0 proto tcp from 24.2.74.178 to any port 80 -> \
192.168.1.23
また、フィルタリングの前に変換が行われ、送信先 IP アドレスおよび/または送信先ポートが、 rdr ルールに指定されているリダイレクションアドレス/ポートにマッチするよう変更された、 変換済のパケットとしてフィルタリングエンジンは見ることになる ということに注意する必要があります。 例として、以下のシナリオを見てみましょう。
リダイレクションルールは以下のとおりです。
rdr on tl0 proto tcp from 192.0.2.1 to 24.65.1.13 port 80 \
-> 192.168.1.5 8000
ここで、rdr の処理前のパケットは以下のとおりです。
次に、rdr の処理後のパケットは以下のようになります。
フィルタリングエンジンは、変換が行われた後の IP パケットを見ることになります。
外部からアクセスされるシステムを、分離されたネットワーク上に厳重に制限することで、 このような危険性を最小化することができます。このようなネットワークは、しばしば 非武装地帯 (DMZ) やプライベートサービスネットワーク (PSN) と呼ばれます。この方法なら、 DMZ/PSM とやり取りされるトラフィックを注意深くフィルタリングすることにより、 もし web サーバが不正侵入された場合でも、その影響を DMZ/PSM ネットワーク内に限定することができます。
server = 192.168.1.40
rdr on $ext_if proto tcp from any to $ext_if port 80 -> $server \
port 80
しかし、リダイレクションルールが LAN 上のクライアントから試験された場合は 正しく動作しません。その理由は、リダイレクションルールが、指定された インターフェイス (例の中の外部インターフェイス、$ext_if) を通過するパケットに対してのみ適用されるものだからです。 つまり、LAN 上のホストから、 ファイアウォールの外部アドレスに接続する場合、外部インターフェイスに対して パケットが実際にわたされることを意味しないからです。ファイアウォール上の TCP/IP プロトコルスタックは、着信パケットの送信先アドレスを、自身のアドレスや エイリアスと比較し、そして自身への接続が可及的速やかに内部インターフェイスに わたさなければならないものであることを検出します。そのようなパケットは、物理的に 外部インターフェイスにわたされるわけではありませんし、スタックはこのような転送を 決してシミュレートすることはありません。ですので、PF は外部インターフェイス上の これらのパケットを決して見ることはありませんし、外部インターフェイス上に 指定されているリダイレクションルールが適用されることもありません。
内部インターフェイス用にふたつ目のリダイレクションルールを追加することは、 何ら意図した効果を持ちません。ローカルのクライアントがファイアウォール上の 外部アドレスに接続する場合、TCP のハンドシェイクの最初のパケットは、 ファイアウォールを通過して内部インターフェイスに届けられます。 リダイレクションルールが適用され、送信先アドレスが内部サーバのそれと置換 されます。パケットは、内部インターフェイスを通過して内部に転送され、そして 内部サーバに届けられますが、このパケットの送信元アドレスは変換されているわけでは ありませんので、ローカルのクライアントのアドレスを保持し続けていることになり、 サーバはその応答を直接クライアントに対して返送してしまいます。その結果として、 ファイアウォールは決してその応答パケットを見ることはなく、適正に逆変換を行う 機会も奪われてしまうことになります。一方で、クライアントは、決して期待していない 送信元からの応答を受け取ることとなるので、それを廃棄してしまいます。このように TCP のハンドシェイクが失敗してしまいますので、接続が確立されることはないのです。
しかし、しばしば、LAN 上のクライアントが外部のクライアントとして 同じ内部のサーバに透過的に接続したい場合があると思います。 この問題に対しては、以下のようにいくつかの解決策があります。
ローカルのクライアントは、その名前解決中に、内部サーバのアドレスを受け取らなければ ならないので、ローカルのホストからの問い合わせに対する回答は、外部からの問い合わせに 対するものと異なるものを返すよう、DNS サーバを設定することが可能です。ローカルの クライアントはローカルのサーバに直接接続するため、ファイアウォールが関与することは ありません。これによって、パケットはファイアウォールを通して送信される必要がないので、 ローカルのトラフィックを軽減することができます。
ファイアウォールに付加的なネットワークインターフェイスを追加し、ローカルのサーバを クライアントのネットワークから専用のネットワーク (DMZ) に移動することで、ローカルの クライアントからの接続を、外部接続のリダイレクションと同じ方法でリダイレクトする ことができるようになります。この分離されたネットワークを使用することは、サーバを 残りのローカルのホストから隔離することにより、セキュリティを改善することができるなど、 いくつかの優位性を持ちます。(私たちの例では、インターネットからアクセス可能な) サーバは、やはり不正侵入される危険性がありますが、すべての接続はファイアウォールを 通過しなければならないので、このサーバが他のローカルのホストに直接アクセスすることは できません。
転送すべきポートをリスンし、あるいはリスン中のポートにリダイレクトされる 内部インターフェイス上の接続を得るための、一般的な TCP のプロキシを ファイアウォール上に設定することができます。ローカルのクライアントが ファイアウォールに接続する際、プロキシが接続を受け付け、内部サーバに対して ふたつ目の接続を確立します。そして、これらのふたつの接続の間で、データの 転送を行います。
単純なプロキシは、 inetd(8) と nc(1) とを使用して生成することができます。以下の /etc/inetd.conf のエントリは、 ループバックアドレス (127.0.0.1) のポート 5000 に結合した、リスンするためのソケットを生成します。 この接続は、サーバ 192.168.1.10 のポート 80 に転送されます。
127.0.0.1:5000 stream tcp nowait nobody /usr/bin/nc nc -w \
20 192.168.1.10 80
以下のリダイレクションルールは、内部インターフェイスのポート 80 を プロキシに転送します。
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
127.0.0.1 port 5000
内部インターフェイス上の付加的な NAT ルールによって、上記の 不足している送信元アドレスの変換が行われるようになります。
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
$server
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> \
$int_if
これは、クライアントからの最初のパケットが内部ネットワークを通して転送される際に、 クライアントの送信元アドレスがファイアウォールの内部アドレスで置換されるという 再変換の原因となってしまうでしょう。内部サーバがファイアウォールに応答を返しますが、 ファイアウォールはローカルのクライアントに転送する際に、NAT と RDR の両方の変換の 逆が行われることになります。この構図は、これがそれぞれの反射された接続に対応した、 分離されたふたつの状態を生成してしまいますので、やや複雑なものとなります。 たとえば、外部のホストが (他のリダイレクションを経由して) 開始した接続や ファイアウォール自身などの、NAT ルールが他のトラフィックに対して 適用されてしまわないよう、注意しなければなりません。 上記の rdr ルールは、TCP/IP プロトコルスタックが、 内部ネットワークの内側の送信先アドレスを持って内部インターフェイスに到着した パケットを見るようになります。 (クライアントに相手が直接到達可能であることを通知し、反射を行わせないようにするための) ICMP redirect メッセージをスタックが発行するのを防止するため、 以下のようにしてゲートウェイのリダイレクションを無効化してください。
# sysctl -w net.inet.ip.redirect=0
# sysctl -w net.inet6.ip6.redirect=0 (if using IPv6)
しかし、一般的には、その前に言及した解決法を、この方法の代わりに使用すべきでしょう。
[前に戻る: ネットワークアドレス変換 (NAT)] [目次] [次に進む: ルールセット作成の近道]