From ebd435db53ae80ac8004e14f058c39129d61d5d1 Mon Sep 17 00:00:00 2001 From: sjlleo Date: Wed, 25 May 2022 10:48:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20report=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=92=8CrDNS=E5=8F=8D=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reporter/reporter.go | 96 +++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/reporter/reporter.go b/reporter/reporter.go index 7513319..b9fedbe 100644 --- a/reporter/reporter.go +++ b/reporter/reporter.go @@ -1,10 +1,10 @@ package reporter import ( - "errors" "fmt" "net" "strings" + "sync" "github.com/xgadget-lab/nexttrace/ipgeo" "github.com/xgadget-lab/nexttrace/trace" @@ -24,9 +24,12 @@ func New(rs *trace.Result, ip string) Reporter { } type reporter struct { - targetIP string - routeReport map[uint16][]routeReportNode - routeResult *trace.Result + targetTTL uint16 + targetIP string + routeReport map[uint16][]routeReportNode + routeReportLock sync.Mutex + routeResult *trace.Result + wg sync.WaitGroup } type routeReportNode struct { @@ -40,30 +43,42 @@ func experimentTag() { fmt.Println("Route-Path 功能实验室") } -func (r *reporter) generateRouteReportNode(ip string, ipGeoData ipgeo.IPGeoData) (routeReportNode, error) { - rpn := routeReportNode{} - go func() { - ptr, err := net.LookupAddr(ip) - if err == nil { - if strings.Contains(strings.ToLower(ptr[0]), "ix") { - rpn.ix = true - } else { - rpn.ix = false - } - } - }() +func (r *reporter) generateRouteReportNode(ip string, ipGeoData ipgeo.IPGeoData, ttl uint16) { + var success bool = true + + defer r.wg.Done() + + rpn := routeReportNode{} + ptr, err := net.LookupAddr(ip) + + if err == nil { + if strings.Contains(strings.ToLower(ptr[0]), "ix") { + rpn.ix = true + } else { + rpn.ix = false + } + } + // TODO: 这种写法不好,后面再重构一下 + // 判断反向解析的域名中又或者是IP地理位置数据库中,是否出现了 IX if strings.Contains(strings.ToLower(ipGeoData.Isp), "exchange") || strings.Contains(strings.ToLower(ipGeoData.Isp), "ix") || strings.Contains(strings.ToLower(ipGeoData.Owner), "exchange") || strings.Contains(strings.ToLower(ipGeoData.Owner), "ix") { rpn.ix = true } + + // TODO: 正则判断POP并且提取带宽大小等信息 + + // CN2 需要特殊处理,因为他们很多没有ASN + // 但是目前这种写法是不规范的,属于凭空标记4809的IP + // TODO: 用更好的方式显示 CN2 骨干网的路由 Path if strings.HasPrefix(ip, "59.43") { rpn.asn = "4809" } else { rpn.asn = ipGeoData.Asnumber } + // 无论最后一跳是否为存在地理位置信息(AnyCast),都应该给予显示 if (ipGeoData.Country == "" || ipGeoData.Country == "LAN Address" || ipGeoData.Country == "-") && ip != r.targetIP { - return rpn, errors.New("GeoData Search Failed") + success = false } else { if ipGeoData.City == "" { rpn.geo = []string{ipGeoData.Country, ipGeoData.Prov} @@ -80,35 +95,55 @@ func (r *reporter) generateRouteReportNode(ip string, ipGeoData ipgeo.IPGeoData) } else { rpn.isp = ipGeoData.Isp } - return rpn, nil + + // 有效记录 + if success { + // 锁住资源,防止同时写panic + r.routeReportLock.Lock() + // 添加到MAP中 + r.routeReport[ttl] = append(r.routeReport[ttl], rpn) + // 写入完成,解锁释放资源给其他协程 + r.routeReportLock.Unlock() + } } func (r *reporter) InitialBaseData() Reporter { - var nodeIndex uint16 = 1 reportNodes := map[uint16][]routeReportNode{} - for i := uint16(0); int(i) < len(r.routeResult.Hops); i++ { + + r.routeReport = reportNodes + r.targetTTL = uint16(len(r.routeResult.Hops)) + + for i := uint16(0); i < r.targetTTL; i++ { traceHop := r.routeResult.Hops[i][0] if traceHop.Success { currentIP := traceHop.Address.String() - rpn, err := r.generateRouteReportNode(currentIP, *traceHop.Geo) - if err == nil { - reportNodes[nodeIndex] = append(reportNodes[nodeIndex], rpn) - nodeIndex += 1 - } + r.wg.Add(1) + go r.generateRouteReportNode(currentIP, *traceHop.Geo, i) } } - r.routeReport = reportNodes + + // 等待所有的子协程运行完毕 + r.wg.Wait() return r } func (r *reporter) Print() { + var beforeActiveTTL uint16 = 1 r.InitialBaseData() - for i := uint16(1); int(i) < len(r.routeReport)+1; i++ { + + for i := uint16(1); i < r.targetTTL; i++ { + // 计算该TTL内的数据长度,如果为0,则代表没有有效数据 + if len(r.routeReport[i]) == 0 { + // 跳过改跃点的数据整理 + continue + } nodeReport := r.routeReport[i][0] + if i == 1 { fmt.Printf("AS%s %s「%s『%s", nodeReport.asn, nodeReport.isp, nodeReport.geo[0], nodeReport.geo[1]) } else { - nodeReportBefore := r.routeReport[i-1][0] + nodeReportBefore := r.routeReport[beforeActiveTTL][0] + // ASN 相同,同个 ISP 内部的数据传递 if nodeReportBefore.asn == nodeReport.asn { // Same ASN but Coutry or City Changed if nodeReportBefore.geo[0] != nodeReport.geo[0] { @@ -119,8 +154,11 @@ func (r *reporter) Print() { } } } else { + // ASN 不同,跨 ISP 的数据传递,这里可能会出现 POP、IP Transit、Peer、Exchange fmt.Printf("』」") if int(i) != len(r.routeReport)+1 { + // 部分 Shell 客户端可能无法很好的展示这个特殊字符 + // TODO: 寻找其他替代字符 fmt.Printf("\n ╭╯\n ╰") } if nodeReport.ix { @@ -130,6 +168,8 @@ func (r *reporter) Print() { } } } + // 标记为最新的一个有效跃点 + beforeActiveTTL = i } fmt.Println("』」") }