TCP/IPで通信を行う場合、通信先の端末は「IPアドレス」と「ポート番号」で特定します。組織内ではセキュリティや運用コストの観点から、インターネット上のIPアドレス( グローバルIPアドレス )を直接使うのではなく、組織内で独自に割り当てたIPアドレス( プライベートIPアドレス )を利用することが多いです。
プライベートIPアドレスが使われるとインターネットを介して端末同士を直接指定できません。
そのため、直接端末同士で通信を行うP2P通信の実現が困難になるのですが、WebアプリのP2P通信実現のためによく利用されている「 WebRTC 」では「 ホールパンチング 」と呼ばれる方法でこれを解決しています。
プライベートIPアドレスが割り振られた端末でインターネット上の端末と通信するためには NAT ( Network Address Translation )という技術が利用されます。
NATは、プライベートIPアドレスをグローバルIPアドレスに変換することで、インターネット上の接続先と通信できるようにする技術です。
正確にはポートの変換も行う場合NAPTとなりますが、この記事ではNATと呼ぶことにします。
NATではプライベートIPアドレスの端末が外部と通信を行う際、 プライベートIPアドレスとポート番号の組み合わせをグローバルIPアドレスと空いているポート番号に一時的に紐づける ことで、通信先からの返信を受け取れるようにします。
ここで割り当てられたポート番号を別の端末に伝えれば、その端末からも通信できるのではないかという発想が「 ホールパンチング 」です(最初に通信を行うことで通信用の穴が開くイメージであるためホールパンチングと呼ばれます)。
なおTCPはコネクション確立のために3ウェイハンドシェイクが必要であり、ホールパンチングだけで通信を確立するのは困難です。そのためWebRTCのNAT越えの直接P2P通信では主にUDPが使われることから「UDPホールパンチング」とも呼ばれます。
WebRTCではこの方法を実現するために、「 STUNサーバー 」という役割のサーバーと通信を行うことでNATに通信用の穴を開けると同時に自身と通信するためのグローバルIPアドレスとポート番号を取得するようになっています。
STUNサーバーから得られたグローバルIPアドレスとポート番号などWebRTCの接続に必要な情報は「 ICE Candidate 」と呼ばれます。
「Candidate(候補)」という単語が含まれているのは経路が複数存在し、候補となる情報が複数になることがあるからです (なおICE CandidateにはSTUNから得た情報以外の情報も含まれますがここでは割愛します)。
これを自身と通信したいP2Pの通信相手に伝える作業を「 シグナリング 」と呼びますが、WebRTCの仕様ではこのシグナリングの方法は定められておらずアプリケーションごとに独自で検討する必要があります。
一般的には何かしらWebSocketなどの双方向通信が可能なプロトコルでサーバーに接続しておき、そこを経由して伝えるような仕組みが多いです。

さて、「 ホールパンチング 」は最初に行った通信相手用の情報で他の通信相手と通信できるようになるという面白い方法ですが、セキュリティ的な観点から考えるとちょっと怖い気もします。
実際、NATの種類によってはセキュリティ対策の度合いが異なり、ある宛先用に開けた穴を使い回せるタイプもあれば、厳格に制限するタイプもあります。
この動作の違いによって、NATは主に以下の4種類に分類されます。
-
フルコーン型
一度通信用に開けたポートは、どの端末からでも通信可能 -
制限コーン型
一度でも通信したことのあるIPの端末とのみ通信可能 -
ポート制限コーン型
一度でも通信したことのあるIPとポートからのみ通信可能 -
対称型(シンメトリック型)
通信相手ごとに割り当てられるポート番号が変わり、ある相手用に開けた穴は他の相手からは一切利用できない
WebRTCでは制限コーン型やポート制限コーン型であれば双方の端末から同時にパケットを送り合う仕組みがあり、多くの場合でP2P接続が成功します。
一方、対称型のNATでは通信相手ごとに割り当てられるポート番号が変わるため、ホールパンチングができずP2P通信できないことが多いです。
少々あいまいな表現となっているのは、上記動作が定められた仕様ではなくルーターの設計やネットワークの構成にも依存するためです。最終的には実際に試してみるのが確実です。
今回詳細は記載しませんが、直接通信できない場合は別途「 TURNサーバー 」というサーバーを用意することでパケットをサーバー経由させて通信する方法もあります。
TURNサーバーを利用することで直接P2P通信ができない場合やUDP通信が禁止されている環境でも通信が可能になりますが、通信の遅延が大きくなったりサーバーの運用コストがかかるなどのデメリットもありますので導入には慎重な検討が必要です。
WebRTCのNAT越えでのP2P実現のベースとなっている「 ホールパンチング 」のご紹介でした。
NATの動作をうまく利用して特別な追加機能がなくても端末間通信を実現できる面白い技術ですよね。
ただ実際に利用可能かどうかはルーターの仕様やネットワークの構成に依存しますので、特性を考慮の上利用する必要があります。
ご参考になれば幸いです。

