master v2.1.0.beta
兔子 8 months ago
parent 5ece8b96bb
commit 68f1eef7a6

@ -24,6 +24,8 @@ var dns, ipinfoaddr string
var timeout int var timeout int
var maxHop int var maxHop int
var disableIpInfo bool var disableIpInfo bool
var bindAddr string
var hideIncorrect bool
func init() { func init() {
CmdNatClient.Flags().StringVarP(&natc.ServiceTarget, "target", "t", "", "forward server target address") CmdNatClient.Flags().StringVarP(&natc.ServiceTarget, "target", "t", "", "forward server target address")
@ -48,6 +50,8 @@ func init() {
CmdNetTrace.Flags().IntVarP(&timeout, "timeout", "t", 800, "超时时间,单位毫秒") CmdNetTrace.Flags().IntVarP(&timeout, "timeout", "t", 800, "超时时间,单位毫秒")
CmdNetTrace.Flags().IntVarP(&maxHop, "max-hop", "m", 32, "最大跳数") CmdNetTrace.Flags().IntVarP(&maxHop, "max-hop", "m", 32, "最大跳数")
CmdNetTrace.Flags().BoolVarP(&disableIpInfo, "disable-ipinfo", "D", false, "禁用ip信息查询") CmdNetTrace.Flags().BoolVarP(&disableIpInfo, "disable-ipinfo", "D", false, "禁用ip信息查询")
CmdNetTrace.Flags().StringVarP(&bindAddr, "bind", "b", "0.0.0.0", "绑定地址")
CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点")
Cmd.AddCommand(CmdNetTrace) Cmd.AddCommand(CmdNetTrace)
} }
@ -86,7 +90,7 @@ var CmdNetTrace = &cobra.Command{
} }
for _, target := range args { for _, target := range args {
starlog.Infoln("Traceroute to ", target) starlog.Infoln("Traceroute to ", target)
Traceroute(target, dns, maxHop, time.Millisecond*time.Duration(timeout), ipinfoaddr) Traceroute(target, bindAddr, dns, maxHop, time.Millisecond*time.Duration(timeout), ipinfoaddr, hideIncorrect)
fmt.Println("-----------------------------") fmt.Println("-----------------------------")
} }
}, },

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

Loading…
Cancel
Save