ノード A から [ ping 10.1.2.1 ] コマンドを実行すると、ICMP パケットが生成されます。 このパケットの IP ヘッダーには、ルーティングに必要な各種情報が格納され、ペイロードには ICMP の情報が格納されます。
↑図3: ping コマンド
このパケットを送信するため、ノード A は自身が持つルーティングテーブルからノード B への経路を探し出しますが、ノード B は別セグメントに属しますので、パケットをデフォルトゲートウェイへ送信しなければなりません。
↑図4: route print コマンド
ここまでは L3 の役割でしたが、ここからは L2 の役割に変わります。
ノード A は ICMP パケットを Ethernet フレームのペイロードとしてカプセル化し、また MAC ヘッダーにノード A とデフォルトゲートウェイの MAC アドレスを指定します。 ところが自身が持つ ARP テーブルからデフォルトゲートウェイの MAC アドレスを探しますが、ARP キャッシュが空っぽなのでアドレスを解決できません。
↑図5: arp -a コマンド
ここからが ARP の動作です。
ノード A はデフォルトゲートウェイの MAC アドレスを解決するために ARP Request フレームを生成します。 このとき生成される ARP Request と、ルータからのレスポンスである ARP Reply フレームは、図2のモノが使われます。 このフレームの送受信により、ノード A の ARP テーブルにはデフォルトゲートウェイのエントリーが追加されます。
↑図6: ARP キャッシュが更新された
デフォルトゲートウェイの MAC アドレスを解決できたノード A は、ICMP パケットをカプセル化したフレームの MAC ヘッダーに、この MAC アドレスを指定します。 ここでようやくフレームを送信する準備が整います。 たったひとつのフレームを送信するだけなのに、裏ではこういう動きをしています。 裏方仕事の大切さが分かりますね。
Ping データが格納されたフレームはルータに届きます。 ルータはフレームを L3 まで紐解いていき、宛先ネットワークを自身のルーティングテーブルから探します。 Cisco ルータでは [ p# show ip route ] コマンドを使います。 余談ですが [ p# show ip protocols ] との違いがイマイチわからないワタクシ。 いつかは分かることを信じて次に進みます。。
↑図7: ルータのルーティングテーブル
ルーティングテーブルから送信ネットワークに最適なルート (今回はインターフェース) が判明したら、ルータは再びパケットをカプセル化してフレームを生成します。 ここでもノード A のときと同様に ARP キャッシュからノード B またはネクストホップの MAC アドレスを探します。 ルータの ARP テーブルは図1で確認できますので、ここの情報を MAC ヘッダーの宛先アドレスに書き換えます。
こうしてルータが eth1 からフレームを送信し、ようやノード B に Ping データが格納されたフレームが届きます。 Ping を受け取ったノード B の ARP キャッシュに、ルータとの ARP 情報がない場合は、これと全く逆の手順を追ってノード A へ Ping リプライを返します。 シンプルですけど、無駄のない動きですよね。
ちなみにですが、ノード B が受け取ったフレームの送信元 MAC アドレスはルータのアドレスが指定されています。 物理的な MAC アドレスは、ノードを経由するたびに書き換わることを忘れないようにしましょう。 これを忘れてしまうと (え、なんで MAC アドレスが書き変わってるの!? ……あ、そうか書き換わるんだった…) と僕のように毎回疑問に思ってしまい、些細ですが無駄な時間を過ごす羽目になってしまいますわよ。(///)
たとえば、あるノードに IP アドレスを設定する場合、それが DHCP などの自動割り当て機能を利用しているならば、基本的には IP アドレスが重複する可能性が低いです。 けれども固定アドレス、すなわち人間が手動で IP アドレスを設定する場合などは、ちょっとした不注意によって IP アドレスを重複させて設定してしまうことがあります。
そんな僕は、まだ IP アドレスの重複設定に涙したことはありません。 それよりも僕はノードに IP アドレスを手動で設定したとき 「デフォルトゲートウェイの設定」 をしょっちゅう間違えます。 (あれれー?? なんで Ping がセグメント越えないのォ!?) なんてことに永遠と悩んで、結果的に給料泥棒だった経験は沢山あったり。。
↑図12: こんなアラート見たことありません? これね GARP の苗木。
そんな GARP の動作を以下にメモします。
GARP も基本的には ARP と同じように Request はブロードキャスト、Reply はユニキャストでフレームを送受信しますが、特徴的なところは ARP Request のデータ部分に "Sender IP address" と "Target IP address" に自ノードの IP アドレスが指定されることです。 この IP アドレスを先行して設定しているノードがこのフレームを受信すると 「このアドレスは私が既に使用していますよ」 といった ARP Reply を送信元ノードへ送り返します。 そして、この ARP Reply を受信した送信元ノードは 「あぁ、この IP アドレスは使われているんだな」 と判断し、その IP アドレスを無効にします。
↑図13: GARP の ARP Request フレーム
GARP の概要を初めて目にしたとき (なんか難しそう…) と構えてしまいましたが、実のところ GARP の目的は IP アドレス競合の防止ですから、確かに自ノードの IP アドレスを指定した ARP Request をブロードキャスト送信すれば、レスポンスがあった場合にそれが重複 IP アドレスであることが分かりますね。 すげーシンプルなんですねぇ。。
上図15を例にノード間の通信動作をメモしますと、ノード A からノード B へ向けて通信するときは、互いが同一セグメントですのでノード B を ARP 処理します。 また、ノード B からノード C へ向けた通信は、互いが別セグメントに属しますのでルータを ARP 処理します。 ここまではいつも通りですね。
さて、問題はここからです。 ノード A からノード C に対して通信を行なうとき、本来ならばノード B と同様にノード A はルータを ARP 処理すればよいですが、なんせノード A のプレフィックスは /16 ですから、ノード C を 「同一セグメントに属したノード」 と勘違いしたまま、ARP Request をノード C へ向けて送信してしまいます。 しかし、ルータは ARP Request をセグメント越えさせませんので、ノード C はフレームを受け取ることができず、結果的に通信は失敗に終わります。
↑図16: ノード A は何も悪くない。 悪いのはそういう環境を作らせた人…
このような状況を助けてくれるのが、この Proxy ARP です。
上図16 の状況にて、ルータに Proxy ARP を設定した場合の動作をメモします。 先ほどと同様に、ノード A からノード C へ向けて ARP Request をブロードキャスト送信すると、ルータはこのフレームを受信します。 するとルータはProxy ARP 機能が ON になっていますので、その ARP Request の宛先であるノード C へのルートが確立されていることを確認できたら、「ノード C への通信はオレが代わりに転送してやるわい!!」 と言わんばかりに、ルータが ARP Reply を投げ返します。
ちなみにですが、ルータが放った ARP Request フレームを受け取ったノード A の ARP キャッシュには、ノード C へ繋がる機器の MAC アドレスに、ルータの MAC アドレスが登録されます。 当たり前っちゃ当たり前なのですが、念のために以下に ARP テーブルの画像をペチャリと貼り付けておきます。
図19は、ノード A が PPTP サーバのヤマハルータ (192.168.123.254) へ PPTP 接続を試みると、PPTP クライアントとして 10.1.1.100 の IP アドレスを割り当てる環境です。 この環境で試そうとしている内容は、PPTP クライアントとしてルータにリモート接続したノード A から、同一セグメントに属するノード B へ Ping を送信したらどうなるかです。
さっそくノード A からノード B へ Ping (ping 10.1.1.101) を送信したところ、レスポンスはありませんでした。 繋がっていないようです。 ただ、このときノード B の Wireshark を確認するとノード A からの ICMP Request パケットは受信できています。 しかし続くノード B の ARP Request フレームがタイムアウトを起こしています。 このことから、ノード B はノード A の ARP 解決に失敗していることが分かります。
↑図20: Ping のリクエストは通る。 けどリプライ前の ARP Request が失敗する
なぜノード A の ARP 解決に失敗しているのか。 それを順を追って確認していきます。
まずノード B が ARP Request を送信する理由は、ARP キャッシュにノード A の MAC アドレスが未登録だからなのは言うまでもありませんね。 よってこの ARP Request の Target IP Address フィールドには、ノード A の IP アドレスである 10.1.1.100 が指定されます。 ノード B はこのフレームをブロードキャスト送信します。
↑図21: Target IP Address にはノード A の IP アドレスが指定されるが…
次にノード A は、このフレームを受信しなければなりません。 ですが、よく考えてみるとノード A は PPTP クライアントですから、ノード A の物理インターフェースには ARP Request が届きません。 ではどのインターフェースに届くのか? それは PPTP サーバであるヤマハルータのインターフェースです。 ところがヤマハルータのインターフェースには 10.1.1.254 が割り当てられていますので、Target IP Address にノード A の IP アドレス 10.1.1.100 が指定されたこの ARP Request は、ルータは 「自分宛てのモノではない」 と認識し、受信したフレームを破棄してしまいます。