Non-blocking sockets • TTL batching • Adaptive waits • Async DNS • Tunable pacing
$ sudo ./fastrace google.com
fastrace 0.4.0
Tracing route to google.com (142.250.180.174)
Maximum hops: 30, Probes per hop: 3, Protocol: UDP
TTL | IP Address (RTT ms) Hostname
----+-----------------------------------------
1 | -> 192.168.1.1 ( 2.60 ms)
2 | * * * (timeout)
3 | * * * (timeout)
4 | -> 185.89.159.5 ( 6.81 ms)
5 | -> 37.26.80.129 ( 9.22 ms)
6 | -> 193.77.91.225 ( 29.88 ms) bsn-77-91-225.static.siol.net
7 | -> 193.77.107.46 ( 33.62 ms) bsn-77-107-46.static.siol.net
Fastrace is a blazingly fast traceroute utility designed for network diagnostics and performance analysis. It maps the route that packets take across an IP network from source to destination, providing detailed timing information and identifying potential bottlenecks or routing issues.
Pure C: libc + raw sockets, nothing else
Sets TTL once per hop and sends probes in bursts to cut syscalls
Poll timing aligns to the next hop deadline to reduce idle spins
Event-driven pipeline with monotonic timing for stable RTTs
Inter-probe delay flag (-d) to balance burstiness and jitter
Tree-style hops show load-balanced branches and precise RTTs
Dedicated thread for reverse lookups keeps the probe loop unblocked
Bounds-checked ICMP handling and strict resource cleanup
Compact data structures sized to your trace configuration
Fastrace uses two socket types for maximum effectiveness:
SOCK_DGRAM) for sending probe packetsSOCK_RAW) for receiving router responsessend_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
recv_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
Each probe is tracked using a specialized structure with monotonic timing:
typedef struct {
int ttl; /* Time-to-Live value */
int probe; /* Probe sequence number */
struct timespec sent_time; /* Monotonic timestamp when sent */
bool received; /* Whether response was received */
struct in_addr addr; /* Address of responding hop */
double rtt; /* Round-trip time in ms */
int port; /* UDP port used for this probe */
} probe_t;
Fastrace implements a configurable multi-TTL probing system with runtime-adjustable concurrency:
// Default concurrency window (tunable via -c flag)
config.max_active_ttls = 6;
// Probes per hop (tunable via -q flag)
config.num_probes = 3;
// Inter-probe delay in microseconds (tunable via -d flag)
config.probe_delay_us = 250;
Multiple TTLs stay in flight at once. Probes for a hop are batched under a single TTL setsockopt, cutting syscall overhead. Tuning -c, -q, and -d lets you balance speed and jitter.
The response processor uses a poll()-driven loop with non-blocking sockets to drain ICMP bursts. Time is monotonic throughout for stable RTT math:
int process_responses(int timeout_ms) {
struct pollfd pfd = { .fd = recv_sock, .events = POLLIN | POLLERR | POLLHUP };
if (timeout_ms > 0 && poll(&pfd, 1, timeout_ms) <= 0) return 0;
return drain_icmp_socket();
}
static double timespec_diff_ms(const struct timespec *start, const struct timespec *end) {
time_t sec = end->tv_sec - start->tv_sec;
long nsec = end->tv_nsec - start->tv_nsec;
if (nsec < 0) { sec -= 1; nsec += 1000000000L; }
return (double)sec * 1000.0 + (double)nsec / 1000000.0;
}
Hostname lookups are offloaded to a dedicated background thread to prevent blocking the main packet loop:
static void *dns_worker(void *arg) {
while (dns_running) {
// ... wait for queue item ...
if (getnameinfo(...) == 0) {
host_cache_store(item->addr, host);
}
}
return NULL;
}
Fastrace provides a structured visual representation of network paths:
7 │→ 72.14.209.224 ( 60.76 ms)
└→ 72.14.223.184 ( 61.65 ms)
8 │→ 142.251.244.109 ( 59.57 ms)
└→ 216.239.62.49 ( 71.36 ms)
└→ 142.250.210.95 ( 70.25 ms)
Designed to stay fast and responsive under load: batched TTL sends, adaptive waits, non-blocking sockets, and async DNS.
Multiple TTLs in flight plus batched probes cut total trace time.
Fewer syscalls per hop and tight data structures reduce CPU and memory use.
Monotonic clock for RTTs avoids drift from wall-clock adjustments.
Tree-style rendering highlights branching paths and per-hop RTTs.
The project includes a Makefile for easy compilation and installation:
# Standard optimized build
make
# Build with debugging symbols
make debug
# Build with maximum performance optimizations
make optimized
# Install to system (default: /usr/local/bin)
sudo make install
# Uninstall from system
sudo make uninstall
# Clean build artifacts
make clean
# Disable DNS lookups for faster output
sudo ./fastrace -n google.com
# Set maximum hops and probes per hop
sudo ./fastrace -m 20 -q 5 google.com
# Adjust concurrent TTL window, pacing, and timeouts
sudo ./fastrace -c 8 -d 250 -W 2 -t 700 google.com
# Use custom base port
sudo ./fastrace -P 40000 google.com
# Show version
./fastrace -V
| Option | Description |
|---|---|
-n | Disable reverse DNS lookups |
-m <hops> | Maximum hop count (1-128, default 30) |
-q <probes> | Probes per hop (1-10, default 3) |
-c <count> | Concurrent TTL window size (default 6) |
-W <ms> | Poll wait timeout in milliseconds (default 2) |
-t <ms> | Hop completion timeout in milliseconds (default 700) |
-d <us> | Inter-probe delay in microseconds (default 250) |
-P <port> | Base UDP destination port (default 33434) |
-V | Print version information |
-h | Display help message |
gcc -O3 -pthread -o fastrace fastrace.c
For maximum performance:
gcc -O3 -march=native -mtune=native -flto -pthread -o fastrace fastrace.c
sudo ./fastrace <target>
Example:
sudo ./fastrace google.com
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>