Message Formats (Nachrichtenformate)
ICMP-Nachrichten werden unter Verwendung des grundlegenden IP-Headers gesendet. Das erste Oktett des Datenteils des Datagramms ist ein ICMP-Typfeld; der Wert dieses Feldes bestimmt das Format der verbleibenden Daten. Jedes Feld, das als „unused (nicht verwendet)" gekennzeichnet ist, ist für zukünftige Erweiterungen reserviert und muss beim Senden Null sein, aber Empfänger sollten diese Felder nicht verwenden (außer um sie in die Prüfsumme einzubeziehen). Sofern nicht anders angegeben, sind die Werte der Internet-Header-Felder wie folgt:
IP-Header-Felder für ICMP
Version
4
IHL (Internet Header Length, Internet-Header-Länge)
Internet-Header-Länge in 32-Bit-Wörtern.
Type of Service (Diensttyp)
0
Total Length (Gesamtlänge)
Länge des Internet-Headers und der Daten in Oktetten.
Identification, Flags, Fragment Offset (Identifikation, Flags, Fragment-Offset)
Verwendet bei der Fragmentierung, siehe [1].
Time to Live (Lebensdauer)
Lebensdauer in Sekunden; da dieses Feld bei jeder Maschine, in der das Datagramm verarbeitet wird, dekrementiert wird, sollte der Wert in diesem Feld mindestens so groß sein wie die Anzahl der Gateways, die dieses Datagramm durchqueren wird.
Protocol (Protokoll)
ICMP = 1
Header Checksum (Header-Prüfsumme)
Das 16-Bit-Einerkomplement der Einerkomplement-Summe aller 16-Bit-Wörter im Header. Zur Berechnung der Prüfsumme sollte das Prüfsummenfeld Null sein. Diese Prüfsumme kann in Zukunft ersetzt werden.
Source Address (Quelladresse)
Die Adresse des Gateways oder Hosts, der die ICMP-Nachricht erstellt. Sofern nicht anders angegeben, kann dies jede der Adressen eines Gateways sein.
Destination Address (Zieladresse)
Die Adresse des Gateways oder Hosts, an den die Nachricht gesendet werden soll.
ICMP-Nachrichtenformat
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 |
| (Format variiert nach Type) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type-Feld (8 Bits)
Identifiziert den ICMP-Nachrichtentyp. Häufige Werte:
| Wert | Nachrichtentyp |
|---|---|
| 0 | Echo Reply (Echo-Antwort) |
| 3 | Destination Unreachable (Ziel nicht erreichbar) |
| 4 | Source Quench (Quelldrosselung) |
| 5 | Redirect (Umleitung) |
| 8 | Echo Request (Echo-Anfrage) |
| 11 | Time Exceeded (Zeit überschritten) |
| 12 | Parameter Problem (Parameterproblem) |
| 13 | Timestamp Request (Zeitstempelanfrage) |
| 14 | Timestamp Reply (Zeitstempelantwort) |
| 15 | Information Request (Informationsanfrage) |
| 16 | Information Reply (Informationsantwort) |
Code-Feld (8 Bits)
Bietet zusätzlichen Kontext für den Nachrichtentyp. Die Bedeutung hängt vom Type-Feld ab.
Beispiel - Destination Unreachable (Type 3) Codes:
- 0 = Netzwerk nicht erreichbar
- 1 = Host nicht erreichbar
- 2 = Protokoll nicht erreichbar
- 3 = Port nicht erreichbar
- 4 = Fragmentierung erforderlich, aber DF gesetzt
- 5 = Quellenroute fehlgeschlagen
Checksum-Feld (16 Bits)
Die Prüfsumme ist das 16-Bit-Einerkomplement der Einerkomplement-Summe der ICMP-Nachricht, beginnend mit dem ICMP-Type-Feld. Zur Berechnung der Prüfsumme sollte das Prüfsummenfeld Null sein.
Prüfsummen-Berechnungsalgorithmus:
// Pseudocode für ICMP-Prüfsummenberechnung
uint16_t calculate_icmp_checksum(uint8_t *data, int length) {
uint32_t sum = 0;
// Alle 16-Bit-Wörter summieren
for (int i = 0; i < length; i += 2) {
uint16_t word = (data[i] << 8) + data[i+1];
sum += word;
}
// Wenn die Länge ungerade ist, das letzte Byte hinzufügen
if (length % 2 == 1) {
sum += (data[length-1] << 8);
}
// 32-Bit-Summe auf 16 Bits falten
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Einerkomplement zurückgeben
return ~sum;
}
Überprüfung:
// Empfänger überprüft durch Berechnung der Prüfsumme über die gesamte Nachricht
// (einschließlich des Prüfsummenfelds). Das Ergebnis sollte 0xFFFF sein.
bool verify_icmp_checksum(uint8_t *message, int length) {
uint16_t result = calculate_icmp_checksum(message, length);
return (result == 0xFFFF);
}
Vollständige ICMP-Paketstruktur
Ethernet-Frame
┌──────────────────────────────────────────┐
│ Ethernet-Header │
├──────────────────────────────────────────┤
│ IP-Header │
│ - Version: 4 │
│ - IHL: 5 (20 Bytes) │
│ - Protocol: 1 (ICMP) │
│ - Source IP: 192.168.1.1 │
│ - Dest IP: 10.0.0.1 │
├──────────────────────────────────────────┤
│ ICMP-Nachricht │
│ ┌────────────────────────────────────┐ │
│ │ Type (8 Bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Code (8 Bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Checksum (16 Bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Nachrichtenspezifische Daten │ │
│ │ (variiert nach Type und Code) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Fehlernachrichtenformat
Für Fehlernachrichten (Types 3, 4, 5, 11, 12) enthält der Nachrichtentext:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Warum ursprüngliche Daten einschließen?
- Ermöglicht dem Empfänger die Identifizierung, welche Übertragung den Fehler verursacht hat
- Enthält Quell-/Zielports für Demultiplexing
- Bietet Kontext für Fehlerbehandlung
Beispiel:
Ursprüngliches TCP-Segment:
┌─────────────────────────────────────┐
│ IP-Header (20 Bytes) │
│ - Src: 192.168.1.10 │
│ - Dst: 203.0.113.50 │
│ - Protocol: 6 (TCP) │
├─────────────────────────────────────┤
│ TCP-Header (20 Bytes) │
│ - Src Port: 54321 │
│ - Dst Port: 80 │
│ - Seq: 1000 │
├─────────────────────────────────────┤
│ TCP-Daten │
└─────────────────────────────────────┘
ICMP-Fehlernachricht enthält:
┌─────────────────────────────────────┐
│ ICMP-Header (8 Bytes) │
│ - Type: 3 │
│ - Code: 1 (Host Unreachable) │
├─────────────────────────────────────┤
│ Ursprünglicher IP-Header (20 Bytes) │ ← Vollständiger IP-Header
├─────────────────────────────────────┤
│ Erste 8 Bytes des TCP-Headers │ ← Enthält Ports
│ - Src Port: 54321 │
│ - Dst Port: 80 │
└─────────────────────────────────────┘
Die 8 Bytes des TCP-Headers reichen aus, um zu identifizieren:
- Quell- und Zielports
- Ermöglicht Demultiplexing des Fehlers zum richtigen Socket
Anfragenachrichtenformat
Für Anfrage-/Antwortnachrichten (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 und Sequence Number:
- Verwendet, um Anfragen mit Antworten abzugleichen
- Identifier: Normalerweise die Prozess-ID des Absenders
- Sequence Number: Erhöht sich mit jeder Nachricht
Beispiel - Ping-Sitzung:
Anfrage 1: ID=12345, Seq=1, Type=8
Antwort 1: ID=12345, Seq=1, Type=0
Anfrage 2: ID=12345, Seq=2, Type=8
Antwort 2: ID=12345, Seq=2, Type=0
Anfrage 3: ID=12345, Seq=3, Type=8
Antwort 3: ID=12345, Seq=3, Type=0
Abgleich: Antwort stimmt mit Anfrage überein, wenn (ID, Seq) identisch sind
Feldbeschreibungen
Nicht verwendete Felder
Jedes Feld, das als „unused (nicht verwendet)" oder „reserved (reserviert)" gekennzeichnet ist:
- Sender: MUSS auf Null setzen
- Empfänger:
- MUSS in Prüfsummenberechnung einbeziehen
- SOLLTE NICHT interpretieren oder für irgendeinen Zweck verwenden
- Ermöglicht zukünftige Protokollerweiterungen
Nachrichtenspezifische Felder
Verschiedene ICMP-Nachrichtentypen verwenden zusätzliche Felder. Siehe individuelle Nachrichtentyp-Spezifikationen für Details.
Verarbeitungsrichtlinien
Verantwortlichkeiten des Senders
-
Geeigneten IP-Header konstruieren:
- Protocol = 1 (ICMP) setzen
- Geeignete TTL setzen
- IP-Header-Prüfsumme berechnen
-
ICMP-Nachricht konstruieren:
- Korrekten Type und Code setzen
- Nachrichtenspezifische Felder ausfüllen
- Nicht verwendete Felder auf Null setzen
- ICMP-Prüfsumme berechnen
-
Kontext für Fehler einschließen:
- Ursprünglichen IP-Header einschließen
- Erste 64 Bits der ursprünglichen Daten einschließen
Verantwortlichkeiten des Empfängers
-
IP-Header validieren:
- IP-Header-Prüfsumme prüfen
- Zieladresse überprüfen
-
ICMP-Nachricht validieren:
- ICMP-Prüfsumme überprüfen
- Type- und Code-Werte prüfen
-
Nachricht verarbeiten:
- Relevante Informationen extrahieren
- Zu geeignetem Handler demultiplexen
- Geeignete Aktion ergreifen
-
Fehlerbehandlung:
- Ungültige Nachrichten stillschweigend verwerfen
- SENDE KEINE ICMP-Fehler über ICMP-Fehler
Byte-Reihenfolge
Alle Multi-Byte-Felder werden in Netzwerk-Byte-Reihenfolge (Big-Endian) übertragen:
- Höchstwertiges Byte zuerst
- Entspricht IP-Header-Konventionen
Beispiel:
// Prüfsummenwert: 0x1234
// Drahtformat: [0x12] [0x34]
uint16_t checksum = 0x1234;
uint8_t byte1 = (checksum >> 8) & 0xFF; // 0x12
uint8_t byte2 = checksum & 0xFF; // 0x34
// Auf dem Draht: byte1 wird zuerst übertragen, dann byte2
Implementierungshinweis: Alle ICMP-Nachrichtentypen teilen diese gemeinsame Header-Struktur. Die Interpretation der Felder nach der Prüfsumme variiert je nach Nachrichtentyp. Implementierungen müssen alle definierten Nachrichtentypen behandeln und nicht erkannte Typen stillschweigend verwerfen.