The Internet is not One Wire
When you open a website, it feels instant and it feels like one step. In reality, that request hops through a chain of routers — your home router, your ISP's equipment, regional exchange points, possibly several other providers' networks — before reaching the server, and the reply doesn't always retrace the same path back. Every device along that chain is owned by someone different, and none of them owe you any information about themselves. A page loading slowly could be a problem at any single point along that invisible chain.
The Problem
You run a speed test and it's fine. You ping a server and it's fine. But something in between is slow, or dropping packets. You want to know where — not "is the internet broken," but which specific hop is adding the latency.
The tool everyone reaches for is traceroute. Almost everyone's been told to "run a traceroute" by tech support at some point. Almost nobody's asked how it maps a path across networks it has zero control over — using nothing but error messages and a clever abuse of a field that was never meant for this.
Definitions of terms
Packet — data isn't sent as one stream; it's chopped into small chunks called packets, each with a header saying where it's from and where it's going.
Router / hop — a device that receives a packet and forwards it one step closer to its destination. Each router along the way is a "hop"; a typical trip involves 10-20 of them.
IP address — the numeric address that identifies a device on a network, like a postal address for a house.
TTL (Time To Live) — a small counter on every packet that stops it looping forever if routing goes wrong. It counts hops, not time.
ICMP — a companion protocol used specifically for routers to report problems back to a sender (e.g. "this packet couldn't be delivered"). It carries diagnostics, not web pages.
RTT (Round-Trip Time) — how long a packet takes to reach a destination and get a reply back. What "ping" measures — and what traceroute measures at every hop.
UDP / TCP — the two common ways data gets carried. TCP is reliable and connection-based; UDP is faster but not guaranteed. Traceroute uses one or the other (or ICMP directly) just to trigger a reply from each hop.
Firewall — filters traffic by rule, often deliberately blocking the diagnostic messages traceroute depends on — a big part of why it doesn't always give a clean answer.
The trick: TTL was never supposed to do this
Every router that forwards a packet decrements its TTL by 1. If a router decrements it to 0, it drops the packet and sends back an ICMP "Time Exceeded" message — from its own IP address.
That's the whole mechanism:
Send a packet with TTL = 1 — the first router drops it and replies. Now you know hop 1.
Send another with TTL = 2 — it survives hop 1, dies at hop 2, hop 2 replies.
Repeat, incrementing TTL each round, until a packet reaches the destination and gets a normal reply instead.
You're not asking routers "who are you." You're deliberately killing your own packets at increasing distances and reading the return address off the death certificate. Nobody designed TTL for this — traceroute is squatting on ICMP's error-reporting behavior.
What's actually inside those packets
A traceroute implementation needs three things per hop:
The outgoing probe — a UDP packet to an unlikely-open port (classic Unix traceroute), an ICMP Echo Request (Windows tracert, most modern tools), or a TCP SYN (useful against firewalls that only allow port 80/443)
A raw socket, to set the TTL field and read raw ICMP responses — this is why traceroute needs elevated privileges
A timer, started when the probe is sent, stopped when the reply lands — that delta is the per-hop RTT
Most implementations send 3 probes per TTL rather than 1, since a single RTT is noisy (queueing delay, load balancing). The ICMP reply also embeds the original packet's header, which is how a reply gets matched back to the specific probe that triggered it, even with several TTLs in flight at once.
Where the clean textbook version falls apart
ICMP gets blocked, selectively. Routers and firewalls often rate-limit or drop Time Exceeded messages as hardening. The result is silence — a * * * — not an error. That doesn't mean the router doesn't exist, just that it chose not to say so.
MPLS hides hops entirely. Large ISP backbones can carry a packet through several physical routers that never individually reply the way a normal hop would. A single "hop" in your trace might actually be several real devices collapsed into one.
Asymmetric routing breaks the "path" model. Traceroute only shows the forward path. The ICMP reply's return path can be completely different — so a hop's RTT reflects the outbound trip plus however long that provider's return path happens to take, not a clean one-way measurement.
Load balancing means the path isn't singular. Routers often spread traffic across multiple equal-cost links. Your three probes at one TTL can get load-balanced differently, showing the same "hop" as two or three different IPs — not route instability, just multiple real paths being sampled.
Rate limiting produces false "bad hop" readings. A router deprioritizing ICMP under load looks identical, from the outside, to one that's actually overloaded. This is the most common misread of traceroute output — a mid-path timeout doesn't necessarily mean that link is broken.
Building this as a real-time tool
Classic CLI traceroute is a batch process — send everything, wait, print a table. Hop discovery can take several seconds per hop with packet loss involved, so a tool people actually watch needs a different shape:
Hops stream to the client as they resolve, not batch at the end
The frontend renders a partial, growing path, with timeout / still-probing / resolved as distinct states.
Because ICMP needs raw sockets and elevated privileges (and a browser shouldn't do that work anyway), the natural split is a backend that owns the probing and a thin frontend that visualizes whatever comes over a persistent connection.
Why this is worth understanding
Traceroute looks simple because its output looks simple — a numbered list of IPs and times. Underneath, it's a workaround built on an error-handling side effect, read through a network that actively resists being mapped: routers that stay silent on purpose, paths that aren't singular, backbones that hide their internals. Understanding the mechanism is really understanding why the output can't always be trusted at face value.
I built a real-time version of this — Rust/axum backend doing the actual ICMP probing, React frontend streaming hops over WebSocket as they resolve — called traceroute-te. Code's on GitHub: traceroute-te.
Top comments (0)