Message Formats (Formats de messages)
Les messages ICMP sont envoyés en utilisant l'en-tête IP de base. Le premier octet de la portion de données du datagramme est un champ de type ICMP ; la valeur de ce champ détermine le format des données restantes. Tout champ étiqueté « unused (non utilisé) » est réservé pour des extensions futures et doit être zéro lors de l'envoi, mais les récepteurs ne doivent pas utiliser ces champs (sauf pour les inclure dans le checksum). Sauf indication contraire, les valeurs des champs d'en-tête Internet sont les suivantes :
Champs d'en-tête IP pour ICMP
Version
4
IHL (Internet Header Length, Longueur d'en-tête Internet)
Longueur de l'en-tête Internet en mots de 32 bits.
Type of Service (Type de service)
0
Total Length (Longueur totale)
Longueur de l'en-tête Internet et des données en octets.
Identification, Flags, Fragment Offset (Identification, Drapeaux, Décalage de fragment)
Utilisés dans la fragmentation, voir [1].
Time to Live (Durée de vie)
Durée de vie en secondes ; comme ce champ est décrémenté à chaque machine dans laquelle le datagramme est traité, la valeur dans ce champ devrait être au moins aussi grande que le nombre de passerelles que ce datagramme traversera.
Protocol (Protocole)
ICMP = 1
Header Checksum (Checksum d'en-tête)
Le complément à un sur 16 bits de la somme en complément à un de tous les mots de 16 bits dans l'en-tête. Pour calculer le checksum, le champ checksum devrait être zéro. Ce checksum peut être remplacé à l'avenir.
Source Address (Adresse source)
L'adresse de la passerelle ou de l'hôte qui compose le message ICMP. Sauf indication contraire, cela peut être n'importe laquelle des adresses d'une passerelle.
Destination Address (Adresse de destination)
L'adresse de la passerelle ou de l'hôte auquel le message doit être envoyé.
Format de message 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 |
| (Le format varie selon le Type) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Champ Type (8 bits)
Identifie le type de message ICMP. Valeurs courantes :
| Valeur | Type de message |
|---|---|
| 0 | Echo Reply (Réponse d'écho) |
| 3 | Destination Unreachable (Destination inaccessible) |
| 4 | Source Quench (Limitation de source) |
| 5 | Redirect (Redirection) |
| 8 | Echo Request (Demande d'écho) |
| 11 | Time Exceeded (Temps dépassé) |
| 12 | Parameter Problem (Problème de paramètre) |
| 13 | Timestamp Request (Demande d'horodatage) |
| 14 | Timestamp Reply (Réponse d'horodatage) |
| 15 | Information Request (Demande d'information) |
| 16 | Information Reply (Réponse d'information) |
Champ Code (8 bits)
Fournit un contexte supplémentaire pour le type de message. La signification dépend du champ Type.
Exemple - Codes Destination Unreachable (Type 3) :
- 0 = Réseau inaccessible
- 1 = Hôte inaccessible
- 2 = Protocole inaccessible
- 3 = Port inaccessible
- 4 = Fragmentation nécessaire mais DF défini
- 5 = Échec de route source
Champ Checksum (16 bits)
Le checksum est le complément à un sur 16 bits de la somme en complément à un du message ICMP commençant par le champ Type ICMP. Lors du calcul du checksum, le champ checksum devrait être zéro.
Algorithme de calcul du checksum :
// Pseudo-code pour le calcul du checksum ICMP
uint16_t calculate_icmp_checksum(uint8_t *data, int length) {
uint32_t sum = 0;
// Additionner tous les mots de 16 bits
for (int i = 0; i < length; i += 2) {
uint16_t word = (data[i] << 8) + data[i+1];
sum += word;
}
// Si la longueur est impaire, ajouter le dernier octet
if (length % 2 == 1) {
sum += (data[length-1] << 8);
}
// Replier la somme de 32 bits en 16 bits
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Retourner le complément à un
return ~sum;
}
Vérification :
// Le récepteur vérifie en calculant le checksum sur l'ensemble du message
// (y compris le champ checksum). Le résultat devrait être 0xFFFF.
bool verify_icmp_checksum(uint8_t *message, int length) {
uint16_t result = calculate_icmp_checksum(message, length);
return (result == 0xFFFF);
}
Structure complète du paquet ICMP
Trame Ethernet
┌──────────────────────────────────────────┐
│ En-tête Ethernet │
├──────────────────────────────────────────┤
│ En-tête IP │
│ - Version : 4 │
│ - IHL : 5 (20 octets) │
│ - Protocol : 1 (ICMP) │
│ - Source IP : 192.168.1.1 │
│ - Dest IP : 10.0.0.1 │
├──────────────────────────────────────────┤
│ Message ICMP │
│ ┌────────────────────────────────────┐ │
│ │ Type (8 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Code (8 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Checksum (16 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Données spécifiques au message │ │
│ │ (varie selon Type et Code) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Format de message d'erreur
Pour les messages d'erreur (Types 3, 4, 5, 11, 12), le corps du message inclut :
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Pourquoi inclure les données originales ?
- Permet au récepteur d'identifier quelle transmission a causé l'erreur
- Contient les ports source/destination pour le démultiplexage
- Fournit le contexte pour le traitement des erreurs
Exemple :
Segment TCP original :
┌─────────────────────────────────────┐
│ En-tête IP (20 octets) │
│ - Src : 192.168.1.10 │
│ - Dst : 203.0.113.50 │
│ - Protocol : 6 (TCP) │
├─────────────────────────────────────┤
│ En-tête TCP (20 octets) │
│ - Src Port : 54321 │
│ - Dst Port : 80 │
│ - Seq : 1000 │
├─────────────────────────────────────┤
│ Données TCP │
└─────────────────────────────────────┘
Le message d'erreur ICMP inclut :
┌─────────────────────────────────────┐
│ En-tête ICMP (8 octets) │
│ - Type : 3 │
│ - Code : 1 (Host Unreachable) │
├─────────────────────────────────────┤
│ En-tête IP original (20 octets) │ ← En-tête IP complet
├─────────────────────────────────────┤
│ Premiers 8 octets de l'en-tête TCP │ ← Contient les ports
│ - Src Port : 54321 │
│ - Dst Port : 80 │
└─────────────────────────────────────┘
Les 8 octets de l'en-tête TCP suffisent pour identifier :
- Les ports source et destination
- Permet le démultiplexage de l'erreur vers le bon socket
Format de message de requête
Pour les messages de requête/réponse (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 et Sequence Number :
- Utilisés pour faire correspondre les requêtes avec les réponses
- Identifier : Généralement l'ID de processus de l'expéditeur
- Sequence Number : S'incrémente avec chaque message
Exemple - Session Ping :
Requête 1 : ID=12345, Seq=1, Type=8
Réponse 1 : ID=12345, Seq=1, Type=0
Requête 2 : ID=12345, Seq=2, Type=8
Réponse 2 : ID=12345, Seq=2, Type=0
Requête 3 : ID=12345, Seq=3, Type=8
Réponse 3 : ID=12345, Seq=3, Type=0
Correspondance : La réponse correspond à la requête quand (ID, Seq) sont identiques
Descriptions des champs
Champs non utilisés
Tout champ étiqueté « unused (non utilisé) » ou « reserved (réservé) » :
- Expéditeur : DOIT définir à zéro
- Récepteur :
- DOIT inclure dans le calcul du checksum
- NE DEVRAIT PAS interpréter ou utiliser à quelque fin que ce soit
- Permet des extensions de protocole futures
Champs spécifiques aux messages
Différents types de messages ICMP utilisent des champs supplémentaires. Voir les spécifications individuelles de type de message pour plus de détails.
Directives de traitement
Responsabilités de l'expéditeur
-
Construire un en-tête IP approprié :
- Définir Protocol = 1 (ICMP)
- Définir un TTL approprié
- Calculer le checksum de l'en-tête IP
-
Construire le message ICMP :
- Définir le Type et le Code corrects
- Remplir les champs spécifiques au message
- Mettre à zéro les champs non utilisés
- Calculer le checksum ICMP
-
Inclure le contexte pour les erreurs :
- Inclure l'en-tête IP original
- Inclure les premiers 64 bits des données originales
Responsabilités du récepteur
-
Valider l'en-tête IP :
- Vérifier le checksum de l'en-tête IP
- Vérifier l'adresse de destination
-
Valider le message ICMP :
- Vérifier le checksum ICMP
- Vérifier les valeurs Type et Code
-
Traiter le message :
- Extraire les informations pertinentes
- Démultiplexer vers le gestionnaire approprié
- Prendre l'action appropriée
-
Gestion des erreurs :
- Rejeter silencieusement les messages invalides
- NE PAS envoyer d'erreurs ICMP concernant les erreurs ICMP
Ordre des octets
Tous les champs multi-octets sont transmis en ordre des octets réseau (gros-boutiste) :
- L'octet le plus significatif en premier
- Correspond aux conventions de l'en-tête IP
Exemple :
// Valeur du checksum : 0x1234
// Format sur le réseau : [0x12] [0x34]
uint16_t checksum = 0x1234;
uint8_t byte1 = (checksum >> 8) & 0xFF; // 0x12
uint8_t byte2 = checksum & 0xFF; // 0x34
// Sur le réseau : byte1 transmis en premier, puis byte2
Note d'implémentation : Tous les types de messages ICMP partagent cette structure d'en-tête commune. L'interprétation des champs après le checksum varie selon le type de message. Les implémentations doivent gérer tous les types de messages définis et rejeter silencieusement les types non reconnus.