Traceroute : How it works

Traceroute is a computer network diagnostic tool for displaying the route (path) and measuring transit delays of packets across an Internet Protocol (IP) network. It utilizes the IP protocol’s time to live (TTL) field and attempts to elicit an ICMP TIME_EXCEEDED response from each gateway along the path to the host.

This tool verifies the path by which our packet should reach the destination, without actually sending the data. This post is not anything about how this tool works it’s rather about the concept this tools uses for fulfilling our purpose.

We can always refer the Linux man and info pages for gaining the knowledge about how to use this tool.

You should kow the basics first

Each IP packet that we send on the internet has a field called as TTL. TTL stands for Time To Live. we can measure TTL by the  no of hops. Its the maximum number of hops that a packet can travel through across the internet, before its discarded. Hops are the computers, routers, or any devices that comes in between the source and the destination. If there is no TTL in an IP packet, the packet will flow endlessly from one router to another and on and on forever searching for the destination. Operating System automatically handles TTL value, although we can change it with the help of few tools.

Now If the destination is not found after traveling through too many hops, the receiving router will drop the packet and informs the original sender. Let’s say I need to reach 8.8.8.8 Ip address, and my default TTL value is 30 hops. Which means i can travel a maximum of 30 hops to reach my destination, before which the packet is dropping. Each router that comes in between the source and destination will go on reducing the TTL value before sending to the next router.

Which means if i have a default TTL value of 30, then my first router will reduce it to 29 and then send that to the next router across the path. Again the receiving router will make it 28 and send to the next and so on. If a router receives a packet with TTl of 1, the packet will be discarded. But the router which discards the packet will inform the original sender that the TTL value has exceeded. Once the receiver gets the message he will come to know about the sender.

How Traceroute comes to know about the address of every hop in between

From the above explanation it is clear that not every hop will send it’s address back, but what if we send a packet purposely with TTL value of 1 and keep this value increasing every time. What I understood is same as below picture.

Path of your Packet

Now let’s hit the track with our first trace-route to public DNS(8.8.8.8).

[email protected]:~# traceroute 8.8.8.8 (8.8.8.8), 64 hops max, 52 byte packets 
1  192.168.43.1 (192.168.43.1)  2.357 ms  6.989 ms  2.296 ms 
2  * * * 
3  10.206.168.69 (10.206.168.69)  129.117 ms  145.590 ms  155.697 ms 
4  125.17.150.37 (125.17.150.37)  147.365 ms  144.195 ms  128.473 ms 
5  182.79.243.26 (182.79.243.26)  38.917 ms 182.79.201.81 (182.79.201.81)  127.271 ms 182.79.189.233 (182.79.189.233)  35.057 ms 
6  72.14.242.178 (72.14.242.178)  127.955 ms  38.018 ms  45.597 ms 
7  72.14.238.205 (72.14.238.205)  40.407 ms  38.012 ms 74.125.37.207 (74.125.37.207)  40.345 ms 
8  66.249.94.191 (66.249.94.191)  38.951 ms 72.14.239.11 (72.14.239.11)  36.261 ms 209.85.240.149 (209.85.240.149)  35.446 ms 
9  google-public-dns-a.google.com (8.8.8.8)  39.661 ms  37.398 ms  34.450 ms

Just to note the fact that when we run traceroute command on any Linux System, it sends UDP packet by default. Although we can change the packet type to ICMP packet by sending the following command.

If you want your traceroute not to send the DNS queries to every hosts it finds in between, you can use -n as well.

So, what basically we are sending in a UDP packet when we create a traceroute request.

  • My source address
  • Destination address
  • Any random invalid UDP port (something between 33434 to 33534)

Let’s go back to the question that how Traceroute works, for that we need to see the packets flowing between the source and the destination once the traceroute is in progress. We need to use tcpdump while being in traceroute.  So run the traceroute in one terminal and run the following command in another terminal. the output of tcpdump will be huge and I have only selected those packets which will make some sense here. These are only “sent” packets, we will discuss about the “received” ones later.

Sent packets

[email protected]:~# tcpdump -n '(icmp or udp)' -vvv
06:50:32.806228 IP (tos 0x0, ttl 1, id 36023, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.47433 > 8.8.8.8.33434: [bad udp cksum 0x1c58 -> 0xb296!] UDP, length 32
06:50:32.806419 IP (tos 0x0, ttl 1, id 36024, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.40290 > 8.8.8.8.33435: [bad udp cksum 0x1c58 -> 0xce7c!] UDP, length 32
06:50:32.806560 IP (tos 0x0, ttl 1, id 36025, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.35624 > 8.8.8.8.33436: [bad udp cksum 0x1c58 -> 0xe0b5!] UDP, length 32
06:50:32.806738 IP (tos 0x0, ttl 2, id 36026, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60415 > 8.8.8.8.33437: [bad udp cksum 0x1c58 -> 0x7fdd!] UDP, length 32
06:50:32.806840 IP (tos 0x0, ttl 2, id 36027, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.35889 > 8.8.8.8.33438: [bad udp cksum 0x1c58 -> 0xdfaa!] UDP, length 32
06:50:32.806934 IP (tos 0x0, ttl 2, id 36028, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.36412 > 8.8.8.8.33439: [bad udp cksum 0x1c58 -> 0xdd9e!] UDP, length 32
06:50:32.807037 IP (tos 0x0, ttl 3, id 36029, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60729 > 8.8.8.8.33440: [bad udp cksum 0x1c58 -> 0x7ea0!] UDP, length 32
06:50:32.807135 IP (tos 0x0, ttl 3, id 36030, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.46338 > 8.8.8.8.33441: [bad udp cksum 0x1c58 -> 0xb6d6!] UDP, length 32
06:50:32.807238 IP (tos 0x0, ttl 3, id 36031, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.47240 > 8.8.8.8.33442: [bad udp cksum 0x1c58 -> 0xb34f!] UDP, length 32
06:50:32.807353 IP (tos 0x0, ttl 4, id 36032, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.43531 > 8.8.8.8.33443: [bad udp cksum 0x1c58 -> 0xc1cb!] UDP, length 32
06:50:32.807465 IP (tos 0x0, ttl 4, id 36033, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.55511 > 8.8.8.8.33444: [bad udp cksum 0x1c58 -> 0x92fe!] UDP, length 32
06:50:32.808134 IP (tos 0x0, ttl 4, id 36034, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.35693 > 8.8.8.8.33445: [bad udp cksum 0x1c58 -> 0xe067!] UDP, length 32
06:50:32.808241 IP (tos 0x0, ttl 5, id 36035, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60477 > 8.8.8.8.33446: [bad udp cksum 0x1c58 -> 0x7f96!] UDP, length 32
06:50:32.808363 IP (tos 0x0, ttl 5, id 36036, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.33245 > 8.8.8.8.33447: [bad udp cksum 0x1c58 -> 0xe9f5!] UDP, length 32
06:50:32.808459 IP (tos 0x0, ttl 5, id 36037, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.38748 > 8.8.8.8.33448: [bad udp cksum 0x1c58 -> 0xd475!] UDP, length 32
06:50:32.808592 IP (tos 0x0, ttl 6, id 36038, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.51565 > 8.8.8.8.33449: [bad udp cksum 0x1c58 -> 0xa263!] UDP, length 32
06:50:32.810348 IP (tos 0x0, ttl 6, id 36039, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60722 > 8.8.8.8.33450: [bad udp cksum 0x1c58 -> 0x7e9d!] UDP, length 32
06:50:32.810502 IP (tos 0x0, ttl 6, id 36040, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.50103 > 8.8.8.8.33451: [bad udp cksum 0x1c58 -> 0xa817!] UDP, length 32
06:50:32.810625 IP (tos 0x0, ttl 7, id 36041, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.59487 > 8.8.8.8.33452: [bad udp cksum 0x1c58 -> 0x836e!] UDP, length 32
06:50:32.810796 IP (tos 0x0, ttl 7, id 36042, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.42533 > 8.8.8.8.33453: [bad udp cksum 0x1c58 -> 0xc5a7!] UDP, length 32
06:50:32.810912 IP (tos 0x0, ttl 7, id 36043, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.54200 > 8.8.8.8.33454: [bad udp cksum 0x1c58 -> 0x9813!] UDP, length 32
06:50:32.811067 IP (tos 0x0, ttl 8, id 36044, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.56924 > 8.8.8.8.33455: [bad udp cksum 0x1c58 -> 0x8d6e!] UDP, length 32
06:50:32.845409 IP (tos 0x0, ttl 8, id 36045, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.51400 > 8.8.8.8.33456: [bad udp cksum 0x1c58 -> 0xa301!] UDP, length 32
06:50:32.848205 IP (tos 0x0, ttl 8, id 36046, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.56695 > 8.8.8.8.33457: [bad udp cksum 0x1c58 -> 0x8e51!] UDP, length 32
06:50:32.849031 IP (tos 0x0, ttl 9, id 36047, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.54709 > 8.8.8.8.33458: [bad udp cksum 0x1c58 -> 0x9612!] UDP, length 32
06:50:32.855201 IP (tos 0x0, ttl 9, id 36048, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.42612 > 8.8.8.8.33459: [bad udp cksum 0x1c58 -> 0xc552!] UDP, length 32
06:50:32.866843 IP (tos 0x0, ttl 9, id 36050, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.34496 > 8.8.8.8.33460: [bad udp cksum 0x1c58 -> 0xe505!] UDP, length 32
06:50:32.867272 IP (tos 0x0, ttl 10, id 36051, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.57698 > 8.8.8.8.33461: [bad udp cksum 0x1c58 -> 0x8a62!] UDP, length 32
06:50:32.869469 IP (tos 0x0, ttl 10, id 36052, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.42083 > 8.8.8.8.33462: [bad udp cksum 0x1c58 -> 0xc760!] UDP, length 32
06:50:32.875879 IP (tos 0x0, ttl 10, id 36053, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.41109 > 8.8.8.8.33463: [bad udp cksum 0x1c58 -> 0xcb2d!] UDP, length 32
06:50:32.886702 IP (tos 0x0, ttl 11, id 36054, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60209 > 8.8.8.8.33464: [bad udp cksum 0x1c58 -> 0x8090!] UDP, length 32
06:50:32.892325 IP (tos 0x0, ttl 11, id 36056, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.42739 > 8.8.8.8.33465: [bad udp cksum 0x1c58 -> 0xc4cd!] UDP, length 32
06:50:32.892444 IP (tos 0x0, ttl 11, id 36057, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.46551 > 8.8.8.8.33466: [bad udp cksum 0x1c58 -> 0xb5e8!] UDP, length 32
06:50:32.892562 IP (tos 0x0, ttl 12, id 36058, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.44633 > 8.8.8.8.33467: [bad udp cksum 0x1c58 -> 0xbd65!] UDP, length 32
06:50:32.896807 IP (tos 0x0, ttl 12, id 36059, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.33849 > 8.8.8.8.33468: [bad udp cksum 0x1c58 -> 0xe784!] UDP, length 32
06:50:32.897147 IP (tos 0x0, ttl 12, id 36060, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.58760 > 8.8.8.8.33469: [bad udp cksum 0x1c58 -> 0x8634!] UDP, length 32
06:50:32.897773 IP (tos 0x0, ttl 13, id 36061, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.35287 > 8.8.8.8.33470: [bad udp cksum 0x1c58 -> 0xe1e4!] UDP, length 32
06:50:32.901009 IP (tos 0x0, ttl 13, id 36062, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.43776 > 8.8.8.8.33471: [bad udp cksum 0x1c58 -> 0xc0ba!] UDP, length 32
06:50:32.901482 IP (tos 0x0, ttl 13, id 36063, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.34979 > 8.8.8.8.33472: [bad udp cksum 0x1c58 -> 0xe316!] UDP, length 32
06:50:32.908783 IP (tos 0x0, ttl 14, id 36065, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.40664 > 8.8.8.8.33473: [bad udp cksum 0x1c58 -> 0xcce0!] UDP, length 32

Details of above dump

Let’s analyze the above dump which will describe the process of traceroute.

  • My machine will make a packet with destination ip address of 8.8.8.8 and a destination port number between 33434 to 33534 and the main thing we should note that the TTL value is 1. But as you can see there are basically three UDP packets sent with TTL value of 1. The reason is traceroute sends 3 packets to calculate the round trip time. If you observe closely, all the packets are sent to different port numbers. It is done so that it can be identified later that which packet is in response of which packet so that the RTT can be calculated accurately.

    Round-trip time (RTT), also called round-trip delay, is the time for a signal pulse or packet to travel from a specific source to a specific destination and back again.

  • No my packet will reach to the next hop and it will reduce the TTL value by 1. It means the value is now zero(1-1). So the hop will send back the packet along with TTL time exceeded message. It will also contain the 28 byte header.
  • As the TTL time exceeded message is received by my source it will come to know about the address of the first hop. (cool isn’t it.. )
  • Now the same process will be repeated but with the TTL value of 2, so that it reaches the second hop before TTL becomes zero again.
  • Once the TTL is zero, it will send the TTL time exceeded message back to my source address along with 28 byte header. Thus now we know the address of the second hop as well.
  • The sequence goes on by increasing the the TTL value by 1 every time.
  • Finally once the packet reaches to 8.8.8.8(i.e. the destination address), the destination will send a message saying ICMP Destination/PORT Unreachable, because we were sending the message to the invalid port  if you remember.
  • My source address knows that the packet has reached to the destination so traceroute will stop sending any further packets.

Analyze it further

Now, let’s analyze the packet which we received during the traceroute. Again this is not the complete one.

[email protected]:~# tcpdump -n '(icmp)' -vvv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:30:22.044706 IP (tos 0xc0, ttl 255, id 343, offset 0, flags [none], proto ICMP (1), length 56)
    10.0.2.2 > 10.0.2.15: ICMP time exceeded in-transit, length 36
    IP (tos 0x0, ttl 1, id 8401, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.33931 > 8.8.8.8.33434: UDP, length 32
14:30:22.044718 IP (tos 0xc0, ttl 255, id 344, offset 0, flags [none], proto ICMP (1), length 56)
    10.0.2.2 > 10.0.2.15: ICMP time exceeded in-transit, length 36
    IP (tos 0x0, ttl 1, id 8402, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.60023 > 8.8.8.8.33435: UDP, length 32
14:30:22.044719 IP (tos 0xc0, ttl 255, id 345, offset 0, flags [none], proto ICMP (1), length 56)
    10.0.2.2 > 10.0.2.15: ICMP time exceeded in-transit, length 36
    IP (tos 0x0, ttl 1, id 8403, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.46862 > 8.8.8.8.33436: UDP, length 32
14:30:22.048157 IP (tos 0xc0, ttl 1, id 346, offset 0, flags [none], proto ICMP (1), length 88)
    192.168.43.1 > 10.0.2.15: ICMP time exceeded in-transit, length 68
    IP (tos 0x0, ttl 1, id 8404, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.54591 > 8.8.8.8.33437: [udp sum ok] UDP, length 32
14:30:22.049428 IP (tos 0xc0, ttl 1, id 347, offset 0, flags [none], proto ICMP (1), length 88)
    192.168.43.1 > 10.0.2.15: ICMP time exceeded in-transit, length 68
    IP (tos 0x0, ttl 1, id 8405, offset 0, flags [none], proto UDP (17), length 60)

Above dump describes all the theory what we discussed above. Also observe the difference in reply once the packet reaches to the destination in below dump.

14:30:22.160132 IP (tos 0xc0, ttl 9, id 370, offset 0, flags [none], proto ICMP (1), length 88)
    8.8.8.8 > 10.0.2.15: ICMP 8.8.8.8 udp port 33463 unreachable, length 68
    IP (tos 0x0, ttl 9, id 8440, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.42962 > 8.8.8.8.33463: [udp sum ok] UDP, length 32
14:30:22.160302 IP (tos 0xc0, ttl 9, id 371, offset 0, flags [none], proto ICMP (1), length 88)
    8.8.8.8 > 10.0.2.15: ICMP 8.8.8.8 udp port 33462 unreachable, length 68
    IP (tos 0x0, ttl 9, id 8439, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.51003 > 8.8.8.8.33462: [udp sum ok] UDP, length 32
14:30:22.165691 IP (tos 0xc0, ttl 9, id 372, offset 0, flags [none], proto ICMP (1), length 88)
    8.8.8.8 > 10.0.2.15: ICMP 8.8.8.8 udp port 33461 unreachable, length 68
    IP (tos 0x0, ttl 9, id 8435, offset 0, flags [none], proto UDP (17), length 60)
    10.0.2.15.39324 > 8.8.8.8.33461: [udp sum ok] UDP, length 32

This was the mechanism behind the traceroute.

Traceroute Vs Tracert

The major difference between these two is the platform on which they work. While traceroute works on Unix based operating systems and Tracert works on windows OS. One more noted difference is in packet they send for traceroute. As we seen Unix sends an UDP packet unless we specify the packet type by using a separate flag, but Windows always send the ICMP packet for the same purpose. One sample command on windows interface looks like this.

C:\Users\iosec.in>tracert -d 8.8.8.8

Tracing route to 8.8.8.8 over a maximum of 30 hops

  1    <1 ms    <1 ms    <1 ms  10.80.22.3
  2    <1 ms    <1 ms    <1 ms  10.80.15.1
  3     1 ms     2 ms     2 ms  10.80.14.1
  4     2 ms     2 ms     2 ms  125.17.163.65
  5     2 ms     1 ms     2 ms  192.168.1.1
  6     *        *        *     Request timed out.
  7     *        *        *     Request timed out.
  8    17 ms    12 ms    12 ms  172.25.86.25
  9    12 ms    11 ms    11 ms  172.29.210.46
 10    10 ms    10 ms    10 ms  172.31.244.45
 11    10 ms    10 ms    10 ms  172.31.167.50
 12    10 ms    10 ms    10 ms  121.240.1.46
 13    11 ms     9 ms    11 ms  72.14.236.57
 14    11 ms    10 ms    10 ms  209.85.143.105
 15    10 ms    10 ms    10 ms  8.8.8.8

Trace complete.

You can analyze the traffic and the packets in windows as well although you need to install few softwares first.

  • WinPcap- Windows Packet Capture (WinPcap) is the Windows version of the libpcap library; it includes a driver to support capturing packets.
  • WinDump- Windump is nothing but the tcpdump for windows.
  • Wireshark- Wireshark is basically a network capture tool, we can use it for both capturing and analyzing purposes with many extra features as well(We can discuss it some other time).

We will go through the process quickly for windows as well.

Once you have downloaded all the software, open the command prompt with Administrator.

Go to the directory where you have windump downloaded and run the following command. It will list all the Network Adapters configured with numbers.

C:\Downloads>WinDump.exe -D

The output will look like something below(Masked for my safety. ;)).

1.\Device\NPF_{XXXXXXXX-XXXX-42ED-9725-XXXXXXXXXXXX} (Microsoft)
2.\Device\NPF_{XXXXXXXX-XXXX-4A17-9FC3-0CFA1C838EF7} (Microsoft)
3.\Device\NPF_{XXXXXXXX-XXXX-4B80-9EC5-XXXXXXXXXXXX} (MS NDIS 6.0 LoopBack Driver)
4.\Device\NPF_{XXXXXXXX-XXXX-4738-XXXX-XXXXXXXXXXXX} (Intel(R) Ethernet Connection (2) XXXX-XX)

Run the below command to capture packets and write on the file.

C:\Downloads>windump -i 4 -q -w C:\perflogs\diagTraces -n -C 30 -W 10 -U -s 0
windump: listening on \Device\NPF_{XXXXXXXX-XXXX-XXXX-A003-XXXXXXXXXXXX}

What are those switches

Well I know there are lots of things to explain in above commands. Below is about those switches.

  • -i is the number of NIC selected in the previous step( I have chosen the Ethernet Adapter)
  • -q is quiet mode
  • -w <name> is the prefix of the files to create
  • -n  the logging will not resolve host names, all data will be in IP address format
  • -W the number of circular log files to retain in addition to the current log file, specify in <path> where the files will be present
  • -U upon saving each packet, it will be written to the output file
  • -s decreases the amount of packet buffering, set this to zero
  • -C the size in Millions of Bytes the logs files so grow to before moving to the next file

Now If you go to the location, you will see one log file created, you can create this as a text file as well. Otherwise open this with the help of WireShark. You will see the same kind of packets as we already seen in case of Unix.

You can play around with the commands and the outputs. Do drop your valuable comments and feedback.

One comment