|
|
|
@ -32,7 +32,7 @@ func useCustomeDNS(dns []string) {
|
|
|
|
|
net.DefaultResolver = &resolver
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Traceroute(address string, dns string, maxHops int, timeout time.Duration, ipinfoAddr string) {
|
|
|
|
|
func Traceroute(address string, bindaddr string, dns string, maxHops int, timeout time.Duration, ipinfoAddr string, hideIncorrect bool) {
|
|
|
|
|
ipinfo := net.ParseIP(address)
|
|
|
|
|
if ipinfo == nil {
|
|
|
|
|
{
|
|
|
|
@ -51,9 +51,9 @@ func Traceroute(address string, dns string, maxHops int, timeout time.Duration,
|
|
|
|
|
address = addr.String()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
traceroute(address, maxHops, timeout, ipinfoAddr)
|
|
|
|
|
traceroute(address, bindaddr, maxHops, timeout, ipinfoAddr, hideIncorrect)
|
|
|
|
|
}
|
|
|
|
|
func traceroute(address string, maxHops int, timeout time.Duration, ipinfoAddr string) {
|
|
|
|
|
func traceroute(address string, bindaddr string, maxHops int, timeout time.Duration, ipinfoAddr string, hideIncorrect bool) {
|
|
|
|
|
ipinfo := net.ParseIP(address)
|
|
|
|
|
if ipinfo == nil {
|
|
|
|
|
starlog.Errorln("IP地址解析失败:", address)
|
|
|
|
@ -74,18 +74,16 @@ func traceroute(address string, maxHops int, timeout time.Duration, ipinfoAddr s
|
|
|
|
|
replyType = ipv6.ICMPTypeEchoReply
|
|
|
|
|
proto = 58
|
|
|
|
|
}
|
|
|
|
|
c, err := icmp.ListenPacket(network, "0.0.0.0")
|
|
|
|
|
if bindaddr == "" {
|
|
|
|
|
bindaddr = "0.0.0.0"
|
|
|
|
|
}
|
|
|
|
|
c, err := icmp.ListenPacket(network, bindaddr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
|
|
dst, err := net.ResolveIPAddr(resolveIP, address)
|
|
|
|
|
if err != nil {
|
|
|
|
|
starlog.Errorln("IP地址解析失败:", address, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if maxHops == 0 {
|
|
|
|
|
maxHops = 32
|
|
|
|
|
}
|
|
|
|
@ -95,6 +93,13 @@ func traceroute(address string, maxHops int, timeout time.Duration, ipinfoAddr s
|
|
|
|
|
}
|
|
|
|
|
exitfor:
|
|
|
|
|
for i := 1; i <= maxHops; i++ {
|
|
|
|
|
retry := 0
|
|
|
|
|
doRetry:
|
|
|
|
|
dst, err := net.ResolveIPAddr(resolveIP, address)
|
|
|
|
|
if err != nil {
|
|
|
|
|
starlog.Errorln("IP地址解析失败:", address, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if atomic.LoadInt32(&firstTargetHop) <= int32(i) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@ -134,34 +139,73 @@ exitfor:
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply := make([]byte, 1500)
|
|
|
|
|
err = c.SetReadDeadline(time.Now().Add(timeout))
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tSetReadDeadline error: %v\n", i, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
n, peer, err := c.ReadFrom(reply)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tReadFrom error: %v\n", i, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
duration := time.Since(start)
|
|
|
|
|
now := time.Now()
|
|
|
|
|
exitrecheck:
|
|
|
|
|
for {
|
|
|
|
|
reply := make([]byte, 1500)
|
|
|
|
|
err = c.SetReadDeadline(time.Now().Add(timeout))
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tSetReadDeadline error: %v\n", i, err)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
n, peer, err := c.ReadFrom(reply)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tReadFrom error: %v\n", i, err)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
duration := time.Since(start)
|
|
|
|
|
|
|
|
|
|
rm, err := icmp.ParseMessage(proto, reply[:n])
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tParseMessage error: %v\n", i, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
rm, err := icmp.ParseMessage(proto, reply[:n])
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("%d\tParseMessage error: %v\n", i, err)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch rm.Type {
|
|
|
|
|
case exceededType:
|
|
|
|
|
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
case replyType:
|
|
|
|
|
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
break exitfor
|
|
|
|
|
default:
|
|
|
|
|
fmt.Printf("%d\tgot %+v from %v; want echo reply;%s\n", i, rm, peer, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
switch rm.Type {
|
|
|
|
|
case exceededType:
|
|
|
|
|
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
break exitrecheck
|
|
|
|
|
case replyType:
|
|
|
|
|
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
if peer.String() == dst.String() {
|
|
|
|
|
break exitfor
|
|
|
|
|
}
|
|
|
|
|
case ipv4.ICMPTypeEcho, ipv6.ICMPTypeEchoRequest:
|
|
|
|
|
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
|
|
|
|
|
if retry < 1 {
|
|
|
|
|
retry++
|
|
|
|
|
goto doRetry
|
|
|
|
|
}
|
|
|
|
|
if !hideIncorrect {
|
|
|
|
|
fmt.Printf("%d\tInvalid Echo Request:%s (%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
}
|
|
|
|
|
break exitrecheck
|
|
|
|
|
}
|
|
|
|
|
case ipv4.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeDestinationUnreachable:
|
|
|
|
|
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
|
|
|
|
|
if retry < 1 {
|
|
|
|
|
retry++
|
|
|
|
|
goto doRetry
|
|
|
|
|
}
|
|
|
|
|
if !hideIncorrect {
|
|
|
|
|
fmt.Printf("%d\tInvalid DstInv Request:%s (%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
}
|
|
|
|
|
break exitrecheck
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
|
|
|
|
|
if retry < 1 {
|
|
|
|
|
retry++
|
|
|
|
|
goto doRetry
|
|
|
|
|
}
|
|
|
|
|
if !hideIncorrect {
|
|
|
|
|
fmt.Printf("%d\tgot %+v from %v (%s) %s\n", i, rm.Type, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
|
|
|
|
|
}
|
|
|
|
|
break exitrecheck
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|