Loading learning content...
Every ICMP message—whether an urgent error report or a routine ping—must travel across the network like any other data. But how exactly does this work? ICMP doesn't have its own transport mechanism; it cannot directly place frames on the wire or make routing decisions.
Instead, ICMP relies on IP for delivery. This creates an elegant but sometimes confusing relationship: ICMP is a Layer 3 protocol that rides inside another Layer 3 protocol. ICMP messages are encapsulated within IP packets, just like TCP segments or UDP datagrams.
Understanding this encapsulation is crucial for several reasons:
By the end of this page, you will understand exactly how ICMP messages are encapsulated within IP packets, the IP header fields relevant to ICMP transport, how ICMP messages are identified during packet processing, the relationship between source/destination addresses in ICMP scenarios, ICMP fragmentation behavior and implications, and how to read ICMP packets in network captures.
Understanding ICMP encapsulation requires clarity on the relationship between ICMP and IP. This relationship is unique in the protocol stack and often misunderstood.
ICMP's Dual Nature
ICMP occupies a peculiar position:
Architecturally, ICMP is a Layer 3 (Network Layer) protocol. It operates at the same conceptual level as IP itself and is defined as an integral part of IP implementation. RFC 791 mandates ICMP support.
Operationally, ICMP is a user of IP. Every ICMP message is encapsulated in an IP packet for transmission. ICMP has no independent way to reach the network.
This duality means ICMP is both:
Comparison with Transport Protocols
To clarify ICMP's position, compare how different protocols use IP:
| Protocol | IP Protocol Number | Layer | Carried by IP? |
|---|---|---|---|
| TCP | 6 | Layer 4 (Transport) | Yes—TCP segments in IP packets |
| UDP | 17 | Layer 4 (Transport) | Yes—UDP datagrams in IP packets |
| ICMP | 1 | Layer 3 (Network) | Yes—ICMP messages in IP packets |
| OSPF | 89 | Layer 3 (Network) | Yes—OSPF messages in IP packets |
| IGMP | 2 | Layer 3 (Network) | Yes—IGMP messages in IP packets |
Notice that ICMP shares its encapsulation pattern with other Layer 3 protocols like OSPF and IGMP. All are carried directly in IP packets using the Protocol field in the IP header to identify them.
The key distinction from TCP and UDP:
For exams and practical work, memorize these IP protocol numbers: 1 = ICMP, 2 = IGMP, 6 = TCP, 17 = UDP, 41 = IPv6 encapsulation, 47 = GRE, 50 = ESP, 51 = AH, 58 = ICMPv6, 89 = OSPF. These appear constantly in packet analysis and firewall rules.
Let's examine the complete structure of an ICMP packet as it appears on the wire. Remember that ICMP is encapsulated within IP, which is encapsulated within a Layer 2 frame (e.g., Ethernet).
The Full Encapsulation Stack
12345678910111213141516171819202122232425262728293031323334353637383940414243
# Complete ICMP Echo Request as it appears on the wire ┌──────────────────────────────────────────────────────────────┐│ ETHERNET FRAME ││ (14 bytes) │├──────────────────────────────────────────────────────────────┤│ Dest MAC (6) │ Src MAC (6) │ EtherType 0x0800 (2) ││ (next-hop) │ (sender) │ (indicates IPv4) │└──────────────────────────────────────────────────────────────┘ ↓┌──────────────────────────────────────────────────────────────┐│ IPv4 HEADER ││ (20 bytes minimum) │├──────────────────────────────────────────────────────────────┤│ Ver=4 │IHL=5│ TOS │ Total Length │├───────┴─────┴──────┴─────────────────────────────────────────┤│ Identification │ Flags │ Fragment Offset │├─────────────────────────┴───────┴────────────────────────────┤│ TTL │ Protocol=1 │ Header Checksum ││ │ (ICMP!) │ │├─────────────┴────────────┴───────────────────────────────────┤│ Source IP Address │├──────────────────────────────────────────────────────────────┤│ Destination IP Address │└──────────────────────────────────────────────────────────────┘ ↓┌──────────────────────────────────────────────────────────────┐│ ICMP MESSAGE ││ (8+ bytes) │├──────────────────────────────────────────────────────────────┤│ Type=8 │ Code=0 │ Checksum ││ (Echo Req)│ │ │├───────────┴───────────┴──────────────────────────────────────┤│ Identifier │ Sequence Number │├───────────────────────┴──────────────────────────────────────┤│ Data ││ (typically 56 bytes for ping) │└──────────────────────────────────────────────────────────────┘ ↓┌──────────────────────────────────────────────────────────────┐│ ETHERNET FCS ││ (4 bytes CRC) │└──────────────────────────────────────────────────────────────┘Size Calculations
For a typical ping (Echo Request with 56 bytes of data):
| Component | Size (bytes) |
|---|---|
| Ethernet Header | 14 |
| IPv4 Header | 20 |
| ICMP Header | 8 |
| ICMP Data | 56 |
| Ethernet FCS | 4 |
| Total | 102 bytes |
The reported size often excludes Ethernet header/FCS, so you'll see "84 bytes" in ping output (IP header + ICMP header + data).
The Protocol Field: The Key Identifier
The Protocol field in the IP header (byte 9, value = 1) is how receiving systems know the payload is ICMP. When an IP packet arrives:
The Protocol field is how IP performs 'demultiplexing'—directing payloads to the correct upper-layer protocol handler. This is analogous to how EtherType in Ethernet (0x0800 for IPv4, 0x86DD for IPv6) directs frames to the correct network layer protocol.
While ICMP has its own header, the encapsulating IP header contains fields critical to ICMP's operation. Understanding how these fields are set for ICMP traffic helps with analysis and troubleshooting.
| IP Field | Typical ICMP Value | Significance |
|---|---|---|
| Version | 4 | IPv4; ICMPv6 uses IP Version 6 |
| IHL | 5 (no options) | Usually minimum header; options rare |
| TOS/DSCP | 0 (best effort) | ICMP rarely uses QoS; can be set for monitoring |
| Total Length | Variable | IP header + ICMP header + ICMP data |
| Identification | Unique per packet | For fragment reassembly if needed |
| Flags (DF) | Usually 0 | ICMP can be fragmented; DF often 0 |
| TTL | 64/128/255 | Varies by OS; critical for traceroute |
| Protocol | 1 | Always 1 for ICMP |
| Source Address | Sender's IP | Where the ICMP message originates |
| Destination Address | Target IP | Where the ICMP message goes |
Special Considerations for Source and Destination
For ICMP Error Messages, the addressing follows specific rules:
This means the error message travels back to the original sender, carrying information about what went wrong.
For ICMP Query Messages (Echo, etc.):
The reply essentially swaps source and destination addresses.
12345678910111213141516171819202122232425262728293031323334353637383940414243
# Scenario: Host 192.168.1.10 pings 8.8.8.8 # ICMP Echo Request packet:IP Header: Source: 192.168.1.10 (ping sender) Destination: 8.8.8.8 (ping target) Protocol: 1 (ICMP) TTL: 64 ICMP Message: Type: 8 (Echo Request) Code: 0 ID: 12345 Seq: 1 # ICMP Echo Reply packet:IP Header: Source: 8.8.8.8 (responder) Destination: 192.168.1.10 (original sender) Protocol: 1 (ICMP) TTL: 117 (started at 128, 11 hops back) ICMP Message: Type: 0 (Echo Reply) Code: 0 ID: 12345 (same as request!) Seq: 1 (same as request!) # ─────────────────────────────────────────────────────────────# Scenario: Packet from 192.168.1.10 to 10.99.0.50 fails# Router 172.16.0.1 has no route to 10.99.0.0/8 # ICMP Destination Unreachable packet:IP Header: Source: 172.16.0.1 (router that detected error) Destination: 192.168.1.10 (original sender, from failed packet) Protocol: 1 (ICMP) TTL: 64 (fresh TTL for error message) ICMP Message: Type: 3 (Destination Unreachable) Code: 0 (Network Unreachable) Data: [Original IP header + first 8 bytes of payload]When a router generates an ICMP error message, it uses a fresh TTL (typically 255 or the system default), NOT the remaining TTL from the failed packet. This ensures the error message has sufficient TTL to reach the original sender, even if the original packet's TTL was low when the error occurred.
ICMP includes its own checksum field that verifies the integrity of the ICMP message. This checksum is separate from and in addition to the IP header checksum.
Checksum Algorithm
ICMP uses the same checksum algorithm as IP and TCP—the one's complement sum of 16-bit words:
Verification reverses this: sum all 16-bit words (including checksum). If the result is all 1s (0xFFFF), the checksum is valid.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
# ICMP Checksum Calculation Example (Python) def calculate_icmp_checksum(data: bytes) -> int: """ Calculate ICMP checksum using one's complement sum. Args: data: Complete ICMP message with checksum field set to 0 Returns: 16-bit checksum value """ # Ensure even length (pad with zero if needed) if len(data) % 2: data += b'\x00' # Sum all 16-bit words checksum = 0 for i in range(0, len(data), 2): word = (data[i] << 8) + data[i + 1] checksum += word # Fold 32-bit sum to 16 bits (add carries) while checksum >> 16: checksum = (checksum & 0xFFFF) + (checksum >> 16) # One's complement return ~checksum & 0xFFFF # Example: Echo Request# Type=8, Code=0, Checksum=0 (to calculate), ID=0x0001, Seq=0x0001# Data: "Hello" = 0x48 0x65 0x6C 0x6C 0x6F import struct # Build ICMP message with checksum = 0icmp_type = 8icmp_code = 0icmp_checksum = 0icmp_id = 1icmp_seq = 1icmp_data = b"Hello" icmp_header = struct.pack("!BBHHH", icmp_type, icmp_code, icmp_checksum, icmp_id, icmp_seq)icmp_packet = icmp_header + icmp_data # Calculate checksumchecksum = calculate_icmp_checksum(icmp_packet)print(f"Calculated checksum: 0x{checksum:04X}") # Rebuild packet with correct checksumicmp_header = struct.pack("!BBHHH", icmp_type, icmp_code, checksum, icmp_id, icmp_seq)final_packet = icmp_header + icmp_dataWhat the ICMP Checksum Covers
The ICMP checksum covers the entire ICMP message:
What the ICMP Checksum Does NOT Cover
The ICMP checksum does not cover the IP header. That's the job of the IP header checksum. This division of responsibility means:
Important Difference from TCP/UDP
TCP and UDP include a pseudo-header in their checksum calculation that covers source IP, destination IP, protocol, and length. This binds the transport segment to its IP addresses.
ICMP does not use a pseudo-header. The ICMP checksum covers only the ICMP message itself. This has security implications—ICMP messages can theoretically be placed into different IP packets (though this would typically fail other validation).
By default, Wireshark may show 'checksum unverified' for ICMP because checksum offloading to NICs is common. Enable checksum verification in Preferences → Protocols → IPv4 if you need to analyze checksum correctness. Invalid checksums indicate corruption or malformed packets.
Since ICMP messages are encapsulated in IP packets, they're subject to IP's fragmentation rules. Understanding how fragmentation affects ICMP is important for troubleshooting.
Can ICMP Messages Be Fragmented?
Yes—ICMP messages can be fragmented if they exceed path MTU. However, this is rare in practice because:
Fragmentation of Error Messages
ICMP error messages include originating packet data (IP header + 8 bytes). Even so, typical error messages are:
Total: ~36 bytes minimum—well under any reasonable MTU.
1234567891011121314151617181920212223242526
# Demonstrating ICMP fragmentation with large ping # Default ping (56 bytes data) - single packet$ ping -c 1 8.8.8.8# Results in: 56 data + 8 ICMP header + 20 IP header = 84 bytes total # Large ping that WILL fragment on 1500-byte MTU path$ ping -c 1 -s 3000 8.8.8.8# Results in: 3000 data + 8 ICMP header + 20 IP header = 3028 bytes# Must fragment into: # Fragment 1: 1480 data bytes + 20 IP header = 1500 bytes# Fragment 2: 1480 data bytes + 20 IP header = 1500 bytes # Fragment 3: 68 data bytes + 20 IP header = 88 bytes # Ping with Don't Fragment to test MTU$ ping -c 1 -s 1472 -M do 8.8.8.8# 1472 + 8 + 20 = 1500 bytes exactly - works on standard Ethernet $ ping -c 1 -s 1473 -M do 8.8.8.8# 1473 + 8 + 20 = 1501 bytes - exceeds 1500 MTU# If path has exactly 1500 MTU, this returns:# "ping: local error: message too long, mtu=1500" # Capture fragmented ICMP with tcpdump$ sudo tcpdump -i eth0 'icmp or ip[6:2] & 0x3fff != 0' -v# The filter catches ICMP and any fragmented IP packetsThe Reassembly Problem
When ICMP messages are fragmented:
This creates challenges:
The "First Fragment Only" Error Rule
Recall from error generation rules: ICMP errors are only sent for the first fragment of a fragmented datagram. Why?
In modern networks, fragmentation creates problems: performance overhead, security risks, firewall complexity. Path MTU Discovery exists specifically to avoid fragmentation. If you see fragmented ICMP, investigate why—it usually indicates MTU misconfiguration somewhere in the path.
Analyzing ICMP traffic in tools like Wireshark is an essential skill for network troubleshooting. Let's walk through reading ICMP packets in captures.
Identifying ICMP Packets
In Wireshark/tcpdump, ICMP packets are identified by:
123456789101112131415161718192021222324252627282930313233343536373839404142
# Wireshark display for ICMP Echo Request Frame 1: 98 bytes on wire, 98 bytes capturedEthernet II, Src: 00:11:22:33:44:55, Dst: 66:77:88:99:aa:bbInternet Protocol Version 4, Src: 192.168.1.10, Dst: 8.8.8.8 Version: 4 Header Length: 20 bytes Total Length: 84 Identification: 0x1234 Flags: 0x00 Fragment Offset: 0 Time to Live: 64 Protocol: ICMP (1) ← Identifies as ICMP! Header Checksum: 0x5678 Source: 192.168.1.10 Destination: 8.8.8.8Internet Control Message Protocol Type: 8 (Echo Request) ← ICMP Type Code: 0 ← ICMP Code Checksum: 0xabcd [correct] Identifier (BE): 12345 ← For matching replies Sequence (BE): 1 ← Sequence number Data (56 bytes) ← Ping payload # ─────────────────────────────────────────────────────────────# Wireshark display for ICMP Destination Unreachable Frame 42: 70 bytes on wire, 70 bytes capturedInternet Protocol Version 4, Src: 10.0.0.1, Dst: 192.168.1.10 Protocol: ICMP (1)Internet Control Message Protocol Type: 3 (Destination Unreachable) Code: 1 (Host Unreachable) ← Specific error reason Checksum: 0x4321 [correct] Unused: 0 ─── Embedded/Original IP Header ─── Internet Protocol Version 4, Src: 192.168.1.10, Dst: 10.99.0.50 Protocol: TCP (6) [This is the original packet that failed!] ─── First 8 bytes of original payload ─── TCP: Src Port: 54321, Dst Port: 80, Seq: 12345678 [Original TCP connection information]Key Analysis Points
For Echo Request/Reply:
For Destination Unreachable:
For Time Exceeded:
| Filter | Purpose |
|---|---|
| icmp | All ICMP traffic |
| icmp.type == 8 | Echo Requests only |
| icmp.type == 0 | Echo Replies only |
| icmp.type == 3 | All Destination Unreachable |
| icmp.type == 3 && icmp.code == 4 | Fragmentation Needed (PMTUD) |
| icmp.type == 11 | Time Exceeded (traceroute) |
| ip.addr == 8.8.8.8 && icmp | ICMP to/from specific host |
| icmp && !icmp.type == 8 && !icmp.type == 0 | ICMP errors only (no ping) |
| ip.proto == 1 | Alternative: IP protocol 1 (ICMP) |
Wireshark's default coloring highlights ICMP in pink/light red, making it visually distinct. Errors (Destination Unreachable, etc.) often appear in darker shades. Use View → Coloring Rules to customize, or View → Colorize Conversation to track specific ICMP flows.
Understanding ICMP encapsulation is crucial for writing effective firewall rules. Because ICMP is carried within IP, firewalls must examine both layers to make proper filtering decisions.
Firewall Rule Structure for ICMP
Typical firewall rules for ICMP include:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
# Linux iptables ICMP rules examples # Allow ping replies (outbound, from your host)iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT # Allow incoming pings (be selective!)iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # Allow essential ICMP error messages (REQUIRED for proper operation)iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPTiptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT # Specifically allow Fragmentation Needed (critical for PMTUD!)iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT # Block ICMP Redirect (security risk)iptables -A INPUT -p icmp --icmp-type redirect -j DROP # Rate limit pings to prevent flood attacksiptables -A INPUT -p icmp --icmp-type echo-request \ -m limit --limit 1/second --limit-burst 4 -j ACCEPTiptables -A INPUT -p icmp --icmp-type echo-request -j DROP # ─────────────────────────────────────────────────────────────# Windows Firewall (netsh) # Allow ICMP Echo Request (inbound ping)netsh advfirewall firewall add rule name="Allow Ping" \ protocol=icmpv4:8,any dir=in action=allow # Block ICMP Redirectnetsh advfirewall firewall add rule name="Block Redirect" \ protocol=icmpv4:5,any dir=in action=block # ─────────────────────────────────────────────────────────────# Cisco ACL for ICMP ! Allow essential ICMPaccess-list 100 permit icmp any any echo-replyaccess-list 100 permit icmp any any unreachableaccess-list 100 permit icmp any any time-exceededaccess-list 100 permit icmp any any packet-too-big ! Deny ICMP redirectaccess-list 100 deny icmp any any redirect ! Allow echo request with rate limiting (requires separate mechanism)access-list 100 permit icmp any any echoRecommended ICMP Filtering Policy
Based on security and operational requirements:
| ICMP Type | Recommendation | Rationale |
|---|---|---|
| Echo Reply (0) | ALLOW | Needed for outbound ping to work |
| Destination Unreachable (3) | ALLOW | Essential for proper TCP behavior |
| MUST ALLOW | Critical for PMTUD |
| Source Quench (4) | DROP or IGNORE | Deprecated, potential DoS vector |
| Redirect (5) | DROP | Security risk, rarely needed |
| Echo Request (8) | RATE-LIMIT | Allow diagnostics, prevent flood |
| Time Exceeded (11) | ALLOW | Essential for traceroute, loop detection |
| Parameter Problem (12) | ALLOW | Useful for debugging, rare |
| Timestamp (13/14) | DROP | Obsolete, potential info disclosure |
| Address Mask (17/18) | DROP | Obsolete, security risk |
Blocking 'Fragmentation Needed' (Type 3, Code 4) breaks Path MTU Discovery, causing 'PMTUD black holes' where TCP connections work for small data but hang for large transfers. This is one of the most common ICMP-related misconfigurations in enterprise networks.
Understanding how ICMP messages are packaged within IP packets is fundamental for network analysis, firewall configuration, and protocol comprehension. We've examined the complete encapsulation stack:
What's Next
We've now covered ICMP's purpose, error messages, query messages, and encapsulation. The final page of this module will examine ICMP Types—a comprehensive reference to all ICMP message types with their codes, meanings, and practical applications. This serves as both a summary and a quick-reference guide for network engineers.
You now understand how ICMP messages are encapsulated within IP packets, the role of IP header fields in ICMP transport, and how to analyze ICMP traffic in captures. You can configure appropriate firewall rules that protect the network while preserving essential ICMP functionality. Next, we complete the module with a comprehensive ICMP types reference.