P2Pとファイアウォール


さて、P2Pにおいて厄介なシステムとしてファイアウォールが挙げられます。ここではファイアウォールをP2P通信がうまく通過する方法について説明します。まずはファイアウォールの内側のユーザがグローバルアドレスを持っているユーザと通信する方法を考えて見ましょう。
1.パケットフィルタリング
通常のブロードバンドルータはポート番号をチェックし、ルータが制限しているポートは外部へ通信できないようにしています。そのため、このファイアウォールにおいて外部と通信するには、ルータに設定している外部へ通過させるポート番号において、P2Pサービスに必要なポート番号も追加する必要があります。もし管理者によって適切なポート番号を透過できない場合、P2Pサービスのポート番号をHTTPやHTTPSなどのポート番号に変更して通過させる方法があります。(ただし対応方法はソフトに依存します。)
2.プロキシ
プロキシは会社や大学など組織内部から外部への通信をするときに良く用いられます。プロキシを使うと組織内部のアドレスを外部から隠蔽できる他、通信内容の記録、キャッシュによる通信効率の向上などを図る事ができます。

プロキシには汎用プロキシと専用プロキシの2つが挙げられます。汎用プロキシはSocksが代表で、いろいろなプロトコルに対応ができます。一方専用プロキシは通常アプリケーションゲートウェイと呼ばれ、通信内容をチェックして妥当な通信しか通過させません。

まず汎用プロキシを説明しましょう。Socksの場合、あるクライアントソフトがプロキシを使う場合、ソフトをSocksに対応させなければいけません。ですからP2Pソフトがこのプロキシを通過させるにはSocksクライアントになる必要があります。ただし、あるソフトをSocksクライアントにするにはそれほど困難ではありません。Socksでもポート番号によって通信を制限することができます。ただし、Socksではアプリケーションレイヤまで上って通信をチェックしているわけではありません。(通称サーキットゲートウェイと呼ばれる事もある。)そこで、HTTPやHTTPSなどのポートで通信させることができれば、汎用プロキシは外部へ通信させる事が可能となります。

次に専用プロキシの場合を説明します。専用プロキシはアプリケーションレイヤまでチェックするため、その通信内容(例えば命令など)が本当に正しいか確認します。そのため、この専用プロキシを通過させるには単にサービスとして使えるポート番号を変えるだけではいけません。もし専用プロキシを通過させるなら、専用プロキシが通過を許しているプロトコルをP2Pソフトがエミュレーションする必要があるでしょう。事実、プロキシを通過させることで有名なSoftEtherではHTTPSの動作を真似ることで、この問題を解決しています。


ファイアウォールを通過させるシステムを作りにくい場合にはSoftEtherと併用することも考えられるでしょう。

さて、これでファイアウォール内部から外部のユーザの通信ができました。では次にファイアウォールの外側のユーザからファイアウォールの内部へ通信させるにはどのようにすれば良いのでしょうか?

ここではP2Pプログラミングで有名なJXTAを例に取り説明します。今、ファイアウォールの内側のノードAと外側のノードBがいます。ノードAはノードBと定期的に接続しますが、特にノードBをJXTAではルータピアと言います。まず、ノードAに通信したいノードCはノードBにAに対する通信要求のメッセージを送ります。ノードAはノードBに対して定期的に接続し、ノードBがノードAに関するメッセージを預かってないか調べます。今、ノードCがノードAでの接続要求のメッセージをもらっているので、そのメッセージをノードA、B接続時にノードBがノードAにプッシュします。これで、ノードAからノードCへ通信することができます。

さてこれでファイアウォールの内部と外部(グローバルアドレスが付いている場合)のノードで通信ができました。しかし問題一つ挙がります。それはファイアウォールの内部にあるノードAと、異なるファイアウォールの内部にあるノードBはどのように通信すれば良いのでしょうか?解決方法は2つあります。


1.外部ノードまたはサーバを使う方法
これはノードAとノードBと通信するときに、グローバルアドレスを割り当て入るノードC を介する方法です。つまり通信はA⇔C⇔Bとなります。CはP2Pネットワークに参加しているノードでも良いのですが、サーバでも構いません。この方法はP2Pアプリで一般的に用いられている方法です。
2.UDP hole punchingを使う方法
この技術は比較的に新しい技術で、P2P-VoIP等で普及していくと思われる方法です。 NATファイアウォール間通信で有効な技術で、ユーザクライアントソフトに対して特別な 設定をする必要はありません。まずはNATの説明からしましょう。

NATにはFull Cone NAT,Restricted Cone NAT,Port-Restricted Cone NAT,Symmetric NATの4つが挙げられます。まずはFull Cone NATを説明します。

下の図がFull Cone NATの原理図です。A,Bがファイアウォール外側のサーバでCはファイアウォール内側のクライアントです。

ここで、A⇒Firewall、B⇒Firewallの通信先ポートが同じ(ここでは62000)になっていることに注目してください。なお、Restricted Cone NATとは、アドレス変換はFull Cone NATと同じで、外部から内部への通信はCから通信したIPアドレス先しかできないこと、Port-Restricted Cone NATは外部から内部への通信においてIPアドレスだけでなく、ポート番号もCから通信したものと一致しないと許可しないものです。(逆にFull Cone NATは外部から内部への通信においてIPアドレス、ポート番号の制限はなし。) 次の図がSymmetric NATの原理図です。

A⇒Firewall、B⇒Firewallの通信先が異なるポートであること(ここでは62000と62001)であることがわかるでしょう。なお、NATについてより詳しく知りたい方は、
IPv6Style:Terenedoの説明 http://www.ipv6style.jp/jp/tryout/20030929/index.shtml
を見ればよいでしょう。

さて、UDP hole punchingは先ほど紹介した4つのNATのうち、Full Cone NAT,Restricted Cone NAT,Port-Restricted Cone NATに適用できる技術です。ではその概要を説明しましょう。

下図に、ノードA、ノードBがいて、それぞれFirewall_A Firewall_Bがいます。また登録サーバCがいます。

A⇔Bの通信ステップは次のとおりです。

ちょっとテクニカルなのでわかりにくいとは思いますが、その場合には一度絵を描いてみるとすっきりすると思います。注意する点としてこの通信はUDPであることを気をつけてください。TCPだと通信が非対称のため、このテクニックは使う事ができません。

このUDP hole punchingはRFC3489で規定しているSTUN(Simple Traversal of UDP Through NATs)でも使われています。また、Symmetric NAT間での通信を行う試みもいろいろとされています。


参考文献:
ファイアウォール構築:オライリージャパン
JXTAの全て P2P Javaプログラミング:日経BP社
P2P communication across middleboxes (draft-ford-midcom-p2p-01.txt)

さて、次はP2Pでの匿名通信路の説明を行います。

NEXT

TOPページに戻る