NAT動作をめぐる誤解まとめ

概要

この記事では、P2P通信の快適性などに大きく影響するところでありつつ、メーカー・プロバイダ側からそれほど積極的に情報が提供されているとは言えないNAT機器の動作について、よくある誤解をいくつか取り上げて解説します。

NAT動作に関する前提知識(cone NAT, symmetric NATあるいはEIM/APDFなどの用語)NATタイプ、ポートセービングIPマスカレード、UDPホールパンチング、STUN - turgenev’s blogなども参照してください(多少被っている内容もあります)。

Map-e(v6プラス・OCNバーチャルコネクトなど)ではポート開放ができない?

この記事を読む人でここを勘違いしている人はあまりいないと思いますが、まずは初歩的なところから行ってみましょう。Map-eによるIPv4 over IPv6(IPoE)通信ではIPv4のグローバルアドレスが割り当てられますが、他のユーザーと共有されており、自分に割り当てられた一部のポートしか使うことができません。OCNバーチャルコネクトなら1008個、v6プラスなら240個などと、サービスにより違いもあります。

グローバルIPへのNATはあくまでユーザー側で好き勝手に行えるので、この割り当てられた範囲内のポートであればポート開放などは自由に設定することができます。ただしTP-Link製など一部のルーターはMap-eで動かすとポート開放ができないものもあるようです。Map-eは多分国内の独自規格なので国産のルーターを買ったほうが安全な気がします。

また、一部のプロバイダではIPoE IPv6接続とPPPoE接続を同時に使わせてくれるところもあり、これだとPPPoEの方でポート開放ができます(ただし速度が遅くなるかもしれない)。これに関しては自分の過去記事のフレッツ光関連の設定について(ドコモ光、ひかり電話、IPoE/IPv4 over IPv6とPPPoEの併用など) - turgenev’s blogIPoE/PPPoE併用時(など)に一つの端末から同時に複数の接続経路を利用する - turgenev’s blogを含めて多くの情報があると思います。

あと、IPv6に関してはそもそもNATがないのでファイアウォールに穴をあければ自由にポート開放(と呼ぶのが正しいかわかりませんがそれと同等のこと)ができます。

DS-Lite(transix・クロスパスなど)ではポート開放ができない?

まあこれは基本的には正しいです。DS-Liteではプロバイダ側でNATが行われるため、グローバルIPに来た通信の扱いには手が出せません。

ただし、DS-LiteのNATはキャリア回線などと同じくフルコーンNATで、これはUDPだけでなくTCPもです。つまり、内側のTCPポートからインターネット側に何らかのパケットを送信してグローバルIP上のポートが割り当てられたとすると、その割り当てが有効な間はこのグローバルIP上のポートは任意の場所からの通信を受け入れて内側に通すようになります。つまり一時的にポートが開放された状態になるということです。

ということは、適当なホストにむけて一定間隔でkeepaliveパケットみたいなのを送っておけばそのTCPポートはいつまでも開放されるということになります。Natternatmapはこれをやってくれるようです。

TCPではなくUDPに関して言えば、まさにこれと同じことをやるのがUDPホールパンチングです。ポート開放の目的がVPNであれば、UDPホールパンチングをやってくれるVPNソフトウェア(tailscaleとかzerotierとかSoftEtherとかhamachiとか)を使うことで、ポート開放と同等の(リレーサーバーを介しない)VPN通信環境が実現できます。Tailscaleであれば他ユーザーにデバイスをシェアする機能もあるので友人同士などであればこれを使って(ポート開放が必要な)ゲームのマルチプレイをすることもできます。

まあとはいえ普通にポート開放ができたほうが何かと嬉しいので、(この記事でこのあと説明する色々な要素を加味した上で)自分だったらMap-eを選ぶと思います。

ポートセービングIPマスカレードとSymmetric NATは同じ意味?

違います。これはNATタイプ、ポートセービングIPマスカレード、UDPホールパンチング、STUN - turgenev’s blogのAddress Dependent Mappingあたりの説明をちゃんと読めばわかると思うのですが、ポートセービングIPマスカレード(ポートの共有)が行われることとSymmetric NATであることは基本的には完全に独立です。「ポートの共有を行わないSymmetric NAT」も「ポートの共有を許容し、結果として同じ内側(Address, Port)から複数の異なる宛先への通信に同じポートが使われる可能性があるNAT」も何の矛盾もなく可能です。

唯一、確実に言えることは、「ポートの共有が行われるならEndpoint Independent Mapping(cone NAT)ではない」ということです。EIMではないからといってSymmetric NATであるとは限らないというだけの話です。

ただ、ポートの共有を行わないSymmetric NATではEIMよりもかなり多くのポートを消費してしまうので、「Symmetric NATならばポートの共有を行う実装が多い」というのは傾向としては正しいのかもしれません。これに関しては色々なSymmetric NAT実装を見てみないとわかりません。

v6プラスとかはポートが少ないからポートセービングIPマスカレードを搭載しているYAMAHAとかNECルーターを買うべき?

これも間違いです。Linuxのnetfilterのconnection trackingとNAT動作の仕組み - turgenev’s blogでも解説していますが、多くの安物のルーターに搭載されていると思われるLinux(netfilter)のNAT機能はデフォルトでポートセービングIPマスカレードを行います。TCPUDP両方で有効です。家にあるBuffaloとNEC(Aterm)の最安価格帯の機種でも、NTT製のHGWでもそうでした。CentOSでOCNバーチャルコネクト | QuintRokkこのへんでも問題なくポートが使いまわされていることが確認できます。

もちろん他の性能面で差はあれど、少なくともポートの枯渇を避けるためという理由で高級品を買う必要はありません。

念のためですがポートセービングIPマスカレードが搭載されていればv6プラスの240ポートであっても困ることはまずありません。

EIM/ADF(アドレス制限コーンNAT)はNATタイプBになる?

間違いです。Nintendo Switchでは「NATタイプ」をA-Dの4段階で判定でき、EIM/EIF(フルコーン)ならA、EIM/APDF(ポート制限コーン)ならBになるのですが、両者の間にあたるEIM/ADF(アドレス制限コーン)についてはフルコーンと同じくNATタイプAになります。よく読まれているイカスミカフェの「NAT」「NAT越え」「NATタイプ」ってなーに?や、スプラトゥーン2とNATの奥深い関係(2ページ目) | 日経クロステック(xTECH)などでは間違って記述されているため注意が必要です。おそらく、EIM/ADFの実機がほとんどなくてテストしていないのでしょう。Nintendo Switch の「NATタイプ」判定条件 #Network - Qiitaは正しいです。

実際、UDPホールパンチングの成立条件の表を見ていると、EIM/ADFではEIM/EIFと同じく任意の相手とP2Pが成立するので、タイプAと判定されるのは妥当です(厳密には毎回違うアドレスが割り当てられるような変なNATが相手だったら通信は成立しにくくなりますが、そんなものは普通はありません)。

SymmetricPort RestrictedConeRestrictedConeFull ConeFull ConeRestricted Cone×Port RestrictedCone××Symmetric

またEIFと違ってADFは既知のアドレスとの通信しか通さないのでセキュリティ的にもベターです。逆にEIM/EIF以外のNATタイプは、既知のアドレスからの通信しか内側に通さず、かつ既知のアドレスからの通信であれば(相手が適切なポートを使用すれば)内側に通ってしまうという点ですべて同じです(TCPのConnection Dependent Filteringなどは除く)。そう考えるとEIM/ADFは妥協点として一番良さそうな気がします。

ただ、実装が不十分(EIM/ADFを想定していない)だとEIM/ADFとSymmetricの間でのUDPホールパンチングが成立しない可能性も否定はできず、そこは実装ごとに調べるしかないです。

実機を触る機会がなくてPS4/PS5やXBoxでの判定がわからないので、だれか試せた人がいればコメントで教えてください。

DMZするとフルコーンNATになってNATタイプがAとか1になる?

現象としては大体そうですが厳密には違います。

DMZホスト機能とは、(ほとんど)全てのルーターのポートを番号を変えずに特定IPに転送する機能で、言い換えれば特定のIPの全ポートを開放することになります。基本的には直接インターネットに接続されたような格好になりフィルタリングの類もなくなるのでNATタイプはA(あるいはタイプ1、オープン)になることが多いでしょう。任天堂のページでも公式に案内されています。また英語圏でもiptablesでfull cone NATを作る方法などとして紹介されているのを見かけます。

ただ、少なくともnetfilterの挙動に関して言えば、絶対に固定で内側ポートと同じ番号が割り当てられるというわけではなく、他のIPと競合すれば意図したポートが割り当てられない(結果としてEIMにならない)可能性はあります。まあこれは確率的には低いのでUDPホールパンチングが成立しにくくなる心配をする必要はありません。

あとは一応、内側からの通信では全然別のポートが割り当てられる(DNATが固定なだけでSNATはランダム、とか)という動作の可能性もあり、これだとSTUNとかを使おうとするとうまくいかなくなる気がします(外部からの接続を受け入れるだけなら問題ない)。そんな実装はあまりないのかもしれませんが。

それと、DMZホストでは全てのポートが常時開放されています。EIM/EIFはあくまでマッピングが存在する間だけ「一時的にポートが開放される」動作です。ゲーム機に使うなら気にする必要はなさそうですが一応セキュリティ的にはEIM/EIFのほうが少しだけマシです。

余談ですが、DMZホスト的なことをするにしても1-1023の特権ポートを開放するのは危険なので1024-65535(あるいは可能なら32768-65535などエフェメラルポートの範囲のみ)にしておいた方が無難です(40000-65535で十分だったという情報があります)。一時期、任天堂でも間違って案内されていたようです。

これも余談ですがこの「DMZホスト機能」がある時点でそのルーターには何らかの形でポートセービングIPマスカレードが備わっていることが明らかです。さもなければ、全ポートが特定のIPに転送されている状態で別の端末がインターネット通信できるはずがありません。

あとこれも余談ですが、この「DMZホスト機能」というのは、原義の「DMZ」とは全く別物です(参考:ブロードバンドルータのDMZホスト機能 2台のルータでDMZを用いたネットワークを構築し安全に自宅サーバを公開する | 積水成淵日記natテーブルを利用したLinuxルータの作成:習うより慣れろ! iptablesテンプレート集(2)(6/6 ページ) - @ITなど)。

DS-LiteはEIMなのにポートが1024しかないから枯渇すると詰む?

EIMということは家の中の機器が何かポートを使用するごとに1024個のうち1つが消費されるので、まあまあ人数が多かったりすると実際わりと枯渇するようです。それでNATもキャリア側でやってるから手が出せなくて詰み、という主張です。

まあ普通に使っているだけならそうなりますが、むこうのNATが機能不足ならこちらで勝手にポートセービングIPマスカレードをして出口を絞ってやれば解決します。つまり適当なLinuxマシンとかYAMAHA/NECみたいなルーターを用意して、家の全部の機器をその配下にして、出口ポート数を1024に絞ってNATして、それからDS-Liteルーターに食わせれば、そもそも出口が1024個なのでキャリア側では絶対に枯渇しないというわけです。

ちなみに出口を絞ってNATするのは単に使うポートを少なくするだけなので潜在的には安物ルーターでも全然できるはずなんですが、残念ながらこれを自由に設定させてくれるような安物ルーターは無さそうです。もしあったらそれを使うといいと思います。

あとそもそもDS-LiteってプライベートIPがついたLAN内のパケットをそのままIPv6にラップして家の外に出してるので、NATしておいた方がセキュリティ的にも安心感はあるかもしれません。

ただしこれだとDS-LiteのEIM/EIFの旨味がなくなってしまうので、必要に応じて一部の通信(VPNのポートとかNintendo Switchとか)は直接DS-Liteルーターの配下につないでおくのがよさそうです。その場合ポートセービング担当のルーターのほうは500ポートだとかもうちょい絞っておいてもよさそうです。

Map-eはDMZができないからNATタイプAとか1にするのは無理?

v6プラスとかOCNバーチャルコネクトは使えるポートが制限されているからDMZが使えなくてNATタイプAにするのは絶対無理、だからフルコーンNATなDS-Liteを使うべき(あるいはPPPoEパススルーしろ)、といった感じの主張です。

これは間違いです。あくまで市販ルーターの実装がフルコーン/制限コーンNATでないというだけで、出口ポートの数が制限されていてもフルコーン/制限コーンNATはできますし、そうすればちゃんとNATタイプAになります。DMZはフルコーンNATにするための一つの方法であり、必要条件ではありません。ただしこれもやっぱりLinuxYAMAHAルーターNECの高いルーターか、そのあたりが必要です。

Linuxでフルコーン/制限コーンNATを動かす方法についてはLinuxでポートセービングIPマスカレード付きの制限コーン風NAT(EIM/ADF)を動かす - turgenev’s blogを参照してください。YAMAHAとかNECでは、ポートセービングIPマスカレードを設定で無効にするとフルコーンNATになるはずです。

TCPはホールパンチングには基本使わないしフルコーンにすると枯渇のおそれがあるので、P2P通信(ゲーム機など)のUDP通信だけフルコーンにするのがいいと思います(NETルーターでの設定例: https://twitter.com/xpzr4/status/1527318238400757761)。

とはいえ初心者にはかなり設定が難しいと思うので、ネットワークに自信がなくて家族の人数が少なくてサーバー公開も必要なくて対戦ゲームが快適にできることは重要という場合はDS-Liteを選ぶのがいいかもしれません。

RFC 4787のNAT分類ではMappingがEIM/ADM/APDM、FilteringがEIF/ADF/APDFで、3x3=9種類ある?

これどこにもちゃんと書いてないけど多分嘘だと思うんですよね…詳しくはNATタイプ、ポートセービングIPマスカレード、UDPホールパンチング、STUN - turgenev’s blogを見てくださいという感じなのですが、例えばマッピングがAPDMなのにフィルタリングはEIFって、少なくともポート共有が有効な場合はどう考えてもありえません(マッピングに存在しない宛先から通信が来たとして、一体どの内側ポートに転送すればいいのか?)。要するにFilteringよりもMappingのほうが細かいのはありえないということです。

結局、EIMならEIF/ADF/APDF、ADMならADF/APDF、APDMならAPDF、という計6種類になると思います。念のためですがnetfilter搭載の多くのルーターはこのどれにも入りません。

RFC 3489の分類はガバガバだ!とRFC 4787は言っていますが、結局大して分ける必要なかったんじゃん?という…

二重ルーターだとSymmetric NATになる?

これもNATタイプ、ポートセービングIPマスカレード、UDPホールパンチング、STUN - turgenev’s blogに書きましたが、間違いです。複数あったら最も厳しいポリシーに揃えられるというだけで、EIM/EIFを10個つなげたところで全体はEIM/EIFのままです。

二重ルーターが問題になるとよく言われているのはおそらくUPnPの関係だと思います。UPnPは自分を直接管轄している一つ外側のルーターに対してポートの開放を要求するものであり、それがグローバルIP上のポートじゃなかったらうまくいかないという話です。一応、UPnPブリッジとかいう機能があれば二重ルーターでもちゃんとUPnPできるという話もあるようです。

UPnP自体はセキュリティ的に怪しいらしいので基本的には無効にして、NAT動作を工夫するのとあとは静的ポート開放をちゃんとやるのが良いと思います。

TCPでホールパンチングするのは無理?

これもNATタイプ(ryに書いたものですが、NATタイプが同じであればUDPホールパンチングとTCPホールパンチングの難易度は変わりません。

しかし実際には、TCPに関しては、既知の相手であっても外側からの通信は受け入れないというRFC 4787でいうところのConnection Dependent Filteringの動作をするNATが多く(netfilterがそうなっている)、こうなるとホールパンチングは困難になります。

UDPホールパンチングのためにはNATはEIMでなければいけないのでポートセービングIPマスカレードは不可能?

ここまでちゃんと読めていればわかると思いますが、NATが「ほとんどの場合にEIMのように振る舞う」ためには、必ずしもNATが「厳密にEIMの定義に従っている」必要はありません。

さらに、NATタイプ(ryに書いた通り、宛先アドレスが異なる場合のみに限ってポートセービングIPマスカレードを認める場合は、フィルタリングをADFにすることができます。つまり、以下のようにすれば、EIM/ADF「的」な動作とポートセービングIPマスカレードを両立できます。

  • 通信相手のアドレスのみに関するマッピングを使用する。(ポート番号は含めない)
  •  
  • 内側のポートがインターネットの新規の相手と通信しようとした際、その内側のポートに(別の相手との通信のために)直近で割り当てられたものと同じポートを原則として割り当てる。(=EIM的な動作)
    • (その内側のポートの使用履歴が無ければ、内側のポートと同じ番号、あるいはそれが利用不可ならランダムな番号を割り当てる)
  • ただし、そのポートを通ってその相手(のアドレス)と通信している他の内側ポートがすでに存在して競合する場合は、別のランダムなポートを割り当てる
    • そのポートを通って他の相手と通信している内側ポートが存在する分には競合しないのでそのまま割り当てる(=ポートセービングIPマスカレード
  • マッピングに一致する外側からの通信はすべて内側に通す(既知のアドレスなら、未知のポートからの通信でも通る)

こうすれば、近接したタイミングで同じポートから2つの相手と通信した際には同じポートが割り当てられることが期待され(EIM)、既知のアドレスからの通信はすべて内側に通り(ADF)、かつアドレスが異なる場合はポートセービングIPマスカレードができます。

一般には同じアドレスの異なるポートに大量のコネクションを張ることはあまりない(だいたい53, 80, 443とかしか使わない)ので、ポートも条件に入れたポートセービングIPマスカレードとほぼ同等の効果が得られるはずです。

というわけでこれをLinuxで実際に動かしたという記事がLinuxでポートセービングIPマスカレード付きの制限コーン風NAT(EIM/ADF)を動かす - turgenev’s blogです。実際、手元でもホールパンチングとポートセービングIPマスカレードが両立することを確認しています。

まとめ

思った以上にいろいろな種類の誤解があることがわかります。NAT動作は原理としては単純な話ばかりなので、適当な情報を鵜呑みにせずにちゃんと整理して考えてみるのが大事だと感じます。

元をたどれば、RFC 3489やRFC 4787が網羅的でない雑な分類を提示したために、UDPホールパンチングやポートセービングIPマスカレードという実際の使い勝手に影響を与える部分に関して深く考察されることがないままCone NAT/Symmetric NATという二元論が広まってしまったことが要因にあるでしょう。実は、draft-naito-nat-port-overlapping-01という文書がこの記事で書いたような事実に触れているのですが、残念ながらこれが正式なRFCに反映されることはなかったようです。

時代はIPv6へと移行してきており、IPv4でのNATに脚光が当たることはもはやないのかもしれませんが、少しでもNATに関する正しい理解が広まることを願っています。

質問などあればお気軽にどうぞ。