How does traceroute work?

Lately I’ve been reading Interconnections by Radia Perlman (great lastname!). It’s an old, but still relevant book which describes how low-level networking technologies work, such as ethernet. The book contains many insights and anecdotes. On page 236 I came across this gem:

The traceroute utility is a clever hack designed to force each router along the path, in turn, to return an error report. It works by setting the TTL first to 1 (causing the first router to send an error report back to the source) and then setting it to 2 (causing the next router to send an error report) and so forth until the packet reaches the destination.

I had never considered how traceroute worked before, and by reading that paragraph, I instantly understood. The Time To Live (TTL) field in an IP header was intended to hold the number of seconds for which the IP packet is valid, after which it can be dropped. In practice, it is used as a decrementing hop count, whereby every router that forwards the packet reduces the TTL value by one. IPv6 packets have the “hop limit” header field which is better named and serves the same purpose.

When a router decrements a packet’s hop count value to zero, it sends an ICMP time exceeded error message back to the source IP address in the packet, otherwise it forwards the packet onward.

Modern versions of the traceroute program don’t just send one packet at a time though. To speed things up it sends several packets with varying hop counts at once, so the program doesn’t have to wait for each router to respond before issuing the next packet.

Do protocols matter?

The traceroute program installed on my computer sends UDP datagrams by default, but can also be configured to send TCP or ICMP messages instead. All of these rely on the same principle of setting the hop count to a small number, and awaiting an ICMP time exceeded error message.

However some routers may block certain ports by firewall, hence using TCP on port 80, an ICMP echo request (ping) or UDP on port 53 (DNS) might be more likely to succeed than a UDP datagram on a random unused port.

Traceroute with Perl

The module Net::Traceroute::PurePerl implements the traceroute functionality in Perl. I installed the module from CPAN and ran it on the Perl.com domain using this one liner:

$ sudo $(which perl) -MNet::Traceroute::PurePerl -wE \
  'my $n=Net::Traceroute::PurePerl->new(host=>"perl.com");$n->traceroute();$n->pretty_print'

Because the script opens a raw socket, it needed to be run with root privileges. I use a locally-managed perl, so the subcommand $(which perl) ensured my local perl was run instead of the system one. This is the output I got:

traceroute to perl.com (207.171.7.45), 30 hops max, 40 byte packets
 1 192.168.1.1        1.98 ms    2.02 ms    1.96 ms
 2 * * *
 3 68.173.200.108    14.25 ms   15.03 ms   15.43 ms
 4 68.173.198.32     21.36 ms   16.54 ms   16.77 ms
 5 107.14.19.24      21.44 ms
 5 66.109.6.78       21.68 ms   10.39 ms
 6 66.109.6.27       12.58 ms   15.19 ms   14.55 ms
 7 66.109.5.119      16.93 ms   13.88 ms   20.49 ms
 8 154.54.10.209     14.68 ms   18.87 ms   13.28 ms
 9 154.54.44.217     12.37 ms
 9 154.54.80.177     19.20 ms   18.18 ms
10 154.54.40.106     32.09 ms
10 154.54.40.110     14.15 ms
10 154.54.40.106     14.30 ms
11 154.54.24.222     30.80 ms
11 154.54.7.158      30.87 ms
11 154.54.24.222     33.32 ms
12 154.54.28.70      42.33 ms   44.74 ms
12 154.54.28.130     41.91 ms
13 154.54.29.222     62.53 ms
13 154.54.30.162     60.21 ms   60.57 ms
14 154.54.42.65      72.04 ms   71.75 ms
14 154.54.42.77      70.90 ms
15 154.54.45.162     81.26 ms   81.30 ms   90.29 ms
16 154.54.42.102     80.39 ms
16 154.54.25.150     82.34 ms   83.04 ms
17 38.88.197.82      83.23 ms   91.67 ms   82.39 ms
18 207.171.30.62     83.17 ms   72.52 ms   77.83 ms

The first entry is my wifi router. I’m guessing the second is my modem, which did not respond (hence the asterisks). You can see the succession of IP addresses for each router (technically, interface) that responded to the packets. The 18th entry is the last hop because Perl.com (207.171.7.45) sits on the same network (207.171.0.0/18).

Net::Traceroute::PurePerl currently lacks IPv6 support, and hasn’t been updated in a while. The documentation lists IPv6 as a todo item, so if you’re interested in traceroute programming, this might be a good opportunity to send a patch. If the author doesn’t respond, you can always fork the distribution!

Tags

David Farrell

David is a professional programmer who regularly tweets and blogs about code and the art of programming.

Browse their articles

Feedback

Something wrong with this article? Help us out by opening an issue or pull request on GitHub