公開IPアドレスは1つなのに、ルーターの内側には十数台のデバイスがいます。あなたのiPadは、3つ先のネットワークのモバイル回線の上。それなのに、リモートデスクトップアプリは、1秒足らずで、片方からもう片方への直接接続を開きます。たいてい、間に中継サーバーを挟むこともなく。その魔法の正体が、ICE、STUN、TURN、ホールパンチング、そしてシンメトリックNATをめぐる厄介な真実です。
なぜ重要なのか
ある火曜日の朝を思い浮かべてください。Mac miniは自宅にあり、公開IPv4アドレスが1つだけのルーターの内側にいます。iPadは電車の中で、独自のアドレス変換を何層も重ねた通信事業者のモバイルネットワークにつながっています。2台のデバイスの間には、少なくとも2つ、おそらく3つのNATがあります。どちらのマシンも、既定では外のインターネットから到達できません。
それでも、iPadでRemioを開いてMacをタップすれば、1秒後にはデスクトップが目の前にあります。映像と入力は、2台のデバイスの間を直接流れます。クラウドの中継サーバーも、画面を再エンコードするプロキシも、間にはありません。
これを可能にしている技術には名前があり(NAT越え)、その背後にはSTUN、TURN、ICEという、明確に定義されたプロトコル群があります。これらはWebRTCがブラウザのビデオ通話に使っているのと同じプロトコルで、現代のP2Pリモートデスクトップが、画面のフレームを第三者のデータセンター経由にせずに済む理由でもあります。この記事では、それぞれが何をするのか、なぜ存在するのか、そしてルーターの陰に隠れた2台のデバイスの間で、最も遅延の小さい経路を見つけるために、どう組み合わさるのかを順に説明します。
60秒でわかるNATの問題
インターネットは、すべてのデバイスが、公開経路を持つ自分専用のアドレスを持つように設計されていました。IPv4のアドレス空間全体は約43億個。1981年には十分でしたが、1990年代の終わりには、明らかに足りなくなりました。
その対策が、ネットワークアドレス変換(NAT)でした。ルーターは、ISPからIPv4の公開アドレスを1つ受け取ります。家庭内では、すべてのデバイスが、予約された範囲(通常は192.168.x.xや10.x.x.x)のプライベートアドレスを持ちます。ノートPCがパケットを外に出すと、ルーターは送信元アドレスを自分の公開IPに書き換え、その対応を記憶して転送します。返信が戻ってくると、ルーターは対応を調べて、宛先をノートPCに書き戻します。
だからこそ、外からの接続は既定ではうまくいきません。外から見ると、ノートPCにはアドレスがなく、あるのはルーターだけです。見知らぬ誰かがyour-router-public-ip:5060に送ったパケットは、対応の記憶がないルーターに当たり、破棄されます。
P2Pアプリにとって、これがすべての勝負どころです。両方のピアが、先に外向きに何かを送った記憶がなければパケットを転送しないルーターの内側にいます。どちらも相手に「電話をかける」ことはできません。ルーターと協力して、一時的な経路を開く必要があります。
ホールパンチング:ファイアウォールに、戻りの通信を通させる
からくりは、こうです。ルーターのNATテーブルは、5つ組(送信元IP、送信元ポート、宛先IP、宛先ポート、プロトコル)をキーにしています。デバイスが1.2.3.4:5678へ外向きのUDPパケットを送ると、ルーターは「1.2.3.4:5678から自分の公開IPのポートXに、何らかのUDPパケットが戻ってきたら、このデバイスのポートYへ転送する」という一時的なエントリーを作ります。
このエントリーは、一定の時間(通常は30〜60秒)だけ存在し、何かが更新しない限り期限切れになります。その時間内であれば、宛先アドレスからのどんなパケットも受け入れられます。
これが、P2Pアプリが使う鍵穴です。両方のピアが互いの公開アドレスを知っていれば、それぞれが同時に、相手に向けて外向きのUDPパケットを1つ送れます。それぞれのルーターが、外向きの対応を開きます。最初のパケットは、相手のルーターがまだ対応を開いていないので、破棄されるかもしれません。しかし、2つ目のパケットには、行き先があります。その瞬間から、両方のルーターは、ごく普通の外向きの会話を転送しているつもりになり、2台のデバイスは直接やり取りしています。
これをUDPホールパンチングと呼びます。ちょっとした奇跡のようですが、文書化も十分にされており(RFC 5128)、実環境のほとんどの家庭用NATで動作します。残るケース、つまりシンメトリックNAT、CGNAT、企業のファイアウォールが、そもそもTURNが存在する理由です。
ホールパンチングはハックではありません。外向きのパケットが、内向きの許可を作る。それがNATの設計上の明確な契約であり、P2Pアプリは、その外向きのパケットをわざと送っているだけです。
STUN:「自分の公開アドレスは?」
ホールパンチングには、ひとつの前提条件があります。各ピアは、自分の公開側のアドレスを知っていなければなりません。そうでないと、相手にどこへパケットを送ればよいかを伝えられないからです。そのアドレスは、デバイスの内側からは見えません。iPadが見ているのは、自分のローカルなWi-Fiアドレス(192.168.1.42)です。ルーターがパケットを書き換えた後に、残りのインターネットが目にするアドレスは、まったく別のものです。
STUN(Session Traversal Utilities for NAT、RFC 5389)は、これを解決する小さなプロトコルです。流れは、拍子抜けするほど簡単です。
- ピアが、公開されているSTUNサーバーにUDPパケットを送ります。(Remioは、冗長性のために、CloudflareとGoogleの両方の公開STUNサーバーを使います。)
- STUNサーバーは、通信路上から送信元のIPとポートを読み取ります。これはまさに、そのピアのNAT変換後の公開アドレスです。
- STUNサーバーは、そのアドレスを本文に入れて返信します。「私から見える限り、あなたは
203.0.113.42:48291です。」 - これで、ピアは、相手側にどのアドレスを知らせればよいかがわかります。
この公開側のアドレスは、ICEの用語ではサーバーリフレクシブ候補と呼ばれます。コストは、ほぼゼロです。接続のセットアップ中に1往復するだけで、接続が確立された後は、帯域も遅延も一切増えません。STUNの唯一の仕事は、2つのピアを互いに引き合わせることです。やり取りが始まれば、STUNサーバーの出番はありません。
TURN:ホールパンチングが失敗したとき
ホールパンチングはほとんどのNATで動作しますが、すべてではありません。失敗するケースは現実にあり、それが存在しないふりをするP2Pアプリは、少なからぬ割合のユーザーで、単純に接続できなくなります。
主な悪役は、こちらです。
- シンメトリックNAT。宛先ごとに別々の公開ポートを割り当てるNATです。STUNは、ピアにあなたがポート48291にいると伝えます(STUNサーバーが見たのがそのポートだからです)。ところが、あなたが相手のアドレスにパケットを送ると、ルーターは別のポート、たとえば48317を選びます。相手のルーターは、予期しないポートから来たパケットなので拒否します。ホールパンチングは破綻します。
- キャリアグレードNAT(CGNAT)。モバイル回線や多くのISPのネットワークでは、通信事業者側にもう1段NATを重ねています。知らないうちに2つのNATの内側にいて、両方が協力しなければならないこともあります。CGNATはシンメトリックであることが多く、管理者としてアクセスすることもできません。
- 制限の厳しい企業のファイアウォール。一部の企業ネットワークは、外向きのUDPをすべて遮断するか、特定の宛先にしか許可しません。ホールパンチングにはUDPの経路が必要で、それがなければ見込みはありません。
こうしたケースの最後の頼みが、TURN(Traversal Using Relays around NAT、RFC 5766)です。TURNサーバーは、両方のピアが到達できる中継サーバーです。常に外部からの通信を受け入れる公開アドレスを持っているからです。各ピアは、TURNサーバーへ普通の外向きのTLS接続を行い(どのNATも許可します)、サーバーが双方の間でバイトを転送します。
TURNには、実際のコストがあります。映像のパケットの1つ1つが、余分なネットワークのホップを通らなければなりません。同じ地域のTURN中継サーバーなら、ラウンドトリップの遅延が約30〜80ミリ秒増えます。地域をまたぐ場合(たとえば、東京のピアとサンパウロのピアのために、フランクフルトの中継サーバーを使う場合など)は、80〜200ミリ秒になることもあります。TURNの運営者も帯域の費用を負担します。ストリームのすべてのビットが、運営者の回線を通るからです。
だからこそ、よく設計されたアプリは、ホールパンチングが失敗したと確認できたときにだけ、TURNを使います。その判断は、ICEが自動で行います。
ICE:すべての候補を並行して試す
Interactive Connectivity Establishment(RFC 8445)は、これらすべてを束ねる振り付けです。ICEは、戦略を先に決めたりしません。各ピアについて、あらゆる可能な候補アドレスを集め、そのリスト全体を相手側と交換し、両方のスタックがすべての候補ペアを並行して調べて、最初に動作するものを見つけるために競い合います。
ICEは通常、各ピアについて、次のものを集めます。
- ホスト候補:すべてのネットワークインターフェース(イーサネット、Wi-Fi、仮想インターフェース、IPv4とIPv6)のローカルIPアドレスのすべて。
- サーバーリフレクシブ候補:STUNサーバーから得た公開アドレス。
- リレー候補:TURNサーバー上に割り当てられたアドレス。
2つのピアは、これらのリストを、シグナリングチャネルを通じて交換します。Remioの場合、それはrelay.remio.netへの小さなWebSocket接続で、ICE候補とWebRTCのセッション記述(SDP)を運びます。メディアが流れ始めれば、もうやることはありません。
両方のリストがそろうと、ICEは接続性チェックを始めます。各ピアが、優先順位の順に、すべての候補ペアに沿ってSTUNバインディングリクエストのパケットを送ります。優先順位は、最も遅延の小さい経路を優先するように設計されています。
- ホストからホスト:両方のピアが同じローカルネットワークにいる場合です。理想的なケースで、遅延は数百マイクロ秒、ルーターは関与しません。
- ホストからサーバーリフレクシブ、またはサーバーリフレクシブからサーバーリフレクシブ:ピアが別々のネットワークにいて、それぞれのNATをホールパンチングで越える場合です。実際に「インターネット越しのP2P」というとき、たいていこれを指します。
- 中継サーバーが絡むものすべて:最後の手段です。優先順位の高い経路が、すべて接続性チェックに失敗したときにだけ使われます。
両方向が成功した最初の候補ペアが勝者として指名され、その経路に沿ってメディアが流れ始めます。この一連の処理は、通常1秒足らずで完了します。
ICEは、候補を継続的に集め続けます。セッションの途中でより良い経路が現れた場合(たとえば、スマートフォンがモバイル回線を離れてWi-Fiに入った場合)、ICEは通話を切らずに、新しい経路に再指名できます。
RemioがP2Pを強く優先する理由
Remioはリモートデスクトップアプリであり、ビデオ通話ではありません。遅延の予算は厳しいものです。ホストマシンの前に座っているように感じるには、キャプチャ、エンコード、ネットワーク、デコード、描画のパイプライン全体が、ごく小さくなければなりません。LANでは約8 msで、残りはディスプレイ自身の60 Hzのリフレッシュ周期(1フレームあたり約16.7 ms)です。余計なホップは、すべて罪です。
LAN上のP2P直接接続では、その予算のうち、ネットワークの部分はラウンドトリップで約1〜5ミリ秒です。中継サーバーはなく、バイトは1台のデバイスからもう1台へまっすぐ流れます。Remioのパイプラインでは、これがLANで約8 msの処理にまとまります(社内測定。残りはディスプレイ自身の60 Hzのリフレッシュ周期)。入力は次のフレームが描画される前に届き、リモートのマシンはローカルと見分けがつきません。
TURNを経由した接続では、同じ地域の中継サーバーであっても、ネットワークの部分が30〜80ミリ秒に跳ね上がります。ユーザーが体感する遅延の合計は、40〜100 msになります。ほとんどの作業には十分使えますが、素早いドラッグや、連続クリックでは、体感できます。トラックパッドが、自分のものとは少し違う感触になります。
その差こそが、私たちがセッションをP2Pに留めるために、これほど手間をかける理由です。RemioのWebRTCスタックは、IPv4とIPv6の両方の候補を集め、複数のSTUNサーバーと並行してやり取りし、ICEの候補ペアの選択では、積極的に直接経路を優先します。社内では、測定した接続のRTTを使ってネットワークを分類することまでしています。15 ms未満ならLANとわかるので、エンコーダーは高い値から始まり、はるかに多くの帯域を使えます。それより遅いものはWANとして扱われ、より控えめに調整されます。
そして、これは競合他社がしばしばこっそり省く部分ですが、経路にかかわらず、接続はエンドツーエンドで暗号化されます。画面が当社のサーバーに触れることはなく、TURN中継サーバーでさえ、暗号文しか目にしません。鍵は、どのピクセルが動くよりも前の、ハンドシェイクの間に、2つのピアの間で直接ネゴシエートされるからです。バイトがP2Pで流れても、TURN経由で流れても、Remioのシグナリングサーバーも、TURNの運営者も、それを読めません。P2Pとは、データの経路に第三者が一切いないということです。
中継が避けられないとき(それでも大丈夫です)
ときには、ネットワークの神様がノーと言うこともあります。両端のシンメトリックNAT、厳しいISPを使うモバイル回線の二重CGNAT、既知のクラウドプロバイダー向けの外向きTLSしか許可しない企業のファイアウォール。これらは現実に、よくある構成です。そうした場合、セッションは、中継サーバーを経由するしかなく、そうでなければ成立しません。
RemioのTURNバックエンドはCloudflare Callsで、ほとんどのユーザーの近くにある、世界規模の中継ネットワークを使えます。ICEが中継経路を選ぶと、体験は「ローカルのよう」から「Splashtopのよう」に下がります。十分に使えますが、違いはわかります。同じ地域の中継サーバーでは、追加される遅延は30〜80 msで、地域をまたぐと200 msに達することもあります。
重要なのは、データは、それでもエンドツーエンドで暗号化されていることです。Cloudflareに見えるのは、片方へ向かう暗号化されたUDPパケットと、もう片方へ向かう暗号化されたUDPパケットだけです。課金のためにバイト数を数えることはできますが、画面も、キー入力も、セッションの内容も見られません。Remio側に復号するポイントもありません。パイプラインの中に、Remioのクラウドは存在しないからです。当社はCloudflare経由でTURNサービスを運用しており、ペイロードには一切触れません。
これが、セキュリティホワイトペーパーでさらに詳しく説明している設計です。要点は、P2Pでも中継でも、脅威モデルは同じということです。
IPv6という抜け道
IPv6のアドレスは340澗(3.4 × 1038)個。地球上のすべての砂粒に、それぞれ専用の公開IPを割り当てても、数兆個のおつりがくるほどです。IPv6だけの世界では、NATはほぼ不要です。IPv6に対応した2台のデバイスは、互いのアドレスにパケットを送るだけで、障害になるのは、どちらかの端のホストファイアウォールだけです。
自宅とモバイル回線の両方でIPv6が使えるなら、両端がIPv6のときに、一部のアプリの接続が速くなることに気づいたかもしれません。「候補を集め、ペアを調べる」という一連の動きに、障害が少なくなるからです。発見すべきNAT変換も、STUNへの往復も必要なく、あるのは直接のアドレスだけです。
ただし、落とし穴があります。2026年になっても、世界的な展開は、まだ完了していません。多くの家庭用ルーターは、IPv6への対応が不十分か、まったく非対応です。多くの企業ネットワークは、外部からのIPv6を既定でブロックします。無線区間ではIPv6を提供しても、他の場所ではIPv4にブリッジする通信事業者もあります。純粋なIPv6同士の経路は存在しますが、それだけを唯一の手段として頼ることはできません。
そこでRemioは、本格的なP2Pスタックのすべてがそうであるように、IPv4とIPv6の両方の候補を集め、ICEに競わせます。直接のIPv6経路があって動作するなら、遅延の面では通常それが勝ちます。なければ、ホールパンチングを使ったIPv4が引き継ぎます。両方失敗すれば、中継です。ユーザーがこれらを目にすることは一切なく、接続はただ確立されます。
セッションがどの経路を使っているかを知る方法
セッションがどの経路になったか気になりますか? Remioの接続インジケーターは、その種類をわかりやすい言葉で表示します。P2Pなら「直接」、TURNなら「リレー」です。開発者向けの統計パネルでは、指名されたペアの候補タイプ(host、srflx、relay)や測定したRTTを含む、WebRTCの状態の全体を確認できます。
簡単な読み方をいくつか挙げます。
- RTTが5 ms未満、直接:ホストと同じLAN上にいます。最良のケースです。約8 msの処理(残りはディスプレイ自身の60 Hzのリフレッシュ周期)が実現できます。
- RTTが5〜15 ms、直接:同じWi-Fiネットワークですが、アクセスポイントやメッシュのホップが1つ増えています。それでも優秀です。
- RTTが15〜80 ms、直接:ホストとは別のネットワークにいて、ホールパンチングが成功しました。インターネット越しのP2Pが動いています。
- RTTが30〜80 ms、リレー(同じ地域):シンメトリックNATまたはキャリアグレードNATが、ホールパンチングを阻みました。近くのCloudflare TURNが引き継ぎました。
- RTTが80〜200 ms、リレー:地理的に離れたTURN経由か、あなたとホストが大きく離れた地域にいます。
自宅でも確実にリレーにフォールバックしてしまうなら、よくある原因は、シンメトリックNATを行うISPのモデム、自宅回線のIPv4 CGNAT(光回線の再販事業者では、意外とよくあります)、外部からのUDPをブロックする過剰なファイアウォールです。リモートデスクトップのラグを減らすためのガイドで、よくある原因を順に確認できます。両方のデバイスが同じネットワーク内にあるなら、LAN直接接続のページが近道です。
実環境のパフォーマンス値
ここまでをまとめて、Remioのセッションがたどりうるさまざまな経路ごとに、本番環境で測定している遅延の数値をご紹介します。
- LANのP2P直接接続:ネットワークRTTは1〜5 ms。エンドツーエンド(入力イベントからピクセルの更新まで)は、パイプラインの残りの部分が協調して、約8 msの処理(残りはディスプレイ自身の60 Hzのリフレッシュ周期)です。
- 余分なホップがある同一ネットワークのWi-Fi:ネットワークRTTは5〜10 ms。
- TURN中継、同じ地域:ネットワークRTTは30〜80 ms。
- TURN中継、地域をまたぐ:ネットワークRTTは80〜200 ms。
- 4G/5Gモバイル回線、ホールパンチングしたP2P:ネットワークRTTは40〜100 ms。
これらはRemioのベンチマークの数値と一致しており、LANとWANのしきい値をRTT 15 msに設定した理由でもあります。直接経路を、中継(最小30 ms)やモバイル回線(最小40 ms)の経路から、ほとんど誤判定なくはっきり分けられるからです。
NAT越えは、個々のプロトコルは単純なのに、組み合わせが厄介な分野のひとつです。ほとんどのユーザーは、ICE、STUN、TURNの存在を知る必要は一切なく、どこからどこへでも素早くつながるアプリを体験するだけでしょう。気づかれないとき、プロトコルは仕事をしています。気づいたとき、たとえば、セッションの開始に少し時間がかかったり、「直接」が「リレー」に変わったりしたときには、もう頭の中のモデルが手に入っています。
Remioのネイティブなパイプラインと、1〜5 msのネットワーク遅延を約8 msの処理(残りはディスプレイ自身の60 Hzのリフレッシュ周期)に変える選択については、ネイティブが重要な理由をご覧ください。中継経路の脅威モデルについては、セキュリティホワイトペーパーをご覧ください。あるいは、機能を見て、Remioをダウンロードして、動作を体感してみてください。