Message Formats
ICMP messages are sent using the basic IP header. The first octet of the data portion of the datagram is an ICMP type field; the value of this field determines the format of the remaining data. Any field labeled "unused" is reserved for later extensions and must be zero when sent, but receivers should not use these fields (except to include them in the checksum). Unless otherwise noted, the values of the internet header fields are as follows:
IP Header Fields for ICMP
Version
4
IHL (Internet Header Length)
Internet header length in 32-bit words.
Type of Service
0
Total Length
Length of internet header and data in octets.
Identification, Flags, Fragment Offset
Used in fragmentation, see [1].
Time to Live
Time to live in seconds; as this field is decremented at each machine in which the datagram is processed, the value in this field should be at least as great as the number of gateways which this datagram will traverse.
Protocol
ICMP = 1
Header Checksum
The 16-bit one's complement of the one's complement sum of all 16-bit words in the header. For computing the checksum, the checksum field should be zero. This checksum may be replaced in the future.
Source Address
The address of the gateway or host that composes the ICMP message. Unless otherwise noted, this can be any of a gateway's addresses.
Destination Address
The address of the gateway or host to which the message should be sent.
ICMP Message Format
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 varies by Type) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type Field (8 bits)
Identifies the ICMP message type. Common values:
| Value | Message Type |
|---|---|
| 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 Field (8 bits)
Provides additional context for the message type. The meaning depends on the Type field.
Example - Destination Unreachable (Type 3) Codes:
- 0 = Network unreachable
- 1 = Host unreachable
- 2 = Protocol unreachable
- 3 = Port unreachable
- 4 = Fragmentation needed but DF set
- 5 = Source route failed
Checksum Field (16 bits)
The checksum is the 16-bit one's complement of the one's complement sum of the ICMP message starting with the ICMP Type field. When computing the checksum, the checksum field should be zero.
Checksum Calculation Algorithm:
// Pseudocode for ICMP checksum calculation
uint16_t calculate_icmp_checksum(uint8_t *data, int length) {
uint32_t sum = 0;
// Sum all 16-bit words
for (int i = 0; i < length; i += 2) {
uint16_t word = (data[i] << 8) + data[i+1];
sum += word;
}
// If length is odd, add the last byte
if (length % 2 == 1) {
sum += (data[length-1] << 8);
}
// Fold 32-bit sum to 16 bits
while (sum >> 16) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
// Return one's complement
return ~sum;
}
Verification:
// Receiver verifies by computing checksum over entire message
// (including the checksum field). Result should be 0xFFFF.
bool verify_icmp_checksum(uint8_t *message, int length) {
uint16_t result = calculate_icmp_checksum(message, length);
return (result == 0xFFFF);
}
Complete ICMP Packet Structure
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 Message │
│ ┌────────────────────────────────────┐ │
│ │ Type (8 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Code (8 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Checksum (16 bits) │ │
│ ├────────────────────────────────────┤ │
│ │ Message-specific data │ │
│ │ (varies by Type and Code) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Error Message Format
For error messages (Types 3, 4, 5, 11, 12), the message body includes:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Why Include Original Data?
- Allows receiver to identify which transmission caused the error
- Contains source/destination ports for demultiplexing
- Provides context for error handling
Example:
Original 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 Data │
└─────────────────────────────────────┘
ICMP Error Message includes:
┌─────────────────────────────────────┐
│ ICMP Header (8 bytes) │
│ - Type: 3 │
│ - Code: 1 (Host Unreachable) │
├─────────────────────────────────────┤
│ Original IP Header (20 bytes) │ ← Full IP header
├─────────────────────────────────────┤
│ First 8 bytes of TCP Header │ ← Contains ports
│ - Src Port: 54321 │
│ - Dst Port: 80 │
└─────────────────────────────────────┘
The 8 bytes of TCP header are sufficient to identify:
- Source and destination ports
- Allows demultiplexing error to correct socket
Query Message Format
For query/reply messages (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 and Sequence Number:
- Used to match requests with replies
- Identifier: Usually process ID of sender
- Sequence Number: Increments with each message
Example - Ping Session:
Request 1: ID=12345, Seq=1, Type=8
Reply 1: ID=12345, Seq=1, Type=0
Request 2: ID=12345, Seq=2, Type=8
Reply 2: ID=12345, Seq=2, Type=0
Request 3: ID=12345, Seq=3, Type=8
Reply 3: ID=12345, Seq=3, Type=0
Matching: Reply matches Request when (ID, Seq) are identical
Field Descriptions
Unused Fields
Any field labeled "unused" or "reserved":
- Sender: MUST set to zero
- Receiver:
- MUST include in checksum calculation
- SHOULD NOT interpret or use for any purpose
- Allows for future protocol extensions
Message-Specific Fields
Different ICMP message types use additional fields. See individual message type specifications for details.
Processing Guidelines
Sender Responsibilities
-
Construct proper IP header:
- Set Protocol = 1 (ICMP)
- Set appropriate TTL
- Calculate IP header checksum
-
Construct ICMP message:
- Set correct Type and Code
- Fill in message-specific fields
- Zero out unused fields
- Calculate ICMP checksum
-
Include context for errors:
- Include original IP header
- Include first 64 bits of original data
Receiver Responsibilities
-
Validate IP header:
- Check IP header checksum
- Verify destination address
-
Validate ICMP message:
- Verify ICMP checksum
- Check Type and Code values
-
Process message:
- Extract relevant information
- Demultiplex to appropriate handler
- Take appropriate action
-
Error handling:
- Discard invalid messages silently
- Do NOT send ICMP errors about ICMP errors
Byte Order
All multi-byte fields are transmitted in network byte order (big-endian):
- Most significant byte first
- Matches IP header conventions
Example:
// Checksum value: 0x1234
// Wire format: [0x12] [0x34]
uint16_t checksum = 0x1234;
uint8_t byte1 = (checksum >> 8) & 0xFF; // 0x12
uint8_t byte2 = checksum & 0xFF; // 0x34
// On wire: byte1 transmitted first, then byte2
Implementation Note: All ICMP message types share this common header structure. The interpretation of fields after the checksum varies by message type. Implementations must handle all defined message types and silently discard unrecognized types.