Message Formats (Formati dei messaggi)
I messaggi ICMP vengono inviati utilizzando l'header IP di base. Il primo ottetto della porzione dati del datagramma è un campo Type ICMP; il valore di questo campo determina il formato dei dati rimanenti. Qualsiasi campo contrassegnato come "unused (non utilizzato)" è riservato per future estensioni e deve essere zero quando inviato, ma i destinatari non dovrebbero utilizzare questi campi (tranne che per includerli nel checksum). Se non diversamente specificato, i valori dei campi dell'header Internet sono i seguenti:
Campi dell'header IP per ICMP
Version
4
IHL (Internet Header Length, Lunghezza header Internet)
Lunghezza dell'header Internet in parole di 32 bit.
Type of Service (Tipo di servizio)
0
Total Length (Lunghezza totale)
Lunghezza dell'header Internet e dei dati in ottetti.
Identification, Flags, Fragment Offset (Identificazione, Flag, Offset frammento)
Utilizzati nella frammentazione, vedere [1].
Time to Live (Tempo di vita)
Tempo di vita in secondi; poiché questo campo viene decrementato in ogni macchina in cui il datagramma viene elaborato, il valore in questo campo dovrebbe essere almeno uguale al numero di gateway che questo datagramma attraverserà.
Protocol (Protocollo)
ICMP = 1
Header Checksum (Checksum header)
Il complemento a uno a 16 bit della somma in complemento a uno di tutte le parole a 16 bit nell'header. Per calcolare il checksum, il campo checksum dovrebbe essere zero. Questo checksum può essere sostituito in futuro.
Source Address (Indirizzo sorgente)
L'indirizzo del gateway o host che crea il messaggio ICMP. Se non diversamente specificato, questo può essere uno qualsiasi degli indirizzi di un gateway.
Destination Address (Indirizzo di destinazione)
L'indirizzo del gateway o host a cui il messaggio deve essere inviato.
Formato del messaggio 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 |
| (Il formato varia in base al Type) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Campo Type (8 bit)
Identifica il tipo di messaggio ICMP. Valori comuni:
| Valore | Tipo di messaggio |
|---|---|
| 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 |
Campo Code (8 bit)
Fornisce contesto aggiuntivo per il tipo di messaggio. Il significato dipende dal campo Type.
Esempio - Codici Destination Unreachable (Type 3):
- 0 = Rete non raggiungibile
- 1 = Host non raggiungibile
- 2 = Protocollo non raggiungibile
- 3 = Porta non raggiungibile
- 4 = Frammentazione richiesta ma DF impostato
- 5 = Instradamento sorgente fallito
Campo Checksum (16 bit)
Il checksum è il complemento a uno a 16 bit della somma in complemento a uno del messaggio ICMP, a partire dal campo Type ICMP. Per calcolare il checksum, il campo checksum dovrebbe essere zero.
Algoritmo di calcolo del checksum:
// Pseudocodice per il calcolo del checksum ICMP
uint16_t calculate_icmp_checksum(uint8_t *data, int length) {
uint32_t sum = 0;
// Somma tutte le parole a 16 bit
for (int i = 0; i < length; i += 2) {
uint16_t word = (data[i] << 8) + data[i+1];
sum += word;
}
// Se la lunghezza è dispari, aggiungi l'ultimo byte
if (length % 2 == 1) {
sum += (data[length-1] << 8);
}
// Riduci la somma a 32 bit a 16 bit
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Restituisci il complemento a uno
return ~sum;
}
Verifica:
// Il destinatario verifica calcolando il checksum sull'intero messaggio
// (incluso il campo checksum). Il risultato dovrebbe essere 0xFFFF.
bool verify_icmp_checksum(uint8_t *message, int length) {
uint16_t result = calculate_icmp_checksum(message, length);
return (result == 0xFFFF);
}
Struttura completa del pacchetto ICMP
Frame Ethernet
┌──────────────────────────────────────────┐
│ Header Ethernet │
├──────────────────────────────────────────┤
│ Header IP │
│ - Version: 4 │
│ - IHL: 5 (20 byte) │
│ - Protocol: 1 (ICMP) │
│ - Source IP: 192.168.1.1 │
│ - Dest IP: 10.0.0.1 │
├──────────────────────────────────────────┤
│ Messaggio ICMP │
│ ┌────────────────────────────────────┐ │
│ │ Type (8 bit) │ │
│ ├────────────────────────────────────┤ │
│ │ Code (8 bit) │ │
│ ├────────────────────────────────────┤ │
│ │ Checksum (16 bit) │ │
│ ├────────────────────────────────────┤ │
│ │ Dati specifici del messaggio │ │
│ │ (varia in base a Type e Code) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Formato dei messaggi di errore
Per i messaggi di errore (Types 3, 4, 5, 11, 12), il corpo del messaggio contiene:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Perché includere i dati originali?
- Consente al destinatario di identificare quale trasmissione ha causato l'errore
- Include porte sorgente/destinazione per il demultiplexing
- Fornisce contesto per la gestione degli errori
Esempio:
Segmento TCP originale:
┌─────────────────────────────────────┐
│ Header IP (20 byte) │
│ - Src: 192.168.1.10 │
│ - Dst: 203.0.113.50 │
│ - Protocol: 6 (TCP) │
├─────────────────────────────────────┤
│ Header TCP (20 byte) │
│ - Src Port: 54321 │
│ - Dst Port: 80 │
│ - Seq: 1000 │
├─────────────────────────────────────┤
│ Dati TCP │
└─────────────────────────────────────┘
Il messaggio di errore ICMP contiene:
┌─────────────────────────────────────┐
│ Header ICMP (8 byte) │
│ - Type: 3 │
│ - Code: 1 (Host Unreachable) │
├─────────────────────────────────────┤
│ Header IP originale (20 byte) │ ← Header IP completo
├─────────────────────────────────────┤
│ Primi 8 byte dell'header TCP │ ← Include porte
│ - Src Port: 54321 │
│ - Dst Port: 80 │
└─────────────────────────────────────┘
Gli 8 byte dell'header TCP sono sufficienti per identificare:
- Porte sorgente e destinazione
- Consente il demultiplexing dell'errore al socket corretto
Formato dei messaggi di richiesta
Per i messaggi di richiesta/risposta (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 e Sequence Number:
- Utilizzati per abbinare richieste con risposte
- Identifier: Tipicamente l'ID del processo del mittente
- Sequence Number: Incrementato ad ogni messaggio
Esempio - Sessione Ping:
Richiesta 1: ID=12345, Seq=1, Type=8
Risposta 1: ID=12345, Seq=1, Type=0
Richiesta 2: ID=12345, Seq=2, Type=8
Risposta 2: ID=12345, Seq=2, Type=0
Richiesta 3: ID=12345, Seq=3, Type=8
Risposta 3: ID=12345, Seq=3, Type=0
Abbinamento: La risposta corrisponde alla richiesta quando (ID, Seq) sono identici
Descrizioni dei campi
Campi non utilizzati
Qualsiasi campo contrassegnato come "unused (non utilizzato)" o "reserved (riservato)":
- Mittente: DEVE impostare a zero
- Destinatario:
- DEVE includere nel calcolo del checksum
- NON DOVREBBE interpretare o utilizzare per alcuno scopo
- Consente future estensioni del protocollo
Campi specifici del messaggio
I diversi tipi di messaggio ICMP utilizzano campi aggiuntivi. Vedere le specifiche individuali dei tipi di messaggio per i dettagli.
Linee guida per l'elaborazione
Responsabilità del mittente
-
Costruire header IP appropriato:
- Impostare Protocol = 1 (ICMP)
- Impostare TTL appropriato
- Calcolare checksum header IP
-
Costruire messaggio ICMP:
- Impostare Type e Code corretti
- Compilare campi specifici del messaggio
- Impostare campi non utilizzati a zero
- Calcolare checksum ICMP
-
Includere contesto per errori:
- Includere header IP originale
- Includere primi 64 bit di dati originali
Responsabilità del destinatario
-
Validare header IP:
- Verificare checksum header IP
- Controllare indirizzo di destinazione
-
Validare messaggio ICMP:
- Verificare checksum ICMP
- Controllare valori Type e Code
-
Elaborare messaggio:
- Estrarre informazioni rilevanti
- Demultiplexare al gestore appropriato
- Intraprendere azione appropriata
-
Gestione errori:
- Scartare silenziosamente messaggi non validi
- NON INVIARE errori ICMP su errori ICMP
Ordine dei byte
Tutti i campi multi-byte vengono trasmessi in ordine byte di rete (Big-Endian):
- Byte più significativo per primo
- Conforme alle convenzioni dell'header IP
Esempio:
// Valore checksum: 0x1234
// Formato sul cavo: [0x12] [0x34]
uint16_t checksum = 0x1234;
uint8_t byte1 = (checksum >> 8) & 0xFF; // 0x12
uint8_t byte2 = checksum & 0xFF; // 0x34
// Sul cavo: byte1 trasmesso per primo, poi byte2
Nota di implementazione: Tutti i tipi di messaggio ICMP condividono questa struttura comune dell'header. L'interpretazione dei campi dopo il checksum varia in base al tipo di messaggio. Le implementazioni devono gestire tutti i tipi di messaggio definiti e scartare silenziosamente i tipi non riconosciuti.