ICMP, Ping, TTL and Path MTU Discovery
- ICMP (RFC 792) is IP's error and diagnostic channel. It rides directly in IP packets (protocol number 1), and its header is 1 byte type, 1 byte code, 2 bytes checksum, then message-specific data.
- Ping sends an Echo Request (type 8) and waits for an Echo Reply (type 0). The round trip time is measured at the sender. A default ping is 84 bytes on the wire: 20 IP + 8 ICMP + 56 payload.
- TTL is a hop count, not a time. Every router decrements it; at 0 the router drops the packet and sends Time Exceeded (type 11, code 0). IPv6 calls it Hop Limit.
- Path MTU Discovery depends on ICMP: a router that cannot forward a packet with DF set drops it and returns type 3 code 4 (IPv4) or Packet Too Big, type 2 (IPv6). Block that message and large transfers hang while small ones work.
- Blocking all ICMP is not "safe". Filter selectively: blanket blocking breaks PMTUD, and on IPv6 it breaks neighbour discovery too.
Mental model
The postal service sends you two kinds of slips. One is "return to sender, address unknown", a note from a sorting office that could not deliver your letter and says why. The other is a delivery confirmation you request on purpose: you send a letter to a friend asking "please reply the moment you get this", then time the round trip.
Where it breaks: the slips themselves travel by post. A sorting office may be too busy to write one, or may have a policy of never writing them, so no slip does not mean the letter arrived.
ICMP is the error and diagnostic channel of IP, a bit like stderr and exit codes for the network: the data path stays silent on success and reports failures out of band. Ping is a health-check RPC at layer 3 with no port, no connection and no application behind it.
Where it breaks: stderr is reliable and unconditional. ICMP is best effort, itself subject to loss, rate limiting and filtering, and routers answer it on a slow path, so absence of a message is weak evidence.
How it works
ICMP is inside IP
ICMP messages are carried in IP packets with the protocol field set to 1 (IP packet, RFC 792). There is no TCP or UDP header and no port. Every message starts the same way:
For an error message the sender gets the offending packet's IP header plus the first 8 bytes of its payload (RFC 792). Eight bytes is enough to cover the source and destination ports of TCP and UDP, so the host can find the socket that sent the packet. Modern routers often quote more (RFC 1812 asks for as much as fits in 576 bytes), and RFC 4884 adds a length field and extension objects. Two rules stop error storms (RFC 1122, section 3.2.2): never send an ICMP error about an ICMP error, and never send one for a broadcast or a non-first fragment.
Ping: echo request and reply
ping builds an Echo Request, type 8, code 0, with an identifier (to tell concurrent pings apart), a sequence number that increments, and a payload. The target copies all three into an Echo Reply, type 0, and sends it back. Ping notes the time when it sent each request and subtracts it from the arrival time of the matching reply. That difference is the RTT. Operational use, flags and mtr are on ping and mtr; this page owns the mechanism.
Worked example: reading real ping output
This is ping -c 4 8.8.8.8 on macOS (the per-reply lines are elided). The statistics line is the one to read:
- 56 data bytes is the default payload. Add 8 bytes of ICMP header and each reply is 64 bytes, which is what ping prints. Add the 20-byte IPv4 header and the packet is 84 bytes on the wire (before the link-layer header).
- ttl=116 is the TTL left in the reply when it arrived, not the TTL of your request. The remote host picked a starting value and every router on the return path subtracted 1. A start of 128 would mean 12 hops back. One number cannot prove that: the start value is a guess (see initial TTL by OS).
- Loss 0.0% means every request got a reply. min/avg/max is the spread of RTTs, and stddev (called mdev on Linux) is the jitter: 3.4 ms on a 32 ms average is a steady path.
TTL is a hop limit
Every IPv4 packet carries a Time To Live field (IP packet). The name is a historical leftover: it was meant to be seconds, but in practice every router subtracts exactly 1, so it is a hop count limit. A router that would take it to 0 drops the packet and sends Time Exceeded (type 11, code 0) to the source, quoting the dropped packet. TTL exists for loop protection: a packet in a routing loop dies instead of circulating forever. IPv6 renamed the field Hop Limit (IPv6) and its Time Exceeded is type 3. Traceroute turns this behaviour into a path-mapping tool; see traceroute for the traceroute half.
Path MTU Discovery
Links differ in MTU (MTU, MSS and fragmentation owns the depth). Hosts avoid fragmentation by setting DF (Don't Fragment) on every packet. A router that cannot forward a DF packet because the next link is too small drops it and returns ICMP type 3, code 4, Fragmentation Needed and DF Set. RFC 1191 puts the next-hop MTU in the low 16 bits of the otherwise unused word. The sender lowers its path MTU for that destination and resends in smaller packets.
IPv6 works the same way with one difference: routers never fragment IPv6 packets, so Packet Too Big (type 2, RFC 4443, RFC 8201) is mandatory, not an optimisation. It carries a 32-bit MTU field and is sent whenever a packet does not fit.
Deep dive
Types and codes that matter
The type names the message and the code refines it. Names below follow the IANA ICMP registry.
| Type | Name (IANA) | Codes and notes |
|---|---|---|
| 0 | Echo Reply | Code 0. The ping answer. |
| 3 | Destination Unreachable | Codes 0 to 15. See the next table. |
| 5 | Redirect | 0 network, 1 host, 2 TOS and network, 3 TOS and host. A router tells a host a better first hop exists; hosts often ignore them today. |
| 8 | Echo | Code 0. IANA names it Echo; everyone says Echo Request. |
| 11 | Time Exceeded | 0 TTL exceeded in transit, 1 fragment reassembly time exceeded. Code 0 powers traceroute. |
| 12 | Parameter Problem | 0 pointer indicates the error, 1 missing a required option, 2 bad length. |
Type 3 is the one with the long code list. The codes you meet in practice:
| Code | IANA name | Typical cause |
|---|---|---|
| 0 | Net Unreachable | A router has no route to the destination network. |
| 1 | Host Unreachable | The last-hop router got no ARP answer for the host. |
| 2 | Protocol Unreachable | The host does not implement the IP protocol number. |
| 3 | Port Unreachable | No socket on that UDP port. This is how traceroute knows it arrived. |
| 4 | Fragmentation Needed and DF Set | Path MTU Discovery. Carries the next-hop MTU. |
| 9, 10 | Communication with Destination Network / Host is Administratively Prohibited | A filter said no (RFC 1122). Codes 6 and 7, destination network and host unknown, are also in the registry. |
| 13 | Communication Administratively Prohibited | A router ACL or firewall rejected the packet (RFC 1812). Prefer it to a silent drop when you want fast failure. |
The registry defines codes 0 to 15 for type 3. Type 4, Source Quench, once asked a sender to slow down and is deprecated (RFC 6633); congestion control lives in TCP now.
ICMPv6 (RFC 4443) has its own numbering, with errors below 128 and informational messages from 128:
| Type | Name | Role |
|---|---|---|
| 1 | Destination Unreachable | No route, administratively prohibited, address unreachable, port unreachable. |
| 2 | Packet Too Big | The IPv6 equivalent of type 3 code 4. Carries the MTU. Mandatory. |
| 3 | Time Exceeded | Code 0 hop limit exceeded in transit, code 1 reassembly time exceeded. |
| 4 | Parameter Problem | A header field or option was bad. |
| 128 and 129 | Echo Request and Echo Reply | Ping for IPv6. |
| 133 to 137 | Router Solicitation, Router Advertisement, Neighbor Solicitation, Neighbor Advertisement, Redirect | Neighbour discovery (RFC 4861). It replaces ARP, so IPv6 on a LAN does not work without it (IPv6, ARP). |
The PMTUD black hole
PMTUD fails silently when the ICMP message never reaches the sender. The usual cause is a firewall that drops all ICMP, so the Fragmentation Needed or Packet Too Big message is lost on the way back. The symptoms are a signature:
- The TCP handshake works, because SYN and SYN-ACK are small.
- Small requests and responses work. Anything that fills a full-size segment, such as a large HTTP response or a TLS certificate chain, hangs.
- The sender keeps retransmitting a packet that is too big and never learns why.
Fixes, from best to worst:
- Allow the right ICMP: type 3 code 4 for IPv4 and type 2 for IPv6, in every direction a router might send it from. RFC 4890 lists which ICMPv6 types a firewall must pass.
- Clamp the MSS at the edge so TCP never builds packets that are too large. MSS clamping rewrites the MSS option in SYNs; the mechanism is in MTU, MSS and fragmentation.
- Use Packetization Layer PMTUD, which does not need ICMP: the sender probes with growing packet sizes and treats loss as the signal (RFC 4821, and the datagram version RFC 8899, which QUIC builds on). Linux enables it with
net.ipv4.tcp_mtu_probing.
Initial TTL by OS
The TTL a reply arrives with is the starting value minus the hops it crossed, so if you guess the starting value you can estimate the hops. Common starting values are 64 on Linux and macOS, 128 on Windows and 255 on many routers. On macOS sysctl net.inet.ip.ttl printed 64. The estimate is a heuristic: the value is configurable, and a reply of 116 from a far host could be 128 minus 12 or something else entirely. Do not treat it as OS fingerprinting evidence.
ICMP rate limiting
Routers and hosts limit how many ICMP messages they originate. On Linux net.ipv4.icmp_ratelimit is the minimum gap between messages of the limited types in milliseconds (default 1000, kernel docs), and icmp_msgs_per_sec caps the host total. Routers apply control-plane policing for the same reason. Two consequences matter for reading output:
- A router forwards traffic on its fast path but builds ICMP replies on a slow path, so a high RTT or loss at a middle hop in ping or mtr often says nothing about the traffic that passes through it. Loss only counts if it persists to the final hop (ping and mtr).
- A PMTUD message can itself be rate limited, which makes a flaky black hole.
ICMP as an attack surface
ICMP has been abused as an amplifier and a payload. Smurf sent a ping to a broadcast address with the victim's spoofed source, so every host replied to the victim. Networks fixed it by not forwarding directed broadcasts by default (RFC 2644). The ping of death exploited reassembly bugs with oversized fragmented echo requests, and hosts were patched. Today the live concerns are ICMP floods (DDoS), ICMP redirects used to divert traffic, and tunnelling data in echo payloads. The defence is selective filtering and rate limits, not blanket drops (firewalls and segmentation).
Textbook vs real world
| The textbook says | Production does | Why |
|---|---|---|
| Block ICMP for security | Allow type 3 code 4, ICMPv6 type 2 and neighbour discovery; rate-limit the rest | Blocking everything breaks Path MTU Discovery and IPv6 on the LAN |
| Ping failed, so the host is down | A failed ping means no reply came back | ICMP may be filtered, rate limited or deprioritised while the service works fine |
| Ping measures network latency | It measures network plus the target's ICMP handling | Echo is answered by the kernel or a slow control plane, which adds delay a TCP connection to the same host would not see |
| TTL is a time in seconds | TTL is a hop count | Routers subtract 1 per hop regardless of how long they held the packet |
In production
- Cloudflare documented a real PMTUD failure: a networking change broke path MTU discovery on its servers and users on IPv6-over-IPv4 tunnels could not reach its services (Path MTU discovery in practice, 2015).
- AWS security groups only allow inbound traffic you permit, so ICMP is not allowed by default. The EC2 documentation says an instance can receive Path MTU Discovery responses (Destination Unreachable, Fragmentation Needed and Don't Fragment was Set, type 3 code 4, for IPv4) when the connection is tracked or the security group allows inbound ICMP, and that a network ACL can still block them (EC2 network MTU).
- Health checks choose between ICMP and TCP. An ICMP check says the host's network stack is up; a TCP or HTTP check says the service is. Use the one that matches what you are promising.
History and evolution
- 1981 RFC 792 defines ICMP, authored by Jon Postel, alongside the IP specification, because IP itself had no way to report delivery problems.
- 1983 Mike Muuss writes
pingat the Ballistic Research Laboratory and names it after sonar, by his own account (The Story of the PING Program). - 1990 Fragmentation made large transfers slow and fragile, so RFC 1191 defines Path MTU Discovery using type 3 code 4.
- 1990s Ping of death and smurf attacks lead operators to filter ICMP wholesale, which in turn creates PMTUD black holes. RFC 4821 (2007) answers with probing that needs no ICMP.
- 1998 to 2006 ICMPv6 is specified (RFC 2463, replaced by RFC 4443) and absorbs neighbour discovery.
- Now ICMP is rate limited everywhere and ICMPv6 is essential. QUIC does its own datagram PMTU probing (RFC 8899).
- Next More reliance on TCP and QUIC based probes and packetization-layer discovery, with ICMP kept as a hint.
Hands-on
macOS:
-D sets DF. On a 1500-byte link, -s 1472 plus 8 ICMP plus 20 IP is exactly 1500 and succeeds. One byte more fails at once with this real macOS output, because the local interface refuses:
Linux uses a different flag for the same test, and Windows differs again:
When a router further along the path has a smaller MTU, Linux ping (iputils) reports the type 3 code 4 message with the MTU it carried. The shape of the output is below, with an illustrative router address:
Binary-search the largest -s that passes to find the path MTU. To watch ICMP on the wire:
Look for the ICMP echo request and echo reply pairs, and for unreachable - need to frag (mtu 1400) lines. On Linux, ip route get <dst> shows the cached path MTU after a discovery.
Gotchas
Interview questions
Show answer
Suspect a PMTUD black hole. The handshake and small responses fit in small packets; a full-size segment hits a link with a smaller MTU and the ICMP Fragmentation Needed message is filtered. Confirm with ping -M do -s 1472 and smaller sizes, and with a capture showing retransmitted full-size segments. Fix by allowing type 3 code 4 and ICMPv6 type 2, or clamp the MSS.
Follow-ups:
- Why do small requests work? They fit under every link's MTU, so no router ever needs to send the error.
- Why not just lower the MTU? You would have to do it on every host; clamping the MSS at the edge is the usual workaround.
Show answer
Ping sends an ICMP Echo Request, type 8, with an identifier and sequence number. The target answers with an Echo Reply, type 0, copying them back. Ping measures the RTT as arrival time minus send time, and counts a request with no reply as lost.
Follow-ups:
- Is there a port? No. ICMP has no ports and sits directly on IP, protocol 1.
- What is in a default packet? 20 bytes IP, 8 bytes ICMP and 56 bytes payload, 84 in total.
Show answer
TTL is a hop limit in the IP header. Each router subtracts 1 and drops the packet when it would reach 0, sending ICMP Time Exceeded (type 11, code 0) to the source. It exists to stop packets circulating in routing loops.
Follow-ups:
- Is it seconds? No, it is hops, whatever the name says.
- What is it in IPv6? Hop Limit, with Time Exceeded as ICMPv6 type 3.
Show answer
The sender sets DF. A router that cannot forward the packet drops it and returns ICMP type 3 code 4 with the next-hop MTU, and the sender retries with smaller packets. In IPv6 routers never fragment, so Packet Too Big, type 2, does the same job.
Follow-ups:
- What breaks it? Any filter that drops those ICMP messages, producing a black hole.
- Is there a way without ICMP? Packetization Layer PMTUD, RFC 4821 and RFC 8899.
Show answer
ICMP is separate from TCP. A firewall or cloud security group may drop Echo Requests while allowing port 443. A failed ping means no reply came back, not that the host is down.
Follow-ups:
- How would you test reachability then? Connect to the real port.
- Could the host be rate limiting? Yes, so a few lost pings are weak evidence.
Show answer
IPv6 depends on it. Neighbour discovery (types 133 to 137) replaces ARP, and Packet Too Big is the only way a sender learns the path MTU because routers do not fragment. RFC 4890 lists the types a firewall must allow.
Follow-ups:
- What can be dropped? Echo can be filtered at the edge, and unneeded types rate limited.
Show answer
Probably not. A router answers ICMP on a rate-limited slow path, so loss there is its own policing. If traffic reaches the destination without loss, forwarding is fine. Loss that continues from that hop to the end is real.
Follow-ups:
- What would confirm it? The final hop's loss in
mtrover many samples.
Fun facts
- IANA still lists type 8 as Echo, not Echo Request; the registry has codes 0 to 15 for Destination Unreachable.
- Ping is named after sonar, per its author's own story, and a default ping is 84 bytes at the IP level.
- ICMP has no port numbers. Ping uses an identifier field in place of a port to tell concurrent pings apart.
- The next-hop MTU in a type 3 code 4 message did not exist in the original RFC 792, which is why very old routers send 0 and why RFC 1191 gives hosts a table of plateau sizes to guess from.
Cheat sheet
- Protocol 1 - ICMP in IPv4. IPv6 uses next header 58.
- 8 and 0 - Echo Request and Echo Reply (ICMPv6: 128 and 129).
- 11, code 0 - TTL exceeded in transit (ICMPv6: type 3).
- 3, code 4 - Fragmentation Needed and DF Set (ICMPv6: type 2, Packet Too Big).
- 84 bytes - default ping on the wire: 20 IP + 8 ICMP + 56 data.
- 1472 - the largest ping payload that fits a 1500-byte MTU (1472 + 28).
- 1280 bytes - the minimum IPv6 MTU (RFC 8200).
- 64, 128, 255 - common initial TTLs: Linux and macOS, Windows, many routers.