Fast and lightweight ping library for Golang with multi-host support.
- ICMP sockets:
- UDP port 0 means "let the kernel pick a free number"
- ICMP Echo Message ID is UDP port, so multiple instances of Pinger do not collide
- Support for custom setsockopt(2) and sendmsg(2) options
- Support for Linux kernel RX and TX timestamps with SO_TIMESTAMPING
- IPv4 and IPv6 support
- ICMP sequence numbers manager (no random): O(1) time, 256kB of memory
- Context awareness
- go >= 1.18
- Linux kernel >= 3.11
You may need to adjust
ping_group_range
sysfs to allow the creation of ICMP sockets:
$ echo 0 2147483647 > /proc/sys/net/ipv4/ping_group_range
Here is a simple traceroute(8) implementation:
dst := net.IPv4(8, 8, 8, 8)
p, err := New(nil)
if err != nil {
fmt.Println(err)
return
}
defer p.Close()
ctx, cancel := context.WithCancel(context.Background())
var g errgroup.Group
g.Go(func() error {
return p.Listen(ctx)
})
defer func() {
cancel()
if err := g.Wait(); !errors.Is(err, context.Canceled) {
fmt.Println(err)
}
}()
for ttl := uint8(1); ttl < math.MaxUint8-1; ttl++ {
fmt.Printf("%3d: ", ttl)
r, err := p.PingContextTimeout(ctx, dst, 1*time.Second, TTL(ttl))
if errors.Is(err, context.DeadlineExceeded) {
// no answer from current hop
fmt.Println("...")
continue
}
from := dst
switch err := err.(type) {
case nil:
case TimeExceededError:
from = err.From()
default:
fmt.Println(err)
return
}
fmt.Printf("%-15s %s\n", from, r.RTT)
if err == nil {
return
}
}
fmt.Println("TTL maxed out")