Time to Live and Hop Limits
The Internet has no central map and no supervisor. Each
router
makes a purely local decision — "for this destination, my next hop is over there" — and hands the
packet on. That decentralisation is the Internet's genius, but it hides a lurking danger: what if the
routing tables briefly disagree and point at each other? A packet could be flung back and
forth between two routers, or loop endlessly around a ring, consuming bandwidth forever and never
arriving. Multiply that by millions of packets and a routing glitch would melt the network.
The safety valve is a single small counter carried in every IP packet: the Time to Live
(TTL) in IPv4, renamed the Hop Limit in IPv6. Every router that forwards the packet
decrements it by one; when it hits zero, the packet is thrown away and a polite complaint is mailed back
to the sender. It is a self-destruct timer that guarantees no packet can wander the Internet forever —
and, in a lovely twist, the very same mechanism is what lets traceroute draw you a map of
the path your packets take.
The field: one byte, counting down
TTL lives in the IPv4 header as an 8-bit unsigned integer — so it ranges from 0 to 255.
The rule the network layer enforces is deliberately dumb and therefore bullet-proof:
-
Every router decrements TTL by exactly 1 as it forwards the packet (it is the
forwarding router that decrements, not the source).
-
If the result is 0, the packet is discarded — not forwarded — and the router sends
an ICMP Time Exceeded message (Type 11, Code 0) back to the source address.
-
Because the counter can only fall, a packet can survive at most (initial TTL) hops.
Any loop is broken after a bounded number of trips, no matter how confused the routing tables are.
In IPv6 the field is functionally identical but was given the honest name Hop Limit,
because — despite the words "time to live" — it has nothing to do with clocks. The original
1981 spec (RFC 791) imagined routers subtracting the number of seconds a packet had waited, so
that TTL really was a lifespan in time. In practice routers forward in microseconds and nobody bothered
with sub-second bookkeeping, so TTL quietly became a pure hop counter. IPv6 simply
stopped pretending.
Watch the counter fall
Follow a packet launched with TTL = 4 across a path of routers. Each hop shaves one off the counter. If
the destination is more than four hops away, the packet dies in transit and the router that
killed it sends an ICMP Time Exceeded back — the packet never reaches the destination at all.
Notice the off-by-one that trips everyone up: a packet sent with TTL = n
reaches a router n hops away carrying TTL = 1, and it is that router
which decrements to 0 and drops it. So TTL = n lets a packet touch
n routers but travel through the last one only as far as its own doorstep.
How traceroute turns a defence into a map
Here is the trick that makes TTL famous. Suppose you want to discover every router on the path to a
distant host. You cannot ask the network for its map — none exists. But you can make each
router in turn announce itself, by deliberately sending packets that are engineered to die at exactly
the hop you want to probe:
-
Send a probe with TTL = 1. The first router decrements it to 0, drops it,
and returns an ICMP Time Exceeded — whose source address is that router's. You just learned
hop 1.
-
Send a probe with TTL = 2. It sails past the first router (decremented to 1) and dies
at the second, which reveals itself. You learned hop 2.
-
Keep incrementing the TTL. Each value k elicits a reply from the
k-th router, so the replies arrive in order and paint the whole path — until
a probe finally reaches the destination itself (which replies differently, e.g. an ICMP Port
Unreachable for classic UDP traceroute, or an Echo Reply for the ICMP variant).
The round-trip time of each reply also tells you the latency to that hop, which is why
traceroute prints a growing ladder of routers with millisecond timings. The defensive
self-destruct timer has been repurposed into the Internet's favourite diagnostic tool.
// A toy traceroute. We know the true path; the tool does NOT — it discovers
// it hop by hop, using the ICMP Time Exceeded that each dying probe triggers.
const truePath = ["10.0.0.1", "203.0.113.9", "198.51.100.4", "192.0.2.77"]; // hidden from the tool
const DEST = "192.0.2.200";
// Simulate sending one probe: the router at index (ttl-1) is the one that
// decrements to 0 and answers. If ttl reaches the destination, DEST answers.
function sendProbe(ttl: number): { responder: string; reachedDest: boolean } {
if (ttl > truePath.length) return { responder: DEST, reachedDest: true };
return { responder: truePath[ttl - 1], reachedDest: false };
}
console.log(`traceroute to ${DEST}`);
for (let ttl = 1; ttl <= 30; ttl++) {
const { responder, reachedDest } = sendProbe(ttl);
const rtt = (2 + ttl * 3 + Math.round(Math.random() * 4)); // pretend ms
console.log(`${String(ttl).padStart(2)} ${responder.padEnd(15)} ${rtt} ms`);
if (reachedDest) { console.log(" reached destination — done."); break; }
}
Different operating systems start their packets at different TTLs: Linux and macOS use
64, Windows uses 128, and many routers and older Cisco/Solaris stacks use
255. Those are the three common initial values, and they are far enough apart to be a
useful fingerprint.
When a reply arrives at you carrying, say, TTL = 57, you can reason backwards: the nearest "round"
starting value at or above 57 is 64, so the packet almost certainly started at 64 (a Linux/macOS box)
and crossed 64 - 57 = 7 routers to reach you. A reply with TTL = 250 started
at 255 and is only 5 hops away. Network tools and passive-fingerprinting scanners lean on exactly this
arithmetic to estimate both the remote OS and the hop distance — from a single packet, with no
traceroute at all.
Other lives of the little counter
Because "drop me after N hops" is such a clean primitive, TTL gets borrowed for jobs beyond loop
prevention:
-
Scoping multicast. A multicast packet sent with TTL = 1 never leaves the local link;
TTL = 0 means "this host only." Applications use tiny TTLs to keep service-discovery chatter (mDNS,
SSDP) from escaping the LAN.
-
The GTSM security trick. BGP routers that peer directly are always exactly one hop
apart, so the Generalized TTL Security Mechanism (RFC 5082) sends BGP packets with TTL = 255
and rejects any arriving with TTL < 254. A forged packet from a distant attacker will have been
decremented on the way and is instantly discarded — you cannot fake being one hop away.
-
Detecting forwarding loops in the wild. A sudden storm of ICMP Time Exceeded messages
from the same pair of routers is the classic signature of a routing loop caused by a
mis-configuration or a slow-to-converge protocol.
The abbreviation is wildly overloaded, and conflating the meanings causes real bugs. The
IP TTL on this page is a hop count in a packet header — a small integer,
usually 64/128/255, decremented per router. But you will also meet a DNS record TTL,
which is a duration in seconds telling resolvers how long to cache an answer
(e.g. 300 s), and a cache/CDN TTL, a freshness lifetime for stored objects. Those two
really are times; the IP one is not.
The trap: someone reads "IP TTL = 64" and imagines 64 seconds, or sets a DNS TTL of 64 thinking it
controls routing. They are unrelated fields that happen to share a three-letter name. When you see TTL,
first ask which layer — a packet header (hops), a DNS answer (cache seconds), or an HTTP/CDN
object (freshness seconds).