mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-08-28 18:20:38 +08:00
Compare commits
17 Commits
v0.0.6-202
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f0e0dfcc89 | ||
![]() |
57ce6640f2 | ||
![]() |
c4cff51507 | ||
![]() |
6c92bf5f27 | ||
![]() |
18a47035fe | ||
![]() |
76508d7b27 | ||
![]() |
ab887766fb | ||
![]() |
3045cc198a | ||
![]() |
6f8f3ed60c | ||
![]() |
c7a4dd9475 | ||
![]() |
a011cf049f | ||
![]() |
b68a7e8a20 | ||
![]() |
cd99074950 | ||
![]() |
9737562e39 | ||
![]() |
6f679f403f | ||
![]() |
a74e6c177e | ||
![]() |
02804c1b21 |
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.7-$(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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# backtrace
|
# backtrace
|
||||||
|
|
||||||
[](https://hits.spiritlhl.net)
|
[](https://hits.spiritlhl.net) [](https://github.com/oneclickvirt/backtrace/releases)
|
||||||
|
|
||||||
[](https://github.com/oneclickvirt/backtrace/actions/workflows/main.yaml)
|
[](https://github.com/oneclickvirt/backtrace/actions/workflows/main.yaml)
|
||||||
|
|
||||||
@ -16,9 +16,12 @@
|
|||||||
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
||||||
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
||||||
- [x] 支持对主流接入点的线路检测,方便分析国际互联能力
|
- [x] 支持对主流接入点的线路检测,方便分析国际互联能力
|
||||||
|
- [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地址
|
||||||
|
|
||||||
|
相关输出和查询结果的说明:[跳转](https://github.com/oneclickvirt/ecs/blob/master/README_NEW_USER.md#%E4%B8%8A%E6%B8%B8%E5%8F%8A%E5%9B%9E%E7%A8%8B%E7%BA%BF%E8%B7%AF%E6%A3%80%E6%B5%8B)
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
下载、安装、更新
|
下载、安装、更新
|
||||||
@ -52,6 +55,8 @@ backtrace
|
|||||||
```
|
```
|
||||||
Usage: backtrace [options]
|
Usage: backtrace [options]
|
||||||
-h Show help information
|
-h Show help information
|
||||||
|
-ip string
|
||||||
|
Specify IP address for bgptools
|
||||||
-ipv6
|
-ipv6
|
||||||
Enable ipv6 testing
|
Enable ipv6 testing
|
||||||
-log
|
-log
|
||||||
@ -70,7 +75,7 @@ rm -rf /usr/bin/backtrace
|
|||||||
## 在Golang中使用
|
## 在Golang中使用
|
||||||
|
|
||||||
```
|
```
|
||||||
go get github.com/oneclickvirt/backtrace@v0.0.6-20250805081606
|
go get github.com/oneclickvirt/backtrace@v0.0.7-20250811023541
|
||||||
```
|
```
|
||||||
|
|
||||||
## 概览图
|
## 概览图
|
||||||
|
@ -42,19 +42,16 @@ type PoPResult struct {
|
|||||||
Result string
|
Result string
|
||||||
}
|
}
|
||||||
|
|
||||||
// retryConfig 重试配置
|
|
||||||
type retryConfig struct {
|
type retryConfig struct {
|
||||||
maxRetries int
|
maxRetries int
|
||||||
timeouts []time.Duration
|
timeouts []time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认重试配置:3次重试,超时时间分别为3s、4s、5s
|
|
||||||
var defaultRetryConfig = retryConfig{
|
var defaultRetryConfig = retryConfig{
|
||||||
maxRetries: 2,
|
maxRetries: 2,
|
||||||
timeouts: []time.Duration{5 * time.Second, 6 * time.Second},
|
timeouts: []time.Duration{5 * time.Second, 6 * time.Second},
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeWithRetry 执行带重试的HTTP请求
|
|
||||||
func executeWithRetry(client *req.Client, url string, config retryConfig) (*req.Response, error) {
|
func executeWithRetry(client *req.Client, url string, config retryConfig) (*req.Response, error) {
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for attempt := 0; attempt < config.maxRetries; attempt++ {
|
for attempt := 0; attempt < config.maxRetries; attempt++ {
|
||||||
@ -88,10 +85,12 @@ func getISPAbbr(asn, name string) string {
|
|||||||
|
|
||||||
func getISPType(asn string, tier1 bool, direct bool) string {
|
func getISPType(asn string, tier1 bool, direct bool) string {
|
||||||
switch {
|
switch {
|
||||||
case tier1 && model.Tier1Global[asn] != "":
|
case tier1 && direct && model.Tier1Global[asn] != "":
|
||||||
return "Tier1 Global"
|
return "Tier1 Global"
|
||||||
case model.Tier1Regional[asn] != "":
|
case tier1 && direct && model.Tier1Regional[asn] != "":
|
||||||
return "Tier1 Regional"
|
return "Tier1 Regional"
|
||||||
|
case tier1 && !direct:
|
||||||
|
return "Tier1 Indirect"
|
||||||
case model.Tier2[asn] != "":
|
case model.Tier2[asn] != "":
|
||||||
return "Tier2"
|
return "Tier2"
|
||||||
case model.ContentProviders[asn] != "":
|
case model.ContentProviders[asn] != "":
|
||||||
@ -343,7 +342,6 @@ func GetPoPInfo(ip string) (*PoPResult, error) {
|
|||||||
if ip == "" {
|
if ip == "" {
|
||||||
return nil, fmt.Errorf("IP address cannot be empty")
|
return nil, fmt.Errorf("IP address cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
svgPath, err := getSVGPath(ip)
|
svgPath, err := getSVGPath(ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("获取SVG路径失败: %w", err)
|
return nil, fmt.Errorf("获取SVG路径失败: %w", err)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package backtrace
|
package backtrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oneclickvirt/backtrace/model"
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BackTrace(enableIpv6 bool) {
|
func BackTrace(enableIpv6 bool) string {
|
||||||
if model.CachedIcmpData == "" || model.ParsedIcmpTargets == nil || time.Since(model.CachedIcmpDataFetchTime) > time.Hour {
|
if model.CachedIcmpData == "" || model.ParsedIcmpTargets == nil || time.Since(model.CachedIcmpDataFetchTime) > time.Hour {
|
||||||
model.CachedIcmpData = getData(model.IcmpTargets)
|
model.CachedIcmpData = getData(model.IcmpTargets)
|
||||||
model.CachedIcmpDataFetchTime = time.Now()
|
model.CachedIcmpDataFetchTime = time.Now()
|
||||||
@ -15,6 +15,7 @@ func BackTrace(enableIpv6 bool) {
|
|||||||
model.ParsedIcmpTargets = parseIcmpTargets(model.CachedIcmpData)
|
model.ParsedIcmpTargets = parseIcmpTargets(model.CachedIcmpData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var builder strings.Builder
|
||||||
if enableIpv6 {
|
if enableIpv6 {
|
||||||
ipv4Count := len(model.Ipv4s)
|
ipv4Count := len(model.Ipv4s)
|
||||||
ipv6Count := len(model.Ipv6s)
|
ipv6Count := len(model.Ipv6s)
|
||||||
@ -39,14 +40,18 @@ func BackTrace(enableIpv6 bool) {
|
|||||||
break loopIPv4v6
|
break loopIPv4v6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 收集 IPv4 结果
|
||||||
for i := 0; i < ipv4Count; i++ {
|
for i := 0; i < ipv4Count; i++ {
|
||||||
if s[i] != "" {
|
if s[i] != "" {
|
||||||
fmt.Println(s[i])
|
builder.WriteString(s[i])
|
||||||
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 收集 IPv6 结果
|
||||||
for i := ipv4Count; i < totalCount; i++ {
|
for i := ipv4Count; i < totalCount; i++ {
|
||||||
if s[i] != "" {
|
if s[i] != "" {
|
||||||
fmt.Println(s[i])
|
builder.WriteString(s[i])
|
||||||
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -68,10 +73,15 @@ func BackTrace(enableIpv6 bool) {
|
|||||||
break loopIPv4
|
break loopIPv4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 收集结果
|
||||||
for _, r := range s {
|
for _, r := range s {
|
||||||
if r != "" {
|
if r != "" {
|
||||||
fmt.Println(r)
|
builder.WriteString(r)
|
||||||
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 返回完整结果,去掉末尾的换行符
|
||||||
|
result := builder.String()
|
||||||
|
return strings.TrimSuffix(result, "\n")
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,6 @@
|
|||||||
240e:446
|
240e:446
|
||||||
240e:447
|
240e:447
|
||||||
240e:45
|
240e:45
|
||||||
240e:45:8000
|
|
||||||
240e:46
|
240e:46
|
||||||
240e:46:5008
|
240e:46:5008
|
||||||
240e:47
|
240e:47
|
||||||
|
@ -76,9 +76,11 @@
|
|||||||
240e:476:febf
|
240e:476:febf
|
||||||
240e:476:feff
|
240e:476:feff
|
||||||
240e:604:314
|
240e:604:314
|
||||||
|
240e:604:319
|
||||||
240e:60e:8000
|
240e:60e:8000
|
||||||
240e:60e:8001
|
240e:60e:8001
|
||||||
240e:615
|
240e:615
|
||||||
|
240e:61d
|
||||||
240e:62c
|
240e:62c
|
||||||
240e:638:f
|
240e:638:f
|
||||||
240e:63c
|
240e:63c
|
||||||
@ -96,6 +98,7 @@
|
|||||||
240e:713:f021
|
240e:713:f021
|
||||||
240e:733:4c0
|
240e:733:4c0
|
||||||
240e:f6:8002
|
240e:f6:8002
|
||||||
|
240e:f6:8003
|
||||||
2605:9d80:9003
|
2605:9d80:9003
|
||||||
2605:9d80:9013
|
2605:9d80:9013
|
||||||
2605:9d80:9023
|
2605:9d80:9023
|
||||||
|
@ -115,7 +115,6 @@
|
|||||||
2408:8352
|
2408:8352
|
||||||
2408:8353
|
2408:8353
|
||||||
2408:8354
|
2408:8354
|
||||||
2408:8355
|
|
||||||
2408:8360
|
2408:8360
|
||||||
2408:8361
|
2408:8361
|
||||||
2408:8362
|
2408:8362
|
||||||
@ -284,6 +283,7 @@
|
|||||||
2408:866a
|
2408:866a
|
||||||
2408:866b
|
2408:866b
|
||||||
2408:866c
|
2408:866c
|
||||||
|
2408:866c:202
|
||||||
2408:866d
|
2408:866d
|
||||||
2408:866e
|
2408:866e
|
||||||
2408:866f
|
2408:866f
|
||||||
@ -356,7 +356,6 @@
|
|||||||
2408:8813
|
2408:8813
|
||||||
2408:8814
|
2408:8814
|
||||||
2408:8815
|
2408:8815
|
||||||
2408:8816
|
|
||||||
2408:8818
|
2408:8818
|
||||||
2408:8819
|
2408:8819
|
||||||
2408:882c
|
2408:882c
|
||||||
|
@ -99,7 +99,6 @@
|
|||||||
2409:8017:2b06
|
2409:8017:2b06
|
||||||
2409:8017:2c01
|
2409:8017:2c01
|
||||||
2409:8017:2c03
|
2409:8017:2c03
|
||||||
2409:8018:28f0
|
|
||||||
2409:8018:28f1
|
2409:8018:28f1
|
||||||
2409:801a:3802
|
2409:801a:3802
|
||||||
2409:801d:2901
|
2409:801d:2901
|
||||||
@ -294,6 +293,7 @@
|
|||||||
2409:804b:2c06
|
2409:804b:2c06
|
||||||
2409:804b:2c0b
|
2409:804b:2c0b
|
||||||
2409:804b:800
|
2409:804b:800
|
||||||
|
2409:804b:801
|
||||||
2409:804c
|
2409:804c
|
||||||
2409:804c:10
|
2409:804c:10
|
||||||
2409:804c:11
|
2409:804c:11
|
||||||
@ -767,8 +767,10 @@
|
|||||||
2409:8710
|
2409:8710
|
||||||
2409:8713
|
2409:8713
|
||||||
2409:8730
|
2409:8730
|
||||||
|
2409:8730:110
|
||||||
2409:8730:17f
|
2409:8730:17f
|
||||||
2409:8730:18f
|
2409:8730:18f
|
||||||
|
2409:8730:19c
|
||||||
2409:8730:1af
|
2409:8730:1af
|
||||||
2409:8730:30
|
2409:8730:30
|
||||||
2409:8730:50
|
2409:8730:50
|
||||||
@ -786,6 +788,8 @@
|
|||||||
2409:8734:2351
|
2409:8734:2351
|
||||||
2409:8734:2450
|
2409:8734:2450
|
||||||
2409:8734:2451
|
2409:8734:2451
|
||||||
|
2409:8734:c01
|
||||||
|
2409:8734:c10
|
||||||
2409:8738
|
2409:8738
|
||||||
2409:8738:c20
|
2409:8738:c20
|
||||||
2409:8739:fffe
|
2409:8739:fffe
|
||||||
@ -795,6 +799,9 @@
|
|||||||
2409:874e
|
2409:874e
|
||||||
2409:874f
|
2409:874f
|
||||||
2409:8754
|
2409:8754
|
||||||
|
2409:8754:211
|
||||||
|
2409:8754:21e
|
||||||
|
2409:8754:21f
|
||||||
2409:8754:3250
|
2409:8754:3250
|
||||||
2409:8754:34b0
|
2409:8754:34b0
|
||||||
2409:8754:34c0
|
2409:8754:34c0
|
||||||
@ -1082,6 +1089,7 @@
|
|||||||
2409:8958
|
2409:8958
|
||||||
2409:8959
|
2409:8959
|
||||||
2409:895a
|
2409:895a
|
||||||
|
2409:895b
|
||||||
2409:895c
|
2409:895c
|
||||||
2409:895c:f900
|
2409:895c:f900
|
||||||
2409:895c:fc5a
|
2409:895c:fc5a
|
||||||
@ -1529,6 +1537,7 @@
|
|||||||
2409:8c00
|
2409:8c00
|
||||||
2409:8c00:7840
|
2409:8c00:7840
|
||||||
2409:8c02
|
2409:8c02
|
||||||
|
2409:8c02:25c
|
||||||
2409:8c10
|
2409:8c10
|
||||||
2409:8c14
|
2409:8c14
|
||||||
2409:8c15
|
2409:8c15
|
||||||
@ -1540,7 +1549,9 @@
|
|||||||
2409:8c20:1833
|
2409:8c20:1833
|
||||||
2409:8c2f:3800
|
2409:8c2f:3800
|
||||||
2409:8c30
|
2409:8c30
|
||||||
|
2409:8c30:40
|
||||||
2409:8c34
|
2409:8c34
|
||||||
|
2409:8c34:600
|
||||||
2409:8c38
|
2409:8c38
|
||||||
2409:8c38:1a00
|
2409:8c38:1a00
|
||||||
2409:8c39
|
2409:8c39
|
||||||
@ -1585,6 +1596,7 @@
|
|||||||
2409:8c5e:a0
|
2409:8c5e:a0
|
||||||
2409:8c5f
|
2409:8c5f
|
||||||
2409:8c60
|
2409:8c60
|
||||||
|
2409:8c60:2400
|
||||||
2409:8c60:ea00
|
2409:8c60:ea00
|
||||||
2409:8c61
|
2409:8c61
|
||||||
2409:8c62
|
2409:8c62
|
||||||
@ -1613,6 +1625,7 @@
|
|||||||
2409:8c70:3ad4
|
2409:8c70:3ad4
|
||||||
2409:8c70:3ad8
|
2409:8c70:3ad8
|
||||||
2409:8c74
|
2409:8c74
|
||||||
|
2409:8c74:7e10
|
||||||
2409:8c78
|
2409:8c78
|
||||||
2409:8c7a
|
2409:8c7a
|
||||||
2409:8c7c
|
2409:8c7c
|
||||||
@ -1631,6 +1644,7 @@
|
|||||||
2409:8c85:3c02
|
2409:8c85:3c02
|
||||||
2409:8c85:3c03
|
2409:8c85:3c03
|
||||||
2409:8c85:411
|
2409:8c85:411
|
||||||
|
2409:8c85:420
|
||||||
2409:8c85:4400
|
2409:8c85:4400
|
||||||
2409:8c85:4c00
|
2409:8c85:4c00
|
||||||
2409:8c85:5c00
|
2409:8c85:5c00
|
||||||
@ -1681,6 +1695,7 @@
|
|||||||
2409:8d38
|
2409:8d38
|
||||||
2409:8d4c
|
2409:8d4c
|
||||||
2409:8d5a
|
2409:8d5a
|
||||||
|
2409:8d5b
|
||||||
2409:8d5c
|
2409:8d5c
|
||||||
2409:8d5e
|
2409:8d5e
|
||||||
2409:8d5f
|
2409:8d5f
|
||||||
@ -1766,6 +1781,7 @@
|
|||||||
2409:8e34
|
2409:8e34
|
||||||
2409:8e38
|
2409:8e38
|
||||||
2409:8e4c
|
2409:8e4c
|
||||||
|
2409:8e5a
|
||||||
2409:8e5c
|
2409:8e5c
|
||||||
2409:8e5e
|
2409:8e5e
|
||||||
2409:8e5f
|
2409:8e5f
|
||||||
|
@ -194,14 +194,15 @@ func (t *Tracer) serveData(from net.IP, b []byte) error {
|
|||||||
Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
|
Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
|
||||||
}
|
}
|
||||||
// 处理不同类型的ICMP消息
|
// 处理不同类型的ICMP消息
|
||||||
if msg.Type == ipv6.ICMPTypeEchoReply {
|
switch msg.Type {
|
||||||
|
case ipv6.ICMPTypeEchoReply:
|
||||||
if echo, ok := msg.Body.(*icmp.Echo); ok {
|
if echo, ok := msg.Body.(*icmp.Echo); ok {
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Info(fmt.Sprintf("处理IPv6回显应答: ID=%d, Seq=%d", echo.ID, echo.Seq))
|
Logger.Info(fmt.Sprintf("处理IPv6回显应答: ID=%d, Seq=%d", echo.ID, echo.Seq))
|
||||||
}
|
}
|
||||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
||||||
}
|
}
|
||||||
} else if msg.Type == ipv6.ICMPTypeTimeExceeded {
|
case ipv6.ICMPTypeTimeExceeded:
|
||||||
b = getReplyData(msg)
|
b = getReplyData(msg)
|
||||||
if len(b) < ipv6.HeaderLen {
|
if len(b) < ipv6.HeaderLen {
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/oneclickvirt/backtrace/model"
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
. "github.com/oneclickvirt/defaultset"
|
. "github.com/oneclickvirt/defaultset"
|
||||||
@ -62,46 +63,66 @@ func trace(ch chan Result, i int) {
|
|||||||
defer Logger.Sync()
|
defer Logger.Sync()
|
||||||
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv4Names[i], model.Ipv4s[i]))
|
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||||
}
|
}
|
||||||
// 先尝试原始IP地址
|
var allHops [][]*Hop
|
||||||
hops, err := Trace(net.ParseIP(model.Ipv4s[i]))
|
var successfulTraces int
|
||||||
if err != nil {
|
var mu sync.Mutex
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
// 并发执行3次trace
|
||||||
|
for attempt := 1; attempt <= 3; attempt++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(attemptNum int) {
|
||||||
|
defer wg.Done()
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv4Names[i], model.Ipv4s[i]))
|
||||||
|
}
|
||||||
|
// 先尝试原始IP地址
|
||||||
|
hops, err := Trace(net.ParseIP(model.Ipv4s[i]))
|
||||||
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Warn(fmt.Sprintf("第%d次追踪 %s (%s) 失败: %v", attemptNum, model.Ipv4Names[i], model.Ipv4s[i], err))
|
||||||
|
}
|
||||||
|
// 如果原始IP失败,尝试备选IP
|
||||||
|
if tryAltIPs := tryAlternativeIPs(model.Ipv4Names[i], "v4"); len(tryAltIPs) > 0 {
|
||||||
|
for _, altIP := range tryAltIPs {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次尝试备选IP %s 追踪 %s", attemptNum, altIP, model.Ipv4Names[i]))
|
||||||
|
}
|
||||||
|
hops, err = Trace(net.ParseIP(altIP))
|
||||||
|
if err == nil && len(hops) > 0 {
|
||||||
|
break // 成功找到可用IP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil && len(hops) > 0 {
|
||||||
|
mu.Lock()
|
||||||
|
allHops = append(allHops, hops)
|
||||||
|
successfulTraces++
|
||||||
|
mu.Unlock()
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次追踪 %s (%s) 成功,获得%d个hop", attemptNum, model.Ipv4Names[i], model.Ipv4s[i], len(hops)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(attempt)
|
||||||
|
}
|
||||||
|
// 等待所有goroutine完成
|
||||||
|
wg.Wait()
|
||||||
|
// 如果3次都失败
|
||||||
|
if successfulTraces == 0 {
|
||||||
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IP地址"))
|
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IP地址"))
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", model.Ipv4Names[i], model.Ipv4s[i], err))
|
Logger.Error(fmt.Sprintf("%s (%s) 3次尝试都失败,检测不到回程路由节点的IP地址", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||||
}
|
}
|
||||||
ch <- Result{i, s}
|
ch <- Result{i, s}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
asns := extractIpv4ASNsFromHops(hops, model.EnableLoger)
|
// 合并hops结果
|
||||||
// 如果没有找到ASN,尝试备选IP
|
mergedHops := mergeHops(allHops)
|
||||||
if len(asns) == 0 {
|
if model.EnableLoger {
|
||||||
// 尝试从IcmpTargets获取备选IP
|
Logger.Info(fmt.Sprintf("%s (%s) 完成%d次成功追踪,合并后获得%d个hop", model.Ipv4Names[i], model.Ipv4s[i], successfulTraces, len(mergedHops)))
|
||||||
if tryAltIPs := tryAlternativeIPs(model.Ipv4Names[i], "v4"); len(tryAltIPs) > 0 {
|
|
||||||
for _, altIP := range tryAltIPs {
|
|
||||||
if model.EnableLoger {
|
|
||||||
Logger.Info(fmt.Sprintf("尝试备选IP %s 追踪 %s", altIP, model.Ipv4Names[i]))
|
|
||||||
}
|
|
||||||
hops, err = Trace(net.ParseIP(altIP))
|
|
||||||
if err == nil && len(hops) > 0 {
|
|
||||||
newAsns := extractIpv4ASNsFromHops(hops, model.EnableLoger)
|
|
||||||
asns = append(asns, newAsns...)
|
|
||||||
if len(newAsns) > 0 {
|
|
||||||
break // 成功找到可用IP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
asns = removeDuplicates(asns)
|
// 从合并后的hops提取ASN
|
||||||
// // 记录每个hop的信息
|
asns := extractIpv4ASNsFromHops(mergedHops, model.EnableLoger)
|
||||||
// if model.EnableLoger {
|
|
||||||
// for hopNum, hop := range hops {
|
|
||||||
// for nodeNum, node := range hop.Nodes {
|
|
||||||
// Logger.Info(fmt.Sprintf("追踪 %s (%s) - Hop %d, Node %d: %s (RTT: %v)",
|
|
||||||
// model.Ipv4Names[i], model.Ipv4s[i], hopNum+1, nodeNum+1, node.IP.String(), node.RTT))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// 处理不同线路
|
// 处理不同线路
|
||||||
if len(asns) > 0 {
|
if len(asns) > 0 {
|
||||||
var tempText string
|
var tempText string
|
||||||
@ -167,18 +188,16 @@ func trace(ch chan Result, i int) {
|
|||||||
}
|
}
|
||||||
if tempText == (fmt.Sprintf("%v ", model.Ipv4Names[i]) + fmt.Sprintf("%-15s ", model.Ipv4s[i])) {
|
if tempText == (fmt.Sprintf("%v ", model.Ipv4Names[i]) + fmt.Sprintf("%-15s ", model.Ipv4s[i])) {
|
||||||
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
||||||
|
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", model.Ipv4Names[i], model.Ipv4s[i]))
|
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", model.Ipv4Names[i], model.Ipv4s[i], tempText))
|
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,最终结果: %s", model.Ipv4Names[i], model.Ipv4s[i], tempText))
|
||||||
}
|
}
|
||||||
ch <- Result{i, tempText}
|
ch <- Result{i, tempText}
|
||||||
} else {
|
} else {
|
||||||
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IPV4地址"))
|
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IPV4地址"))
|
||||||
|
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IPV4地址", model.Ipv4Names[i], model.Ipv4s[i]))
|
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IPV4地址", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/oneclickvirt/backtrace/model"
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
. "github.com/oneclickvirt/defaultset"
|
. "github.com/oneclickvirt/defaultset"
|
||||||
@ -11,7 +12,7 @@ import (
|
|||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newPacketV6(id uint16, dst net.IP, ttl int) []byte {
|
func newPacketV6(id uint16, _ net.IP, _ int) []byte {
|
||||||
// 使用ipv6包的Echo请求
|
// 使用ipv6包的Echo请求
|
||||||
msg := icmp.Message{
|
msg := icmp.Message{
|
||||||
Type: ipv6.ICMPTypeEchoRequest,
|
Type: ipv6.ICMPTypeEchoRequest,
|
||||||
@ -77,46 +78,66 @@ func traceIPv6(ch chan Result, i int, offset int) {
|
|||||||
defer Logger.Sync()
|
defer Logger.Sync()
|
||||||
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv6Names[i], model.Ipv6s[i]))
|
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||||
}
|
}
|
||||||
// 先尝试原始IP地址
|
var allHops [][]*Hop
|
||||||
hops, err := Trace(net.ParseIP(model.Ipv6s[i]))
|
var successfulTraces int
|
||||||
if err != nil {
|
var mu sync.Mutex
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
// 并发执行3次trace
|
||||||
|
for attempt := 1; attempt <= 3; attempt++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(attemptNum int) {
|
||||||
|
defer wg.Done()
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv6Names[i], model.Ipv6s[i]))
|
||||||
|
}
|
||||||
|
// 先尝试原始IP地址
|
||||||
|
hops, err := Trace(net.ParseIP(model.Ipv6s[i]))
|
||||||
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Warn(fmt.Sprintf("第%d次追踪 %s (%s) 失败: %v", attemptNum, model.Ipv6Names[i], model.Ipv6s[i], err))
|
||||||
|
}
|
||||||
|
// 如果原始IP失败,尝试备选IP
|
||||||
|
if tryAltIPs := tryAlternativeIPs(model.Ipv6Names[i], "v6"); len(tryAltIPs) > 0 {
|
||||||
|
for _, altIP := range tryAltIPs {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次尝试备选IP %s 追踪 %s", attemptNum, altIP, model.Ipv6Names[i]))
|
||||||
|
}
|
||||||
|
hops, err = Trace(net.ParseIP(altIP))
|
||||||
|
if err == nil && len(hops) > 0 {
|
||||||
|
break // 成功找到可用IP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil && len(hops) > 0 {
|
||||||
|
mu.Lock()
|
||||||
|
allHops = append(allHops, hops)
|
||||||
|
successfulTraces++
|
||||||
|
mu.Unlock()
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("第%d次追踪 %s (%s) 成功,获得%d个hop", attemptNum, model.Ipv6Names[i], model.Ipv6s[i], len(hops)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(attempt)
|
||||||
|
}
|
||||||
|
// 等待所有goroutine完成
|
||||||
|
wg.Wait()
|
||||||
|
// 如果3次都失败
|
||||||
|
if successfulTraces == 0 {
|
||||||
s := fmt.Sprintf("%v %-24s %v", model.Ipv6Names[i], model.Ipv6s[i], Red("检测不到回程路由节点的IP地址"))
|
s := fmt.Sprintf("%v %-24s %v", model.Ipv6Names[i], model.Ipv6s[i], Red("检测不到回程路由节点的IP地址"))
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", model.Ipv6Names[i], model.Ipv6s[i]))
|
Logger.Warn(fmt.Sprintf("%s (%s) 3次尝试都失败,检测不到回程路由节点的IP地址", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||||
}
|
}
|
||||||
ch <- Result{i + offset, s}
|
ch <- Result{i + offset, s}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
asns := extractIpv6ASNsFromHops(hops, model.EnableLoger)
|
// 合并hops结果
|
||||||
// 如果没有找到ASN,尝试备选IP
|
mergedHops := mergeHops(allHops)
|
||||||
if len(asns) == 0 {
|
if model.EnableLoger {
|
||||||
// 尝试从IcmpTargets获取备选IP
|
Logger.Info(fmt.Sprintf("%s (%s) 完成%d次成功追踪,合并后获得%d个hop", model.Ipv6Names[i], model.Ipv6s[i], successfulTraces, len(mergedHops)))
|
||||||
if tryAltIPs := tryAlternativeIPs(model.Ipv6Names[i], "v6"); len(tryAltIPs) > 0 {
|
|
||||||
for _, altIP := range tryAltIPs {
|
|
||||||
if model.EnableLoger {
|
|
||||||
Logger.Info(fmt.Sprintf("尝试备选IP %s 追踪 %s", altIP, model.Ipv6Names[i]))
|
|
||||||
}
|
|
||||||
hops, err = Trace(net.ParseIP(altIP))
|
|
||||||
if err == nil && len(hops) > 0 {
|
|
||||||
newAsns := extractIpv6ASNsFromHops(hops, model.EnableLoger)
|
|
||||||
asns = append(asns, newAsns...)
|
|
||||||
if len(newAsns) > 0 {
|
|
||||||
break // 成功找到可用IP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
asns = removeDuplicates(asns)
|
// 从合并后的hops提取ASN
|
||||||
// // 记录每个hop的信息
|
asns := extractIpv6ASNsFromHops(mergedHops, model.EnableLoger)
|
||||||
// if model.EnableLoger {
|
|
||||||
// for hopNum, hop := range hops {
|
|
||||||
// for nodeNum, node := range hop.Nodes {
|
|
||||||
// Logger.Info(fmt.Sprintf("追踪 %s (%s) - Hop %d, Node %d: %s (RTT: %v)",
|
|
||||||
// model.Ipv6Names[i], model.Ipv6s[i], hopNum+1, nodeNum+1, node.IP.String(), node.RTT))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// 处理不同线路
|
// 处理不同线路
|
||||||
if len(asns) > 0 {
|
if len(asns) > 0 {
|
||||||
var tempText string
|
var tempText string
|
||||||
@ -187,7 +208,7 @@ func traceIPv6(ch chan Result, i int, offset int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if model.EnableLoger {
|
if model.EnableLoger {
|
||||||
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", model.Ipv6Names[i], model.Ipv6s[i], tempText))
|
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,最终结果: %s", model.Ipv6Names[i], model.Ipv6s[i], tempText))
|
||||||
}
|
}
|
||||||
ch <- Result{i + offset, tempText}
|
ch <- Result{i + offset, tempText}
|
||||||
} else {
|
} else {
|
||||||
|
73
bk/utils.go
73
bk/utils.go
@ -140,3 +140,76 @@ func tryAlternativeIPs(targetName string, ipVersion string) []string {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mergeHops 合并多个hops结果
|
||||||
|
func mergeHops(allHops [][]*Hop) []*Hop {
|
||||||
|
if len(allHops) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(allHops) == 1 {
|
||||||
|
return allHops[0]
|
||||||
|
}
|
||||||
|
// 找到最大长度
|
||||||
|
maxLen := 0
|
||||||
|
for _, hops := range allHops {
|
||||||
|
if len(hops) > maxLen {
|
||||||
|
maxLen = len(hops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var mergedHops []*Hop
|
||||||
|
// 逐位置合并
|
||||||
|
for pos := 0; pos < maxLen; pos++ {
|
||||||
|
var availableHops []*Hop
|
||||||
|
// 收集当前位置所有可用的hop
|
||||||
|
for _, hops := range allHops {
|
||||||
|
if pos < len(hops) {
|
||||||
|
availableHops = append(availableHops, hops[pos])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(availableHops) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 如果只有一个可用hop,直接使用
|
||||||
|
if len(availableHops) == 1 {
|
||||||
|
mergedHops = append(mergedHops, availableHops[0])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 统计相同的hop(通过比较第一个node的IP)
|
||||||
|
hopCount := make(map[string][]*Hop)
|
||||||
|
for _, hop := range availableHops {
|
||||||
|
var key string
|
||||||
|
if len(hop.Nodes) > 0 && hop.Nodes[0].IP != nil {
|
||||||
|
key = hop.Nodes[0].IP.String()
|
||||||
|
} else {
|
||||||
|
key = "*" // 超时或无响应
|
||||||
|
}
|
||||||
|
if _, exists := hopCount[key]; !exists {
|
||||||
|
hopCount[key] = make([]*Hop, 0)
|
||||||
|
}
|
||||||
|
hopCount[key] = append(hopCount[key], hop)
|
||||||
|
}
|
||||||
|
// 按多数原则选择hop
|
||||||
|
if len(hopCount) == 1 {
|
||||||
|
// 所有hop都相同,选择第一个
|
||||||
|
mergedHops = append(mergedHops, availableHops[0])
|
||||||
|
} else {
|
||||||
|
// 找出最多的hop类型
|
||||||
|
maxCount := 0
|
||||||
|
var majorityHops []*Hop
|
||||||
|
for _, hops := range hopCount {
|
||||||
|
if len(hops) > maxCount {
|
||||||
|
maxCount = len(hops)
|
||||||
|
majorityHops = hops
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果有多数派,使用多数派的第一个
|
||||||
|
if maxCount > 1 || len(hopCount) == 2 {
|
||||||
|
mergedHops = append(mergedHops, majorityHops[0])
|
||||||
|
} else {
|
||||||
|
// 三个都不同,按请求早晚顺序选择第一个
|
||||||
|
mergedHops = append(mergedHops, availableHops[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedHops
|
||||||
|
}
|
||||||
|
89
cmd/main.go
89
cmd/main.go
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oneclickvirt/backtrace/bgptools"
|
"github.com/oneclickvirt/backtrace/bgptools"
|
||||||
@ -24,18 +25,27 @@ type IpInfo struct {
|
|||||||
Org string `json:"org"`
|
Org string `json:"org"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConcurrentResults struct {
|
||||||
|
bgpResult string
|
||||||
|
backtraceResult string
|
||||||
|
bgpError error
|
||||||
|
// backtraceError error
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go func() {
|
go func() {
|
||||||
http.Get("https://hits.spiritlhl.net/backtrace.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false")
|
http.Get("https://hits.spiritlhl.net/backtrace.svg?action=hit&title=Hits&title_bg=%23555555&count_bg=%230eecf8&edge_flat=false")
|
||||||
}()
|
}()
|
||||||
fmt.Println(Green("Repo:"), Yellow("https://github.com/oneclickvirt/backtrace"))
|
fmt.Println(Green("Repo:"), Yellow("https://github.com/oneclickvirt/backtrace"))
|
||||||
var showVersion, showIpInfo, help, ipv6 bool
|
var showVersion, showIpInfo, help, ipv6 bool
|
||||||
|
var specifiedIP string
|
||||||
backtraceFlag := flag.NewFlagSet("backtrace", flag.ContinueOnError)
|
backtraceFlag := flag.NewFlagSet("backtrace", flag.ContinueOnError)
|
||||||
backtraceFlag.BoolVar(&help, "h", false, "Show help information")
|
backtraceFlag.BoolVar(&help, "h", false, "Show help information")
|
||||||
backtraceFlag.BoolVar(&showVersion, "v", false, "Show version")
|
backtraceFlag.BoolVar(&showVersion, "v", false, "Show version")
|
||||||
backtraceFlag.BoolVar(&showIpInfo, "s", true, "Disabe show ip info")
|
backtraceFlag.BoolVar(&showIpInfo, "s", true, "Disabe show ip info")
|
||||||
backtraceFlag.BoolVar(&model.EnableLoger, "log", false, "Enable logging")
|
backtraceFlag.BoolVar(&model.EnableLoger, "log", false, "Enable logging")
|
||||||
backtraceFlag.BoolVar(&ipv6, "ipv6", false, "Enable ipv6 testing")
|
backtraceFlag.BoolVar(&ipv6, "ipv6", false, "Enable ipv6 testing")
|
||||||
|
backtraceFlag.StringVar(&specifiedIP, "ip", "", "Specify IP address for bgptools")
|
||||||
backtraceFlag.Parse(os.Args[1:])
|
backtraceFlag.Parse(os.Args[1:])
|
||||||
if help {
|
if help {
|
||||||
fmt.Printf("Usage: %s [options]\n", os.Args[0])
|
fmt.Printf("Usage: %s [options]\n", os.Args[0])
|
||||||
@ -50,11 +60,11 @@ func main() {
|
|||||||
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.Printf("get ip info err %v \n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
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.Printf("json decode err %v \n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(Green("国家: ") + White(info.Country) + Green(" 城市: ") + White(info.City) +
|
fmt.Println(Green("国家: ") + White(info.Country) + Green(" 城市: ") + White(info.City) +
|
||||||
Green(" 服务商: ") + Blue(info.Org))
|
Green(" 服务商: ") + Blue(info.Org))
|
||||||
@ -62,23 +72,70 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preCheck := utils.CheckPublicAccess(3 * time.Second)
|
preCheck := utils.CheckPublicAccess(3 * time.Second)
|
||||||
if preCheck.Connected && info.Ip != "" {
|
if !preCheck.Connected {
|
||||||
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" {
|
|
||||||
backtrace.BackTrace(false)
|
|
||||||
} else if preCheck.Connected && preCheck.StackType == "IPv6" {
|
|
||||||
backtrace.BackTrace(true)
|
|
||||||
} else {
|
|
||||||
fmt.Println(Red("PreCheck IP Type Failed"))
|
fmt.Println(Red("PreCheck IP Type Failed"))
|
||||||
|
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||||
|
fmt.Println("Press Enter to exit...")
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var useIPv6 bool
|
||||||
|
switch preCheck.StackType {
|
||||||
|
case "DualStack":
|
||||||
|
useIPv6 = ipv6
|
||||||
|
case "IPv4":
|
||||||
|
useIPv6 = false
|
||||||
|
case "IPv6":
|
||||||
|
useIPv6 = true
|
||||||
|
default:
|
||||||
|
fmt.Println(Red("PreCheck IP Type Failed"))
|
||||||
|
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||||
|
fmt.Println("Press Enter to exit...")
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
results := ConcurrentResults{}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var targetIP string
|
||||||
|
if specifiedIP != "" {
|
||||||
|
targetIP = specifiedIP
|
||||||
|
} else if info.Ip != "" {
|
||||||
|
targetIP = info.Ip
|
||||||
|
}
|
||||||
|
if targetIP != "" {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
result, err := bgptools.GetPoPInfo(targetIP)
|
||||||
|
results.bgpError = err
|
||||||
|
if err == nil && result.Result != "" {
|
||||||
|
results.bgpResult = result.Result
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
result := backtrace.BackTrace(useIPv6)
|
||||||
|
results.backtraceResult = result
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
if results.bgpResult != "" {
|
||||||
|
fmt.Print(results.bgpResult)
|
||||||
|
}
|
||||||
|
if results.backtraceResult != "" {
|
||||||
|
fmt.Printf("%s\n", results.backtraceResult)
|
||||||
}
|
}
|
||||||
fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考"))
|
fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考"))
|
||||||
fmt.Println(Yellow("同一目标地址多个线路时,可能检测已越过汇聚层,除了第一个线路外,后续信息可能无效"))
|
fmt.Println(Yellow("同一目标地址多个线路时,检测可能已越过汇聚层,除第一个线路外,后续信息可能无效"))
|
||||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||||
fmt.Println("Press Enter to exit...")
|
fmt.Println("Press Enter to exit...")
|
||||||
fmt.Scanln()
|
fmt.Scanln()
|
||||||
|
@ -2,7 +2,7 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const BackTraceVersion = "v0.0.6"
|
const BackTraceVersion = "v0.0.7"
|
||||||
|
|
||||||
var EnableLoger = false
|
var EnableLoger = false
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user