From 68f1eef7a6879b96141279628c2e3bb05f1c9098 Mon Sep 17 00:00:00 2001 From: starainrt Date: Mon, 18 Mar 2024 13:05:10 +0800 Subject: [PATCH] update --- net/cmd.go | 6 ++- net/trace.go | 112 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/net/cmd.go b/net/cmd.go index 6fc46dd..53a24d8 100644 --- a/net/cmd.go +++ b/net/cmd.go @@ -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("-----------------------------") } }, diff --git a/net/trace.go b/net/trace.go index d8e4f00..e0ee1f7 100644 --- a/net/trace.go +++ b/net/trace.go @@ -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 + } + } } + } }