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  }