連載
» 2003年06月13日 00時00分 公開

基礎から学ぶWindowsネットワーク:第12回 TCP/IPプロトコルを支えるICMPメッセージ (2/3)

[デジタルアドバンテージ,著]

ICMPメッセージの構造

 以下にICMPパケットの構造を示しておく。実際には、この直前にIPパケット(のヘッダ部分)があり、ICMPの通信先や通信元の情報は、そこから得ることになる。

ICMPパケットの構造
ICMPの最小サイズは4bytes+メッセージごとのオプション・サイズとなっている。どのメッセージでも、先頭の4bytesは同じ形になっている。チェックサムはIPヘッダなどと同様に、「1の補数」形式で計算する。

 ICMPパケットには、その機能によって何種類かのパターンがあるが、基本的な構造はこのように、1byteの「タイプ(機能コード)」、1byteの「コード(補助的な機能コード)」、そして2bytesの「チェックサム」フィールドから構成されている。そして必要に応じて何bytesかの追加データ・フィールドが続くことになっている。チェックサムはIPヘッダなどと同じように、「1の補数」形式で計算される。「1の補数」演算については連載第10回の「1.IPパケットの構造」を参照していただきたい。

 先頭にある「タイプ」フィールドは、ICMPメッセージの機能や種類を表す。場合によってはさらに「コード」フィールドを使って、より細かな機能の指定を行うこともある。

 実際に利用可能なICMPの一覧は次のとおりである、ただし、すべてのノードが、すべての種類のタイプをサポートしているわけではなく、非ルータのノード(つまり一般のクライアント・ノード)では、限定的ないくつかのタイプしかサポートされていない。

タイプ 機能
0 エコー応答(echo reply)
3 あて先不達(destination unreachable)
4 ソース・クエンチ(source quench、送信元抑制)
5 リダイレクト要求(redirect、経路変更要求)
8 エコー要求(echo request)
11 時間超過(time exceeded)
12 パラメータ異常(parameter problem)
13 タイムスタンプ要求(timestamp request)
14 タイムスタンプ応答(timestamp reply)
15 情報要求(information request)
16 情報応答(information reply)
17 アドレス・マスク要求(address mask request)
18 アドレス・マスク応答(address mask reply)
ICMPメッセージの一覧
ICMPメッセージの一覧はRFC792RFC950(アドレス・マスク)で定義されている。

 データ部分の使い方はICMPメッセージごとに異なる。ICMPエコー・メッセージでは、ユーザー(アプリケーション)が指定したデータを格納しているが、エラーを返すメッセージでは、エラーの元となった(エラーを引き起こした)IPパケットの先頭部分(IPヘッダ+ユーザー・データの一部)の内容をデータとして格納していることが多い。このデータ部分を解析することにより、どのIPパケットがエラーを引き起こしたのかを調べたり、エラーの発生原因などを詳しく調査したりできるようなっている。ただしOS自体には、このようなICMPのエラー・メッセージを解析するような機能は含まれておらず、一般的にはパケット・アナライザ(ネットワーク上のパケットをキャプチャして解析するツール)などを使って技術者が解析することになる。

 以下、それぞれのICMPメッセージについて詳しく見ていこう。

タイプ8/0―ICMPエコー要求/エコー応答

 「ICMPエコー」は、指定されたエコー・データ・パケットを、2つのTCP/IPノード間で送受信するためのメッセージである。ICMPエコーの送信元が送ったデータ・パケットが相手のノードに届くと、そのデータがそっくりそのまま元のノードへと送り返されてくる。この応答操作ではアプリケーションは介在せず、TCP/IPのプロトコル・スタック自身が応答処理を行う。パラメータとなるデータをそのまま送り返すので「エコー」と呼ばれており、TCP/IPのプロトコル・スタックが稼働しているかどうかを調べるために使われる。TCP/IPをサポートしているノードは必ずこの機能を実装することが求められており、ノードの動作状態を調査するためには欠かせない機能である。一般ユーザーが利用するpingコマンドは、このICMPエコー機能を使って実現されている。

 以下に、ICMPエコーのパケット構造を示しておく。

ICMPエコー・パケットの構造
ICMPエコーには「要求」と「応答」の2種類があり、先頭byteの「タイプ」フィールドで区別する。コード・フィールドは未使用。最初にパケットを送信する側が「要求」を送ると、受信した側が「応答」パケットに変更して、送信元へ返信する。このパケットの前には、IPヘッダ、およびイーサネットなどのデータリンク層のヘッダが存在する。データ部分は可変長であり、最大サイズはIPパケットの最大長に限定される。データ部分の長さは、IPパケットの全体長から自動的に計算される。

 先頭にある「タイプ」フィールドには「エコー要求(8)」か「エコー応答(0)」がセットされる。最初にエコー要求を出す方が、タイプ・フィールドに「エコー要求(8)」をセットしてパケットを送信すると、受信した側では、タイプを「エコー応答(0)」に変えて元のパケットをそのまま返信する。コード・フィールドはこのICMPメッセージでは使用されない(0が入っている)。

 「ID」と「シーケンス番号」は、ICMPエコー・メッセージを利用するアプリケーションが自由に利用できるフィールドである。通常は、エコー・メッセージを送信する側において、送信したパケットを一意に識別できるような数値をセットする。エコー・メッセージでは、これらのフィールドの内容もそのまま変更せずにパケットを送り返すため、受信した側でこれらのフィールドの内容を調べることにより、どのエコー要求に対する応答であるかを識別することができる。同時に複数の要求パケットを送信して、その応答時間が大きくずれているような場合とか、同時に複数のユーザーがpingコマンドを実行した場合でも、どの要求パケットに対する応答であるかが分かるようになる(パケットを送信するたびに異なる値をセットしておく)。

 「echoデータ」フィールドには、ICMPエコー・メッセージを利用するアプリケーションが何らかの値をセットしておく(データの内容は何でもよい)。一般的には、バイナリ・データ(0x00〜0xffまでを順番に1ずつ変更したもの)が使われることが多い。

 以下に、実際のpingコマンドの例を示しておく。データ部には、文字列のようなデータ(実際には+1ずつ値を変えたバイナリ・データ)が入っていることが分かるだろう。

ICMPエコーの例
Windows XPシステム上でpingコマンドを実行した場合の応答パケットの例。アプリケーション(この場合はpingコマンド)が指定したバイナリ・データが相手に送られ、それがそのまま返信されている。
 (1)ICMPメッセージのタイプ。0x00はICMPエコー応答。
 (2)コードは未使用(0x00になっている)。
 (3)ICMPパケットのチェックサム。1の補数演算が使用されている。
 (4)この値は、常に同じ値になっているようである。
 (5)シーケンス番号。1パケット送信するごとに「+0x0100」されているようである。これによって、echo要求とその応答を判別している。
 (6)データ部分の内容は任意。デフォルトでは32bytes。
 (7)ICMPのエコー応答のヘッダ部分。
 (8)この例では、データ部分は'a'から始まるバイナリ・データになっている。1byteごとに+0x01されている。

 ICMPエコーで1度に送信できるデータのサイズは、IPパケットの最大長に制限される(ICMPエコー・パケット自体にはデータ長を表すフィールドは用意されていない)。そのため、例えば64Kbytesといった大きなサイズのエコー・パケットを送信することも可能であるが、現実のTCP/IPネットワークでは、このような巨大なサイズのエコー・パケットは許可していないことが多い。特にファイアウォールが装備された環境では、フラグメンテーションが必要なサイズのIPパケットは許可されていないことがある。IPフラグメントを処理するためには、IPパケット全体を再構築するために一時的にバッファを用意し、ばらばらに到着したフラグメントを順次組み合わせる必要があるが、このためには全部のパケットが到着するまで、TCP/IPのプロトコル・スタック内にそれらを保持しておかなければならない。だがこのような(不完全な)フラグメンテーション・パケットをわざと大量に送りつけると、プロトコル・スタックに負荷がかかり、システムが不安定になる可能性がある。このようなDoS攻撃を避けるため、ファイアウォールの設定によっては、フラグメンテーションが必要なIPパケットの受信はすべて拒否することがある。

 このような事情があるため、pingで利用可能な最大データ長は、ネットワークの設定によって変わることになる。もしフラグメンテーションが許されないとすると、ICMPエコーのパケット・サイズは1つのイーサネット・フレームなどに収まるサイズに制限されることになる。一般的なLAN環境で広く使われているイーサネットでは、最大ユーザー・データ・サイズは1500bytesまでとなっているので、ここからIPヘッダのサイズ(最小で20bytes)とICMPパケットのサイズ(ヘッダ部分だけで8bytes)を引くと、有効なエコー・データの最大サイズは1472bytesとなる。またDSL回線でPPPoEなどが利用されていると、さらに小さなMTUサイズしか利用できないので、もっと小さなサイズのエコー・データしか利用できないことになる。例えばPPPoEを利用するNTTのフレッツADSLなどでは、MTUサイズは1454bytesに制限されているので、フラグメントなしに利用可能なICMPエコーのデータ長は、1454-20-8=1426bytesまでとなる。

 以下で実際にMTUサイズとエコー・データのサイズについて見てみよう。

 すでに述べたように、ICMPエコーを利用するためには、pingコマンドを使う。pingコマンドにはいくつかオプションがあるが、「-f」オプションを使うと、フラグメンテーションを許可しない、というモードになる。具体的には「-f」オプションを使うと、第10回で解説した、IPヘッダ中の「DF(Don't Fragment)ビット」がオンになり、フラグメンテーションが禁止される。もしフラグメンテーションが必要なくらい大きなデータを送信しようとすると、エラーが報告される。

 まずはローカルのイーサネットLAN上でpingを実行してみる。この場合は、フラグメントなしに送信できるエコー・データの最大長は1472bytesのはずである。1472bytesと1473bytesの2通りでpingを実行してみよう。「-f」はフラグメントを許可しないという設定、「-n 1」は1パケットだけ送信するという設定、そして「-l 1472」はエコー・データのサイズを1472bytesにするという設定である。

C:\>ping -f -n 1 -l 1472 192.168.0.1 ……データ長は1472byte

Pinging 192.168.0.1 with 1472 bytes of data:

Reply from 192.168.0.1: bytes=1472 time=5ms TTL=64 ……正しく送信できた

Ping statistics for 192.168.0.1:
    Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 5ms, Maximum = 5ms, Average = 5ms

C:\>ping -f -n 1 -l 1473 192.168.0.1 ……データ長は1473byte

Pinging 192.168.0.1 with 1473 bytes of data:

Packet needs to be fragmented but DF set.
↑↑途中のルータから、エラーで送信できないという応答があった
Ping statistics for 192.168.0.1:
    Packets: Sent = 1, Received = 0, Lost = 1 (100% loss),

 これから分かるように、データ長が1473bytesでは「Packet needs to be fragmented but DF set.(フラグメンテーションが必要なパケット・サイズであるが、DFフラグがセットされていたので送信できない)」というエラーになっている。つまりこのLAN上では、最大MTUは1500bytes(エコー・データのサイズは1472bytes)までということが分かる。

 次は、PPPoEを使ってインターネット接続されている環境において、インターネット上のホストに対してpingを実行してみる。この場合の最大エコー・データ長は1426bytes(1454-20-8=1426bytes)のはずである。

C:\>ping -f -n 1 -l 1426 202.XX.XX.XX ……データ長は1426byte

Pinging 202.XX.XX.XX with 1426 bytes of data:

Reply from 202.XX.XX.XX: bytes=1426 time=17ms TTL=246 ……正しく送信できた

Ping statistics for 202.XX.XX.XX:
    Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 17ms, Maximum = 17ms, Average = 17ms

C:\>ping -f -n 1 -l 1427 202.XX.XX.XX ……データ長は1427byte

Pinging 202.XX.XX.XX with 1427 bytes of data:

Reply from 210.150.YY.YY: Packet needs to be fragmented but DF set.
↑↑途中のルータから、エラーで送信できないという応答があった
Ping statistics for 202.XX.XX.XX:
    Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

 エコー・データのサイズを1427bytesにしてみると、途中のノード(この場合は、インターネット接続に利用しているルータ:210.150.YY.YY)から、DFフラグがセットされているのでフラグメンテーションができない、というエラーが戻ってきている。つまり、インターネットへ接続する経路の途中に、MTUが1454bytesのネットワークが存在しているということが分かる。

 Windows OS自体はもっと長いICMPエコー・パケットが利用できるが(pingコマンドでは最大で65,500bytesまでのデータ長が指定可能)、このように途中で通過するルータやファイアウォールなどの制約を受けて、実際にはもっと小さなサイズしか利用できないことも多い。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。