TL

NAT 越え技術:ホールパンチングと NAT 種別

NAT 配下の端末同士を直接つなぐ仕組みがわかります。ホールパンチングが成立する条件と、Symmetric NAT で破綻して TURN 中継へ退避する理由まで原理から押さえます。

応用NATSTUNTURNWebRTCP2PUDP最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.NAT は外向きで作ったマッピングを再利用する。Full-cone は宛先を問わず再利用、Restricted は宛先 IP/ポートで絞り、Symmetric は宛先ごとに別マッピングを割り当てる。
  • 2.UDP ホールパンチングは、両端が同じ宛先へ外向きパケットを撃ち合うことで互いの NAT に着信用の穴を開ける手法。シグナリングサーバー(STUN)が観測した外側アドレスを交換して成立する。
  • 3.Symmetric NAT は宛先ごとに外側ポートが変わり相手に伝えた穴が無効化されるため直結に失敗する。この場合は TURN サーバーで全トラフィックを中継して通す。

なぜ NAT 越えが難問なのか

NAT 配下の端末は、内側から発信した通信には返事を受け取れますが、外から突然来る着信は変換テーブルに対応が無いため捨てられます。この基本動作は /network/nat/ で扱ったとおりです。問題は、双方が NAT の内側にいる P2P(WebRTC のメディア、オンラインゲーム、ファイル直送など)で起きます。どちらも「先に着信を待つ」側になれないため、素朴には永遠につながりません。

ここで効くのが、NAT が 内側から外へ出たときに作るマッピング(穴) を、戻り通信が一定条件で再利用できるという性質です。両端が「先に外へ撃って穴を開け、その穴へ相手を呼び込む」ことができれば、中継なしで直結できます。これがホールパンチングの核心ですが、成功するかどうかは NAT の 種別 に強く依存します。

NAT 種別:マッピングとフィルタリングを分けて捉える

RFC 3489(旧 STUN)由来の古典的分類では、NAT を4種に分けます。鍵は2つの軸です。ひとつは マッピング挙動(同じ内側アドレスから出すとき、宛先が変わっても同じ外側ポートを使い回すか)、もうひとつは フィルタリング挙動(外から来たパケットを、どの送信元なら穴へ通すか)です。

上の3つは外側ポートを使い回す(cone 型)。Symmetric だけは宛先が変わると外側ポートも変わるのが決定的な違い。
種別外側ポートの割り当て外から通す相手
Full-cone宛先が変わっても同一(内側アドレス単位で固定)誰でも(穴さえ開けば任意の送信元を通す)
Restricted-cone同一(宛先で変えない)こちらが過去に送った宛先 IP からのみ
Port-restricted-cone同一(宛先で変えない)送った宛先 IP かつ同じポートからのみ
Symmetric宛先ペアごとに別ポートを割り当てる送った宛先 IP/ポートからのみ

cone 型に共通するのは、外側ポートが 宛先に依存しない ことです。つまり STUN サーバーへ問い合わせて観測した外側アドレスが、相手ピアへ向けて使う外側アドレスと一致します。フィルタリングの厳しさ(誰を通すか)はホールパンチングの手順で吸収できます。一方 Symmetric は、宛先が変わると外側ポートまで変わるため、STUN で観測した値が相手向けには通用しません。これが後述の破綻原因です。

cone 型でもフィルタは別問題

Full-cone 以外の cone 型は、穴が開いていても許可していない送信元からの着信は落とします。だからホールパンチングでは「両端が互いに相手宛へ外向きパケットを撃つ」ことが必須です。撃つことで相手 IP(および Port-restricted ならポート)がフィルタの許可リストに入り、続く相手の着信が通ります。

STUN:自分の外側アドレスを知る

ホールパンチングを始めるには、まず各端末が 自分が外からどう見えるか(NAT 変換後の外側 IP とポート)を知る必要があります。これを担うのが STUN(Session Traversal Utilities for NAT)です。

Client(内側 192.168.1.10:50000)
  -> STUN サーバー(203.0.113.50:3478) へ Binding Request

STUN サーバーは受信パケットの「送信元」をそのまま返す
  <- Binding Success: XOR-MAPPED-ADDRESS = 198.51.100.7:40000

STUN サーバーは特別なことをせず、受け取ったパケットの送信元 IP/ポート(=その端末の NAT がそのとき作った外側マッピング)を応答に詰めて返すだけです。クライアントは自分の内側アドレスと、返ってきた外側アドレスを比べることで、NAT 配下かどうかと、外側アドレスの値を把握します。

ここで重要なのは、STUN への問い合わせで観測した外側ポートが、そのまま相手ピアへ使えるとは限らない ことです。cone 型なら使えますが、Symmetric では STUN サーバー宛のマッピングと相手ピア宛のマッピングが別物になります。

UDP ホールパンチングの手順

両端 A・B が、シグナリング経路(事前に用意したサーバー経由のチャネル)で互いの外側アドレスを交換できる前提で進めます。シグナリングは制御情報のやり取りだけで、メディア本体は流しません。トランスポートに UDP を使うのは、TCP の対称的な接続確立(3 ウェイハンドシェイク)がホールパンチングと相性が悪いためです(/network/tcp-udp/ 参照)。

1. A,B それぞれ STUN で自分の外側アドレスを取得
     A_pub = 198.51.100.7:40000
     B_pub = 203.0.113.9:50000
2. シグナリングサーバー経由で A_pub と B_pub を相互に交換
3. A は B_pub 宛、B は A_pub 宛へ、ほぼ同時に UDP を送信
     - この「外向き送信」が各自の NAT に穴を開け、
       相手 IP をフィルタの許可リストへ登録する
4. 先に着いた側はフィルタで弾かれることがあるが、
     後続パケットは互いの穴が開いた後なので通る
5. 双方向に到達確認できたら、その経路で直接通信を継続

成立の条件を分解すると次のとおりです。第一に、両端が相手宛へ外向き送信すること。一方だけが待っていてはフィルタが開きません。第二に、cone 型のように STUN 観測アドレス=相手向けアドレス が成り立つこと。第三に、開けた穴が応答到達まで タイムアウトせず維持 されること。UDP マッピングは無通信だと数十秒で消えるため、定期的なパケット送信で温め続けます(この keepalive の必要性は /network/socket-port/ のポート寿命とも通じます)。

ホールパンチングが開けるのは『戻りの穴』

よくある誤解は「相手の NAT をこじ開けている」という理解です。実際には各自が自分の NAT に外向きの穴を開け、相手をその穴の許可リストへ載せているだけです。NAT に脆弱性を突いているのではなく、外向き通信の正規マッピングを両側で同時に使う、という正攻法だと押さえてください。

なぜ Symmetric NAT で破綻するのか

Symmetric NAT は、内側アドレスが同じでも 宛先(IP とポート)が変わるたびに別の外側ポートを割り当てます。この一点がホールパンチングを崩します。

A の NAT が Symmetric の場合:
  A -> STUN(203.0.113.50:3478)  で観測: 198.51.100.7:40000
  A -> B_pub(203.0.113.9:50000) で実際に使う外側: 198.51.100.7:41001 (別ポート)

B は「198.51.100.7:40000 へ撃て」と教わっているが、
A が B 向けに開けた穴は 41001。B の着信は 40000 宛なので
A のフィルタに一致せず破棄される。逆方向も同様にずれる。

STUN で観測した :40000 は STUN サーバー宛に作られた穴であり、相手ピア宛の穴 :41001 とは別物です。相手に伝えたアドレスが指す穴が存在しないため、撃ち合っても到達しません。両端のどちらかが Symmetric なら、もう片方が cone 型でも、外側ポートが事前に予測できないため基本的に直結は失敗します。

ポート番号が連番で増える実装を狙って次のポートを推測する ポート予測 という回避策もありますが、割り当てがランダム化された NAT や CGN(キャリアグレード NAT)では成功率が低く、信頼できる手段にはなりません。

二重 NAT・CGN は特に厳しい

モバイル回線や一部の固定回線では、宅内ルータの外にプロバイダーの大規模 NAT がもう一段あり、しばしば Symmetric 的に振る舞います。自前ルータが cone 型でも、外側の CGN が宛先ごとにポートを変えれば全体として Symmetric 相当になり、ホールパンチングは通りにくくなります。

TURN:直結を諦めて中継する

直結が成立しないときの最終手段が TURN(Traversal Using Relays around NAT)です。TURN サーバーは公開アドレスを持つ 中継器 で、両端は「外向き通信」として TURN へ接続し、以降のメディアを TURN 経由で相手へ転送してもらいます。

A <-(外向き)-> TURN(公開IP) <-(外向き)-> B

A も B も自分から TURN へ発信するため、NAT 種別に関係なく
マッピングが作れる。TURN は A から来たデータを B へ、
B から来たデータを A へリレーする。

要点は、両端ともに 自分から TURN へ外向き接続する ため、Symmetric であっても穴は問題なく開く点です。直結(ホールパンチング)が NAT 種別に依存するのに対し、TURN は中継で確実性を買います。代償は、すべてのトラフィックがサーバーを経由することによる 遅延の増加・帯域コスト・サーバー負荷 です。だから TURN は常用せず、直結が無理なときの退避先に位置づけます。

WebRTC が使う ICE(Interactive Connectivity Establishment)は、この優先順位を体系化した枠組みです。

ICE は候補を集めて総当たりで疎通確認し、つながった中で最も優先度の高い経路を採用する。
候補種別経路優先度の考え方
Host candidate端末のローカル IP で直接同一 LAN なら最速。最優先で試す
Server-reflexive (srflx)STUN で得た外側アドレス経由で直結NAT 越えの本命。ホールパンチングで成立を狙う
Relayed (relay)TURN サーバーで中継最後の保険。確実だが遅延・コスト大で最低優先

ICE は複数の候補(ローカル、STUN 由来、TURN 由来)を集め、ペアごとに疎通確認(connectivity check)を行い、通った中で最良のものを選びます。つまり「まず直結を試し、ダメなら中継へ落ちる」という退避を自動化したものが ICE であり、本記事の STUN・ホールパンチング・TURN はその構成部品にあたります。

まとめ:種別が運命を決める

NAT 越えの成否は、煎じ詰めると マッピングが宛先に依存するか で決まります。cone 型は外側ポートを使い回すため STUN 観測アドレスがそのまま相手に使え、両端が撃ち合えばホールパンチングで直結できます。Symmetric は宛先ごとにポートを変えるため、観測した穴と相手向けの穴がずれて破綻し、TURN 中継へ退避するしかありません。実務では、まず ICE に任せて自動で最良経路を選ばせつつ、TURN を確実な保険として用意しておくのが定石です。NAT そのものの変換テーブルの仕組みは /network/nat/ を、UDP を土台に選ぶ理由は /network/tcp-udp/ を併せて読むと理解が固まります。

ネットワーク Article

NAT 越え技術:ホールパンチングと NAT 種別を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

NAT

比較で見る軸

難易度: advanced / カテゴリ: ネットワーク / タグ数: 6

導入後に効く点

UDP ホールパンチングは、両端が同じ宛先へ外向きパケットを撃ち合うことで互いの NAT に着信用の穴を開ける手法。シグナリングサーバー(STUN)が観測した外側アドレスを交換して成立する。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
ネットワーク
タグ数
6

判断チェックリスト

  • 自社の用途が「NAT / STUN」に近いか確認する。
  • 強みである「NAT は外向きで作ったマッピングを再利用する。Full-cone は宛先を問わず再利用、Restricted は宛先 IP/ポートで絞り、Symmetric は宛先ごとに別マッピングを割り当てる。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

NATSTUNTURNWebRTCP2PNATSTUNTURN