add: 对 Hop 的路由表展示

This commit is contained in:
sjlleo
2022-11-18 04:41:47 -05:00
parent 473ce3c5f2
commit d561063a7c
7 changed files with 184 additions and 9 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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",
},

View File

@@ -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)

View File

@@ -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,
}
}
}

View File

@@ -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
}

View File

@@ -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),
)
}
}
}