Message Formats (メッセージ形式)
ICMPメッセージは、基本的なIPヘッダーを使用して送信されます。データグラムのデータ部分の最初のオクテットはICMPタイプフィールドです。このフィールドの値が残りのデータの形式を決定します。「unused (未使用)」とラベル付けされたフィールドは、将来の拡張のために予約されており、送信時にはゼロでなければなりません (MUST) が、受信者はこれらのフィールドを使用すべきではありません (SHOULD NOT) (チェックサムに含めることを除く)。特に明記されていない限り、インターネットヘッダーフィールドの値は次のとおりです。
ICMPのためのIPヘッダーフィールド
Version (バージョン)
4
IHL (Internet Header Length, インターネットヘッダー長)
32ビットワード単位のインターネットヘッダー長。
Type of Service (サービスタイプ)
0
Total Length (全長)
オクテット単位のインターネットヘッダーとデータの長さ。
Identification, Flags, Fragment Offset (識別子、フラグ、フラグメントオフセット)
フラグメンテーションに使用、[1] を参照。
Time to Live (生存時間)
秒単位の生存時間。このフィールドはデータグラムが処理されるすべてのマシンでデクリメントされるため、このフィールドの値はこのデータグラムが通過するゲートウェイの数以上であるべきです (SHOULD)。
Protocol (プロトコル)
ICMP = 1
Header Checksum (ヘッダーチェックサム)
ヘッダー内のすべての16ビットワードの1の補数和の16ビット1の補数。チェックサムを計算する場合、チェックサムフィールドはゼロであるべきです (SHOULD)。このチェックサムは将来置き換えられる可能性があります (MAY)。
Source Address (送信元アドレス)
ICMPメッセージを構成するゲートウェイまたはホストのアドレス。特に明記されていない限り、これはゲートウェイの任意のアドレスである可能性があります (CAN)。
Destination Address (宛先アドレス)
メッセージを送信すべきゲートウェイまたはホストのアドレス。
ICMPメッセージ形式
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Message Body |
| (形式はTypeによって異なる) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Typeフィールド (8ビット)
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 (情報応答) |
Codeフィールド (8ビット)
メッセージタイプに対する追加のコンテキストを提供します。意味はTypeフィールドに依存します。
例 - Destination Unreachable (Type 3) のコード:
- 0 = ネットワーク到達不能
- 1 = ホスト到達不能
- 2 = プロトコル到達不能
- 3 = ポート到達不能
- 4 = フラグメンテーションが必要だがDFが設定されている
- 5 = 送信元ルート失敗
Checksumフィールド (16ビット)
チェックサムは、ICMPタイプフィールドから始まるICMPメッセージの1の補数和の16ビット1の補数です。チェックサムを計算する場合、チェックサムフィールドはゼロであるべきです (SHOULD)。
チェックサム計算アルゴリズム:
// ICMPチェックサム計算の疑似コード
uint16_t calculate_icmp_checksum(uint8_t *data, int length) {
uint32_t sum = 0;
// すべての16ビットワードを合計
for (int i = 0; i < length; i += 2) {
uint16_t word = (data[i] << 8) + data[i+1];
sum += word;
}
// 長さが奇数の場合、最後のバイトを追加
if (length % 2 == 1) {
sum += (data[length-1] << 8);
}
// 32ビット和を16ビットに畳み込む
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// 1の補数を返す
return ~sum;
}
検証:
// 受信者はメッセージ全体 (チェックサムフィールドを含む) に対して
// チェックサムを計算することで検証します。結果は0xFFFFであるべきです。
bool verify_icmp_checksum(uint8_t *message, int length) {
uint16_t result = calculate_icmp_checksum(message, length);
return (result == 0xFFFF);
}
完全なICMPパケット構造
イーサネットフレーム
┌──────────────────────────────────────────┐
│ イーサネットヘッダー │
├──────────────────────────────────────────┤
│ IPヘッダー │
│ - Version: 4 │
│ - IHL: 5 (20バイト) │
│ - Protocol: 1 (ICMP) │
│ - Source IP: 192.168.1.1 │
│ - Dest IP: 10.0.0.1 │
├──────────────────────────────────────────┤
│ ICMPメッセージ │
│ ┌────────────────────────────────────┐ │
│ │ Type (8ビット) │ │
│ ├────────────────────────────────────┤ │
│ │ Code (8ビット) │ │
│ ├────────────────────────────────────┤ │
│ │ Checksum (16ビット) │ │
│ ├────────────────────────────────────┤ │
│ │ メッセージ固有のデータ │ │
│ │ (TypeとCodeによって異なる) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
エラーメッセージ形式
エラーメッセージ (Types 3, 4, 5, 11, 12) の場合、メッセージ本体には次が含まれます:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Unused = 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
元のデータを含める理由:
- 受信者がどの送信がエラーを引き起こしたかを特定できるようにする
- 多重化のための送信元/宛先ポートを含む
- エラー処理のコンテキストを提供
例:
元のTCPセグメント:
┌─────────────────────────────────────┐
│ IPヘッダー (20バイト) │
│ - Src: 192.168.1.10 │
│ - Dst: 203.0.113.50 │
│ - Protocol: 6 (TCP) │
├─────────────────────────────────────┤
│ TCPヘッダー (20バイト) │
│ - Src Port: 54321 │
│ - Dst Port: 80 │
│ - Seq: 1000 │
├─────────────────────────────────────┤
│ TCPデータ │
└─────────────────────────────────────┘
ICMPエラーメッセージには以下が含まれる:
┌─────────────────────────────────────┐
│ ICMPヘッダー (8バイト) │
│ - Type: 3 │
│ - Code: 1 (Host Unreachable) │
├─────────────────────────────────────┤
│ 元のIPヘッダー (20バイト) │ ← 完全なIPヘッダー
├─────────────────────────────────────┤
│ TCPヘッダーの最初の8バイト │ ← ポートを含む
│ - Src Port: 54321 │
│ - Dst Port: 80 │
└─────────────────────────────────────┘
TCPヘッダーの8バイトは以下を識別するのに十分:
- 送信元と宛先のポート
- 正しいソケットへのエラーの多重化を可能にする
クエリメッセージ形式
クエリ/応答メッセージ (Types 0, 8, 13, 14, 15, 16) の場合:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IdentifierとSequence Number:
- 要求と応答を一致させるために使用
- Identifier: 通常は送信者のプロセスID
- Sequence Number: 各メッセージごとに増加
例 - Pingセッション:
要求1: ID=12345, Seq=1, Type=8
応答1: ID=12345, Seq=1, Type=0
要求2: ID=12345, Seq=2, Type=8
応答2: ID=12345, Seq=2, Type=0
要求3: ID=12345, Seq=3, Type=8
応答3: ID=12345, Seq=3, Type=0
マッチング: (ID, Seq) が同一の場合、応答は要求と一致
フィールドの説明
未使用フィールド
「unused (未使用)」または「reserved (予約済み)」とラベル付けされたフィールド:
- 送信者: ゼロに設定しなければなりません (MUST)
- 受信者:
- チェックサム計算に含めなければなりません (MUST)
- いかなる目的にも解釈または使用すべきではありません (SHOULD NOT)
- 将来のプロトコル拡張を可能にする
メッセージ固有のフィールド
異なるICMPメッセージタイプは追加のフィールドを使用します。詳細については、個々のメッセージタイプの仕様を参照してください。
処理ガイドライン
送信者の責任
-
適切なIPヘッダーを構築する:
- Protocol = 1 (ICMP) を設定
- 適切なTTLを設定
- IPヘッダーチェックサムを計算
-
ICMPメッセージを構築する:
- 正しいTypeとCodeを設定
- メッセージ固有のフィールドを埋める
- 未使用フィールドをゼロにする
- ICMPチェックサムを計算
-
エラーのコンテキストを含める:
- 元のIPヘッダーを含める
- 元のデータの最初の64ビットを含める
受信者の責任
-
IPヘッダーを検証する:
- IPヘッダーチェックサムをチェック
- 宛先アドレスを確認
-
ICMPメッセージを検証する:
- ICMPチェックサムを確認
- TypeとCodeの値をチェック
-
メッセージを処理する:
- 関連情報を抽出
- 適切なハンドラーに多重化
- 適切なアクションを実行
-
エラー処理:
- 無効なメッセージを静かに破棄
- ICMPエラーに関するICMPエラーを送信しない (DO NOT)
バイト順
すべてのマルチバイトフィールドはネットワークバイト順 (ビッグエンディアン) で送信されます:
- 最上位バイトが最初
- IPヘッダーの規則に一致
例:
// チェックサム値: 0x1234
// ワイヤー形式: [0x12] [0x34]
uint16_t checksum = 0x1234;
uint8_t byte1 = (checksum >> 8) & 0xFF; // 0x12
uint8_t byte2 = checksum & 0xFF; // 0x34
// ワイヤー上: byte1が最初に送信され、次にbyte2
実装上の注意: すべてのICMPメッセージタイプは、この共通のヘッダー構造を共有します。チェックサムの後のフィールドの解釈は、メッセージタイプによって異なります。実装は、定義されたすべてのメッセージタイプを処理し、認識されないタイプを静かに破棄しなければなりません (MUST)。