ネットワーク●●●○○

NAT

Network Address Translation ・ なっと

ルータが送信元のアドレスとポートを書き換え、1つのグローバルIPを多数の端末で共有する仕組み。

✦ 30秒で試す — 航海家じゅうの端末が、外からはたった1台に見えている2台が同じ窓口番号で同時に外へ出ると、どうなる?予想してみる

概要

NAT(Network Address Translation)は、パケットが通過するルータで IPアドレスを書き換える仕組みです。最も身近なのは、家庭やオフィスの内側で使う「プライベートIPアドレス」(192.168.x.x など、インターネットでは通用しない住所)と、インターネットで通用する「グローバルIPアドレス」の変換です。自宅の Wi-Fi につながったスマホや PC が、たった1つのグローバルIPアドレスを共有してインターネットを使えるのは、ルータの NAT が裏で住所を書き換え続けているからです。

たとえるなら、NAT は会社の代表電話と交換手です。外から見えるのは代表番号(グローバルIP)だけで、内線番号(プライベートIP)は外には出ません。内側から外へ電話をかけるたびに、交換手であるルータが「この通話は301号室のもの」と台帳に書き留め、返事が来たら台帳を見て正しい部屋に取り次ぎます。逆に、台帳にない相手から突然かかってきた電話は、どの部屋につなげばよいか分からないので取り次げません。

開発の現場では、「サーバのログに残るクライアントのIPアドレスが、実際の端末のものではない」「同じオフィスの全員が同じIPに見える」「外から自宅のPCに直接つなげない」「しばらく放置した接続が突然切れる」といった形で NAT の存在に気づきます。ネットワーク越しの通信をデバッグするうえで、避けて通れない基礎知識です。

なぜ生まれたか

IPv4 のIPアドレスは32ビット、つまり約43億個しかありません。インターネットが研究者のネットワークだった時代には十分な数でしたが、1990年代に商用利用が爆発的に広がると、「地球上のすべての機器に一意のアドレスを割り当てる」という前提が崩れることが確実になりました。実際、アドレスの大元の在庫(IANA の中央プール)は2011年に尽き、アジア太平洋地域の在庫も同じ年に尽きています。

根本的な解決策として設計されたのが、アドレスを128ビットに広げた IPv6 です。しかし世界中の機器とネットワークを一斉に置き換えることはできません。そこで1994年に RFC 1631 として提案されたのが NAT でした。「組織の内側では自由に使えるプライベートアドレスを使い(1996年の RFC 1918 で 10.0.0.0/8・172.16.0.0/12・192.168.0.0/16 が定められました)、外に出る瞬間だけ少数のグローバルアドレスに書き換える」という発想で、グローバルアドレスの消費を劇的に減らしたのです。応急処置として生まれた NAT は、結果的にインターネットの形を30年にわたって決め続けてきました。

詳細

NAPT — ポート番号まで書き換えて1つのIPを共有する

素朴な NAT はプライベートIPとグローバルIPを1対1で変換するだけですが、それではグローバルIPの節約になりません。実際に広く使われているのは NAPT(Network Address Port Translation。Linux では IPマスカレードとも呼ばれます)で、IPアドレスに加えてポート番号も書き換えることで、1つのグローバルIPを多数の端末で同時に共有します。

内側の端末がパケットを外へ送るとき、ルータは「送信元 192.168.1.10:51000 → 変換後 203.0.113.5:62001」のような対応を変換テーブルに書き、パケットの送信元を書き換えて送り出します。外から返事が 203.0.113.5:62001 宛てに届いたら、テーブルを逆に引いて宛先を 192.168.1.10:51000 に書き戻し、内側へ転送します。ポート番号が「どの端末の、どの通信か」を見分ける鍵になるので、1つのグローバルIPで数万の同時通信をさばけるのです。

プライベートネットワークPC192.168.1.10:51000スマホ192.168.1.11:51000NATルータグローバルIP 203.0.113.5外向きに送信元を書き換え戻りはテーブルで逆引きWebサーバ198.51.100.7:443変換テーブル192.168.1.10:51000 ←→ 203.0.113.5:62001192.168.1.11:51000 ←→ 203.0.113.5:62002
NAPT の動き — ルータが変換テーブルを頼りに、送信元のアドレスとポートを書き換える

図の2台はどちらも同じポート 51000 を使っていますが、ルータが外向きには別々のポート(62001 と 62002)に割り当て直すので衝突しません。Web サーバから見ると、2台はどちらも「203.0.113.5 のどこかのポート」で、区別のしようがありません。

行には寿命がある — タイムアウト

変換テーブルの行には有効期限があり、しばらく通信がないと消されます。消さなければ、テーブルは終わった通信の行であふれてしまうからです。目安は UDP で数十秒〜数分、TCP で数分〜数時間ですが、機器によってまちまちで、RFC 4787 や RFC 5382 が「短すぎないこと」を推奨している程度です。「アイドル状態の TCP 接続が、ある日突然切れる」というトラブルの正体が NAT のタイムアウトだった、というのは実務でよくある話です。行が消えたあとに届いた応答は、宛先が分からないので捨てられます。データベースの接続プールや長時間の WebSocket が、定期的に小さなパケットを送る(キープアライブ)のは、この行を生かし続けるためでもあります。

内側の端末からパケットを運んで、ルータで送信元が書き換わる様子と、変換テーブルに行が生まれて消えていく様子を確かめてください。外の見知らぬ相手から送ったパケットがなぜ届かないのかも、テーブルを見れば分かります。

⚡ 体験: パケットを NAT ルータに通して、住所の書き換えを見る
内側(プライベートアドレス)外(インターネット)PC192.168.1.10スマホ192.168.1.11NAT ルータ外: 203.0.113.5Web サーバ198.51.100.7:443見知らぬ相手203.0.113.99:40000サーバから見えた送信元—→ Web:443→ Web:443→ 内側へパケットを運ぶと、ここにヘッダが出ます送信元—宛先—変換テーブル(NAT ルータの台帳)内側外側(書き換え後)相手まだ行はない(内側から送ると生まれる)残り時間
見つけたこと 0 / 4: まだ

内側の PC のパケットをつかんで、NAT ルータへ運んでください(タップでも送れます)。ルータを通るとき、ヘッダの送信元がどう変わるかを見てください。

NAT越え問題 — 内側から始めないと通れない

NAPT の変換テーブルの行は、内側から外への通信をきっかけにしか生まれません。裏を返すと、外から内側の端末へ最初のパケットを送る手段がありません。行のない宛先へのパケットは捨てられるからです。これが「NAT越え(NATトラバーサル)問題」で、オンラインゲーム、IP電話、P2P のファイル共有、ビデオ通話など、端末同士が直接つながりたいアプリケーション共通の悩みになりました。

回避策は大きく3つあります。1つ目はポートフォワーディング(静的な変換)で、「グローバルIPのポート 8080 宛ては、必ず 192.168.1.10 へ」とルータに固定で設定する方法です。2つ目は STUN で、外のサーバに問い合わせて「自分は外からどう見えているか(どのアドレスとポートに変換されたか)」を知り、その情報を相手と交換して、双方から同時にパケットを送り合って行を作る「ホールパンチング」を行います。3つ目は TURN で、どうしても直接つながらない場合に外の中継サーバを経由します。WebRTC はこの3つを組み合わせて、使える経路を自動で探す仕組みを標準で備えています。

NAT の「性格」— コーン型とシンメトリック型

ホールパンチングが効くかどうかは、NAT がどう行を作り、何を通すかという「性格」で決まります。古い STUN の仕様(RFC 3489)は、これを4つに分類しました。一度作った変換を相手を問わず使い回し、誰からでも受け取る「フルコーン」、相手のIPアドレスが一致すれば受け取る「制限コーン」、IPアドレスとポートの両方が一致したときだけ受け取る「ポート制限コーン」、そして相手ごとに別のポートを割り当てる「シンメトリック」です。いまの仕様(RFC 4787)は、この性格を「どう割り当てるか(マッピング)」と「何を受け取るか(フィルタリング)」の2軸に分けて記述します。

コーン型シンメトリック型端末…1.10:51000NATSTUN相手外側 :62001外側 :62001STUN で知った番号が相手にも通じる端末…1.10:51000NATSTUN相手外側 :62001外側 :62007相手ごとに番号が変わり、予告が外れる
コーン型とシンメトリック型の違い — 同じ端末・同じポートから2つの相手へ送ったとき、外側のポートが揃うか、相手ごとにずれるか

コーン型なら、STUN サーバに教わった「外側の住所」がほかの相手に対してもそのまま使われるので、その住所を相手に伝えておけばホールパンチングが成立します。シンメトリック型では、相手が変わるたびに新しいポートが割り当てられるため、STUN で知った番号は STUN サーバとの通信にしか使われず、相手に伝えた住所が外れてしまいます。携帯回線の NAT や企業の NAT にはシンメトリック型が少なくなく、STUN だけでは直結できず TURN の中継に頼ることになります。

同じ NAT の内側にいる端末同士が、グローバルIP宛てに通信しようとする場合もあります。外へ出かけたパケットをルータが内側へ折り返す「ヘアピン NAT(NAT ループバック)」に対応していない機器では、この通信が届きません。家庭内のサーバに、家の中から外向きのドメイン名でアクセスできない、という定番のつまずきの原因です。

副作用としての防御、CGN、そして IPv6

NAT には「外から内側の端末に直接届かない」という性質があるため、結果的に簡易な防御として働いてきました。ただしこれは副作用で、通信の中身を検査しているわけではないので、ファイアウォールの代わりにはなりません。内側の構成を隠せる点は利点でもありますが、VPN や一部の古いプロトコル(ヘッダの中にIPアドレスを書き込むもの)が NAT と相性が悪い原因にもなっています。端末へのプライベートアドレスの配布は通常 DHCP が担い、家庭用ルータでは NAT・DHCP・簡易ファイアウォールが1台に同居しています。

アドレス枯渇が進んだ結果、ISP 自身が NAT を行う CGN(Carrier-Grade NAT)が携帯回線を中心に広まりました。利用者の端末はプライベートアドレス(CGN 用の 100.64.0.0/10 など)しか持たず、多数の契約者で1つのグローバルIPを共有します。家庭のルータの NAT と重なって二重の NAT になることも珍しくありません。こうなると「IPアドレスでユーザーを特定・制限する」という古い設計は成り立たず、アクセス制御やレート制限では「同じIP=同じユーザー」とは限らないことを前提にする必要があります。

IPv6 では、すべての機器にグローバルアドレスを配れるだけの数があるため、アドレスを節約するための NAT は原則として不要になります。端末同士が直接アドレスを指定して通信できるので、NAT越えの苦労もなくなります。ただし「外から勝手に入ってこられない」という NAT の副作用がなくなるぶん、家庭用ルータには、内側から始めた通信の戻りだけを通すステートフルなファイアウォールを既定で入れておくことが求められます。NAT が担っていた役割のうち、アドレスの節約は IPv6 が、門番の役はファイアウォールが引き継ぐ、という整理です。

試問

家の PC とスマホが NAT ルータを通ってインターネットの Web サーバとやり取りする図です。PC のパケットをルータへ運ぶ(タップでも可)と、送信元が書き換わって変換テーブルに行ができ、応答がその行を逆にたどって戻ります。行の寿命は120秒で、「時間を進める」で早送りでき、Web サーバからは「応答を送る」で遅れた応答を返せます。

✦ 命題挑戦中

変換テーブルの行の寿命は120秒。最初の送信から150秒たっても、同じ外側ポートのまま PC へ応答を届けよ

  • PC から送って、外側のポートを割り当ててもらう
  • 最初の送信から 150秒以上たったあとに、PC へ応答が届く
  • そのときの外側のポートが、最初と同じ番号のまま
⚡ 体験: パケットを NAT ルータに通して、住所の書き換えを見る
内側(プライベートアドレス)外(インターネット)PC192.168.1.10スマホ192.168.1.11NAT ルータ外: 203.0.113.5Web サーバ198.51.100.7:443見知らぬ相手203.0.113.99:40000サーバから見えた送信元—→ Web:443→ Web:443→ 内側へパケットを運ぶと、ここにヘッダが出ます送信元—宛先—変換テーブル(NAT ルータの台帳)内側外側(書き換え後)相手まだ行はない(内側から送ると生まれる)残り時間

内側の PC のパケットをつかんで、NAT ルータへ運んでください(タップでも送れます)。ルータを通るとき、ヘッダの送信元がどう変わるかを見てください。