QUICとNATで確かめたいと思うこと (MAP-EでのNATとNAT64)

# はじめに

QUIC + NATがいろいろなところで[話題](https://twitter.com/search?q=QUIC%20NAT)になってます。NATの挙動について推測を含みますが二つまとめてみました。

1. QUICがNATテーブルを枯渇させるとは、どのような状況なのか？ もし本当に枯渇してるなら、MAP-E NATでのポート節約などの収容セッション数を増やす工夫が有効なのではないか？
1. もしNATがIPv4 NAPTではなくて、QUIC + NAT64 になったらどうなるのだろうか？

まだ疑問をまとめるのみです。いずれも緻密なQUIC仕様を正しく理解しつつ、実機の動きも検証が必要ですが、理解もふくめてそこまで至っていない状況であることをご承知ください。

# まとめ

* **その１ NATルータの送信元ポートの割り当て方法について**
  - 利用可能なポート数に制約のあるMAP-E CEのNATはセッションテーブルが枯渇しにくよう、送信元ポートを節約する割り当方法がある。
  - ポート節約の工夫が取り入れられた市販のブロードバンドルータはどのぐらいあるだろうか？
  - 実際にTCPではうまく動いているようだが、UDPのときにどうなるか？
  - TCPとUDPのそれぞれのNATで異なる扱いをするNATルータがある。TCPはうまく動くのに、UDP(QUIC)だと問題が出る場合がある。
 
* **その２ DNS + NAT64とQUIC**
  - QUICプロトコルにはIPアドレスを直にQUICパケットに埋め込んで相手に通知する状況がある。DNS + NAT64でどうなるのだろうか？

# その１ ポート数の制約によるセッション数の不足

QUIC + NAT の問題の一つがNATルータでのセッション数の枯渇ですが、セッションのキャパシティを三つの尺度に分けてみます。

  * (p1) スペックや性能からの上限
    * [ハードリミット] ハードウェアやOS設定の制約からのセッション上限数
    * [実効的リミット] カタログの装置スペックは十分だが、実際動かししてみたら収容セッション数が少なかった
  * (p2) 送信元ポートとして使える範囲に起因する同時セッション数の上限数

(p1)の改善は、世の中に普及してしまった古いルータのハードウェア交換や、ファームウェアをどう更新してもらうかの難しい問題です。(p1)の後者は、スペックには、例えば10,000など十分大きな値が掲載されているのに、実物は1,000ぐらいでダメになると言う装置検証ではよくある場面です。さらにタチが悪いのはセッション数が増加すると、動くけど遅くなるようなデバッグしにくいケースもあるでしょう。

(p1)は難しい問題ですが、ここでは(p2)の送信元ポート数の制限に引っかかる場合に着目します。

## NATルータでの送信元ポートの割当方式とQUICへの影響

下記で扱う方式は、Port Restrict Cone NATと深く関連するものの、単にNATルータからのoutgoingパケットに対して、変換後のパケットの送信元ポート番号の値として何を選ぶのか？だけを気にしています。Cone, SymmetricなどのNATタイプの分類とは独立の話です。

  * (方式1) 新規にセッションを生成するとき、セッションごとに送信元ポート番号に異なる値を割り当てる。
    * 例えば、セッションを2つ同時に生成したとき宛先IPv4アドレスが同じ/異なるどちらの場合でも、NATルータは送信元ポート番号として異なる値(64001, 64002)を割り当てる。生成できるセッションの最大数は送信元ポート範囲の大きさに限られる。例えば、送信元ポート範囲の大きさが240しかなければ、同時に生成できるセッション数は240までに限られてしまう。

  * (方式2) 宛先IPv4アドレスが異なっていれば、同じ送信元ポート番号を割り当ててもよい。
    * 異なる宛先IPv4アドレス(A, B)に対してセッションを生成するとき、NATルータは送信元ポート番号に同じ値(64001, 64001)を割り当ててよい。宛先IPv4アドレスがバラけていれば、送信元ポート範囲の制約を超えてセッション数を生成できる。ただし同じポート番号が使えるのは、宛先IPv4アドレスが異なっている場合のみで、同じ宛先IPv4アドレスに対して同時に2本コネクションを生成する場合は(方式1)が必要となる。

QUICの通信に対して(方式1)のNATを適用した時、UDPはタイムアウトまで待たないとテーブルからセッション状態が消去できない問題が複合するので、影響が見えやすくなっていると思います。


## MAP-E CE (Customer Edge)でのポートを節約するNAT

MAP−E方式では、事業者にもよってもことなりますが、240～1008程度をユーザに割り当てます。CEのNATに(方式1)方式を使うと、すぐに割当ポートを食い尽くしてしまいます。JPNEが発行している、[徹底解説v6プラス](https://www.jpne.co.jp/ebooks/v6plus-ebook.pdf)の `8.2.7 ポートが枯渇した` の節では、５タプルを使ってセッションを識別する(方式2)相当の方法によってポート数の不足を緩和できることを説明しています。

> **徹底解説v6プラス 8.2.7 ポートが枯渇した 節より：**
> 誤解されがちな点として、ポートの枯渇が発生するのは、「同一宛先IPv4アドレスかつ同一宛先ポートに対して多数の通信を行った場合のみ」です。MAP-EにおいてIPv4 NATで変換される通信セッションは、5タプルと呼ばれる5つの要素（通信プロトコル、宛先IPv4アドレス、送信元IPv4アドレス、宛先ポート、送信元ポート）によって識別されます。送信元ポート以外の4つの要素がすべて同じ状態で、送信元ポートの差異によってしか識別できない通信が極端に多くなってしまった状態が、MAP-Eにおける「ポートの枯渇」です。


#### ヤマハルータ

同様な方式の実装として、ヤマハルータをMAP-E CEとして利用するための機能として[ポートセービングNAT](http://www.rtpro.yamaha.co.jp/RT/docs/nat-descriptor/nat-abstruct.html#policy2)があります。TCPのNAT変換に対して(方式2)を適用するものです。[ドキュメント](http://www.rtpro.yamaha.co.jp/RT/docs/nat-descriptor/nat-compatibility.html)は設定だけでなく方式を詳細に解説していて価値ありです。ポートセービングNATはTCPへの適用であり、UDPには適用されないと記載されています。UDPに対しては(方式1)で変換です。さらにUDPのNATセッションタイマがデフォルト900秒と長めに設定されていることとあいまって、QUICでは顕著に影響が見えるのかもしれません。

#### ASAMAP

内部動作の詳細を見つけることができたMAP-E CEの実装として、ASAMAPも宛先IPv4アドレスまでを含めてセッションを区別するキーとしていました。[MAP-E Tutorial | JANOG31 meeting (p34)](https://www.janog.gr.jp/meeting/janog31/doc/janog31-MAP-asama-01.pdf)に記載があります。

#### Linux iptables のSNAT機能

https://quintrokk.subness.net/?p=2003

上記のリンクでは、OCNバーチャルコネクト向けのCEを設定する様子を解説しています。この中で宛先IPアドレスが異なれば、同一の送信元ポートを再利用できる、ポートセービングNATと同等な動作がふれられています。

## 確かめたいこと

- 市販のブロードバンドルータのNAT実装がどうなっているのか？ (方式1)(方式2)どちらで実装されているか？
- 市販ルータの土台になっていそうなLinux標準の[iptablesでMAP-E CEを実装する方法](https://www.google.com/search?q=MAP-E+iptables&oq=MAP-E+iptables)の、SNATでの送信元ポート番号の割り当て方法が(方式1)になっていないか確かめたい。
    - MAP-E設定では、`--connlimit-daddr` と `--connlimit-upto` を組み合わせて、同一宛先IPv4アドレスへ張れるセッション数を制限を入れている方もいるなど設定者によって様々チューニングされている。亜種の中でQUICに影響を出すようなものはないか？

- MAP-E CEの環境で、端末へのIPv6 RAを止めて、IPv4 only環境でHTTP/3のサービスをたくさん使う生活をする。


# その２ DNS + NAT64とQUIC

IPアドレスを直にQUICパケットに埋め込んで相手に通知する状況とNAT64を組み合わせた状況について考察します。かなりニッチな状況だと思います。そもそも、この機能をサービス提供者が利用するのか？　使ったとしてユーザからみて体感するような悪影響が出るのか？ いずれも要考察です。

IPアドレスをQUICパケットに直に埋め込む状況の一つが、トランスポートパラメータ `preferred_address` です。サーバが使ってほしいIPアドレスとポート番号の組をクライアントへ通知することができます。例えば、同じサーバが異なる2つのIPアドレスA, B持っていたとして、最初はクライアントにIPアドレスAへ接続させていたが、あとからIPアドレスBを通知して、QUICコネクションは維持したままエンドポイントをBへ変更させるような状況です。

クライアントはサーバからのIPアドレスBの通知を受けたあと、クライアント側からパス(通知されたIPアドレスBとポート番号)を検証するので、自然と、NAT rebinding (セッションテーブルの更新)も行われることになります。ここでNAT64を考えているので、サーバはIPv4シングルスタックで運用さているので、IPアドレスA, BのアドレスファミリはIPv4である前提です。

一方、DNS + NAT64では、クライアントはIPv6シングルスタックなので、IPv4アドレスBの情報を与えられても利用することができません。クライアントはサーバのIPv4アドレス情報を名前解決を通じてIPv6アドレス `64:ff9b::[IPv４アドレスを埋め込んだもの]` に変換された形で得ます。クライアントアプリが、自分はNAT64配下で動いていることを検出して、通知されたIPv4アドレスに`64:ff9b::/96` のWell-known prefixを補って接続すれば良いかもしれませんが、一般的なアプリケーションにそのような特別な動きを期待することはできません。

---
■ QUIC + NAT64なんて使われるの？　と思いましたが、

https://www.janog.gr.jp/meeting/janog48/ipv6/

上記の取り組みもあり、DNS + NAT64や464XLAT方式でのIPv4サーバへのアクセスが一定規模で、かつ、しばらく使われることになりそうです。Android向けの464XLATなら、クライアントアプリケーションはIPv4をしゃべるので問題にならなさそうです。

■ 標準化の過去の議論

https://github.com/quicwg/base-drafts/issues/2122

過去の標準化の議論でも同じ疑問が出ていました。上記のissueで、モバイル事業者にはDNS + NAT64へのニーズがあることが言及されています。QUICv1では解決していないのか、すでに何らかの解があるのかは、まだ理解に至っていません。RFCとして出来上がったQUIC仕様も緻密ですが、過去の議論を読み解くのもなかなか大変です。

# さいごに

HTTP/3, QUICの導入で、ただでさえ深いNATの悩みがさらに深くなります。ますますNATなんて捨てたくなってきます。QUICでサービスを提供するなら、IPv4 onlyはダメ。IPv6対応もいっしょに出してほしいです。これが本質的な解だと思います。

# 参考にした資料

- [YAMAHAルータで特定のUDPトラフィック（QUICとか）のタイムアウトを変更する | qiita](https://qiita.com/ynakatake/items/ae346847c3d713bd925d)
- [OCNバーチャルコネクト対応機能 | ヤマハルータのドキュメント](http://www.rtpro.yamaha.co.jp/RT/docs/ocn_map_e/index.html)
- [NVR500でv6プラスに接続してみた | 疲労コンパイル](http://dotsukareta.blogspot.com/2018/06/)
- [QUICとNATと | JANOG48 meeting](https://www.janog.gr.jp/meeting/janog48/lt4/)