A Rust reimplementation of the classic traceroute utility, written for a
Computer Networking final project. It traces the route IP packets take across
the network to a destination host by sending probes with progressively
increasing TTL values and recording the ICMP Time Exceeded / Destination Unreachable replies it gets back from each hop.
The CLI surface is modeled after the standard Linux traceroute tool, so most
of its short flags work the same way (-n, -q, -m, -f, -w, -p,
etc.).
- UDP probing — implemented (this is the default mode).
- ICMP probing (
-I) — module stub; not yet implemented. - TCP SYN probing (
-T) — module stub; not yet implemented. - UDP-Lite, raw IP, MTU discovery, AS-path lookup, gateway routing,
per-probe send-wait, alternate source addresses — flags are parsed but
the corresponding behavior is marked
TODOinsrc/args.rs.
In practice, the working subset today is: UDP traceroute over IPv4 or IPv6 with configurable TTL range, query count, ports, packet size, and numeric vs. reverse-DNS output.
rtraceroute/
├── Cargo.toml # Crate manifest — declares clap, dns-lookup, and pnet
├── Cargo.lock
└── src/
├── main.rs # Entry point: parses args, resolves the host,
│ # drives the probe loop, formats hop output
├── args.rs # clap-derived `Args` struct + `Config` it lowers into,
│ # plus the `Method` / `ResolvedMethod` enums
├── dns.rs # Forward (`resolve_hostname`) and reverse
│ # (`reverse_resolve`) name resolution helpers
└── probe/
├── mod.rs # `Prober` trait, `ProbeResult`, `ProbeReply` types —
│ # the abstraction every transport implements
├── udp.rs # `UdpProber` — the only fully implemented backend.
│ # Sends UDP packets, listens on a raw ICMP socket,
│ # and matches replies back to probes by inspecting
│ # the original UDP header echoed in the ICMP payload
├── icmp.rs # `IcmpProber` placeholder (stub)
└── tcp.rs # `TcpProber` placeholder (stub)
main.rsparses command-line arguments viaargs::Args::parse()and lowers them into aConfigstruct.- The destination hostname is resolved through
dns::resolve_hostname, honoring-4/-6if the user forced an address family. - A
UdpProberis constructed against the resolved IP. It opens two raw sockets viapnet::transport: one for sending UDP and one for receiving ICMP error replies. - The main loop walks TTL values from
first_ttlup tomax_ttl. For each TTL it callsprober.probe(...), which sendsqueries_per_hopUDP packets at that TTL and collects replies (or timeouts) for each. - Each
ProbeReplyis formatted into a traceroute-style line and printed. The loop terminates when a reply comes back from the destination itself.
probe/mod.rs defines:
pub trait Prober<T>: Sized {
fn new(destination: IpAddr, opts: T) -> Result<Self>;
fn probe(
&mut self,
force_src_port: Option<u16>,
force_dst_port: Option<u16>,
packet_len: u16,
hops: u8,
probes: u8,
) -> Result<Option<ProbeReply>>;
}This is the seam where future ICMP and TCP backends will plug in. Each
implementation is responsible for owning whatever sockets it needs and
turning a (TTL, port, count) request into a ProbeReply containing one
ProbeResult (Reply { ip, rtt } or Timeout) per probe sent.
- clap
4.5— derive-style CLI parsing. - pnet
0.35— raw socket transport channels and packet construction (UDP, ICMP). - dns-lookup
3.0— reverse DNS viagetnameinfo.
HOWTO.mdfor build and usage instructions.