Skip to content

migfernandes01/traceroute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

traceroute

A pure-Go traceroute library supporting ICMP and UDP probe protocols.

How it works

Traceroute discovers the network path to a destination by sending probe packets with incrementing IP Time-To-Live (TTL) values, starting at 1. Each router along the path decrements the TTL; when it hits zero the router drops the packet and sends back an ICMP Time Exceeded message, revealing its address. When the probe finally reaches the destination, the response changes (ICMP Echo Reply for ICMP probes, ICMP Destination Unreachable for UDP probes), signaling the trace is complete.

ICMP mode (default)

Sends ICMP Echo Request packets. Each probe carries a unique identifier and sequence number used to match replies. The same ICMP socket is used for both sending probes and receiving replies.

UDP mode

Sends UDP packets to incrementing high-numbered destination ports (starting at 33434). A separate ICMP socket listens for Time Exceeded and Destination Unreachable errors. The destination port embedded in the ICMP error payload is used to match replies back to probes.

Unprivileged sockets

The library first attempts to open an unprivileged ICMP datagram socket (udp4), which works without root on macOS and on Linux when net.ipv4.ping_group_range includes the current user's GID. If that fails, it falls back to raw sockets (ip4:icmp), which require root or CAP_NET_RAW.

Install

go get github.com/migfernandes01/traceroute

Usage

One-shot trace

import "github.com/migfernandes01/traceroute/traceroute"

result, err := traceroute.Trace("google.com", nil)
if err != nil {
    log.Fatal(err)
}
fmt.Println(result)

Custom configuration

result, err := traceroute.Trace("google.com", &traceroute.Config{
    Protocol:  traceroute.UDP,
    MaxHops:   20,
    NumProbes: 1,
    Timeout:   2 * time.Second,
})

Reusable Client

For multiple traces, use a Client to open the ICMP listener once and reuse it:

client, err := traceroute.NewClient(&traceroute.Config{
    MaxHops:   20,
    NumProbes: 1,
    Timeout:   2 * time.Second,
})
if err != nil {
    log.Fatal(err)
}
defer client.Close()

for _, host := range []string{"google.com", "cloudflare.com"} {
    result, err := client.Trace(host)
    if err != nil {
        log.Printf("%s: %v", host, err)
        continue
    }
    fmt.Println(result)
}

A Client is not safe for concurrent use. Sequential Trace() calls on the same Client reuse the listener socket.

Config options

Field Default Description
Protocol ICMP traceroute.ICMP or traceroute.UDP
MaxHops 30 Maximum TTL value
NumProbes 3 Probes sent per hop
Timeout 3s Per-probe reply timeout
ResolveHostnames true Reverse DNS lookup on hop addresses
Port 33434 Initial destination port (UDP only)

Pass nil for sensible defaults.

Running tests

Unit tests (no network or privileges required):

go test -short ./traceroute/

Integration tests (require network access; unprivileged sockets work on macOS, may need root or CAP_NET_RAW on Linux):

go test -v ./traceroute/

Run specific integration tests:

go test -v -run TestTraceICMPGoogle ./traceroute/
go test -v -run TestTraceMSSQLServer ./traceroute/
go test -v -run TestClientMultipleTraces ./traceroute/

If unprivileged sockets aren't available on your system:

sudo go test -v ./traceroute/

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages