mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-08-05 07:07:00 +08:00
Compare commits
No commits in common. "main" and "v0.0.5-20250727160732" have entirely different histories.
main
...
v0.0.5-202
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -27,7 +27,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git config --global user.name 'github-actions'
|
git config --global user.name 'github-actions'
|
||||||
git config --global user.email 'github-actions@github.com'
|
git config --global user.email 'github-actions@github.com'
|
||||||
TAG="v0.0.6-$(date +'%Y%m%d%H%M%S')"
|
TAG="v0.0.5-$(date +'%Y%m%d%H%M%S')"
|
||||||
git tag $TAG
|
git tag $TAG
|
||||||
git push origin $TAG
|
git push origin $TAG
|
||||||
echo "TAG=$TAG" >> $GITHUB_ENV
|
echo "TAG=$TAG" >> $GITHUB_ENV
|
||||||
|
@ -15,10 +15,14 @@
|
|||||||
- [x] 支持对```CTGNET```、```CN2GIA```和```CN2GT```线路的判断
|
- [x] 支持对```CTGNET```、```CN2GIA```和```CN2GT```线路的判断
|
||||||
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
||||||
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
||||||
- [x] 支持对主流接入点的线路检测,方便分析国际互联能力
|
|
||||||
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
||||||
- [x] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
- [x] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
||||||
|
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
下载、安装、更新
|
下载、安装、更新
|
||||||
@ -70,7 +74,7 @@ rm -rf /usr/bin/backtrace
|
|||||||
## 在Golang中使用
|
## 在Golang中使用
|
||||||
|
|
||||||
```
|
```
|
||||||
go get github.com/oneclickvirt/backtrace@v0.0.6-20250801151556
|
go get github.com/oneclickvirt/backtrace@v0.0.5-20250629024536
|
||||||
```
|
```
|
||||||
|
|
||||||
## 概览图
|
## 概览图
|
||||||
|
315
bgptools/pop.go
315
bgptools/pop.go
@ -1,315 +0,0 @@
|
|||||||
package bgptools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"html"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/imroc/req/v3"
|
|
||||||
"github.com/oneclickvirt/backtrace/model"
|
|
||||||
"github.com/oneclickvirt/defaultset"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ASCard struct {
|
|
||||||
ASN string
|
|
||||||
Name string
|
|
||||||
Fill string
|
|
||||||
Stroke string
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Arrow struct {
|
|
||||||
From string
|
|
||||||
To string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Upstream struct {
|
|
||||||
ASN string
|
|
||||||
Name string
|
|
||||||
Direct bool
|
|
||||||
Tier1 bool
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PoPResult struct {
|
|
||||||
TargetASN string
|
|
||||||
Upstreams []Upstream
|
|
||||||
Result string
|
|
||||||
}
|
|
||||||
|
|
||||||
func getISPAbbr(asn, name string) string {
|
|
||||||
if abbr, ok := model.Tier1Global[asn]; ok {
|
|
||||||
return abbr
|
|
||||||
}
|
|
||||||
if idx := strings.Index(name, " "); idx != -1 && idx > 18 {
|
|
||||||
return name[:idx]
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
func getISPType(asn string, tier1 bool, direct bool) string {
|
|
||||||
switch {
|
|
||||||
case tier1 && model.Tier1Global[asn] != "":
|
|
||||||
return "Tier1 Global"
|
|
||||||
case model.Tier1Regional[asn] != "":
|
|
||||||
return "Tier1 Regional"
|
|
||||||
case model.Tier2[asn] != "":
|
|
||||||
return "Tier2"
|
|
||||||
case model.ContentProviders[asn] != "":
|
|
||||||
return "CDN Provider"
|
|
||||||
case model.IXPS[asn] != "":
|
|
||||||
return "IXP"
|
|
||||||
case direct:
|
|
||||||
return "Direct"
|
|
||||||
default:
|
|
||||||
return "Indirect"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValidIP(ip string) bool {
|
|
||||||
return net.ParseIP(ip) != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSVGPath(client *req.Client, ip string) (string, error) {
|
|
||||||
if !isValidIP(ip) {
|
|
||||||
return "", fmt.Errorf("invalid IP address: %s", ip)
|
|
||||||
}
|
|
||||||
url := fmt.Sprintf("https://bgp.tools/prefix/%s#connectivity", ip)
|
|
||||||
resp, err := client.R().Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to fetch BGP info for IP %s: %w", ip, err)
|
|
||||||
}
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return "", fmt.Errorf("HTTP error %d when fetching BGP info for IP %s", resp.StatusCode, ip)
|
|
||||||
}
|
|
||||||
body := resp.String()
|
|
||||||
re := regexp.MustCompile(`<img[^>]+id="pathimg"[^>]+src="([^"]+)"`)
|
|
||||||
matches := re.FindStringSubmatch(body)
|
|
||||||
if len(matches) < 2 {
|
|
||||||
return "", fmt.Errorf("SVG path not found for IP %s", ip)
|
|
||||||
}
|
|
||||||
return matches[1], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadSVG(client *req.Client, svgPath string) (string, error) {
|
|
||||||
uuid := uuid.NewString()
|
|
||||||
url := fmt.Sprintf("https://bgp.tools%s?%s&loggedin", svgPath, uuid)
|
|
||||||
resp, err := client.R().Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to download SVG: %w", err)
|
|
||||||
}
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return "", fmt.Errorf("HTTP error %d when downloading SVG", resp.StatusCode)
|
|
||||||
}
|
|
||||||
bodyBytes, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to read SVG response body: %w", err)
|
|
||||||
}
|
|
||||||
return string(bodyBytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseASAndEdges(svg string) ([]ASCard, []Arrow) {
|
|
||||||
svg = html.UnescapeString(svg)
|
|
||||||
var nodes []ASCard
|
|
||||||
var edges []Arrow
|
|
||||||
nodeRE := regexp.MustCompile(`(?s)<g id="node\d+" class="node">(.*?)</g>`)
|
|
||||||
edgeRE := regexp.MustCompile(`(?s)<g id="edge\d+" class="edge">(.*?)</g>`)
|
|
||||||
asnRE := regexp.MustCompile(`<title>AS(\d+)</title>`)
|
|
||||||
nameRE := regexp.MustCompile(`xlink:title="([^"]+)"`)
|
|
||||||
fillRE := regexp.MustCompile(`<polygon[^>]+fill="([^"]+)"`)
|
|
||||||
strokeRE := regexp.MustCompile(`<polygon[^>]+stroke="([^"]+)"`)
|
|
||||||
titleRE := regexp.MustCompile(`<title>AS(\d+)->AS(\d+)</title>`)
|
|
||||||
for _, match := range nodeRE.FindAllStringSubmatch(svg, -1) {
|
|
||||||
block := match[1]
|
|
||||||
asn := ""
|
|
||||||
if a := asnRE.FindStringSubmatch(block); len(a) > 1 {
|
|
||||||
asn = a[1]
|
|
||||||
}
|
|
||||||
name := "unknown"
|
|
||||||
if n := nameRE.FindStringSubmatch(block); len(n) > 1 {
|
|
||||||
name = strings.TrimSpace(n[1])
|
|
||||||
}
|
|
||||||
fill := "none"
|
|
||||||
if f := fillRE.FindStringSubmatch(block); len(f) > 1 {
|
|
||||||
fill = f[1]
|
|
||||||
}
|
|
||||||
stroke := "none"
|
|
||||||
if s := strokeRE.FindStringSubmatch(block); len(s) > 1 {
|
|
||||||
stroke = s[1]
|
|
||||||
}
|
|
||||||
if asn != "" {
|
|
||||||
nodes = append(nodes, ASCard{
|
|
||||||
ASN: asn,
|
|
||||||
Name: name,
|
|
||||||
Fill: fill,
|
|
||||||
Stroke: stroke,
|
|
||||||
ID: "",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, match := range edgeRE.FindAllStringSubmatch(svg, -1) {
|
|
||||||
block := match[1]
|
|
||||||
if t := titleRE.FindStringSubmatch(block); len(t) == 3 {
|
|
||||||
edges = append(edges, Arrow{
|
|
||||||
From: t[1],
|
|
||||||
To: t[2],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nodes, edges
|
|
||||||
}
|
|
||||||
|
|
||||||
func findTargetASN(nodes []ASCard) string {
|
|
||||||
for _, n := range nodes {
|
|
||||||
if n.Fill == "limegreen" || n.Stroke == "limegreen" || n.Fill == "green" {
|
|
||||||
return n.ASN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(nodes) > 0 {
|
|
||||||
return nodes[0].ASN
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func findUpstreams(targetASN string, nodes []ASCard, edges []Arrow) []Upstream {
|
|
||||||
upstreamMap := map[string]bool{}
|
|
||||||
for _, e := range edges {
|
|
||||||
if e.From == targetASN {
|
|
||||||
upstreamMap[e.To] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var upstreams []Upstream
|
|
||||||
for _, n := range nodes {
|
|
||||||
if !upstreamMap[n.ASN] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
isTier1 := (n.Fill == "white" && n.Stroke == "#005ea5")
|
|
||||||
upstreamType := getISPType(n.ASN, isTier1, true)
|
|
||||||
upstreams = append(upstreams, Upstream{
|
|
||||||
ASN: n.ASN,
|
|
||||||
Name: n.Name,
|
|
||||||
Direct: true,
|
|
||||||
Tier1: isTier1,
|
|
||||||
Type: upstreamType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if len(upstreams) == 1 {
|
|
||||||
currentASN := upstreams[0].ASN
|
|
||||||
for {
|
|
||||||
nextUpstreams := map[string]bool{}
|
|
||||||
for _, e := range edges {
|
|
||||||
if e.From == currentASN {
|
|
||||||
nextUpstreams[e.To] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(nextUpstreams) != 1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var nextASN string
|
|
||||||
for asn := range nextUpstreams {
|
|
||||||
nextASN = asn
|
|
||||||
break
|
|
||||||
}
|
|
||||||
found := false
|
|
||||||
for _, existing := range upstreams {
|
|
||||||
if existing.ASN == nextASN {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var nextNode *ASCard
|
|
||||||
for _, n := range nodes {
|
|
||||||
if n.ASN == nextASN {
|
|
||||||
nextNode = &n
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nextNode == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
isTier1 := (nextNode.Fill == "white" && nextNode.Stroke == "#005ea5")
|
|
||||||
upstreamType := getISPType(nextNode.ASN, isTier1, false)
|
|
||||||
upstreams = append(upstreams, Upstream{
|
|
||||||
ASN: nextNode.ASN,
|
|
||||||
Name: nextNode.Name,
|
|
||||||
Direct: false,
|
|
||||||
Tier1: isTier1,
|
|
||||||
Type: upstreamType,
|
|
||||||
})
|
|
||||||
currentASN = nextASN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return upstreams
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPoPInfo(ip string) (*PoPResult, error) {
|
|
||||||
if ip == "" {
|
|
||||||
return nil, fmt.Errorf("IP address cannot be empty")
|
|
||||||
}
|
|
||||||
client := req.C().ImpersonateChrome()
|
|
||||||
svgPath, err := getSVGPath(client, ip)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("获取SVG路径失败: %w", err)
|
|
||||||
}
|
|
||||||
svg, err := downloadSVG(client, svgPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("下载SVG失败: %w", err)
|
|
||||||
}
|
|
||||||
nodes, edges := parseASAndEdges(svg)
|
|
||||||
if len(nodes) == 0 {
|
|
||||||
return nil, fmt.Errorf("未找到任何AS节点")
|
|
||||||
}
|
|
||||||
targetASN := findTargetASN(nodes)
|
|
||||||
if targetASN == "" {
|
|
||||||
return nil, fmt.Errorf("无法识别目标 ASN")
|
|
||||||
}
|
|
||||||
upstreams := findUpstreams(targetASN, nodes, edges)
|
|
||||||
colWidth := 18
|
|
||||||
center := func(s string) string {
|
|
||||||
runeLen := len([]rune(s))
|
|
||||||
if runeLen >= colWidth {
|
|
||||||
return string([]rune(s)[:colWidth])
|
|
||||||
}
|
|
||||||
padding := colWidth - runeLen
|
|
||||||
left := padding / 2
|
|
||||||
right := padding - left
|
|
||||||
return strings.Repeat(" ", left) + s + strings.Repeat(" ", right)
|
|
||||||
}
|
|
||||||
var result strings.Builder
|
|
||||||
perLine := 5
|
|
||||||
for i := 0; i < len(upstreams); i += perLine {
|
|
||||||
end := i + perLine
|
|
||||||
if end > len(upstreams) {
|
|
||||||
end = len(upstreams)
|
|
||||||
}
|
|
||||||
batch := upstreams[i:end]
|
|
||||||
var line1, line2, line3 []string
|
|
||||||
for _, u := range batch {
|
|
||||||
abbr := getISPAbbr(u.ASN, u.Name)
|
|
||||||
asStr := center("AS" + u.ASN)
|
|
||||||
abbrStr := center(abbr)
|
|
||||||
typeStr := center(u.Type)
|
|
||||||
line1 = append(line1, defaultset.White(asStr))
|
|
||||||
line2 = append(line2, abbrStr)
|
|
||||||
line3 = append(line3, defaultset.Blue(typeStr))
|
|
||||||
}
|
|
||||||
result.WriteString(strings.Join(line1, ""))
|
|
||||||
result.WriteString("\n")
|
|
||||||
result.WriteString(strings.Join(line2, ""))
|
|
||||||
result.WriteString("\n")
|
|
||||||
result.WriteString(strings.Join(line3, ""))
|
|
||||||
result.WriteString("\n")
|
|
||||||
}
|
|
||||||
return &PoPResult{
|
|
||||||
TargetASN: targetASN,
|
|
||||||
Upstreams: upstreams,
|
|
||||||
Result: result.String(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package bgptools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetPoPInfo(t *testing.T) {
|
|
||||||
result, err := GetPoPInfo("23.128.228.123")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("目标 ASN: %s\n", result.TargetASN)
|
|
||||||
fmt.Println(len(result.Upstreams))
|
|
||||||
fmt.Println(result.Upstreams)
|
|
||||||
fmt.Println("上游信息:")
|
|
||||||
fmt.Print(result.Result)
|
|
||||||
}
|
|
@ -33,9 +33,7 @@
|
|||||||
2409:8004:3821
|
2409:8004:3821
|
||||||
2409:8004:3822
|
2409:8004:3822
|
||||||
2409:8004:3841
|
2409:8004:3841
|
||||||
2409:8004:3842
|
|
||||||
2409:8004:3843
|
2409:8004:3843
|
||||||
2409:8004:3844
|
|
||||||
2409:8004:38c0
|
2409:8004:38c0
|
||||||
2409:8004:801
|
2409:8004:801
|
||||||
2409:8004:807
|
2409:8004:807
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oneclickvirt/backtrace/bgptools"
|
|
||||||
backtrace "github.com/oneclickvirt/backtrace/bk"
|
backtrace "github.com/oneclickvirt/backtrace/bk"
|
||||||
"github.com/oneclickvirt/backtrace/model"
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
"github.com/oneclickvirt/backtrace/utils"
|
"github.com/oneclickvirt/backtrace/utils"
|
||||||
@ -46,12 +45,12 @@ func main() {
|
|||||||
fmt.Println(model.BackTraceVersion)
|
fmt.Println(model.BackTraceVersion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
info := IpInfo{}
|
|
||||||
if showIpInfo {
|
if showIpInfo {
|
||||||
rsp, err := http.Get("http://ipinfo.io")
|
rsp, err := http.Get("http://ipinfo.io")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("Get ip info err %v \n", err.Error())
|
fmt.Errorf("Get ip info err %v \n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
|
info := IpInfo{}
|
||||||
err = json.NewDecoder(rsp.Body).Decode(&info)
|
err = json.NewDecoder(rsp.Body).Decode(&info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("json decode err %v \n", err.Error())
|
fmt.Errorf("json decode err %v \n", err.Error())
|
||||||
@ -62,12 +61,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preCheck := utils.CheckPublicAccess(3 * time.Second)
|
preCheck := utils.CheckPublicAccess(3 * time.Second)
|
||||||
if preCheck.Connected && info.Ip != "" {
|
|
||||||
result, err := bgptools.GetPoPInfo(info.Ip)
|
|
||||||
if err == nil {
|
|
||||||
fmt.Print(result.Result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if preCheck.Connected && preCheck.StackType == "DualStack" {
|
if preCheck.Connected && preCheck.StackType == "DualStack" {
|
||||||
backtrace.BackTrace(ipv6)
|
backtrace.BackTrace(ipv6)
|
||||||
} else if preCheck.Connected && preCheck.StackType == "IPv4" {
|
} else if preCheck.Connected && preCheck.StackType == "IPv4" {
|
||||||
|
1
go.mod
1
go.mod
@ -3,7 +3,6 @@ module github.com/oneclickvirt/backtrace
|
|||||||
go 1.24.5
|
go 1.24.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/imroc/req/v3 v3.54.0
|
github.com/imroc/req/v3 v3.54.0
|
||||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
||||||
golang.org/x/net v0.41.0
|
golang.org/x/net v0.41.0
|
||||||
|
2
go.sum
2
go.sum
@ -6,8 +6,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
@ -2,7 +2,7 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const BackTraceVersion = "v0.0.6"
|
const BackTraceVersion = "v0.0.5"
|
||||||
|
|
||||||
var EnableLoger = false
|
var EnableLoger = false
|
||||||
|
|
||||||
@ -76,82 +76,3 @@ var (
|
|||||||
CachedIcmpDataFetchTime time.Time
|
CachedIcmpDataFetchTime time.Time
|
||||||
ParsedIcmpTargets []IcmpTarget
|
ParsedIcmpTargets []IcmpTarget
|
||||||
)
|
)
|
||||||
|
|
||||||
var Tier1Global = map[string]string{
|
|
||||||
"174": "Cogent",
|
|
||||||
"1299": "Arelion",
|
|
||||||
"3356": "Lumen",
|
|
||||||
"3257": "GTT",
|
|
||||||
"7018": "AT&T",
|
|
||||||
"701": "Verizon",
|
|
||||||
"2914": "NTT",
|
|
||||||
"6453": "Tata",
|
|
||||||
"3320": "DTAG",
|
|
||||||
"5511": "Orange",
|
|
||||||
"3491": "PCCW",
|
|
||||||
"6461": "Zayo",
|
|
||||||
"6830": "Liberty",
|
|
||||||
"6762": "Sparkle",
|
|
||||||
"12956": "Telxius",
|
|
||||||
"702": "Verizon",
|
|
||||||
}
|
|
||||||
|
|
||||||
var Tier1Regional = map[string]string{
|
|
||||||
"4134": "ChinaNet",
|
|
||||||
"4837": "China Unicom",
|
|
||||||
"9808": "China Mobile",
|
|
||||||
"4766": "Korea Telecom",
|
|
||||||
"2516": "KDDI",
|
|
||||||
"7713": "Telkomnet",
|
|
||||||
"9121": "Etisalat",
|
|
||||||
"7473": "SingTel",
|
|
||||||
"4637": "Telstra",
|
|
||||||
"5400": "British Telecom",
|
|
||||||
"2497": "IIJ",
|
|
||||||
"3462": "Chunghwa Telecom",
|
|
||||||
"3463": "TWNIC",
|
|
||||||
"12389": "SoftBank",
|
|
||||||
"3303": "MTS",
|
|
||||||
"45609": "Reliance Jio",
|
|
||||||
}
|
|
||||||
|
|
||||||
var Tier2 = map[string]string{
|
|
||||||
"6939": "HurricaneElectric",
|
|
||||||
"20485": "Transtelecom",
|
|
||||||
"1273": "Vodafone",
|
|
||||||
"1239": "Sprint",
|
|
||||||
"6453": "Tata",
|
|
||||||
"6762": "Sparkle",
|
|
||||||
"9002": "RETN",
|
|
||||||
"7922": "Comcast",
|
|
||||||
"23754": "Rostelecom",
|
|
||||||
"3320": "DTAG",
|
|
||||||
}
|
|
||||||
|
|
||||||
var ContentProviders = map[string]string{
|
|
||||||
"15169": "Google",
|
|
||||||
"32934": "Facebook",
|
|
||||||
"54113": "Fastly",
|
|
||||||
"20940": "Akamai",
|
|
||||||
"13335": "Cloudflare",
|
|
||||||
"14618": "Amazon AWS",
|
|
||||||
"55102": "Netflix CDN",
|
|
||||||
"4685": "CacheFly",
|
|
||||||
"16509": "Amazon",
|
|
||||||
"36040": "Amazon CloudFront",
|
|
||||||
"36459": "EdgeCast",
|
|
||||||
"24940": "CDNetworks",
|
|
||||||
}
|
|
||||||
|
|
||||||
var IXPS = map[string]string{
|
|
||||||
"5539": "IX.br",
|
|
||||||
"25291": "HKIX",
|
|
||||||
"1200": "AMS-IX",
|
|
||||||
"6695": "DE-CIX",
|
|
||||||
"58558": "LINX",
|
|
||||||
"395848": "France-IX",
|
|
||||||
"4713": "JPNAP",
|
|
||||||
"4635": "SIX",
|
|
||||||
"2906": "MSK-IX",
|
|
||||||
"1273": "NIX.CZ",
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user