func RunTrace(host string, source string, source6 string, maxrtt time.Duration, maxttl int, DNScache *LookupCache, cb Callback) ([]Hop, error) {
	hops := make([]Hop, 0, maxttl)
	var res trace
	var err error
	isIPv6 := false
	addrList, err := net.LookupIP(host)
	if nil != err {
		return nil, err
	}
	for _, addr := range addrList {
		if addr.To4() != nil {
			res.dest, err = net.ResolveIPAddr("ip4:icmp", addr.String())
			break
		}
	}
	if nil == res.dest {
		for _, addr := range addrList {
			if addr.To16() != nil {
				isIPv6 = true
				res.dest, err = net.ResolveIPAddr("ip6:58", addr.String())
				break
			}
		}
	}
	if nil == res.dest {
		return nil, errors.New("Unable to resolve destination host")
	}
	res.maxrtt = maxrtt
	res.maxttl = maxttl
	res.id = rand.Int() % 0x7fff
	if isIPv6 {
		res.msg = icmp.Message{Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ID: res.id, Seq: 1}}
	} else {
		res.msg = icmp.Message{Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ID: res.id, Seq: 1}}
	}
	res.netmsg, err = res.msg.Marshal(nil)
	if nil != err {
		return nil, err
	}
	if !isIPv6 {
		res.conn, err = net.ListenPacket("ip4:icmp", source)
	} else {
		res.conn, err = net.ListenPacket("ip6:58", source6)
	}
	if nil != err {
		return nil, err
	}
	defer res.conn.Close()
	if isIPv6 {
		res.ipv6conn = ipv6.NewPacketConn(res.conn)
		defer res.ipv6conn.Close()
		if err := res.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true); err != nil {
			return nil, err
		}
		var f ipv6.ICMPFilter
		f.SetAll(true)
		f.Accept(ipv6.ICMPTypeTimeExceeded)
		f.Accept(ipv6.ICMPTypeEchoReply)
		f.Accept(ipv6.ICMPTypeDestinationUnreachable)
		if err := res.ipv6conn.SetICMPFilter(&f); err != nil {
			return nil, err
		}
	} else {
		res.ipv4conn = ipv4.NewPacketConn(res.conn)
		defer res.ipv4conn.Close()
	}
	timeouts := 0
	for i := 1; i <= maxttl; i++ {
		next := res.Step(i)
		if nil != next.Addr {
			addrString := next.Addr.String()
			if nil != DNScache {
				next.Host = DNScache.LookupHost(addrString)
				next.AS = DNScache.LookupAS(addrString)
			}
		}
		if nil != cb {
			cb(next, i, 1)
		}
		hops = append(hops, next)
		if next.Final {
			break
		}
		if next.Timeout {
			timeouts++
		} else {
			timeouts = 0
		}
		if timeouts == MaxTimeouts {
			break
		}
	}
	return hops, nil
}
RunTrace preforms traceroute to specified host
package tracelib
import (
	"encoding/binary"
	"errors"
	"math/rand"
	"net"
	"time"
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)
const (
	ProtocolICMP = 1
	ProtocolICMP6 = 58
	MaxTimeouts = 3
)
type trace struct {
	conn     net.PacketConn
	ipv4conn *ipv4.PacketConn
	ipv6conn *ipv6.PacketConn
	msg      icmp.Message
	netmsg   []byte
	id       int
	maxrtt   time.Duration
	maxttl   int
	dest     net.Addr
}
type Callback func(info Hop, hopnum int, round int)