github.com/nxtrace/NTrace-core@v1.3.1-0.20240513132635-39169291e8c9/fast_trace/fast_trace.go (about)

     1  package fastTrace
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"github.com/fatih/color"
     7  	"github.com/nxtrace/NTrace-core/ipgeo"
     8  	"github.com/nxtrace/NTrace-core/printer"
     9  	"github.com/nxtrace/NTrace-core/trace"
    10  	"github.com/nxtrace/NTrace-core/tracelog"
    11  	"github.com/nxtrace/NTrace-core/util"
    12  	"github.com/nxtrace/NTrace-core/wshandle"
    13  	"log"
    14  	"net"
    15  	"os"
    16  	"os/signal"
    17  	"strings"
    18  	"time"
    19  )
    20  
    21  type FastTracer struct {
    22  	TracerouteMethod trace.Method
    23  	ParamsFastTrace  ParamsFastTrace
    24  }
    25  
    26  type ParamsFastTrace struct {
    27  	SrcDev         string
    28  	SrcAddr        string
    29  	BeginHop       int
    30  	MaxHops        int
    31  	RDns           bool
    32  	AlwaysWaitRDNS bool
    33  	Lang           string
    34  	PktSize        int
    35  	Timeout        time.Duration
    36  	File           string
    37  }
    38  
    39  type IpListElement struct {
    40  	Ip       string
    41  	Desc     string
    42  	Version4 bool // true for IPv4, false for IPv6
    43  }
    44  
    45  var oe = false
    46  
    47  func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
    48  	fmt.Fprintf(color.Output, "%s\n", color.New(color.FgYellow, color.Bold).Sprintf("『%s %s 』", location, ispCollection.ISPName))
    49  	fmt.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IP, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize)
    50  
    51  	ip, err := util.DomainLookUp(ispCollection.IP, "4", "", true)
    52  	if err != nil {
    53  		log.Fatal(err)
    54  	}
    55  	var conf = trace.Config{
    56  		BeginHop:         f.ParamsFastTrace.BeginHop,
    57  		DestIP:           ip,
    58  		DestPort:         80,
    59  		MaxHops:          f.ParamsFastTrace.MaxHops,
    60  		NumMeasurements:  3,
    61  		ParallelRequests: 18,
    62  		RDns:             f.ParamsFastTrace.RDns,
    63  		AlwaysWaitRDNS:   f.ParamsFastTrace.AlwaysWaitRDNS,
    64  		PacketInterval:   100,
    65  		TTLInterval:      500,
    66  		IPGeoSource:      ipgeo.GetSource("LeoMoeAPI"),
    67  		Timeout:          f.ParamsFastTrace.Timeout,
    68  		SrcAddr:          f.ParamsFastTrace.SrcAddr,
    69  		PktSize:          f.ParamsFastTrace.PktSize,
    70  		Lang:             f.ParamsFastTrace.Lang,
    71  	}
    72  
    73  	if oe {
    74  		fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
    75  		if err != nil {
    76  			return
    77  		}
    78  		defer func(fp *os.File) {
    79  			err := fp.Close()
    80  			if err != nil {
    81  				log.Fatal(err)
    82  			}
    83  		}(fp)
    84  
    85  		log.SetOutput(fp)
    86  		log.SetFlags(0)
    87  		log.Printf("『%s %s 』\n", location, ispCollection.ISPName)
    88  		log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ispCollection.IP, f.ParamsFastTrace.MaxHops, f.ParamsFastTrace.PktSize)
    89  		conf.RealtimePrinter = tracelog.RealtimePrinter
    90  	} else {
    91  		conf.RealtimePrinter = printer.RealtimePrinter
    92  	}
    93  
    94  	_, err = trace.Traceroute(f.TracerouteMethod, conf)
    95  
    96  	if err != nil {
    97  		log.Fatal(err)
    98  	}
    99  	fmt.Println()
   100  }
   101  
   102  func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) {
   103  	// tm means tcp mode
   104  	var c string
   105  	oe = outEnable
   106  
   107  	if paramsFastTrace.File != "" {
   108  		testFile(paramsFastTrace, tm)
   109  		return
   110  	}
   111  
   112  	fmt.Println("Hi,欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂,我们设置的测试目标有限,建议普通用户自测以获得更加精准的路由情况")
   113  	fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6")
   114  	fmt.Print("请选择选项:")
   115  	_, err := fmt.Scanln(&c)
   116  	if err != nil {
   117  		c = "1"
   118  	}
   119  	if c == "2" {
   120  		if paramsFastTrace.SrcDev != "" {
   121  			dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev)
   122  			if addrs, err := dev.Addrs(); err == nil {
   123  				for _, addr := range addrs {
   124  					if (addr.(*net.IPNet).IP.To4() == nil) == true {
   125  						paramsFastTrace.SrcAddr = addr.(*net.IPNet).IP.String()
   126  						// 检查是否是内网IP
   127  						if !(net.ParseIP(paramsFastTrace.SrcAddr).IsPrivate() ||
   128  							net.ParseIP(paramsFastTrace.SrcAddr).IsLoopback() ||
   129  							net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalUnicast() ||
   130  							net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalMulticast()) {
   131  							// 若不是则跳出
   132  							break
   133  						}
   134  					}
   135  				}
   136  			}
   137  		}
   138  		FastTestv6(tm, outEnable, paramsFastTrace)
   139  		return
   140  	}
   141  	if paramsFastTrace.SrcDev != "" {
   142  		dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev)
   143  		if addrs, err := dev.Addrs(); err == nil {
   144  			for _, addr := range addrs {
   145  				if (addr.(*net.IPNet).IP.To4() == nil) == false {
   146  					paramsFastTrace.SrcAddr = addr.(*net.IPNet).IP.String()
   147  					// 检查是否是内网IP
   148  					if !(net.ParseIP(paramsFastTrace.SrcAddr).IsPrivate() ||
   149  						net.ParseIP(paramsFastTrace.SrcAddr).IsLoopback() ||
   150  						net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalUnicast() ||
   151  						net.ParseIP(paramsFastTrace.SrcAddr).IsLinkLocalMulticast()) {
   152  						// 若不是则跳出
   153  						break
   154  					}
   155  				}
   156  			}
   157  		}
   158  	}
   159  
   160  	fmt.Println("您想测试哪些ISP的路由?\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网\n6. 全部")
   161  	fmt.Print("请选择选项:")
   162  	_, err = fmt.Scanln(&c)
   163  	if err != nil {
   164  		c = "1"
   165  	}
   166  
   167  	ft := FastTracer{
   168  		ParamsFastTrace: paramsFastTrace,
   169  	}
   170  
   171  	// 建立 WebSocket 连接
   172  	w := wshandle.New()
   173  	w.Interrupt = make(chan os.Signal, 1)
   174  	signal.Notify(w.Interrupt, os.Interrupt)
   175  	defer func() {
   176  		w.Conn.Close()
   177  	}()
   178  
   179  	if !tm {
   180  		ft.TracerouteMethod = trace.ICMPTrace
   181  		fmt.Println("您将默认使用ICMP协议进行路由跟踪,如果您想使用TCP SYN进行路由跟踪,可以加入 -T 参数")
   182  	} else {
   183  		ft.TracerouteMethod = trace.TCPTrace
   184  	}
   185  
   186  	switch c {
   187  	case "1":
   188  		ft.testFast()
   189  	case "2":
   190  		ft.testCT()
   191  	case "3":
   192  		ft.testCU()
   193  	case "4":
   194  		ft.testCM()
   195  	case "5":
   196  		ft.testEDU()
   197  	case "6":
   198  		ft.testAll()
   199  	default:
   200  		ft.testFast()
   201  	}
   202  }
   203  
   204  func testFile(paramsFastTrace ParamsFastTrace, tm bool) {
   205  	// 建立 WebSocket 连接
   206  	w := wshandle.New()
   207  	w.Interrupt = make(chan os.Signal, 1)
   208  	signal.Notify(w.Interrupt, os.Interrupt)
   209  	defer func() {
   210  		w.Conn.Close()
   211  	}()
   212  
   213  	var tracerouteMethod trace.Method
   214  	if !tm {
   215  		tracerouteMethod = trace.ICMPTrace
   216  		fmt.Println("您将默认使用ICMP协议进行路由跟踪,如果您想使用TCP SYN进行路由跟踪,可以加入 -T 参数")
   217  	} else {
   218  		tracerouteMethod = trace.TCPTrace
   219  	}
   220  
   221  	filePath := paramsFastTrace.File
   222  	file, err := os.Open(filePath)
   223  	if err != nil {
   224  		fmt.Println("Error opening file:", err)
   225  		return
   226  	}
   227  	defer func(file *os.File) {
   228  		err := file.Close()
   229  		if err != nil {
   230  			log.Fatal(err)
   231  		}
   232  	}(file)
   233  	var ipList []IpListElement
   234  	scanner := bufio.NewScanner(file)
   235  	for scanner.Scan() {
   236  		line := scanner.Text()
   237  		parts := strings.SplitN(line, " ", 2)
   238  
   239  		var ip, desc string
   240  		if len(parts) == 2 {
   241  			ip = parts[0]
   242  			desc = parts[1]
   243  		} else if len(parts) == 1 {
   244  			ip = parts[0]
   245  			desc = ip // Set the description to the IP if no description is provided
   246  		} else {
   247  			fmt.Printf("Ignoring invalid line: %s\n", line)
   248  			continue
   249  		}
   250  
   251  		parsedIP := net.ParseIP(ip)
   252  		if parsedIP == nil {
   253  			netIp, err := util.DomainLookUp(ip, "all", "", true)
   254  			if err != nil {
   255  				fmt.Printf("Ignoring invalid IP: %s\n", ip)
   256  				continue
   257  			}
   258  			if len(parts) == 1 {
   259  				desc = ip
   260  			}
   261  			ip = netIp.String()
   262  		}
   263  
   264  		ipElem := IpListElement{
   265  			Ip:       ip,
   266  			Desc:     desc,
   267  			Version4: strings.Contains(ip, "."),
   268  		}
   269  
   270  		ipList = append(ipList, ipElem)
   271  	}
   272  
   273  	if err := scanner.Err(); err != nil {
   274  		fmt.Println("Error reading file:", err)
   275  	}
   276  
   277  	for _, ip := range ipList {
   278  		fmt.Fprintf(color.Output, "%s\n",
   279  			color.New(color.FgYellow, color.Bold).Sprint("『 "+ip.Desc+"』"),
   280  		)
   281  		if util.EnableHidDstIP == "" {
   282  			fmt.Printf("traceroute to %s, %d hops max, %d bytes packets\n", ip.Ip, paramsFastTrace.MaxHops, paramsFastTrace.PktSize)
   283  		} else {
   284  			fmt.Printf("traceroute to %s, %d hops max, %d bytes packets\n", util.HideIPPart(ip.Ip), paramsFastTrace.MaxHops, paramsFastTrace.PktSize)
   285  		}
   286  		var srcAddr string
   287  		if ip.Version4 {
   288  			if paramsFastTrace.SrcDev != "" {
   289  				dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev)
   290  				if addrs, err := dev.Addrs(); err == nil {
   291  					for _, addr := range addrs {
   292  						if (addr.(*net.IPNet).IP.To4() == nil) == false {
   293  							srcAddr = addr.(*net.IPNet).IP.String()
   294  							// 检查是否是内网IP
   295  							if !(net.ParseIP(srcAddr).IsPrivate() ||
   296  								net.ParseIP(srcAddr).IsLoopback() ||
   297  								net.ParseIP(srcAddr).IsLinkLocalUnicast() ||
   298  								net.ParseIP(srcAddr).IsLinkLocalMulticast()) {
   299  								// 若不是则跳出
   300  								break
   301  							}
   302  						}
   303  					}
   304  				}
   305  			}
   306  		} else {
   307  			if paramsFastTrace.SrcDev != "" {
   308  				dev, _ := net.InterfaceByName(paramsFastTrace.SrcDev)
   309  				if addrs, err := dev.Addrs(); err == nil {
   310  					for _, addr := range addrs {
   311  						if (addr.(*net.IPNet).IP.To4() == nil) == true {
   312  							srcAddr = addr.(*net.IPNet).IP.String()
   313  							// 检查是否是内网IP
   314  							if !(net.ParseIP(srcAddr).IsPrivate() ||
   315  								net.ParseIP(srcAddr).IsLoopback() ||
   316  								net.ParseIP(srcAddr).IsLinkLocalUnicast() ||
   317  								net.ParseIP(srcAddr).IsLinkLocalMulticast()) {
   318  								// 若不是则跳出
   319  								break
   320  							}
   321  						}
   322  					}
   323  				}
   324  			}
   325  		}
   326  
   327  		var conf = trace.Config{
   328  			BeginHop:         paramsFastTrace.BeginHop,
   329  			DestIP:           net.ParseIP(ip.Ip),
   330  			DestPort:         80,
   331  			MaxHops:          paramsFastTrace.MaxHops,
   332  			NumMeasurements:  3,
   333  			ParallelRequests: 18,
   334  			RDns:             paramsFastTrace.RDns,
   335  			AlwaysWaitRDNS:   paramsFastTrace.AlwaysWaitRDNS,
   336  			PacketInterval:   100,
   337  			TTLInterval:      500,
   338  			IPGeoSource:      ipgeo.GetSource("LeoMoeAPI"),
   339  			Timeout:          paramsFastTrace.Timeout,
   340  			SrcAddr:          srcAddr,
   341  			PktSize:          paramsFastTrace.PktSize,
   342  			Lang:             paramsFastTrace.Lang,
   343  		}
   344  
   345  		if oe {
   346  			fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
   347  			if err != nil {
   348  				return
   349  			}
   350  			log.SetOutput(fp)
   351  			log.SetFlags(0)
   352  			log.Printf("『%s』\n", ip.Desc)
   353  			log.Printf("traceroute to %s, %d hops max, %d byte packets\n", ip.Ip, paramsFastTrace.MaxHops, paramsFastTrace.PktSize)
   354  			conf.RealtimePrinter = tracelog.RealtimePrinter
   355  			err = fp.Close()
   356  			if err != nil {
   357  				log.Fatal(err)
   358  			}
   359  		} else {
   360  			conf.RealtimePrinter = printer.RealtimePrinter
   361  		}
   362  
   363  		_, err := trace.Traceroute(tracerouteMethod, conf)
   364  		if err != nil {
   365  			log.Fatalln(err)
   366  		}
   367  		fmt.Println()
   368  	}
   369  
   370  }
   371  
   372  func (f *FastTracer) testAll() {
   373  	f.testCT()
   374  	println()
   375  	f.testCU()
   376  	println()
   377  	f.testCM()
   378  	println()
   379  	f.testEDU()
   380  }
   381  
   382  func (f *FastTracer) testCT() {
   383  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CT163)
   384  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CT163)
   385  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CTCN2)
   386  	f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.CT163)
   387  	f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Guangzhou.CT163)
   388  }
   389  
   390  func (f *FastTracer) testCU() {
   391  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU169)
   392  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU9929)
   393  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CU169)
   394  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CU9929)
   395  	f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.CU169)
   396  	f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Guangzhou.CU169)
   397  }
   398  
   399  func (f *FastTracer) testCM() {
   400  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CM)
   401  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CMIN2)
   402  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CM)
   403  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CMIN2)
   404  	f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.CM)
   405  	f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Guangzhou.CM)
   406  }
   407  
   408  func (f *FastTracer) testEDU() {
   409  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
   410  	f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.EDU)
   411  	f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.EDU)
   412  	// 科技网暂时算在EDU里面,等拿到了足够多的数据再分离出去,单独用于测试
   413  	f.tracert(TestIPsCollection.Hefei.Location, TestIPsCollection.Hefei.CST)
   414  }
   415  
   416  func (f *FastTracer) testFast() {
   417  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CT163)
   418  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU169)
   419  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CM)
   420  	f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
   421  }