diff --git a/README.md b/README.md index 5716cd7..35365c5 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,8 @@ nexttrace -T -q 2 -r 1 -table -report 2001:4860:4860::8888 ### IP Database +#### We use [bgp.tools](https://bgp.tools) as a data provider for routing tables. + NextTrace BackEnd is now open-source. https://github.com/sjlleo/nexttrace-backend @@ -196,6 +198,8 @@ Here is our recommended troubleshooting process: ## Credits +BGP.TOOLS provided some data support for this project and we would like to express our sincere gratitude. + [Vincent Young](https://github.com/missuo) (i@yyt.moe) [Sam Sam](https://github.com/samleong123) (samsam123@samsam123.name.my) diff --git a/README_zh_CN.md b/README_zh_CN.md index 1e001ed..30fe2c3 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -133,6 +133,8 @@ nexttrace -T -q 2 -r 1 -table -report 2001:4860:4860::8888 ### IP 数据库 +我们使用[bgp.tools](https://bgp.tools)作为路由表功能的数据提供者。 + ✨NextTrace `LeoMoeAPI` 的后端也开源啦 [GitHub - sjlleo/nexttrace-backend: NextTrace BackEnd](https://github.com/sjlleo/nexttrace-backend) @@ -186,6 +188,8 @@ https://github.com/OwO-Network/nexttrace-enhanced ## Thanks +BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢。 + [Vincent Young](https://github.com/missuo) (i@yyt.moe) [Sam Sam](https://github.com/samleong123) (samsam123@samsam123.name.my) diff --git a/fast_trace/basic.go b/fast_trace/basic.go index 9a015fb..348c4f8 100644 --- a/fast_trace/basic.go +++ b/fast_trace/basic.go @@ -104,7 +104,7 @@ var Guangzhou = BackBoneCollection{ Location: "广州", CT163: ISPCollection{ ISPName: CT163, - IP: "106.37.67.1", + IP: "14.116.225.60", IPv6: "240e:f9:8010::3:110:1", }, diff --git a/ipgeo/ipgeo.go b/ipgeo/ipgeo.go index 6c4fab0..55912e5 100644 --- a/ipgeo/ipgeo.go +++ b/ipgeo/ipgeo.go @@ -5,14 +5,19 @@ import ( ) type IPGeoData struct { - Asnumber string - Country string - Prov string - City string - District string - Owner string - Isp string - Whois string + IP string `json:"ip"` + Asnumber string `json:"asnumber"` + Country string `json:"country"` + Prov string `json:"prov"` + City string `json:"city"` + District string `json:"district"` + Owner string `json:"owner"` + Isp string `json:"isp"` + Domain string `json:"domain"` + Whois string `json:"whois"` + Prefix string `json:"prefix"` + Router map[string][]string `json:"router"` + Source string `json:"source"` } type Source = func(ip string) (*IPGeoData, error) diff --git a/ipgeo/leo.go b/ipgeo/leo.go index e4a3a1d..c142557 100644 --- a/ipgeo/leo.go +++ b/ipgeo/leo.go @@ -1,6 +1,7 @@ package ipgeo import ( + "encoding/json" "errors" "sync" "time" @@ -52,6 +53,9 @@ func receiveParse() { domain = res.Get("owner").String() } + m := make(map[string][]string) + json.Unmarshal([]byte(res.Get("router").String()), &m) + IPPools.pool[gjson.Parse(data).Get("ip").String()] <- IPGeoData{ Asnumber: res.Get("asnumber").String(), Country: res.Get("country").String(), @@ -61,6 +65,8 @@ func receiveParse() { Owner: domain, Isp: res.Get("isp").String(), Whois: res.Get("whois").String(), + Prefix: res.Get("prefix").String(), + Router: m, } } } diff --git a/main.go b/main.go index 1c58ff6..8737266 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ var beginHop = fSet.Int("b", 1, "Set The Begin TTL") var ver = fSet.Bool("V", false, "Print Version") var src_addr = fSet.String("S", "", "Use the following IP address as the source address in outgoing packets") var src_dev = fSet.String("D", "", "Use the following Network Devices as the source address in outgoing packets") +var router = fSet.Bool("R", false, "Show Routing Table [Provided By BGP.Tools]") func printArgHelp() { fmt.Println("\nArgs Error\nUsage : 'nexttrace [option...] HOSTNAME' or 'nexttrace HOSTNAME [option...]'\nOPTIONS: [-VTU] [-d DATAORIGIN.STR ] [ -m TTL ] [ -p PORT ] [ -q PROBES.COUNT ] [ -r PARALLELREQUESTS.COUNT ] [-rdns] [ -table ] -report") @@ -162,6 +163,9 @@ func main() { } else { if *output { conf.RealtimePrinter = tracelog.RealtimePrinter + } else if *router { + conf.RealtimePrinter = printer.RealtimePrinterWithRouter + fmt.Println("路由表数据源由 BGP.Tools 提供,在此特表感谢") } else { conf.RealtimePrinter = printer.RealtimePrinter } diff --git a/printer/realtime_printer_router.go b/printer/realtime_printer_router.go new file mode 100644 index 0000000..18007bb --- /dev/null +++ b/printer/realtime_printer_router.go @@ -0,0 +1,152 @@ +package printer + +import ( + "fmt" + "net" + "strconv" + "strings" + + "github.com/fatih/color" + "github.com/xgadget-lab/nexttrace/trace" +) + +func RealtimePrinterWithRouter(res *trace.Result, ttl int) { + fmt.Printf("%s ", color.New(color.FgHiYellow, color.Bold).Sprintf("%-2d", ttl+1)) + + // 去重 + var latestIP string + tmpMap := make(map[string][]string) + for i, v := range res.Hops[ttl] { + if v.Address == nil && latestIP != "" { + tmpMap[latestIP] = append(tmpMap[latestIP], fmt.Sprintf("%s ms", "*")) + continue + } else if v.Address == nil { + continue + } + + if _, exist := tmpMap[v.Address.String()]; !exist { + tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], strconv.Itoa(i)) + // 首次进入 + if latestIP == "" { + for j := 0; j < i; j++ { + tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%s ms", "*")) + } + } + latestIP = v.Address.String() + } + + tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%.2f ms", v.RTT.Seconds()*1000)) + } + + if latestIP == "" { + fmt.Fprintf(color.Output, "%s\n", + color.New(color.FgWhite, color.Bold).Sprintf("*"), + ) + return + } + + var blockDisplay = false + for ip, v := range tmpMap { + if blockDisplay { + fmt.Printf("%4s", "") + } + if net.ParseIP(ip).To4() == nil { + fmt.Fprintf(color.Output, "%s", + color.New(color.FgWhite, color.Bold).Sprintf("%-25s", ip), + ) + } else { + fmt.Fprintf(color.Output, "%s", + color.New(color.FgWhite, color.Bold).Sprintf("%-15s", ip), + ) + } + + i, _ := strconv.Atoi(v[0]) + + if res.Hops[ttl][i].Geo.Asnumber != "" { + fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("AS%-6s", res.Hops[ttl][i].Geo.Asnumber)) + } else { + fmt.Printf(" %-8s", "*") + } + + if net.ParseIP(ip).To4() != nil { + whoisFormat := strings.Split(res.Hops[ttl][i].Geo.Whois, "-") + if len(whoisFormat) > 1 { + whoisFormat[0] = strings.Join(whoisFormat[:2], "-") + } + + if whoisFormat[0] != "" { + whoisFormat[0] = "[" + whoisFormat[0] + "]" + } + fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("%-16s", whoisFormat[0])) + } + + if res.Hops[ttl][i].Geo.Country == "" { + res.Hops[ttl][i].Geo.Country = "LAN Address" + } + + if net.ParseIP(ip).To4() != nil { + + fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ", + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District), + fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner), + color.New(color.FgHiBlack, color.Bold).Sprintf("%-39s", res.Hops[ttl][i].Hostname), + ) + } else { + fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ", + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City), + color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District), + fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner), + color.New(color.FgHiBlack, color.Bold).Sprintf("%-32s", res.Hops[ttl][i].Hostname), + ) + } + + for j := 1; j < len(v); j++ { + if len(v) == 2 || j == 1 { + fmt.Fprintf(color.Output, "%s", + color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]), + ) + } else { + fmt.Fprintf(color.Output, " / %s", + color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]), + ) + } + } + i = 0 + fmt.Println() + if res.Hops[ttl][i].Geo != nil && !blockDisplay { + fmt.Fprintf(color.Output, "%s %s %s %s %s\n", + color.New(color.FgWhite, color.Bold).Sprintf("-"), + color.New(color.FgHiYellow, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prefix), + color.New(color.FgWhite, color.Bold).Sprintf("路由表"), + color.New(color.FgHiCyan, color.Bold).Sprintf("Beta"), + color.New(color.FgWhite, color.Bold).Sprintf("-"), + ) + GetRouter(&res.Hops[ttl][i].Geo.Router, "AS"+res.Hops[ttl][i].Geo.Asnumber) + } + blockDisplay = true + } +} + +func GetRouter(r *map[string][]string, node string) { + routeMap := *r + for _, v := range routeMap[node] { + if len(routeMap[v]) != 0 { + fmt.Fprintf(color.Output, " %s %s %s\n", + color.New(color.FgWhite, color.Bold).Sprintf("%s", routeMap[v][0]), + color.New(color.FgWhite, color.Bold).Sprintf("%s", v), + color.New(color.FgHiBlue, color.Bold).Sprintf("%s", node), + ) + } else { + fmt.Fprintf(color.Output, " %s %s\n", + color.New(color.FgWhite, color.Bold).Sprintf("%s", v), + color.New(color.FgHiBlue, color.Bold).Sprintf("%s", node), + ) + } + + } +}