---
title: ICMP
source: 'https://academia.sh/en/courses/network-models/icmp'
course: 'Network Models and Protocols'
language: en
updated: '2026-08-17T18:07:08+00:00'
license: 'CC BY-SA 4.0'
---

# ICMP

The format of control messages, the echo test, how the time-to-live field turns into traceroute, path MTU discovery, and the consequences of blocking these messages.

The previous lessons said "the router drops the packet and reports it" several times:
when the time to live runs out, when no route to the destination network can be found,
when the packet is larger than the MTU. How these reports are made has not yet been
explained.

IP itself gives no feedback; it is a best-effort delivery service. Feedback is a
separate protocol's job. This lesson's question is what that protocol says, and what
happens when it cannot.

## The Place of Control Messages

**ICMP (Internet Control Message Protocol)** is the protocol that reports conditions
arising while IP packets are carried. It is carried with value `1` in the IP header's
protocol field — meaning it travels as IP's payload, but it is not a transport-layer
protocol.

Its position looks like an oddity: IP's control protocol is carried inside IP. The
rationale is practical; an ICMP message also needs to be routed, and the mechanism that
routes it is already IP.

ICMP's limits must be known explicitly:

- There is **no guarantee** that an ICMP message will arrive; it can be lost itself.
- When an ICMP message is lost, **no second message is generated**; there is no error
  report for an error report.
- ICMP messages do not **fix** errors; they only report them. The endpoint decides what
  to do.

## Message Format

Every ICMP message begins with an 8-byte header:

| Field | Size | Function |
|---|---|---|
| Type | 1 byte | The message's class |
| Code | 1 byte | Detail within the class |
| Checksum | 2 bytes | Over the entire message |
| Variable field | 4 bytes | Gains meaning based on the type |

In error-reporting messages, the body carries **the IP header of the packet that caused
the error, plus the first bytes of its payload**. This detail matters: the endpoint can
only match an incoming error message to its own connection because of this copy.
Because the copy also contains the first bytes of the transport-layer header, the port
numbers can be read too.

In echo messages, the variable field is used as an identifier and a sequence number:

```python
import struct


def checksum(data: bytes) -> int:
    if len(data) % 2:
        data += b"\x00"
    total = 0
    for i in range(0, len(data), 2):
        total += (data[i] << 8) + data[i + 1]
    while total >> 16:
        total = (total & 0xFFFF) + (total >> 16)
    return ~total & 0xFFFF


def echo_request(ident: int, seq: int, payload: bytes) -> bytes:
    body = struct.pack("!BBHHH", 8, 0, 0, ident, seq) + payload
    value = checksum(body)
    return body[:2] + struct.pack("!H", value) + body[4:]


message = echo_request(ident=0x1234, seq=1, payload=bytes(range(32)))
print("message size:", len(message), "bytes")
print("header      :", message[:8].hex())
print("checksum    :", hex(struct.unpack("!H", message[2:4])[0]))
print("verify      :", checksum(message))

icmp_type, code, _, ident, seq = struct.unpack("!BBHHH", message[:8])
print(f"type={icmp_type} code={code} id={hex(ident)} seq={seq} payload={len(message) - 8} bytes")
```

```
message size: 40 bytes
header      : 0800f4c912340001
checksum    : 0xf4c9
verify      : 0
type=8 code=0 id=0x1234 seq=1 payload=32 bytes
```

The checksum method is the same one built for the IPv4 header in the Encapsulation and
Headers lesson; the difference is that in ICMP it covers the payload as well as the
header. Verification should again come out to zero.

## Message Types

| Type | Code | Meaning | When it is generated |
|---|---|---|---|
| 0 | 0 | Echo reply | In response to an echo request |
| 3 | 0 | Network unreachable | No route to the destination network |
| 3 | 1 | Host unreachable | Target unresponsive on the local network |
| 3 | 3 | Port unreachable | No process listening at the target |
| 3 | 4 | Fragmentation needed, blocked | Packet larger than the MTU and DF set |
| 8 | 0 | Echo request | Reachability test |
| 11 | 0 | Time to live exceeded | TTL reached zero |
| 11 | 1 | Reassembly time exceeded | Fragments not collected in time |
| 12 | 0 | Header error | One of the fields is inconsistent |

Type 3, code 4 carries a distinct significance: the message also carries the acceptable
MTU value, and it is the basis for path MTU discovery.

## The Echo Test

The **echo request** and **echo reply** pair is used to test an address's
reachability. The sender puts in an identifier and an increasing sequence number; the
reply returns the same values. This matches which reply belongs to which request and
measures the round-trip time.

What the test proves and what it does not prove must be kept separate.

**If a reply arrives**, the following are true: a path exists in both directions, the
target interface is active, and the IP layer is working.

**If no reply arrives**, none of this is certain. The target might be down; the target
might be up but not answering echo requests; a filter along the path might have dropped
the request or the reply. No response does not mean the target is not working.

Whether a port is serving cannot be determined with an echo test. Echo is a test at the
IP level; it says nothing about the transport layer or the application layer. A server
that answers echo requests may still have a stalled application.

## Time to Live and Traceroute

The **time to live (TTL)** field in the IP header limits the number of routers a packet
can pass through. Every router decrements the field by one; when it reaches zero, the
router drops the packet and sends a type 11 message to the sender.

The field's original purpose is preventing packets from circulating forever in routing
loops. But the field also serves an entirely different purpose: **traceroute**.

The method is this. A packet with TTL 1 is sent to the destination first; the first
router drops it and reports itself. Then a packet with TTL 2 is sent; the second router
reports. As the value is raised one by one, each step of the path is revealed in turn.
When the destination is reached, the incoming message is not type 11 but either an echo
reply or a port-unreachable report; this marks the end of the sequence.

Since the topology of the path from the example network's client to `198.51.100.20` is
known, which steps the trace will produce can be derived directly:

| TTL | Responder | Role | Reply type |
|---|---|---|---|
| 1 | `192.168.10.193` | Organization router, administration interface | Type 11 |
| 2 | `203.0.113.1` | Provider edge router | Type 11 |
| 3 | `198.51.100.1` | Destination network's edge router | Type 11 |
| 4 | `198.51.100.20` | Destination endpoint | Type 0 or type 3 code 3 |

Three limits must be known when reading traceroute results. Not every step of the
path is required to reply; a step that does not reply appears empty, and this does not
mean it was not traversed. The outbound path is seen, the return path is not; the two
directions can differ. The measured times depend on the intermediate router's priority
for generating error messages and may not reflect the actual delay at that point.

## Path MTU Discovery

The Frame, Packet, Segment lesson defined a way to avoid fragmentation: setting the
don't-fragment flag and shrinking the segment size based on the incoming report. The
report is the ICMP type 3 code 4 message.

The loop works as follows. The sender generates packets sized to its own link's MTU. If
a link along the path has a smaller MTU, that router drops the packet and reports the
MTU value it can accept. The sender lowers the segment size according to that value and
resends. The process continues until packets start getting through.

The method's weak point is its dependence on the ICMP message itself. If the message is
blocked along the path, the sender learns nothing: its packets keep getting dropped, but
it never learns why. This condition is called a **black hole**, and its typical symptom
is this — small requests work, large transfers stall. The echo test succeeds, the
connection is established, the first few bytes go through, and then the stream stops.

It is diagnosed by manually lowering the MTU: if the transfer works once the segment
size is capped, the problem is in path MTU discovery.

## The Cost of Blocking ICMP

ICMP messages are often blocked outright because they reveal information about the
network. This produces several concrete failures:

- **If type 3 code 4 is blocked**, path MTU discovery does not work; a black hole
  forms.
- **If type 3 code 3 is blocked**, a connection attempt to a closed port times out
  instead of being rejected instantly; wait times grow longer.
- **If type 11 is blocked**, traceroute does not work, and routing loops become
  invisible.
- **If types 8 and 0 are blocked**, reachability testing cannot be performed;
  diagnosis proceeds with blind spots.

The measured approach is to select by type rather than block outright: error reports
are let through, and if the response to inbound echo requests needs restricting, it is
limited rather than blocked entirely. Whatever the selection, type 3 code 4 must be let
through; without it, transfers break silently.

## ICMPv6's Expanded Role

In IPv6, ICMP's scope expands markedly. As noted in the ARP lesson, neighbor discovery
is part of ICMPv6; router solicitation and advertisement, duplicate address detection,
and multicast group management also run over this protocol.

This has a direct consequence: **if ICMPv6 is blocked outright, IPv6 does not work.**
Shutting off ICMP in IPv4 makes diagnosis harder; in IPv6 it halts basic functions.
Addresses cannot be configured, neighbors cannot be resolved, routers cannot be found.

## Summary

- ICMP is the control protocol carried as IP's payload; it does not fix errors, only
  reports them, and there is no guarantee of its own delivery.
- Error messages carry the header of the packet that caused the error; the endpoint
  matches the message to its own connection through this copy.
- The echo test shows reachability at the IP level; no response does not mean the
  target is down, and it does not prove a service exists.
- The time-to-live field reveals the path's steps in order through packets sent with
  rising values; the outbound path is seen, the return path is not.
- Path MTU discovery depends on the type 3 code 4 message; if the message is blocked,
  a black hole forms in which small requests work but large transfers stall.
- ICMPv6 also takes on neighbor discovery and router advertisement; blocking it
  outright renders IPv6 unable to work.

## Next Step

Up to this point, every address on the example network was assumed to be assigned by
hand. That assumption cannot hold on a guest network with a hundred devices: entering
address, mask, gateway, and name server information into every device one by one is not
feasible. The next lesson covers the process of leasing addresses, the four steps of
leasing, and how the subnet plan translates into that process.
