github.com/nxtrace/NTrace-core@v1.3.1-0.20240513132635-39169291e8c9/printer/classic_printer.go (about) 1 package printer 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/nxtrace/NTrace-core/trace" 8 ) 9 10 type HopInfo int 11 12 const ( 13 General HopInfo = 0 14 IXP HopInfo = 1 15 Peer HopInfo = 2 16 PoP HopInfo = 3 17 Aboard HopInfo = 4 18 ) 19 20 func findLatestAvailableHop(res *trace.Result, ttl int, probesIndex int) int { 21 for ttl > 0 { 22 // 查找上一个跃点是不是有效结果 23 ttl-- 24 // 判断此TTL跃点是否有效并判断地理位置结构体是否已经初始化 25 if len(res.Hops[ttl]) != 0 && res.Hops[ttl][probesIndex].Success && res.Hops[ttl][probesIndex].Geo != nil { 26 // TTL虽有效,但地理位置API没有能够正确返回数据,依旧不能视为有效数据 27 if res.Hops[ttl][probesIndex].Geo.Country == "" { 28 // 跳过继续寻找上一个有效跃点 29 continue 30 } 31 return ttl 32 } 33 } 34 // 没找到 35 return -1 36 } 37 38 func unifyName(name string) string { 39 if name == "China" || name == "CN" { 40 return "中国" 41 } else if name == "Hong kong" || name == "香港" || name == "Central and Western" { 42 return "中国香港" 43 } else if name == "Taiwan" || name == "台湾" { 44 return "中国台湾" 45 } else { 46 return name 47 } 48 } 49 50 func chinaISPPeer(hostname string) bool { 51 var keyWords = []string{"china", "ct", "cu", "cm", "cnc", "4134", "4837", "4809", "9929"} 52 for _, k := range keyWords { 53 if strings.Contains(strings.ToLower(hostname), k) { 54 return true 55 } 56 } 57 return false 58 } 59 60 func chinaMainland(h trace.Hop) bool { 61 if unifyName(h.Geo.Country) == "中国" && unifyName(h.Geo.Prov) != "中国香港" && unifyName(h.Geo.Prov) != "中国台湾" { 62 return true 63 } else { 64 return false 65 } 66 } 67 68 func makeHopsType(res *trace.Result, ttl int) map[int]HopInfo { 69 // 创建一个字典,存放所有当前TTL的跃点类型集合 70 hopProbesMap := make(map[int]HopInfo) 71 for i := range res.Hops[ttl] { 72 // 判断是否res.Hops[ttl][i]是一个有效的跃点并且地理位置信息已经初始化 73 if res.Hops[ttl][i].Success && res.Hops[ttl][i].Geo != nil { 74 if availableTTL := findLatestAvailableHop(res, ttl, i); availableTTL != -1 { 75 switch { 76 case strings.Contains(res.Hops[ttl][i].Geo.District, "IXP") || strings.Contains(strings.ToLower(res.Hops[ttl][i].Hostname), "ix"): 77 hopProbesMap[i] = IXP 78 case strings.Contains(res.Hops[ttl][i].Geo.District, "Peer") || chinaISPPeer(res.Hops[ttl][i].Hostname): 79 hopProbesMap[i] = Peer 80 case strings.Contains(res.Hops[ttl][i].Geo.District, "PoP"): 81 hopProbesMap[i] = PoP 82 // 2个有效跃点必须都为有效数据,如果当前跳没有地理位置信息或者为局域网,不能视为有效节点 83 case res.Hops[availableTTL][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "" && 84 // 一个跃点在中国大陆,另外一个跃点在其他地区,则可以推断出数据包跨境 85 chinaMainland(res.Hops[availableTTL][i]) != chinaMainland(res.Hops[ttl][i]): 86 // TODO: 将先后2跳跃点信息汇报给API,以完善相关数据 87 hopProbesMap[i] = Aboard 88 } 89 } else { 90 hopProbesMap[i] = General 91 } 92 } 93 } 94 95 return hopProbesMap 96 } 97 98 func ClassicPrinter(res *trace.Result, ttl int) { 99 fmt.Print(ttl + 1) 100 hopsTypeMap := makeHopsType(res, ttl) 101 for i := range res.Hops[ttl] { 102 HopPrinter(res.Hops[ttl][i], hopsTypeMap[i]) 103 } 104 }