DevOps in Linux — Traceroute
Traceroute command introduction
What is traceroute
traceroute
is a widely used command-line utility available in almost all operating systems. It shows you the complete route to a destination address. It also shows the time is taken (or delays) between intermediate routers and prints the route that a packet takes to reach the host.
traceroute
is super useful when you want to know about the route and about all the hops that a packet takes. The following diagram is an example of traceroute
execution flow:
How traceroute works
traceroute
uses the TCP/IP suite of protocols, and sends User Datagram Protocol packets. It leverages a field in Internet Protocol (IP) packet headers that was never really intended for path or route tracing. The header contains the Time to Live (TTL) field, which contains an eight-bit integer value.
This is how it works:
- User invokes the
traceroute
command and specifies a target host. If the host is specified in the form of a domain name, traceroute will attempt to resolve it. traceroute
then sends a data packet towards the target with the TTL value set to “1” (By default Windowstracert
uses ICMP and Linuxtraceroute
useUDP
). The first router in the path will decrement the value by 1, which should trigger a TTL exceeded message that gets sent back to the host on which the traceroute program is running.traceroute
then increases the TTL value to “2”. That first router in the path will still decrement the value by 1, but because the TTL will no longer drop to zero right out of the gate the packet can live on for one more hop. Once the TTL value does hit zero (in this case, at the second router in the path), another TTL exceeded message should be generated and passed back to traceroute.- This process repeats itself, with
traceroute
increasing the TTL by 1 each time, until the destination is reached or an upper limit of hops (default 30) is hit. - When finished, traceroute prints all the hops in the path, along with the amount of time it took to each hop and back (this is known as the Round Trip Time).
The way how traceroute
latency is calculated:
- It timestamps the probe packet when sent
- It timestamp the ICMP response when received
- It then calculate the difference to determine round-trip time.
traceroute Demo
An example of traceroute
run to google.com looks like:
$ traceroute google.com
traceroute to google.com (172.217.23.14), 30 hops max, 60 byte packets
1 10.8.8.1 (10.8.8.1) 14.499 ms 15.335 ms 15.956 ms
2 h37-220-13-49.host.redstation.co.uk (37.220.13.49) 17.811 ms 18.669 ms 19.346 ms
3 92.zone.2.c.dc9.redstation.co.uk (185.20.96.137) 19.096 ms 19.757 ms 20.892 ms
4 203.lc3.redstation.co.uk (185.5.3.221) 28.160 ms 28.415 ms 28.665 ms
5 100.core1.the.as20860.net (62.128.218.33) 26.739 ms 27.840 ms 28.847 ms
6 110.core2.thn.as20860.net (62.128.218.26) 29.112 ms 18.466 ms 19.835 ms
7 be97.asr01.thn.as20860.net (62.128.222.205) 19.986 ms 20.488 ms 21.354 ms
8 * * *
9 216.239.48.143 (216.239.48.143) 24.364 ms 216.239.48.113 (216.239.48.113) 25.069 ms 25.592 ms
10 108.170.233.199 (108.170.233.199) 26.239 ms 27.369 ms 28.031 ms
11 lhr35s01-in-f14.1e100.net (172.217.23.14) 28.642 ms 29.311 ms 29.815 ms
- First line shows the hostname and ip that is to be reached, the maximum number of hops to the host that traceroute will attempt and the size of the byte packets to be sent.
- Each line below lists a hop to get to the destination. The hostname is given, followed by the ip of the hostname, followed by the roudtrip time that it takes for a packet to get to the host and back to the initiating computer. By default,
traceroute
sends 3 packets for each hosts.
Sometimes you might notice one or more lines of your traceroute output is listed only with an asterisk (*). This means that the program did not receive any response from the router at that hop.
Some organizations choose to block or discard the type of packets that traceroute
relies on, either by blocking them with a firewall or configuring routers to discard the packets instead of replying. Traceroute
traffic is also considered low-priority; a busy router may process standard data packets rather than reply to your traceroute request.
traceroute Common Options
$ traceroute -4 google.com ==> use IPv4
$ traceroute -6 google.com ==> use IPv6
$ traceroute -F google.com ==> Do not fragment packet
$ traceroute -f 10 google.com ==> Start from the 10th ttl hop
$ traceroute -g 10.12.13.14 google.com ==> Route the packet through the gate
$ $traceroute -m 5 google.com ==> Only max 5 hops
$ traceroute -n google.com ==> Skip resolve IPs to their domain names
$ traceroute -p 2022 google.com ==> Set destination port
$ traceroute -q 1 google.com ==> Limit number of probes per hop
$ traceroute -i eth2 google.com ==> Set interface to use
$ traceroute -w 1 google.com ==> Set probe response time to 1 second
Simple Python Implementation
Below is a simple Python version of traceroute
import socket
import argparse
DESTINATION_PORT = 33434
MESSAGE = 'test'
def trace_route(destination: str):
# Get the destination ip address.
destination_ip = socket.gethostbyname(destination)
print(f'Tracing the route to {destination_ip}')
# Prepare a socket to send UDP packets.
sending_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sending_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Prepare a socket to listen for ICMP messages.
receiving_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
# Show the ICMP header, since that's where the router address is.
receiving_socket.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
received_ip, current_hop = None, 1
while received_ip != destination_ip:
# Set the socket's TTL to the current hop so that the packet just
# reaches it before being stopped.
sending_socket.setsockopt(
socket.IPPROTO_IP, socket.IP_TTL, current_hop)
# Attempt to send a UDP packet to the destination ip.
sending_socket.sendto(bytes(MESSAGE, 'utf-8'),
(destination_ip, DESTINATION_PORT))
# Receive any incoming ICMP packet. We can ignore the first return
# value from recvfrom, which would be the included data.
_, addr = receiving_socket.recvfrom(1500)
received_ip = addr[0]
print(f'Current hop {current_hop}: ICMP message received from {received_ip}')
current_hop = current_hop + 1
if __name__ == '__main__':
my_parser = argparse.ArgumentParser()
my_parser.add_argument('--dest', type=str, help='Destination host')
args = my_parser.parse_args()
dest_host = args.dest
trace_route(dest_host)