From 701abc344750833f53a8dc1bbdb207b8893ef7d9 Mon Sep 17 00:00:00 2001 From: tsosunchia <59512455+tsosunchia@users.noreply.github.com> Date: Sat, 14 Oct 2023 09:08:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0file=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E8=BF=9B=E8=A1=8C=E8=B7=AF=E7=94=B1=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/cmd.go | 17 ++- fast_trace/fast_trace ipv6.go | 61 ++++---- fast_trace/fast_trace.go | 257 ++++++++++++++++++++++++++++++---- util/dns_test.go | 4 +- util/util.go | 10 +- 5 files changed, 285 insertions(+), 64 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index eb00d89..83b0547 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -69,6 +69,7 @@ func Excute() { Help: "Use DoT Server for DNS Parse [dnssb, aliyun, dnspod, google, cloudflare]"}) lang := parser.Selector("g", "language", []string{"en", "cn"}, &argparse.Options{Default: "cn", Help: "Choose the language for displaying [en, cn]"}) + file := parser.String("", "file", &argparse.Options{Help: "Read IP Address or domain name from file"}) err := parser.Parse(os.Args) if err != nil { @@ -91,7 +92,7 @@ func Excute() { *port = 80 } - if *fast_trace { + if *fast_trace || *file != "" { var paramsFastTrace = fastTrace.ParamsFastTrace{ SrcDev: *srcDev, SrcAddr: *srcAddr, @@ -102,6 +103,7 @@ func Excute() { Lang: *lang, PktSize: *packetSize, Timeout: time.Duration(*timeout) * time.Millisecond, + File: *file, } fastTrace.FastTest(*tcp, *output, paramsFastTrace) @@ -176,21 +178,26 @@ func Excute() { // //go func() { // defer wg.Done() + err = nil if *udp { if *ipv6Only { fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.") os.Exit(0) } - ip = util.DomainLookUp(domain, "4", *dot, *jsonPrint) + ip, err = util.DomainLookUp(domain, "4", *dot, *jsonPrint) } else { if *ipv6Only { - ip = util.DomainLookUp(domain, "6", *dot, *jsonPrint) + ip, err = util.DomainLookUp(domain, "6", *dot, *jsonPrint) } else if *ipv4Only { - ip = util.DomainLookUp(domain, "4", *dot, *jsonPrint) + ip, err = util.DomainLookUp(domain, "4", *dot, *jsonPrint) } else { - ip = util.DomainLookUp(domain, "all", *dot, *jsonPrint) + ip, err = util.DomainLookUp(domain, "all", *dot, *jsonPrint) } } + if err != nil { + fmt.Println(err) + os.Exit(1) + } //}() // //wg.Wait() diff --git a/fast_trace/fast_trace ipv6.go b/fast_trace/fast_trace ipv6.go index 93bef12..b4675ee 100644 --- a/fast_trace/fast_trace ipv6.go +++ b/fast_trace/fast_trace ipv6.go @@ -13,45 +13,49 @@ import ( "os/signal" ) -var pFastTracer ParamsFastTrace +//var pFastTracer ParamsFastTrace func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollection) { - fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) - if err != nil { - return - } - defer func(fp *os.File) { - err := fp.Close() - if err != nil { - log.Fatal(err) - } - }(fp) - - log.SetOutput(fp) - log.SetFlags(0) fmt.Printf("%s『%s %s 』%s\n", printer.YELLOW_PREFIX, location, ispCollection.ISPName, printer.RESET_PREFIX) - log.Printf("『%s %s 』\n", location, ispCollection.ISPName) - fmt.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IPv6, pFastTracer.MaxHops, pFastTracer.PktSize) - log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IPv6, pFastTracer.MaxHops, pFastTracer.PktSize) - ip := util.DomainLookUp(ispCollection.IPv6, "6", "", true) + fmt.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IPv6, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize) + + ip, err := util.DomainLookUp(ispCollection.IPv6, "6", "", true) + if err != nil { + log.Fatal(err) + } var conf = trace.Config{ - BeginHop: pFastTracer.BeginHop, + BeginHop: f.ParamsFastTrace.BeginHop, DestIP: ip, DestPort: 80, - MaxHops: pFastTracer.MaxHops, + MaxHops: f.ParamsFastTrace.MaxHops, NumMeasurements: 3, ParallelRequests: 18, - RDns: pFastTracer.RDns, - AlwaysWaitRDNS: pFastTracer.AlwaysWaitRDNS, + RDns: f.ParamsFastTrace.RDns, + AlwaysWaitRDNS: f.ParamsFastTrace.AlwaysWaitRDNS, PacketInterval: 100, TTLInterval: 500, IPGeoSource: ipgeo.GetSource("LeoMoeAPI"), - Timeout: pFastTracer.Timeout, - PktSize: pFastTracer.PktSize, - Lang: pFastTracer.Lang, + Timeout: f.ParamsFastTrace.Timeout, + SrcAddr: f.ParamsFastTrace.SrcAddr, + PktSize: f.ParamsFastTrace.PktSize, + Lang: f.ParamsFastTrace.Lang, } if oe { + fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) + if err != nil { + return + } + defer func(fp *os.File) { + err := fp.Close() + if err != nil { + log.Fatal(err) + } + }(fp) + log.SetOutput(fp) + log.SetFlags(0) + log.Printf("『%s %s 』\n", location, ispCollection.ISPName) + log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IPv6, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize) conf.RealtimePrinter = tracelog.RealtimePrinter } else { conf.RealtimePrinter = printer.RealtimePrinter @@ -63,7 +67,7 @@ func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollection) { log.Fatal(err) } - println() + fmt.Println() } func (f *FastTracer) testAll_v6() { @@ -114,7 +118,6 @@ func FastTestv6(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { var c string oe = outEnable - pFastTracer = paramsFastTrace fmt.Println("您想测试哪些ISP的路由?\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网\n6. 全部") fmt.Print("请选择选项:") @@ -123,7 +126,9 @@ func FastTestv6(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { c = "1" } - ft := FastTracer{} + ft := FastTracer{ + ParamsFastTrace: paramsFastTrace, + } // 建立 WebSocket 连接 w := wshandle.New() diff --git a/fast_trace/fast_trace.go b/fast_trace/fast_trace.go index bb449a9..4f931f7 100644 --- a/fast_trace/fast_trace.go +++ b/fast_trace/fast_trace.go @@ -1,6 +1,7 @@ package fastTrace import ( + "bufio" "fmt" "github.com/nxtrace/NTrace-core/ipgeo" "github.com/nxtrace/NTrace-core/printer" @@ -12,6 +13,7 @@ import ( "net" "os" "os/signal" + "strings" "time" ) @@ -30,29 +32,25 @@ type ParamsFastTrace struct { Lang string PktSize int Timeout time.Duration + File string +} + +type IpListElement struct { + Ip string + Desc string + Version4 bool // true for IPv4, false for IPv6 } var oe = false func (f *FastTracer) tracert(location string, ispCollection ISPCollection) { - fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) - if err != nil { - return - } - defer func(fp *os.File) { - err := fp.Close() - if err != nil { - log.Fatal(err) - } - }(fp) - - log.SetOutput(fp) - log.SetFlags(0) fmt.Printf("%s『%s %s 』%s\n", printer.YELLOW_PREFIX, location, ispCollection.ISPName, printer.RESET_PREFIX) - log.Printf("『%s %s 』\n", location, ispCollection.ISPName) fmt.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IP, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize) - log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IP, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize) - ip := util.DomainLookUp(ispCollection.IP, "4", "", true) + + ip, err := util.DomainLookUp(ispCollection.IP, "4", "", true) + if err != nil { + log.Fatal(err) + } var conf = trace.Config{ BeginHop: f.ParamsFastTrace.BeginHop, DestIP: ip, @@ -72,6 +70,21 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) { } if oe { + fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) + if err != nil { + return + } + defer func(fp *os.File) { + err := fp.Close() + if err != nil { + log.Fatal(err) + } + }(fp) + + log.SetOutput(fp) + log.SetFlags(0) + log.Printf("『%s %s 』\n", location, ispCollection.ISPName) + log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IP, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize) conf.RealtimePrinter = tracelog.RealtimePrinter } else { conf.RealtimePrinter = printer.RealtimePrinter @@ -82,13 +95,19 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) { if err != nil { log.Fatal(err) } - println() + fmt.Println() } func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { + // tm means tcp mode var c string - pFastTrace := paramsFastTrace oe = outEnable + + if paramsFastTrace.File != "" { + testFile(paramsFastTrace, tm) + return + } + fmt.Println("Hi,欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂,我们设置的测试目标有限,建议普通用户自测以获得更加精准的路由情况") fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6") fmt.Print("请选择选项:") @@ -97,16 +116,41 @@ func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { c = "1" } if c == "2" { + if paramsFastTrace.SrcDev != "" { + dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev) + if addrs, err := dev.Addrs(); err == nil { + for _, addr := range addrs { + if (addr.(*net.IPNet).IP.To4() == nil) == true { + paramsFastTrace.SrcAddr = addr.(*net.IPNet).IP.String() + // 检查是否是内网IP + if !(net.ParseIP(paramsFastTrace.SrcAddr).IsPrivate() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLoopback() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalUnicast() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalMulticast()) { + // 若不是则跳出 + break + } + } + } + } + } FastTestv6(tm, outEnable, paramsFastTrace) return } - - if pFastTrace.SrcDev != "" { - dev, _ := net.InterfaceByName(pFastTrace.SrcDev) + if paramsFastTrace.SrcDev != "" { + dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev) if addrs, err := dev.Addrs(); err == nil { for _, addr := range addrs { - if addr.(*net.IPNet).IP.To4() != nil { - pFastTrace.SrcAddr = addr.(*net.IPNet).IP.String() + if (addr.(*net.IPNet).IP.To4() == nil) == false { + paramsFastTrace.SrcAddr = addr.(*net.IPNet).IP.String() + // 检查是否是内网IP + if !(net.ParseIP(paramsFastTrace.SrcAddr).IsPrivate() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLoopback() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalUnicast() || + net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalMulticast()) { + // 若不是则跳出 + break + } } } } @@ -120,7 +164,7 @@ func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { } ft := FastTracer{ - ParamsFastTrace: pFastTrace, + ParamsFastTrace: paramsFastTrace, } // 建立 WebSocket 连接 @@ -156,6 +200,171 @@ func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) { } } +func testFile(paramsFastTrace ParamsFastTrace, tm bool) { + // 建立 WebSocket 连接 + w := wshandle.New() + w.Interrupt = make(chan os.Signal, 1) + signal.Notify(w.Interrupt, os.Interrupt) + defer func() { + w.Conn.Close() + }() + + var tracerouteMethod trace.Method + if !tm { + tracerouteMethod = trace.ICMPTrace + fmt.Println("您将默认使用ICMP协议进行路由跟踪,如果您想使用TCP SYN进行路由跟踪,可以加入 -T 参数") + } else { + tracerouteMethod = trace.TCPTrace + } + + filePath := paramsFastTrace.File + file, err := os.Open(filePath) + if err != nil { + fmt.Println("Error opening file:", err) + return + } + defer func(file *os.File) { + err := file.Close() + if err != nil { + log.Fatal(err) + } + }(file) + var ipList []IpListElement + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + parts := strings.SplitN(line, " ", 2) + + var ip, desc string + if len(parts) == 2 { + ip = parts[0] + desc = parts[1] + } else if len(parts) == 1 { + ip = parts[0] + desc = ip // Set the description to the IP if no description is provided + } else { + fmt.Printf("Ignoring invalid line: %s\n", line) + continue + } + + parsedIP := net.ParseIP(ip) + if parsedIP == nil { + netIp, err := util.DomainLookUp(ip, "all", "", true) + if err != nil { + fmt.Printf("Ignoring invalid IP: %s\n", ip) + continue + } + if len(parts) == 1 { + desc = ip + } + ip = netIp.String() + } + + ipElem := IpListElement{ + Ip: ip, + Desc: desc, + Version4: strings.Contains(ip, "."), + } + + ipList = append(ipList, ipElem) + } + + if err := scanner.Err(); err != nil { + fmt.Println("Error reading file:", err) + } + + for _, ip := range ipList { + fmt.Printf("%s『%s』%s\n", printer.YELLOW_PREFIX, ip.Desc, printer.RESET_PREFIX) + fmt.Printf("traceroute to %s, %d hops max, %d byte packets\n", ip.Ip, paramsFastTrace.MaxHops, paramsFastTrace.PktSize) + var srcAddr string + if ip.Version4 { + if paramsFastTrace.SrcDev != "" { + dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev) + if addrs, err := dev.Addrs(); err == nil { + for _, addr := range addrs { + if (addr.(*net.IPNet).IP.To4() == nil) == false { + srcAddr = addr.(*net.IPNet).IP.String() + // 检查是否是内网IP + if !(net.ParseIP(srcAddr).IsPrivate() || + net.ParseIP(srcAddr).IsLoopback() || + net.ParseIP(srcAddr).IsLinkLocalUnicast() || + net.ParseIP(srcAddr).IsLinkLocalMulticast()) { + // 若不是则跳出 + break + } + } + } + } + } + } else { + if paramsFastTrace.SrcDev != "" { + dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev) + if addrs, err := dev.Addrs(); err == nil { + for _, addr := range addrs { + if (addr.(*net.IPNet).IP.To4() == nil) == true { + srcAddr = addr.(*net.IPNet).IP.String() + // 检查是否是内网IP + if !(net.ParseIP(srcAddr).IsPrivate() || + net.ParseIP(srcAddr).IsLoopback() || + net.ParseIP(srcAddr).IsLinkLocalUnicast() || + net.ParseIP(srcAddr).IsLinkLocalMulticast()) { + // 若不是则跳出 + break + } + } + } + } + } + } + + var conf = trace.Config{ + BeginHop: paramsFastTrace.BeginHop, + DestIP: net.ParseIP(ip.Ip), + DestPort: 80, + MaxHops: paramsFastTrace.MaxHops, + NumMeasurements: 3, + ParallelRequests: 18, + RDns: paramsFastTrace.RDns, + AlwaysWaitRDNS: paramsFastTrace.AlwaysWaitRDNS, + PacketInterval: 100, + TTLInterval: 500, + IPGeoSource: ipgeo.GetSource("LeoMoeAPI"), + Timeout: paramsFastTrace.Timeout, + SrcAddr: srcAddr, + PktSize: paramsFastTrace.PktSize, + Lang: paramsFastTrace.Lang, + } + + if oe { + fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm) + if err != nil { + return + } + defer func(fp *os.File) { + err := fp.Close() + if err != nil { + log.Fatal(err) + } + }(fp) + + log.SetOutput(fp) + log.SetFlags(0) + log.Printf("『%s』\n", ip.Desc) + log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ip.Ip, paramsFastTrace.MaxHops, paramsFastTrace.PktSize) + conf.RealtimePrinter = tracelog.RealtimePrinter + } else { + conf.RealtimePrinter = printer.RealtimePrinter + } + + _, err := trace.Traceroute(tracerouteMethod, conf) + if err != nil { + log.Fatalln(err) + } + fmt.Println() + } + +} + func (f *FastTracer) testAll() { f.testCT() println() diff --git a/util/dns_test.go b/util/dns_test.go index 568d599..fb5d6a8 100644 --- a/util/dns_test.go +++ b/util/dns_test.go @@ -13,8 +13,8 @@ func TestDNS(t *testing.T) { } func TestDomainLookUp(t *testing.T) { - ips := DomainLookUp("pek-4134.nexttrace-io-fasttrace-endpoint.win.", "all", "", false) + ips, _ := DomainLookUp("pek-4134.nexttrace-io-fasttrace-endpoint.win.", "all", "", false) fmt.Println(ips) - ips = DomainLookUp("pek-4134.nexttrace-io-fasttrace-endpoint.win.", "4", "", false) + ips, _ = DomainLookUp("pek-4134.nexttrace-io-fasttrace-endpoint.win.", "4", "", false) fmt.Println(ips) } diff --git a/util/util.go b/util/util.go index 6af2960..a26918a 100644 --- a/util/util.go +++ b/util/util.go @@ -2,6 +2,7 @@ package util import ( "context" + "errors" "fmt" "github.com/nxtrace/NTrace-core/config" "log" @@ -75,7 +76,7 @@ func LocalIPPortv6(dstip net.IP) (net.IP, int) { return nil, -1 } -func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput bool) net.IP { +func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput bool) (net.IP, error) { // ipVersion: 4, 6, all var ( r *net.Resolver @@ -101,8 +102,7 @@ func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput ips = append(ips, net.ParseIP(v)) } if err != nil { - fmt.Println("Domain " + host + " Lookup Fail.") - os.Exit(1) + return nil, errors.New("DNS lookup failed") } //var ipv6Flag = false @@ -128,7 +128,7 @@ func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput } if (len(ips) == 1) || (disableOutput) { - return ips[0] + return ips[0], nil } else { fmt.Println("Please Choose the IP You Want To TraceRoute") for i, ip := range ips { @@ -147,7 +147,7 @@ func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput fmt.Println("Your Option is invalid") os.Exit(3) } - return ips[index] + return ips[index], nil } }