Handcrafted IP

Building `traceroute` in Go

A quick overview of TCP/IP

TCP/IP Packet

All the important stuff for this exercise is in the IP Layer

  • Source
  • Destination
  • Time To Live

Time To Live (TTL)

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.

Death of a Packet

When the TTL reaches 0, the packet is discarded and an ICMP error message is sent to the sender.

How do we use this to trace the route a packet took?

An ugly diagram

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

The Code

Go Traceroute

By mdp

Go Traceroute

  • 947