【ITニュース解説】VoIP NAT Traversal – Getting Through the Maze

2025年09月05日に「Dev.to」が公開したITニュース「VoIP NAT Traversal – Getting Through the Maze」について初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

ITニュース概要

インターネット電話(VoIP)は、ルーター等のNAT機能により通信が途絶えることがある。この問題を解決するため、自身の公開IPを知るSTUN、通信を中継するTURN、両者を利用し最適な経路を確立するICEという技術が使われている。(114文字)

ITニュース解説

VoIP(Voice over IP)、つまりインターネットを介した音声通話の仕組みを構築しようとすると、しばしば「NATの壁」と呼ばれる問題に遭遇する。これは、通話相手に送ったパケットが相手に届かなかったり、相手からの返答がこちらに届かなかったりすることで、音声が途切れたり通話自体が確立できなかったりする現象を指す。この問題の根源には、ネットワークアドレス変換(NAT)という技術がある。

NATは、家庭や企業のプライベートネットワーク内にある複数のデバイスが、インターネットに接続するためのたった一つのパブリックIPアドレスを共有できるようにする技術だ。例えば、ルーターの向こう側にあるパソコンやスマートフォンは、それぞれ「192.168.1.10」のようなプライベートIPアドレスを持っているが、インターネットから見るとそれらはルーターの持つ単一のパブリックIPアドレスとして認識される。これにより、限られた数のパブリックIPアドレスを効率的に利用できる利点がある。

しかし、VoIPの主要なプロトコルであるSIP(Session Initiation Protocol)とRTP(Real-time Transport Protocol)は、基本的にデバイス同士が直接通信するピア・ツー・ピア(P2P)での動作を前提として設計されている。これらのプロトコルは、通話相手との接続情報をやり取りする際に、しばしばプライベートIPアドレスをメッセージの内部に含んでしまうことがある。例えば、「私は192.168.1.10にいるので、ここに返事をください」という情報がインターネット上に送られても、インターネット上のルーターはそのプライベートIPアドレスを認識できず、どこにパケットを送れば良いか分からなくなり、結果として通話が成立しなくなるのだ。

NATにはいくつかの種類があり、それぞれVoIPの通信に与える影響が異なる。「フルコーンNAT」は、一度マッピングされたポートに対しては、どの外部ホストからでもパケットを受け入れられるため、比較的VoIP通信が通りやすい。「制限付きコーンNAT」は、以前に通信したことのある外部ホストからのみパケットを受け入れる。「ポート制限付きコーンNAT」は、さらに送信元ポートもチェックする。これらに対して「シンメトリックNAT」は、最もVoIPにとって厄介なタイプだ。これは、新しい宛先にパケットを送るたびに新しいポートマッピングを作成するため、単純な「穴開け(ホールパンチング)」と呼ばれる手法が機能しにくくなる。

SIP信号をNATの壁を越えさせるためには、いくつかの工夫が必要になる。SIPメッセージのヘッダーには、しばしば自身のコンタクトアドレスとしてプライベートIPアドレスが記載されることがある。これでは、通話相手がそのプライベートIPアドレスに返信しようとしても失敗してしまう。その解決策の一つが「rport(RFC 3581)」という仕組みだ。これは、クライアントがSIPメッセージのViaヘッダーに「rport」というパラメータを追加することで、サーバー側がヘッダー内のプライベートIPアドレスではなく、実際にパケットが送られてきた送信元ポートに対して応答を返すように促すものだ。また、「コンタクトヘッダーの書き換え」も有効な手段だ。NATを認識できるSBC(Session Border Controller)のようなSIPサーバーは、クライアントが送信したコンタクトヘッダーに含まれるプライベートIPアドレスを、サーバーが認識するクライアントのパブリックIPアドレスとポート番号に書き換えてくれる。

SIPシグナリングが成功したとしても、実際に音声や映像のメディアデータをやり取りするRTPストリームも同様のNAT問題を抱えている。RTPの接続情報を記述するSDP(Session Description Protocol)オファーにも、しばしばプライベートIPアドレスが含まれる場合があるため、メディアデータが流れないという事態が発生する。このRTPのNAT越え問題を解決するために開発されたのが「ICE(Interactive Connectivity Establishment)」フレームワークだ。ICEは、通話に参加するデバイス(ユーザーエージェント)が、自身と相手との間に接続可能な様々な経路(候補アドレス)を複数収集し、それらを優先順位に従って試していくことで、最終的に最も適切な通信経路を確立する仕組みだ。

ICEが収集する候補アドレスには主に三つのタイプがある。一つは「ホスト候補」で、これはデバイスが直接持つローカルのプライベートIPアドレスだ。次に「サーバー反射型候補」は、STUN(Simple Traversal of UDP over NATs)サーバーという中継サーバーを利用して、自分のパブリックIPアドレスとポート番号を発見したものだ。STUNサーバーは、クライアントが「私はインターネットからどのように見えているのか?」と問い合わせると、そのクライアントのパブリックIPとポートを教えてくれる。この方法はコーンNATタイプに対して非常に有効だ。最後に「リレー候補」は、TURN(Traversal Using Relays around NAT)サーバーというメディアリレーサーバーを通じて割り当てられたアドレスだ。これは、シンメトリックNATのようにSTUNが機能しない場合や、ファイアウォールによってUDP通信が厳しく制限されている場合に利用される最終手段だ。TURNサーバーは、まるで郵便局のように、すべてのメディアデータを一旦自分自身が受け取り、それを宛先に転送することで通信を保証する。この方法は確実だが、メディアデータが必ずTURNサーバーを経由するため、通信の遅延が増加し、サーバーリソースのコストも高くなるというデメリットがある。

ICEによる通話設定をさらに高速化する技術として「Trickle ICE」がある。これは、すべての候補アドレスが収集されるのを待ってからまとめて送信するのではなく、見つかった候補から順次送信していくことで、通話の確立時間を短縮するものだ。

RTPストリームが開始される前に、ピア間で選択された候補ペアに対して「STUNバインディングリクエスト」が送信される。これは、実際にその経路が双方向に通信可能であるかを確認するためのヘルスチェックのようなものだ。STUNバインディングリクエストを送り、相手から「OK」という応答が返ってくれば、その経路は有効であると判断され、その後のRTPメディアデータはその経路を通じて流れることになる。

NATを越えるVoIPの実際の流れを見てみよう。例えば、AliceがNATの内側からBobに電話をかけるINVITEメッセージを送る場合、そのメッセージにはいくつかの重要な情報が含まれる。SIPヘッダーでは、「Via」ヘッダーに「rport」パラメータが追加され、Bobからの応答がAliceのNATの正しいポートに返されることを保証する。また、「Contact」ヘッダーには、STUNサーバーを通じて発見されたAliceのパブリックIPアドレスとポート番号が記載される。メッセージに付随するSDPオファーには、RTPストリームに関する情報と共に、ICEが収集した候補アドレスが列挙される。ここにはAliceのローカルプライベートIPアドレスである「ホスト候補」と、STUNサーバーによって発見されたパブリックIPアドレスとポート番号である「サーバー反射型候補」が含まれる。これらの候補には、ICEの認証情報(ufrag, pwd)も含まれる。BobがこのINVITEメッセージを受け取ると、自身の候補アドレスを含む200 OK応答を返す。そして、AliceとBobの間でSTUNバインディングリクエストが交換され、最も適切で機能する通信経路(ホスト候補、サーバー反射型候補、あるいはリレー候補の中から)が選択される。一度経路が確立されれば、実際に音声データであるRTPストリームがその経路を通じて流れるのだ。

まとめると、VoIP通信においてNATを乗り越えるためには、SIPシグナリングに対してはrportの利用やSBCによるコンタクトヘッダーの書き換えといった対策が必要となる。RTPメディアストリームに対しては、ICEフレームワークが中心的な役割を果たす。ICEはSTUNを利用してパブリックIPアドレスとポートを発見し、もしSTUNが失敗するような困難な状況(シンメトリックNATなど)であれば、TURNサーバーを介したリレー通信で確実に接続を保証する。STUNバインディングは、メディア経路が実際に機能していることを確認する重要なステップだ。これらの技術が組み合わさることで、ユーザーはNATの存在を意識することなく、インターネット上で高品質な音声通話を利用できるようになる。

【ITニュース解説】VoIP NAT Traversal – Getting Through the Maze | いっしー@Webエンジニア