A from-scratch reimplementation of the traceroute command in C, as required by
the 42 ft_traceroute subject.
It maps the route IP packets take to a host by sending UDP probes with an
increasing TTL: each router that drops a probe (TTL reached 0) answers with an
ICMP Time Exceeded, and the destination answers with an ICMP Port
Unreachable. Those replies, caught on a raw ICMP socket, reveal one hop per
TTL. Output and indentation match the real traceroute.
make # builds ./ft_traceroute
make re # rebuild from scratch
make clean # remove object files
make fclean # remove objects + binaryft_traceroute needs raw-socket privileges (CAP_NET_RAW) for the ICMP
receive socket: run it as root, with sudo, after
setcap cap_net_raw+ep ./ft_traceroute, or inside the provided Docker
container.
sudo ./ft_traceroute 8.8.8.8
sudo ./ft_traceroute google.com
sudo ./ft_traceroute -m 10 8.8.8.8 # cap the trace at 10 hopsOutput:
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 172.22.0.1 0.151 ms 0.032 ms 0.026 ms
2 192.168.1.1 4.491 ms 3.116 ms 3.120 ms
3 80.10.4.65 5.424 ms 5.142 ms 4.995 ms
4 * * *
- Send socket — a UDP socket. Its TTL is bumped hop by hop with
setsockopt(IP_TTL); each probe targets portbase_port + nso a reply can be paired back to the exact probe that caused it. - Receive socket — a raw
IPPROTO_ICMPsocket.select()waits (up to 3 s) for the matching Time Exceeded / Unreachable error, whose quoted payload carries our original UDP header (source + destination ports) for identification. - No reverse DNS on hops — as the subject requires, hops print bare numeric
addresses (
inet_ntoa); only the destination is resolved once, for the header line. fcntl,pollandppollare never used — reception is driven byselect().
Mandatory (per the subject): --help.
| Flag | Meaning |
|---|---|
--help |
print the help list and exit |
Bonus flags (man traceroute semantics):
| Flag | Meaning |
|---|---|
-i device |
bind the probe socket to this network interface |
-m max_ttl |
maximum number of hops (default 30) |
-p port |
base destination port (default 33434) |
-s src_addr |
use this source address |
-t tos |
set the IP type of service |
Values may be attached (-m10) or given as the next argument (-m 10).
docker/Dockerfile builds a Debian image with the system traceroute for
side-by-side comparison and NET_RAW granted — ft_traceroute itself never
calls any external traceroute.
make docker-build # build the image
make up # start it in background
docker compose exec fttraceroute make re # build inside it
docker compose exec fttraceroute ./ft_traceroute 8.8.8.8
docker compose exec fttraceroute traceroute -n 8.8.8.8 # system reference
make down # stop / remove itinc/ft_traceroute.h public declarations
src/main.c entry point
src/args.c command-line parsing, help/usage
src/resolve.c destination resolution (forward only)
src/traceroute.c sockets, probe send/recv loop, per-hop printing
src/utils.c time math, fatal errors
docker/Dockerfile Debian build/compare environment
Resources:
https://datatracker.ietf.org/doc/html/rfc792 — ICMP https://man7.org/linux/man-pages/man8/traceroute.8.html https://networklessons.com/ip-routing/ipv4-packet-header