Building `traceroute` in Go
The time-to-live value can be thought of as an upper bound on the time that an IP datagram can exist in an Internet system. The TTL field is an 8 bit integer set by the sender, and reduced by every router on the route to its destination.
When the TTL reaches 0, the packet is discarded and an ICMP error message is sent to the sender.
buf := buildTCPPacket()
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0"
if err != nil {
log.Fatalf("ListenPacket failed to listen: %s\n", err)
}
ipv4.NewPacketConn(conn).SetTTL(2)
conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip})
TTD - Time To Die!
Listening for the ICMP error message
func listenICMP(status chan int) {
if handle, err := pcap.OpenLive("en0", 65536, false, 1); err != nil {
panic(err)
// Type 11 is TTLExceeded
} else if err := handle.SetBPFFilter("icmp and icmp[0] == 11"); err != nil {
panic(err)
} else {
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
status <- 0
for packet := range packetSource.Packets() {
src := packet.NetworkLayer().NetworkFlow().Src()
fmt.Printf("Ip: %s ", src)
if host, err := net.LookupAddr(src.String()); err == nil {
fmt.Printf("Host: %s\n", host[0])
}
close(status)
}
}
}
~/src/tcppacket sudo ./tcppacket -ttl 6 www.google.com
Fired Packet at 216.58.216.4 with a ttl of 6
ICMP TTL Exceeded from IP: 207.38.15.78 Host: 821.ae7.irv02-mls-dc-core-b.irv02.latisys.net.
Lets run it
func main() {
ttl := flag.Int("ttl", 64, "the TTL on the packet")
flag.Parse()
dst := flag.Args()[0]
handle := listenICMP()
go handleInboundICMP(handle)
firePacket(dst, ttl)
time.Sleep(10 * time.Second)
fmt.Println("Timeout")
os.Exit(1)
}
A GoRoutine