mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-08-04 22:56:59 +08:00
Compare commits
21 Commits
v0.0.5-202
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
289739fff5 | ||
![]() |
be67c981ad | ||
![]() |
80a27a005b | ||
![]() |
a6adf423ae | ||
![]() |
d6ad936901 | ||
![]() |
e089430958 | ||
![]() |
799d653089 | ||
![]() |
cfed3329d2 | ||
![]() |
461c28f3d1 | ||
![]() |
bf0dc1c95f | ||
![]() |
a36c3eff82 | ||
![]() |
4d5b3fd5cb | ||
![]() |
50b2c706f1 | ||
![]() |
a9d1782d53 | ||
![]() |
30c9877cdc | ||
![]() |
2c4e1609de | ||
![]() |
e82783225d | ||
![]() |
90e0ae0e7e | ||
![]() |
7dffb3b4dd | ||
![]() |
ea5a90a8b1 | ||
![]() |
4fbe7bfb4b |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'github-actions@github.com'
|
||||
TAG="v0.0.5-$(date +'%Y%m%d%H%M%S')"
|
||||
TAG="v0.0.6-$(date +'%Y%m%d%H%M%S')"
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
echo "TAG=$TAG" >> $GITHUB_ENV
|
||||
|
7
.github/workflows/main.yaml
vendored
7
.github/workflows/main.yaml
vendored
@ -55,7 +55,12 @@ jobs:
|
||||
run: |
|
||||
mkdir -p bin
|
||||
cd cmd
|
||||
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ../bin/backtrace-${{ matrix.goos }}-${{ matrix.goarch }} -v -ldflags="-extldflags=-static" .
|
||||
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build \
|
||||
-o ../bin/backtrace-${{ matrix.goos }}-${{ matrix.goarch }} \
|
||||
-v \
|
||||
-ldflags="-extldflags=-static -s -w" \
|
||||
-trimpath \
|
||||
.
|
||||
|
||||
- name: Upload New Assets
|
||||
run: |
|
||||
|
@ -15,14 +15,10 @@
|
||||
- [x] 支持对```CTGNET```、```CN2GIA```和```CN2GT```线路的判断
|
||||
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
||||
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
||||
- [x] 支持对主流接入点的线路检测,方便分析国际互联能力
|
||||
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
||||
- [x] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
||||
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
||||
|
||||
## 使用
|
||||
|
||||
下载、安装、更新
|
||||
@ -74,7 +70,7 @@ rm -rf /usr/bin/backtrace
|
||||
## 在Golang中使用
|
||||
|
||||
```
|
||||
go get github.com/oneclickvirt/backtrace@v0.0.5-20250517095024
|
||||
go get github.com/oneclickvirt/backtrace@v0.0.6-20250801151556
|
||||
```
|
||||
|
||||
## 概览图
|
||||
|
315
bgptools/pop.go
Normal file
315
bgptools/pop.go
Normal file
@ -0,0 +1,315 @@
|
||||
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
|
||||
}
|
19
bgptools/pop_test.go
Normal file
19
bgptools/pop_test.go
Normal file
@ -0,0 +1,19 @@
|
||||
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)
|
||||
}
|
@ -18,6 +18,8 @@
|
||||
2a04:f581:a123
|
||||
2a04:f581:a125
|
||||
2c0f:f7a8:1
|
||||
2c0f:f7a8:2
|
||||
2c0f:f7a8:29
|
||||
2c0f:f7a8:37
|
||||
2c0f:f7a8:47
|
||||
2c0f:f7a8:9011
|
||||
|
@ -129,7 +129,6 @@
|
||||
2a04:f580:9280
|
||||
2a04:f580:9290
|
||||
2c0f:f7a8:9010
|
||||
2c0f:f7a8:9011
|
||||
2c0f:f7a8:9020
|
||||
2c0f:f7a8:9041
|
||||
2c0f:f7a8:9210
|
||||
|
@ -33,6 +33,9 @@
|
||||
2409:8004:3821
|
||||
2409:8004:3822
|
||||
2409:8004:3841
|
||||
2409:8004:3842
|
||||
2409:8004:3843
|
||||
2409:8004:3844
|
||||
2409:8004:38c0
|
||||
2409:8004:801
|
||||
2409:8004:807
|
||||
@ -156,6 +159,7 @@
|
||||
2409:802e:2905
|
||||
2409:802e:2906
|
||||
2409:802e:2909
|
||||
2409:802e:290d
|
||||
2409:802e:2a05
|
||||
2409:802e:2a06
|
||||
2409:802e:2b01
|
||||
@ -184,6 +188,7 @@
|
||||
2409:802f:290b
|
||||
2409:802f:290e
|
||||
2409:802f:290f
|
||||
2409:802f:2915
|
||||
2409:802f:2a05
|
||||
2409:802f:2a0b
|
||||
2409:802f:2b05
|
||||
@ -276,12 +281,16 @@
|
||||
2409:804b:290a
|
||||
2409:804b:290b
|
||||
2409:804b:290c
|
||||
2409:804b:2910
|
||||
2409:804b:2911
|
||||
2409:804b:29ff
|
||||
2409:804b:2b05
|
||||
2409:804b:2b06
|
||||
2409:804b:2b07
|
||||
2409:804b:2b08
|
||||
2409:804b:2b0b
|
||||
2409:804b:2b10
|
||||
2409:804b:2b11
|
||||
2409:804b:2c06
|
||||
2409:804b:2c0b
|
||||
2409:804b:800
|
||||
@ -408,6 +417,9 @@
|
||||
2409:8057:3817
|
||||
2409:8057:3818
|
||||
2409:8057:381a
|
||||
2409:8057:381b
|
||||
2409:8057:381d
|
||||
2409:8057:381e
|
||||
2409:8057:3820
|
||||
2409:8057:800
|
||||
2409:8057:804
|
||||
@ -475,6 +487,7 @@
|
||||
2409:8060:8eb
|
||||
2409:8061
|
||||
2409:8061:2806
|
||||
2409:8061:280a
|
||||
2409:8061:2900
|
||||
2409:8061:2901
|
||||
2409:8061:2902
|
||||
@ -482,6 +495,7 @@
|
||||
2409:8061:2905
|
||||
2409:8061:2906
|
||||
2409:8061:2907
|
||||
2409:8061:290a
|
||||
2409:8061:2a01
|
||||
2409:8061:2a02
|
||||
2409:8061:2a04
|
||||
@ -753,7 +767,18 @@
|
||||
2409:8710
|
||||
2409:8713
|
||||
2409:8730
|
||||
2409:8730:17f
|
||||
2409:8730:18f
|
||||
2409:8730:1af
|
||||
2409:8730:30
|
||||
2409:8730:50
|
||||
2409:8731
|
||||
2409:8731:1bf
|
||||
2409:8731:1cf
|
||||
2409:8731:1df
|
||||
2409:8731:21f
|
||||
2409:8731:22f
|
||||
2409:8731:37f
|
||||
2409:8734
|
||||
2409:8734:1861
|
||||
2409:8734:1871
|
||||
@ -1046,6 +1071,8 @@
|
||||
2409:8938
|
||||
2409:8938:48c4
|
||||
2409:8938:48cc
|
||||
2409:8938:c0
|
||||
2409:8938:c4
|
||||
2409:894c
|
||||
2409:894d
|
||||
2409:894d:e78
|
||||
|
@ -11,6 +11,7 @@
|
||||
2408:862b
|
||||
2408:862e:2ff
|
||||
2408:8638:116
|
||||
2408:8640
|
||||
2408:8649:2a00
|
||||
2408:8652:ff00
|
||||
2408:8656:a52
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/bgptools"
|
||||
backtrace "github.com/oneclickvirt/backtrace/bk"
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
"github.com/oneclickvirt/backtrace/utils"
|
||||
@ -45,12 +46,12 @@ func main() {
|
||||
fmt.Println(model.BackTraceVersion)
|
||||
return
|
||||
}
|
||||
info := IpInfo{}
|
||||
if showIpInfo {
|
||||
rsp, err := http.Get("http://ipinfo.io")
|
||||
if err != nil {
|
||||
fmt.Errorf("Get ip info err %v \n", err.Error())
|
||||
} else {
|
||||
info := IpInfo{}
|
||||
err = json.NewDecoder(rsp.Body).Decode(&info)
|
||||
if err != nil {
|
||||
fmt.Errorf("json decode err %v \n", err.Error())
|
||||
@ -61,6 +62,12 @@ func main() {
|
||||
}
|
||||
}
|
||||
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" {
|
||||
backtrace.BackTrace(ipv6)
|
||||
} else if preCheck.Connected && preCheck.StackType == "IPv4" {
|
||||
|
36
go.mod
36
go.mod
@ -1,33 +1,31 @@
|
||||
module github.com/oneclickvirt/backtrace
|
||||
|
||||
go 1.22.4
|
||||
go 1.24.5
|
||||
|
||||
require (
|
||||
github.com/imroc/req/v3 v3.50.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/imroc/req/v3 v3.54.0
|
||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
||||
golang.org/x/net v0.33.0
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/sys v0.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 // indirect
|
||||
github.com/icholy/digest v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.48.2 // indirect
|
||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
github.com/quic-go/quic-go v0.53.0 // indirect
|
||||
github.com/refraction-networking/utls v1.7.3 // indirect
|
||||
go.uber.org/mock v0.5.2 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
)
|
||||
|
82
go.sum
82
go.sum
@ -1,71 +1,61 @@
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
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/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
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/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.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/imroc/req/v3 v3.50.0 h1:n3BVnZiTRpvkN5T1IB79LC/THhFU9iXksNRMH4ZNVaY=
|
||||
github.com/imroc/req/v3 v3.50.0/go.mod h1:tsOk8K7zI6cU4xu/VWCZVtq9Djw9IWm4MslKzme5woU=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
|
||||
github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
|
||||
github.com/imroc/req/v3 v3.54.0 h1:kwWJSpT7OvjJ/Q8ykp+69Ye5H486RKDcgEoepw1Ren4=
|
||||
github.com/imroc/req/v3 v3.54.0/go.mod h1:P8gCJjG/XNUFeP6WOi40VAXfYwT+uPM00xvoBWiwzUQ=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5 h1:TUM6XzOB7Z7OxyXi3fwlZY9KfuVbvUBusYiNbSfX208=
|
||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
|
||||
github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
|
||||
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
|
||||
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
const BackTraceVersion = "v0.0.5"
|
||||
const BackTraceVersion = "v0.0.6"
|
||||
|
||||
var EnableLoger = false
|
||||
|
||||
@ -76,3 +76,82 @@ var (
|
||||
CachedIcmpDataFetchTime time.Time
|
||||
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