mirror of
https://github.com/nxtrace/NTrace-core.git
synced 2025-08-12 06:26:39 +00:00
Compare commits
14 Commits
v0.1.0a
...
v0.1.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
433c8656a1 | ||
|
|
1542cb4b07 | ||
|
|
06ee8f7373 | ||
|
|
6792bafb02 | ||
|
|
70305caa1c | ||
|
|
671ad82780 | ||
|
|
e62575beba | ||
|
|
d92a1e10d3 | ||
|
|
971d68f93f | ||
|
|
f765dbafae | ||
|
|
ea7feab2f9 | ||
|
|
e941eaa167 | ||
|
|
46e32d697d | ||
|
|
97578e40f7 |
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -1,10 +1,11 @@
|
||||
on:
|
||||
push: # 每次 push 的时候触发
|
||||
push: # 每次带有 tag 的 push 候触发
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
name: Build Release
|
||||
jobs:
|
||||
release:
|
||||
if: startsWith(github.ref, 'refs/tags/') # 只有这次 Commit 是 创建 Tag 时,才进行后续发布操作
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master # checkout 代码
|
||||
@@ -24,4 +25,4 @@ jobs:
|
||||
dist/nexttrace_linux_amd64
|
||||
dist/nexttrace_linux_arm64
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
6
go.mod
6
go.mod
@@ -16,9 +16,9 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rodaine/table v1.0.1 // indirect
|
||||
github.com/stretchr/testify v1.7.1 // indirect
|
||||
github.com/tidwall/gjson v1.14.1 // indirect
|
||||
github.com/rodaine/table v1.0.1
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -9,6 +9,7 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -38,13 +39,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
37
main.go
37
main.go
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/xgadget-lab/nexttrace/methods/udp"
|
||||
"github.com/xgadget-lab/nexttrace/util"
|
||||
"github.com/xgadget-lab/nexttrace/util/printer"
|
||||
"github.com/xgadget-lab/nexttrace/util/reporter"
|
||||
)
|
||||
|
||||
var tcpSYNFlag = flag.Bool("T", false, "Use TCP SYN for tracerouting (default port is 80 in TCP, 53 in UDP)")
|
||||
@@ -19,7 +20,9 @@ var numMeasurements = flag.Int("q", 3, "Set the number of probes per each hop.")
|
||||
var parallelRequests = flag.Int("r", 18, "Set ParallelRequests number. It should be 1 when there is a multi-routing.")
|
||||
var maxHops = flag.Int("m", 30, "Set the max number of hops (max TTL to be reached).")
|
||||
var dataOrigin = flag.String("d", "LeoMoeAPI", "Choose IP Geograph Data Provider [LeoMoeAPI, IP.SB, IPInfo, IPInsight]")
|
||||
var displayMode = flag.String("displayMode", "table", "Choose The Display Mode [table, Besttrace]")
|
||||
var displayMode = flag.String("displayMode", "table", "Choose The Display Mode [table, classic]")
|
||||
var rdnsenable = flag.Bool("rdns", false, "Set whether rDNS will be display")
|
||||
var routeReport = flag.Bool("report", false, "Auto-Generate a Route-Path Report by TCPTraceroute")
|
||||
|
||||
func main() {
|
||||
printer.PrintCopyRight()
|
||||
@@ -40,12 +43,17 @@ func main() {
|
||||
if err != nil {
|
||||
fmt.Println("请赋予 sudo (root) 权限运行本程序")
|
||||
} else {
|
||||
if *displayMode == "Besttrace" {
|
||||
printer.TraceroutePrinter(ip, *res, *dataOrigin)
|
||||
} else if *displayMode == "table" {
|
||||
printer.TracerouteTablePrinter(ip, *res, *dataOrigin)
|
||||
if *routeReport {
|
||||
r := reporter.New(*res, ip.String())
|
||||
r.Print()
|
||||
} else {
|
||||
printer.TracerouteTablePrinter(ip, *res, *dataOrigin)
|
||||
util.Printer(&util.PrinterConfig{
|
||||
IP: ip,
|
||||
DisplayMode: *displayMode,
|
||||
DataOrigin: *dataOrigin,
|
||||
Rdnsenable: *rdnsenable,
|
||||
Results: *res,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +73,17 @@ func main() {
|
||||
if err != nil {
|
||||
fmt.Println("请赋予 sudo (root) 权限运行本程序")
|
||||
} else {
|
||||
if *displayMode == "Besttrace" {
|
||||
printer.TraceroutePrinter(ip, *res, *dataOrigin)
|
||||
} else if *displayMode == "table" {
|
||||
printer.TracerouteTablePrinter(ip, *res, *dataOrigin)
|
||||
if *routeReport {
|
||||
r := reporter.New(*res, ip.String())
|
||||
r.Print()
|
||||
} else {
|
||||
printer.TracerouteTablePrinter(ip, *res, *dataOrigin)
|
||||
util.Printer(&util.PrinterConfig{
|
||||
IP: ip,
|
||||
DisplayMode: *displayMode,
|
||||
DataOrigin: *dataOrigin,
|
||||
Rdnsenable: *rdnsenable,
|
||||
Results: *res,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +93,7 @@ func flagApply() string {
|
||||
flag.Parse()
|
||||
ipArg := flag.Args()
|
||||
if flag.NArg() != 1 {
|
||||
fmt.Println("Args Error\nUsage : ./bettertrace [-T] [-d <dataOrigin> ] [ -m <hops> ] [ -p <port> ] [ -q <probes> ] [ -r <parallelrequests> ] <hostname>")
|
||||
fmt.Println("Args Error\nUsage : ./nexttrace [-T] [-rdns] [-displayMode <displayMode>] [-d <dataOrigin> ] [ -m <hops> ] [ -p <port> ] [ -q <probes> ] [ -r <parallelrequests> ] <hostname>")
|
||||
os.Exit(2)
|
||||
}
|
||||
return ipArg[0]
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/methods"
|
||||
"github.com/xgadget-lab/nexttrace/util/printer"
|
||||
)
|
||||
|
||||
type IPGeoData struct {
|
||||
Asnumber string `json:"asnumber"`
|
||||
Country string `json:"country"`
|
||||
@@ -9,3 +16,24 @@ type IPGeoData struct {
|
||||
Owner string `json:"owner"`
|
||||
Isp string `json:"isp"`
|
||||
}
|
||||
|
||||
type PrinterConfig struct {
|
||||
IP net.IP
|
||||
DataOrigin string
|
||||
DisplayMode string
|
||||
Rdnsenable bool
|
||||
Results map[uint16][]methods.TracerouteHop
|
||||
}
|
||||
|
||||
func Printer(config *PrinterConfig) {
|
||||
switch config.DisplayMode {
|
||||
case "table":
|
||||
printer.TracerouteTablePrinter(config.IP, config.Results, config.DataOrigin, config.Rdnsenable)
|
||||
case "classic":
|
||||
printer.TraceroutePrinter(config.IP, config.Results, config.DataOrigin, config.Rdnsenable)
|
||||
case "json":
|
||||
//TracerouteJSONPrinter(config.Results, config.DataOrigin)
|
||||
default:
|
||||
printer.TraceroutePrinter(config.IP, config.Results, config.DataOrigin, config.Rdnsenable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func PrintCopyRight() {
|
||||
fmt.Println("NextTrace v0.1.0 Alpha \nxgadget-lab 实验室 zhsh (xzhsh.ch) & leo (leo.moe)")
|
||||
fmt.Println("NextTrace v0.1.0 Alpha \nxgadget-lab zhshch (xzhsh.ch) & leo (leo.moe)")
|
||||
}
|
||||
|
||||
func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string) {
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
|
||||
var dataOrigin string
|
||||
|
||||
func TraceroutePrinter(ip net.IP, res map[uint16][]methods.TracerouteHop, dataOrigin string) {
|
||||
func TraceroutePrinter(ip net.IP, res map[uint16][]methods.TracerouteHop, dataOrigin string, rdnsenable bool) {
|
||||
for hi := uint16(1); hi < 30; hi++ {
|
||||
fmt.Print(hi)
|
||||
for _, v := range res[hi] {
|
||||
hopPrinter(v)
|
||||
hopPrinter(v, rdnsenable)
|
||||
if v.Address != nil && ip.String() == v.Address.String() {
|
||||
hi = 31
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func TraceroutePrinter(ip net.IP, res map[uint16][]methods.TracerouteHop, dataOr
|
||||
}
|
||||
}
|
||||
|
||||
func hopPrinter(v2 methods.TracerouteHop) {
|
||||
func hopPrinter(v2 methods.TracerouteHop, rdnsenable bool) {
|
||||
if v2.Address == nil {
|
||||
fmt.Println("\t*")
|
||||
} else {
|
||||
@@ -32,16 +32,17 @@ func hopPrinter(v2 methods.TracerouteHop) {
|
||||
|
||||
ipStr := v2.Address.String()
|
||||
|
||||
// TODO: 判断 err 返回,并且在CLI终端提示错误
|
||||
if dataOrigin == "LeoMoeAPI" {
|
||||
// 判断 err 返回,并且在CLI终端提示错误
|
||||
switch dataOrigin {
|
||||
case "LeoMoeAPI":
|
||||
iPGeoData, err = ipgeo.LeoIP(ipStr)
|
||||
} else if dataOrigin == "IP.SB" {
|
||||
case "IP.SB":
|
||||
iPGeoData, err = ipgeo.IPSB(ipStr)
|
||||
} else if dataOrigin == "IPInfo" {
|
||||
case "IPInfo":
|
||||
iPGeoData, err = ipgeo.IPInfo(ipStr)
|
||||
} else if dataOrigin == "IPInsight" {
|
||||
case "IPInsight":
|
||||
iPGeoData, err = ipgeo.IPInSight(ipStr)
|
||||
} else {
|
||||
default:
|
||||
iPGeoData, err = ipgeo.LeoIP(ipStr)
|
||||
}
|
||||
|
||||
@@ -52,14 +53,19 @@ func hopPrinter(v2 methods.TracerouteHop) {
|
||||
geo = formatIpGeoData(ipStr, iPGeoData)
|
||||
}
|
||||
|
||||
ptr, err := net.LookupAddr(ipStr)
|
||||
|
||||
txt := "\t"
|
||||
if err != nil {
|
||||
txt += fmt.Sprint(ipStr, " ", fmt.Sprintf("%.2f", v2.RTT.Seconds()*1000), "ms ", geo)
|
||||
|
||||
if rdnsenable {
|
||||
ptr, err := net.LookupAddr(ipStr)
|
||||
if err != nil {
|
||||
txt += fmt.Sprint(ipStr, " ", fmt.Sprintf("%.2f", v2.RTT.Seconds()*1000), "ms ", geo)
|
||||
} else {
|
||||
txt += fmt.Sprint(ptr[0], " (", ipStr, ") ", fmt.Sprintf("%.2f", v2.RTT.Seconds()*1000), "ms ", geo)
|
||||
}
|
||||
} else {
|
||||
txt += fmt.Sprint(ptr[0], " (", ipStr, ") ", fmt.Sprintf("%.2f", v2.RTT.Seconds()*1000), "ms ", geo)
|
||||
txt += fmt.Sprint(ipStr, " ", fmt.Sprintf("%.2f", v2.RTT.Seconds()*1000), "ms ", geo)
|
||||
}
|
||||
|
||||
fmt.Println(txt)
|
||||
}
|
||||
}
|
||||
@@ -74,26 +80,35 @@ func formatIpGeoData(ip string, data *ipgeo.IPGeoData) string {
|
||||
}
|
||||
|
||||
// TODO: 判断阿里云和腾讯云内网,数据不足,有待进一步完善
|
||||
if strings.HasPrefix(ip, "9.31.") || strings.HasPrefix(ip, "11.72.") {
|
||||
if strings.HasPrefix(ip, "9.") {
|
||||
res = append(res, "局域网", "腾讯云")
|
||||
} else if strings.HasPrefix(ip, "11.13.") {
|
||||
} else if strings.HasPrefix(ip, "11.") {
|
||||
res = append(res, "局域网", "阿里云")
|
||||
} else if data.Country == "" {
|
||||
res = append(res, "局域网")
|
||||
} else {
|
||||
// 有些IP的归属信息为空,这个时候将ISP的信息填入
|
||||
if data.Owner == "" {
|
||||
data.Owner = data.Isp
|
||||
}
|
||||
if data.District != "" {
|
||||
data.City = data.City + ", " + data.District
|
||||
}
|
||||
res = append(res, data.Country)
|
||||
if data.Prov == "" && data.City == "" {
|
||||
// anyCast或是骨干网数据不应该有国家信息
|
||||
data.Owner = data.Owner + ", " + data.Owner
|
||||
} else {
|
||||
// 非骨干网正常填入IP的国家信息数据
|
||||
res = append(res, data.Country)
|
||||
}
|
||||
|
||||
if data.Prov != "" {
|
||||
res = append(res, data.Prov)
|
||||
}
|
||||
if data.City != "" {
|
||||
res = append(res, data.City)
|
||||
}
|
||||
|
||||
if data.Owner != "" {
|
||||
res = append(res, data.Owner)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package printer
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/rodaine/table"
|
||||
@@ -22,12 +23,12 @@ type rowData struct {
|
||||
Owner string
|
||||
}
|
||||
|
||||
func TracerouteTablePrinter(ip net.IP, res map[uint16][]methods.TracerouteHop, dataOrigin string) {
|
||||
func TracerouteTablePrinter(ip net.IP, res map[uint16][]methods.TracerouteHop, dataOrigin string, rdnsenable bool) {
|
||||
// 初始化表格
|
||||
tbl := New()
|
||||
for hi := uint16(1); hi < 30; hi++ {
|
||||
for _, v := range res[hi] {
|
||||
data := tableDataGenerator(v)
|
||||
data := tableDataGenerator(v, rdnsenable)
|
||||
tbl.AddRow(data.Hop, data.IP, data.Latency, data.Asnumber, data.Country, data.Prov, data.City, data.Owner)
|
||||
if v.Address != nil && ip.String() == v.Address.String() {
|
||||
hi = 31
|
||||
@@ -48,7 +49,7 @@ func New() table.Table {
|
||||
return tbl
|
||||
}
|
||||
|
||||
func tableDataGenerator(v2 methods.TracerouteHop) *rowData {
|
||||
func tableDataGenerator(v2 methods.TracerouteHop, rdnsenable bool) *rowData {
|
||||
if v2.Address == nil {
|
||||
return &rowData{
|
||||
Hop: int64(v2.TTL),
|
||||
@@ -62,29 +63,51 @@ func tableDataGenerator(v2 methods.TracerouteHop) *rowData {
|
||||
|
||||
ipStr := v2.Address.String()
|
||||
|
||||
if strings.HasPrefix(ipStr, "9.") {
|
||||
return &rowData{
|
||||
Hop: int64(v2.TTL),
|
||||
IP: ipStr,
|
||||
Latency: lantency,
|
||||
Country: "局域网",
|
||||
Owner: "腾讯云",
|
||||
}
|
||||
} else if strings.HasPrefix(ipStr, "11.") {
|
||||
return &rowData{
|
||||
Hop: int64(v2.TTL),
|
||||
IP: ipStr,
|
||||
Latency: lantency,
|
||||
Country: "局域网",
|
||||
Owner: "阿里云",
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 判断 err 返回,并且在CLI终端提示错误
|
||||
if dataOrigin == "LeoMoeAPI" {
|
||||
switch dataOrigin {
|
||||
case "LeoMoeAPI":
|
||||
iPGeoData, err = ipgeo.LeoIP(ipStr)
|
||||
} else if dataOrigin == "IP.SB" {
|
||||
case "IP.SB":
|
||||
iPGeoData, err = ipgeo.IPSB(ipStr)
|
||||
} else if dataOrigin == "IPInfo" {
|
||||
case "IPInfo":
|
||||
iPGeoData, err = ipgeo.IPInfo(ipStr)
|
||||
} else if dataOrigin == "IPInsight" {
|
||||
case "IPInsight":
|
||||
iPGeoData, err = ipgeo.IPInSight(ipStr)
|
||||
} else {
|
||||
default:
|
||||
iPGeoData, err = ipgeo.LeoIP(ipStr)
|
||||
}
|
||||
|
||||
ptr, err_LookupAddr := net.LookupAddr(ipStr)
|
||||
if rdnsenable {
|
||||
ptr, err_LookupAddr := net.LookupAddr(ipStr)
|
||||
if err_LookupAddr != nil {
|
||||
IP = fmt.Sprint(ipStr)
|
||||
} else {
|
||||
IP = fmt.Sprint(ptr[0], " (", ipStr, ") ")
|
||||
}
|
||||
} else {
|
||||
IP = fmt.Sprint(ipStr)
|
||||
}
|
||||
|
||||
lantency = fmt.Sprintf("%.2fms", v2.RTT.Seconds()*1000)
|
||||
|
||||
if err_LookupAddr != nil {
|
||||
IP = fmt.Sprint(ipStr)
|
||||
} else {
|
||||
IP = fmt.Sprint(ptr[0], " (", ipStr, ") ")
|
||||
}
|
||||
|
||||
if iPGeoData.Owner == "" {
|
||||
iPGeoData.Owner = iPGeoData.Isp
|
||||
}
|
||||
|
||||
127
util/reporter/reporter.go
Normal file
127
util/reporter/reporter.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package reporter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/ipgeo"
|
||||
"github.com/xgadget-lab/nexttrace/methods"
|
||||
)
|
||||
|
||||
type Reporter interface {
|
||||
Print()
|
||||
}
|
||||
|
||||
func New(rs map[uint16][]methods.TracerouteHop, ip string) Reporter {
|
||||
experimentTag()
|
||||
r := reporter{
|
||||
routeResult: rs,
|
||||
targetIP: ip,
|
||||
}
|
||||
return &r
|
||||
}
|
||||
|
||||
type reporter struct {
|
||||
targetIP string
|
||||
routeReport map[uint16][]routeReportNode
|
||||
routeResult map[uint16][]methods.TracerouteHop
|
||||
}
|
||||
|
||||
type routeReportNode struct {
|
||||
asn string
|
||||
isp string
|
||||
geo []string
|
||||
ix bool
|
||||
}
|
||||
|
||||
func experimentTag() {
|
||||
fmt.Println("Route-Path是一个实验性功能,我们的IP库不能很好的支持我们提供骨干网的地理位置信息,所以IP位置有时候会异常")
|
||||
}
|
||||
|
||||
func reduceRouteReportNode(ip string, ipGeoData ipgeo.IPGeoData) (routeReportNode, error) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if strings.HasPrefix(ip, "59.43") {
|
||||
rpn.asn = "4809"
|
||||
} else {
|
||||
rpn.asn = ipGeoData.Asnumber
|
||||
}
|
||||
|
||||
if ipGeoData.Country == "" || ipGeoData.City == "" {
|
||||
return rpn, errors.New("GeoData Search Failed")
|
||||
} else {
|
||||
rpn.geo = []string{ipGeoData.Country, ipGeoData.City}
|
||||
}
|
||||
if ipGeoData.Isp == "" {
|
||||
rpn.isp = ipGeoData.Owner
|
||||
} else {
|
||||
rpn.isp = ipGeoData.Isp
|
||||
}
|
||||
return rpn, nil
|
||||
}
|
||||
|
||||
func (r *reporter) InitialBaseData() Reporter {
|
||||
var nodeIndex uint16 = 1
|
||||
reportNodes := map[uint16][]routeReportNode{}
|
||||
for i := uint16(1); int(i) < len(r.routeResult)+1; i++ {
|
||||
traceHop := r.routeResult[i][0]
|
||||
if traceHop.Success {
|
||||
currentIP := traceHop.Address.String()
|
||||
ipGeoData, _ := ipgeo.LeoIP(currentIP)
|
||||
rpn, err := reduceRouteReportNode(currentIP, *ipGeoData)
|
||||
if err == nil {
|
||||
reportNodes[nodeIndex] = append(reportNodes[nodeIndex], rpn)
|
||||
nodeIndex += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
r.routeReport = reportNodes
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *reporter) Print() {
|
||||
r.InitialBaseData()
|
||||
//fmt.Println(r.routeReport)
|
||||
for i := uint16(1); int(i) < len(r.routeReport)+1; i++ {
|
||||
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]
|
||||
if nodeReportBefore.asn == nodeReport.asn {
|
||||
// Same ASN but Coutry or City Changed
|
||||
if nodeReportBefore.geo[0] != nodeReport.geo[0] {
|
||||
fmt.Printf("』→ %s『%s", nodeReport.geo[0], nodeReport.geo[1])
|
||||
} else {
|
||||
if nodeReportBefore.geo[1] != nodeReport.geo[1] {
|
||||
fmt.Printf(" → %s", nodeReport.geo[1])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("』」")
|
||||
if int(i) != len(r.routeReport)+1 {
|
||||
fmt.Printf("\n ╭╯\n ╰")
|
||||
}
|
||||
if nodeReport.ix {
|
||||
fmt.Printf("AS%s \033[42;37mIXP\033[0m %s「%s『%s", nodeReport.asn, nodeReport.isp, nodeReport.geo[0], nodeReport.geo[1])
|
||||
} else {
|
||||
fmt.Printf("AS%s %s「%s『%s", nodeReport.asn, nodeReport.isp, nodeReport.geo[0], nodeReport.geo[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("』」")
|
||||
}
|
||||
31
util/reporter/reporter_test.go
Normal file
31
util/reporter/reporter_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package reporter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/methods"
|
||||
"github.com/xgadget-lab/nexttrace/methods/tcp"
|
||||
"github.com/xgadget-lab/nexttrace/util"
|
||||
)
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
ip := util.DomainLookUp("213.226.68.73")
|
||||
tcpTraceroute := tcp.New(ip, methods.TracerouteConfig{
|
||||
MaxHops: uint16(30),
|
||||
NumMeasurements: uint16(1),
|
||||
ParallelRequests: uint16(12),
|
||||
Port: 80,
|
||||
Timeout: time.Second / 2,
|
||||
})
|
||||
res, _ := tcpTraceroute.Start()
|
||||
util.Printer(&util.PrinterConfig{
|
||||
IP: ip,
|
||||
DisplayMode: "classic",
|
||||
DataOrigin: "LeoMoeAPI",
|
||||
Rdnsenable: true,
|
||||
Results: *res,
|
||||
})
|
||||
r := New(*res, ip.String())
|
||||
r.Print()
|
||||
}
|
||||
Reference in New Issue
Block a user