プロキシには汎用プロキシと専用プロキシの2つが挙げられます。汎用プロキシはSocksが代表で、いろいろなプロトコルに対応ができます。一方専用プロキシは通常アプリケーションゲートウェイと呼ばれ、通信内容をチェックして妥当な通信しか通過させません。
まず汎用プロキシを説明しましょう。Socksの場合、あるクライアントソフトがプロキシを使う場合、ソフトをSocksに対応させなければいけません。ですからP2Pソフトがこのプロキシを通過させるにはSocksクライアントになる必要があります。ただし、あるソフトをSocksクライアントにするにはそれほど困難ではありません。Socksでもポート番号によって通信を制限することができます。ただし、Socksではアプリケーションレイヤまで上って通信をチェックしているわけではありません。(通称サーキットゲートウェイと呼ばれる事もある。)そこで、HTTPやHTTPSなどのポートで通信させることができれば、汎用プロキシは外部へ通信させる事が可能となります。
次に専用プロキシの場合を説明します。専用プロキシはアプリケーションレイヤまでチェックするため、その通信内容(例えば命令など)が本当に正しいか確認します。そのため、この専用プロキシを通過させるには単にサービスとして使えるポート番号を変えるだけではいけません。もし専用プロキシを通過させるなら、専用プロキシが通過を許しているプロトコルをP2Pソフトがエミュレーションする必要があるでしょう。事実、プロキシを通過させることで有名なSoftEtherではHTTPSの動作を真似ることで、この問題を解決しています。
さて、これでファイアウォール内部から外部のユーザの通信ができました。では次にファイアウォールの外側のユーザからファイアウォールの内部へ通信させるにはどのようにすれば良いのでしょうか?
ここでは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つあります。
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 hole punchingはRFC3489で規定しているSTUN(Simple Traversal of UDP Through NATs)でも使われています。また、Symmetric NAT間での通信を行う試みもいろいろとされています。