パケットがどこのルータから届いかを、ルーティングに使うとしたら

まず、IP パケットのルーティングは、IP ヘッダから得られる情報のみから判断され、上位プロトコルのヘッダ内容(TCPUDP のヘッダ内容)の影響を受けない。

とすれば、TCP のように、「あるシーケンス番号を持ったパケットに対応する応答パケット」といった概念は、IP パケット自体には存在してなく、IP ヘッダだけで考えれば、そのパケットは「何かに対する応答パケットである」という判断はできず、単にあるアドレスへ送信するパケットであり、1個の IP パケットがどうやって送信されるかを考えれば良いことになる。

IP ヘッダの内容は下記のサイトを参照

http://tokyo.cool.ne.jp/mots/notes/header.html

ここに含まれるアドレス情報は、

  • 送信元 IP アドレス
  • 宛先 IP アドレス

しかない。

今、実際に手元の PC から、www.hatena.ne.jp へブラウザで繋いだときのパケットをキャプチャしてみる。接続環境はB フレッツ回線にブロードバンドルータで NAPT(IP マスカレード)というありきたりな構成。

このときに、www.hatena.ne.jp(59.106.108.86)と PC(192.168.17.248) の間にでやりとりされたパケットの IP ヘッダに含まれるアドレスは、この2つの IP アドレスであって、ルータの IP アドレス(192.168.17.1)は含まれていない。つまり、実際にサーバと PC との間でやりとりされている IP ヘッダだけを見ていては、経由してきたルータの IP アドレスは分からない。

しかし、実際には当然、ルータがパケットを経由して相手に届く。

今回は、手元の PC → サーバの方向のパケットが最初なので、TCP の handshake に先だって、実際には下記のようなパケットがやりとりされている。

  1. PC でデフォルトゲートウェイに設定されている IP アドレス(192.168.17.1)に対する ARP Request のパケットを、宛先 MAC アドレスをブローキャストアドレス(FF:FF:FF:FF:FF:FF:FF)として送信する。
  2. ルータが ARP Reply を返す(これで、PC は 192.168.17.1 の MAC アドレスを知る)。

で、その後、www.hatena.ne.jp と接続するために、TCP の 3-way handshake の最初のパケットが送出されるが、このパケットは、

  • Ether ヘッダに含まれる宛先 MAC アドレス: ルータの MAC アドレス
  • Ether ヘッダに含まれる送信元 MAC アドレス:PC の MAC アドレス
  • IP ヘッダに含まれる宛先 IP アドレス:   www.hatena.ne.jp の IP アドレス
  • IP ヘッダに含まれる送信元 IP アドレス: PC の IP アドレス

となる。このパケットは Ether の MAC アドレスがルータの MAC アドレスであるから、当然、まず、ルータが受け取る。受け取ったルータは、イーサフレームの中にある IP ヘッダを見て(正確に言うと、Ether ヘッダ上にあるイーサタイプを見て中に IP パケットがあると判断し、IP ヘッダの処理に入る。参考:イーサネットフレーム(2ページ目) | 日経 xTECH(クロステック))、宛先アドレスがルータ自身の IP アドレスではないことが分かる。

つまり、ルータの立場になると、受け取ったパケットが

  • MAC アドレスは自分宛
  • だけど、IP アドレスは他人宛

であることから、この IP パケットを転送する必要がある、という判断がなされる。IP パケットがルータが持っているどのインタフェースを通して、どうやって送れば良いかは、ルータが持っているルーティングテーブルによって判断される。

以上が、IP パケットがルータを経由してパケットが相手に届く仕組み。繰り返しになるが、IP パケットのルーティングは IP パケットひとつひとつに対して判断される。もし、「何かのパケットに対する応答パケット」という事がルーティングの判定に使われるとなると、それは IP の上位プロトコルの情報を使っていることになり、また、もともと、UDP には TCP に見られるような応答パケットは存在しない(UDP を使った上位のプロトコルが応答パケットを送信することはある。たとえば、DNS は通常、UDP を使うが、DNS のクエリーに対してレスポンスのパケットを送信するのは、DNS サーバのプログラムの仕事であって、UDPプロトコルが勝手に返答パケットを送るようなことは無い)。つまり、もし、「何らかの応答パケット」というのは TCP の場合に存在するものであって、UDP の場合にはその概念すらない。

参考:http://www4.plala.or.jp/tamo/network/09.transport-udp.html

IP のルーティングが上位のプロトコルに依存しないとすれば、「応答パケット」は存在しないので、もし、届けられたパケットがどのルータから来たのかを判断して、次にパケットを送信する時に使うルータを選択するとなると、それは「何かの応答」ということではなく、「この送信元 IP アドレスからは、以前にこのルータから届いた」という履歴情報を保持しておく必要が出てくる。

ここで、はてなにつないだときのパケットキャプチャした結果を見直してみる。はてなとの間で交わされたパケットの中には、ルータの IP アドレスは含まれていない。このことは、TCP のコネクションが、内→外か外→内とは無関係である。もし関係があるとなると、それは、IP パケットのルーティングが上位プロトコルの情報を使ってないため、IP パケットひとつひとつに対して処理される、ということと矛盾してしまう。

ルータの IP アドレスを知る手立ては、TCP のコネクションの前に送られた ARP パケットであるが、これは、送りたい IP アドレスが、ARP テーブル上に無いために、イーサフレームに設定すべき送信先 MAC アドレスが分からない場合に送るものである。今回の場合は、

  • 送ろうとしたはてなの IP アドレスと、PC の IP アドレスとネットマスクから、同一セグメント上に無いと判断され、PC のルーティングテーブルにしたがって、設定されていたデフォルトゲートウェイに対してパケット送ろうとと思ったが、
  • デフォルトゲートウェイに指定されている IP アドレスに対応する MAC アドレスが ARP テーブル上に無かった。

ということから、ルータの IP アドレスに対する ARP request のパケットがブロードキャストされた。しかし、これは、ルータへ送る時のパケットを作る際に、イーサフレームの送信先 MAC アドレスにルータの MAC アドレスが必要なためであり、ルータの IP アドレスは、はてなと PC の間の通信には直接的には関係ない。

ここで、ルータを経由してはてなから PC が受け取ったパケットを見ると、

  • Ether ヘッダに含まれる宛先 MAC アドレス: PC の MAC アドレス
  • Ether ヘッダに含まれる送信元 MAC アドレス:ルータの MAC アドレス
  • IP ヘッダに含まれる宛先 IP アドレス:   PC の IP アドレス
  • IP ヘッダに含まれる送信元 IP アドレス: www.hatena.ne.jp の IP アドレス

となっている。やはり、ルータの IP アドレスは含まれていない。となると、ある相手から届いたパケットがどのルータから届いたのかを記憶しようとするとなると、それは、

  • 相手の IP アドレス
  • 経由したルータの MAC アドレス

のペアになる。

今のところ、上記のペアを保持してルーティングに利用している、ということが記述されている記事、書籍、サイトをは読んだことが無い。もし、このようなテーブルを保持しているとしたら、ARP テーブルのように保持している期間やテーブル内容を確認、操作する方法があっても良いと思うが、残念ながら、そうった情報を見聞きしたことはない。

参考:http://tkplanning.ddo.jp/ARP.htm

もし、以前に経由したルータがパケットの送信先として選択される、と思われるかたは、

  • 相手の IP アドレスと経由したルータの MAC アドレスを保持するテーブルの存在を示す資料
  • 上記の私が考えた「もしそうだとしたらこうなるはず」というのとは違うロジックで実現する方法

のいずれかを教えてください。