mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-08-02 21:56:58 +08:00
fix: 修复间接上游识别
This commit is contained in:
parent
461c28f3d1
commit
cfed3329d2
@ -15,13 +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点检测,区分国际互联能力
|
||||
|
||||
## 使用
|
||||
|
||||
下载、安装、更新
|
||||
|
164
bgptools/pop.go
164
bgptools/pop.go
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
)
|
||||
|
||||
type ASCard struct {
|
||||
@ -39,82 +40,32 @@ type PoPResult struct {
|
||||
Result string
|
||||
}
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
var tier1Regional = map[string]string{
|
||||
"4134": "ChinaNet",
|
||||
"4837": "China Unicom",
|
||||
"9808": "China Mobile",
|
||||
"4766": "Korea Telecom",
|
||||
"2516": "KDDI",
|
||||
"7713": "Telkomnet",
|
||||
"9121": "Etisalat",
|
||||
}
|
||||
|
||||
var tier2 = map[string]string{
|
||||
"6939": "Hurricane Electric",
|
||||
"20485": "Transtelecom",
|
||||
"1273": "Vodafone",
|
||||
"1239": "Sprint",
|
||||
"6762": "Sparkle",
|
||||
"6453": "Tata",
|
||||
}
|
||||
|
||||
var contentProviders = map[string]string{
|
||||
"15169": "Google",
|
||||
"32934": "Facebook",
|
||||
"54113": "Fastly",
|
||||
"20940": "Akamai",
|
||||
"13335": "Cloudflare",
|
||||
}
|
||||
|
||||
var ixps = map[string]string{
|
||||
"5539": "IX.br",
|
||||
"25291": "HKIX",
|
||||
"1200": "AMS-IX",
|
||||
"6695": "DE-CIX",
|
||||
}
|
||||
|
||||
func getISPAbbr(asn, name string) string {
|
||||
if abbr, ok := tier1Global[asn]; ok {
|
||||
if abbr, ok := model.Tier1Global[asn]; ok {
|
||||
return abbr
|
||||
}
|
||||
if idx := strings.Index(name, " "); idx != -1 {
|
||||
if idx := strings.Index(name, " "); idx != -1 && idx > 18 {
|
||||
return name[:idx]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func getISPType(asn string, tier1 bool) string {
|
||||
func getISPType(asn string, tier1 bool, direct bool) string {
|
||||
switch {
|
||||
case tier1 && tier1Global[asn] != "":
|
||||
case tier1 && model.Tier1Global[asn] != "":
|
||||
return "Tier1 Global"
|
||||
case tier1Regional[asn] != "":
|
||||
case model.Tier1Regional[asn] != "":
|
||||
return "Tier1 Regional"
|
||||
case tier2[asn] != "":
|
||||
case model.Tier2[asn] != "":
|
||||
return "Tier2"
|
||||
case contentProviders[asn] != "":
|
||||
case model.ContentProviders[asn] != "":
|
||||
return "CDN Provider"
|
||||
case ixps[asn] != "":
|
||||
case model.IXPS[asn] != "":
|
||||
return "IXP"
|
||||
default:
|
||||
case direct:
|
||||
return "Direct"
|
||||
default:
|
||||
return "Indirect"
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +187,7 @@ func findUpstreams(targetASN string, nodes []ASCard, edges []Arrow) []Upstream {
|
||||
continue
|
||||
}
|
||||
isTier1 := (n.Fill == "white" && n.Stroke == "#005ea5")
|
||||
upstreamType := getISPType(n.ASN, isTier1)
|
||||
upstreamType := getISPType(n.ASN, isTier1, true)
|
||||
upstreams = append(upstreams, Upstream{
|
||||
ASN: n.ASN,
|
||||
Name: n.Name,
|
||||
@ -245,6 +196,55 @@ func findUpstreams(targetASN string, nodes []ASCard, edges []Arrow) []Upstream {
|
||||
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
|
||||
}
|
||||
|
||||
@ -270,33 +270,39 @@ func GetPoPInfo(ip string) (*PoPResult, error) {
|
||||
return nil, fmt.Errorf("无法识别目标 ASN")
|
||||
}
|
||||
upstreams := findUpstreams(targetASN, nodes, edges)
|
||||
if len(upstreams) > 5 {
|
||||
upstreams = upstreams[:5]
|
||||
}
|
||||
colWidth := 16
|
||||
colWidth := 18
|
||||
center := func(s string) string {
|
||||
runeLen := len([]rune(s))
|
||||
if runeLen >= colWidth {
|
||||
return s[:colWidth]
|
||||
return string([]rune(s)[:colWidth])
|
||||
}
|
||||
padding := colWidth - runeLen
|
||||
left := padding / 2
|
||||
right := padding - left
|
||||
return strings.Repeat(" ", left) + s + strings.Repeat(" ", right)
|
||||
}
|
||||
var line1, line2, line3 []string
|
||||
for _, u := range upstreams {
|
||||
abbr := getISPAbbr(u.ASN, u.Name)
|
||||
line1 = append(line1, center("AS"+u.ASN))
|
||||
line2 = append(line2, center(abbr))
|
||||
line3 = append(line3, center(u.Type))
|
||||
}
|
||||
var result strings.Builder
|
||||
result.WriteString(strings.Join(line1, ""))
|
||||
result.WriteString("\n")
|
||||
result.WriteString(strings.Join(line2, ""))
|
||||
result.WriteString("\n")
|
||||
result.WriteString(strings.Join(line3, ""))
|
||||
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)
|
||||
line1 = append(line1, center("AS"+u.ASN))
|
||||
line2 = append(line2, center(abbr))
|
||||
line3 = append(line3, center(u.Type))
|
||||
}
|
||||
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,
|
||||
|
@ -6,12 +6,14 @@ import (
|
||||
)
|
||||
|
||||
func TestGetPoPInfo(t *testing.T) {
|
||||
result, err := GetPoPInfo("66.70.153.71")
|
||||
result, err := GetPoPInfo("206.190.233.1")
|
||||
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)
|
||||
}
|
||||
|
12
cmd/main.go
12
cmd/main.go
@ -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,15 @@ func main() {
|
||||
}
|
||||
}
|
||||
preCheck := utils.CheckPublicAccess(3 * time.Second)
|
||||
if preCheck.Connected && info.Ip != "" {
|
||||
result, err := bgptools.GetPoPInfo(info.Ip)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("上游信息:")
|
||||
fmt.Print(result.Result)
|
||||
}
|
||||
if preCheck.Connected && preCheck.StackType == "DualStack" {
|
||||
backtrace.BackTrace(ipv6)
|
||||
} else if preCheck.Connected && preCheck.StackType == "IPv4" {
|
||||
|
@ -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