IPv4と互換性のあるアドレス拡張プロトコルを考えてみたら、どういう感じになるんだろうか?

前回の記事ではIPv6の普及がなぜなかなか進まないのかを説明した。一つの根本的な問題は、IPv6がIPv4と互換性がないことだった。では、IPv4と互換性のあるプロトコルは、一体どういうものがありえたのだろうか?

この記事では、ASCIIをUTF-8に拡張したみたいに、IPv4と互換性を維持したままアドレスを64ビットに拡張したプロトコル(ここではIPv4+と呼ぶ)について考えてみたいと思う。そして、IPv4+ならば、IPv6のような長い移行期間を経ることなく、段階的にネットワークをアップグレードしていけることを示そうと思う。

なお、このIPv4+プロトコルは、筆者としてはそれなりに真面目に考えてみたものではあるけれど、単なる思考実験にすぎない。また、ここで提案するものがベストだと主張したいわけでもない。あくまで、現在の知識と経験を元に1995年くらいに戻って考え直せるとしたら、どういう世界がありえたのかを考えてみる話として楽しんでほしい。

IPv4+の基本的なアイデア

IPv4には、NATボックス(ホームルータなど)でプライベートアドレスとグローバルアドレスの変換をしているせいで、インターネット側からNATボックスの内側のホストに直接到達できないという問題があった。NATのプライベート側からグローバル側への接続は、NATボックスが変換をしている本人なので双方向にパケットをやりとりすることができるけど、グローバル側からプライベート側に接続しようとした場合、NATの内側のホストを指定する方法がないので接続しようがない。

IPv4+の基本的なアイデアは、単純に「NATボックスのプライベート側のアドレスをグローバル側から指定できるようにしよう」というものだ。具体的には、NATボックスの外側のグローバルアドレスと、NATボックスの内側のネットワークのプライベートアドレスを連結したものを64ビットアドレスとみなして、インターネット側から到達可能にする。図にすると次のようになる。

画像1

上記の図では、NATボックスに202.213.0.50というグローバルアドレスが振られていて、プライベートアドレスとして192.168.0.0/24というアドレスが使われている。外側から202.213.0.50.192.168.0.12宛のパケットがきた場合、NATボックスは内側の192.168.0.12にパケットを転送する。

上記のようなルーティングを可能にするためには、NATボックスをIPv4+対応にする必要があるが、複雑なUPnPですら普通にルータに実装されていたりするので、ルータの対応具合についてはあまり心配はいらないと思う。IPv4+が十分にシンプルで、かつ適切なタイミングで標準が策定されていれば、どのルータにも「IPv4+対応」シールがついているという状況にすることはたぶんそんなに無理ではなかっただろう。

なお、IPv4+を後方互換性のあるものにするためには、パケットフォーマットを工夫して、IPv4+を理解しないルータやホストにとっては、IPv4+パケットが単なるIPv4パケットに見えるようにする必要がある。

IPv4+のパケットフォーマット

IPv6の問題は、ネットワーク全体がIPv6に対応しない限りIPv6のメリットが感じられないことだった。したがって、IPv4+では段階的にメリットを感じられるようにしたいところだ。理想的には、IPv4+対応ホームルータを買ってくれば、ISPやOSの対応状況に関係なく、すぐにIPv4+を使い始められるというようにしたい。

そのためには、IP拡張ヘッダを使うのは望ましくないだろう。IP拡張ヘッダなどではOSの対応が必要になるけど、OSのアップグレードは数年単位で時間がかかるからだ(例えばIPv6がWindowsに実装されるまでは相当長い期間待つ必要があった)。IPv4+はユーザアプリケーションだけでも実装できるようなものが望ましい。となると、IPv4+はIPv4からみるとUDPパケットとして見えるようなものがよいということになるだろう。

具体的には次のようなフォーマットはどうだろうか。

    0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |Version|  IHL  |    DSCP   |ECN|          Total Length         |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |         Identification        |Flags|      Fragment Offset    |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  Time to Live |    Protocol   |         Header Checksum       |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                  Source Address (First Half)                  |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                Destination Address (First Half)               |
  +===============================================================+
  |          Source Port          |       Destination Port        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |             Length            |           Checksum            |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                  Source Address (Second Half)                 |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                Destination Address (Second Half)              |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |    Protocol   |                                               |
  +===============================================================+
  |                            Payload                            |

上の図では、IPv4ヘッダ部分とIPv4+拡張部分を====という線で区切った。IPv4ヘッダのProtocolフィールドはつねに0x11(UDP)にセットされているものとする。つまりIPv4的にはIPv4+は単なるUDPパケットのように見える。

IPv4+パケットでは、64ビットアドレスは前半と後半に分割されていて、IPヘッダに前半32ビットが、IPv4+ヘッダにアドレスの後半32ビットが入っている。IPヘッダの中にあるアドレスがNATボックスのグローバルアドレス、IPv4+ヘッダの中にあるのがプライベートアドレスだ。

IPv4ではなくIPv4+パケットであることを示すためには、IPv4としてのルーティングや到達可能性に大きな影響を与えなければどのビットを使ってもいいので、例えばDSCPフィールドのビットが全部1であることで表すというのでいいと思う。

IPv4+ヘッダのあとにはペイロードが続いていて、そこにTCPや(本物の)UDPヘッダが入っていることになる。IPv4+を使うためには、IPv4+上にTCPやUDPを実装する必要があるが、基本的にはペイロードとしてそのままTCPやUDPのセグメントを乗せればよいはずだ。

IPv4+のルーティング

さて、上記のようなパケットをインターネットから受け取ったとき、NATボックスは次のように振る舞うことにしよう。

指定されたプライベートアドレスのOSがIPv4+対応の場合: NATボックスはそのままパケットを転送する。OSがIPv4+を直接解釈できるので、拡張されたソケットインターフェイスとカーネル内のTCP/IPv4+実装を使って、アプリケーションはIPv4+パケットを送受信することができる。

OSがIPv4+未対応の場合: NATボックスはIPv4+パケットをUDPにカプセル化して、プライベート側に転送する。そのときUDPのポートはIPv4+ヘッダのポート番号をコピーするものとする。そうすると、IPv4+対応のアプリケーションは、IPv4のUDPパケットとしてIPv4+パケットを受け取ることができて、ユーザランドTCP on UDP実装を使うことで、カプセル化されたIPv4+パケットを送受信することができる。(外向けのパケットのカプセル化は、NATボックスによって、インターネットに送られる前に元に戻されることにする。)

NATボックス経由ではなく直接インターネットにつながっているホストの場合、OSのIPv4+対応具合に応じて、カーネル内TCP/IPv4+かユーザランドTCP/IPv4+実装を使い分けることになる。いずれにせよ、OSの対応状況に関係なく、アプリケーションさえ対応すればIPv4+を話し始めることができる。

IPv4+への完全移行

OSとアプリケーションがIPv4+に移行すれば、あとはNATボックスを段階的に廃止していくことが必要となる。そのためには、たぶん以下のようなプランがいいだろう。

まず、ISPがIPv4+の64ビットアドレスを直接解釈できるルータにアップグレードして、NATボックスを経由せずともIPv4+を直接ルーティングできるようにする。その後、NATボックスをISP側に移して、ユーザにはIPv4+アドレスのみ(従来の意味でいうプライベートアドレスのみ)を配布するようにする。

そうすると実質的にキャリアグレードNATを導入するということになるので、NATボックスにトラフィックが集中しそうだが、ユーザのIPv4+対応が進んでいれば、ほとんどのトラフィックはNATボックスを経由せずにIPv4+を直接解釈するルータによってルーティングされるので、NATボックスを経由するトラフィックはほとんどないはずだ。その状態を維持して、ユーザがほとんどゼロになったら、NATボックスをシャットダウンして、移行は完了する。

移行が完了したあとは、IPv4+の上位32ビットと下位32ビットは特別な意味を持たず、単なるフラットな64ビットアドレスとして運用していくことになる。

まとめ

この記事ではIPv6の代替となる、仮想的なIPv4アドレス拡張プロトコルIPv4+について記述した。IPv4+はIPv4と互換性があり、かつUDPに見えるので、ネットワークやOSのIPv4+対応を待つ必要はなく、導入すればアプリケーション単位ですぐに使い始められるプロトコルになっている。

IPv4+の細かい点やDNSなどの話は詳細になりすぎるので省略したが、上記のような方針で、後方互換性を保ちつつIPv4のアドレスを拡張していくことは技術的に不可能ではなさそうだということが感じてもらえると思う。

IPv4+のパケットフォーマットにはお世辞にもキレイとはいえない(というか、ダミーのUDPヘッダがあったりアドレスが飛び飛びで入っていたりして、ちょっとごちゃごちゃしている)が、後方互換性とスムーズな移行プランのための妥協としては、許容範囲内の設計ではないだろうか。x86の機械語のように、歴史のあるもののバイナリ表現は、増築を繰り返した温泉旅館みたいに複雑になりがちなのだが、生きている標準規格においてその種の複雑さはある程度許さざるを得ないと思う。キレイなフォーマットのx86命令を考えることもできるけど、既存のプログラムを動かせないそんなプロセッサを買う人はいないだろう。

1990年代に、IPv6のようなIPv4とは別のプロトコルではなく、IPv4を拡張する形の互換性のあるプロトコルをプッシュする人たちがいたら、今ごろどういう感じになっていたのか、考えてみるとなかなかおもしろい。もしかしたら、そっちのほうがうまくいっていたのかもしれないと、ちょっと思う。

この記事が気に入ったらサポートをしてみませんか?