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

@ -24,6 +24,8 @@ var dns, ipinfoaddr string
var timeout int
var maxHop int
var disableIpInfo bool
var bindAddr string
var hideIncorrect bool
func init() {
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(&maxHop, "max-hop", "m", 32, "最大跳数")
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)
}
@ -86,7 +90,7 @@ var CmdNetTrace = &cobra.Command{
}
for _, target := range args {
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("-----------------------------")
}
},

@ -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
}
}
}
}
}

Loading…
Cancel
Save