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 }