Banner

Let’s make a trace routing tool from scratch with python.

Abdella Solomon

--

Prerequisites- This article assumes a basic understanding of the python programming language.

Hello, my fellow readers, I am here with another new article which explains how trace routing tools works and we will make the same tool from scratch through out the process. I will keep releasing articles about networking to simplify concepts for my audiences. Follow my page if you haven’t done it yet… that being said, let’s dive into the article.

What is a Traceroute?

Traceroute is a network diagnostic tool used to trace the route of packets from a source computer to a destination computer. It is used to measure the time it takes for packets to travel from one point to another, as well as identify any potential problems along the way. Traceroute can be used to troubleshoot network issues, such as slow connection speeds or packet loss.

Why use Traceroute tools?

Traceroute tools are used to measure the time it takes for a packet of data to travel from one point on a network to another. This is useful for troubleshooting network issues, such as latency or packet loss, and identifying the source of the problem. Traceroute tools can also be used to map out the route that data takes from one point to another, which can be useful for understanding how networks are connected and how traffic is routed.

How does tracerouting work?

It works by sending a series of ICMP (Internet Control Message Protocol) echo request packets with incrementally increasing Time To Live (TTL) values. The TTL value is the number of hops that the packet can travel to before it is discarded. Each router along the path will decrement the TTL value by one and then forward the packet to its next hop. When the TTL value reaches zero, the router will send an ICMP time exceeded message back to the source, which contains information about its IP address and hops count. This process is repeated until the destination is reached, and all of the routers along the path are identified. We will keep watching until the echo sender’s host IP is similar to the host we are tracerouting.

That being said, let’s get started with building the tool. To give you some info, we will be using some libraries and specifically the socket library for communication. This library allows us to get into low-level stuff and that makes it more interesting!

Let’s create a python file and import the necessary libraries first.

import socket
import time
import struct

To go through the libraries quickly, we will use the socket library for communication, the time library for latency measurement, and the struct library for package header generation.

Let’s predefine some variables that will be used for the communication.

TIMEOUT = 3 # seconds
PORT = 33434
ICMP = socket.getprotobyname('icmp')
UDP = socket.getprotobyname('udp')

The ICMP and UDP variables that define the ICMP and UDP protocols for the socket respectively.

For the socket part, we will create two socket objects. One for the ICMP protocol and the other one for the UDP protocol and set their protocols respectively.

icmp_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, ICMP)
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, UDP)

timeout_struct = struct.pack('ll', TIMEOUT, 0)
icmp_sock.bind(("", PORT)) # binding the ICMP protocol to the port.
icmp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeout_struct)

For this example, we will trace the route of the “google.com” host. So, let’s define that and the TTL(Time-To-Live) variable.

host = "google.com"
dest_addr = socket.gethostbyname(host)
ttl = 1

In the above code, we are trying to retrieve the IP address of the host because that is what we will use for stopping the script and knowing that we have reached the destination. And the TTL variable defines the Time-To-Live part.

So, the way TTL work is that we start at 1 and we keep incrementing it after every echo we receive until we reach the point where the echo sender’s IP address is similar to the host’s destination address. Which means, we have reached the destination.

Let’s start an infinite loop where we keep sending an empty packet to the host and incrementing the TTL value until we reach the destination. We will keep the log of the latency and some other details.

print(f"Tracerouting... {host}({dest_addr})")
while True:
udp_sock.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
udp_sock.sendto(b'', (dest_addr, PORT))
start_time = time.time()
no_tries = 3
success = False
done = False
while no_tries > 0:
try:
packet, addr = icmp_sock.recvfrom(512)
success = True
except socket.error:
no_tries -= 1
continue
if addr[0] == dest_addr:
done = True
break
if success:
end_time = time.time()
try:
name = socket.gethostbyaddr(addr[0])[0]
except: pass
t = round((end_time - start_time) * 1000, 4)
print(f"TTL: {ttl} Addr: {name}({addr[0]}) Time: {t}ms")
else:
print(f"TTL: {ttl} * * *")

if done:
break
ttl += 1

print("Traceroute completed.")

That is it! This program is capable of doing trace routing to any host now.
That being said, let me share the whole script with you.

import socket
import time
import struct


TIMEOUT = 3 # seconds
PORT = 33434
ICMP = socket.getprotobyname('icmp')
UDP = socket.getprotobyname('udp')


icmp_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, ICMP)
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, UDP)

timeout_struct = struct.pack('ll', TIMEOUT, 0)
icmp_sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeout_struct)

host = "google.com"
dest_addr = socket.gethostbyname(host)
ttl = 1

print(f"Tracerouting... {host}({dest_addr})")
while True:
udp_sock.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
udp_sock.sendto(b'', (dest_addr, PORT))
start_time = time.time()
no_tries = 3
success = False
done = False
while no_tries > 0:
try:
packet, addr = icmp_sock.recvfrom(512)
success = True
except socket.error:
no_tries -= 1
continue
if addr[0] == dest_addr:
done = True
break
if success:
end_time = time.time()
try:
name = socket.gethostbyaddr(addr[0])[0]
except: pass
t = round((end_time - start_time) * 1000, 4)
print(f"TTL: {ttl} Addr: {name}({addr[0]}) Time: {t}ms")
else:
print(f"TTL: {ttl} * * *")

if done:
break
ttl += 1

print("Traceroute completed.")

Although there are issues with classical trace routing like load balancing problems; we will get into them in my future articles. Let me know your suggestions and feedback in the comment section.
If you enjoyed the article, I guess I deserve a follow and a clap. Please share this article with your friends and family. Stay tuned!

My pages are Twitter Medium LinkedIn Telegram GitHub

Related articles from the author

--

--

Abdella Solomon

A Data Scientist | Programmer | Writer | Freelancer | Lecturer