Compare commits

..

No commits in common. "main" and "v0.0.8-20260501031244" have entirely different histories.

15 changed files with 35 additions and 108 deletions

View File

@ -5,15 +5,12 @@ on:
schedule: schedule:
- cron: '0 0 * * 0' - cron: '0 0 * * 0'
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs: jobs:
fetch-ipv6-prefixes: fetch-ipv6-prefixes:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 检出代码 - name: 检出代码
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -3,22 +3,19 @@ name: CI
on: on:
workflow_dispatch: workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs: jobs:
test: test:
strategy: strategy:
matrix: matrix:
go: ['stable'] go: ['1.22.x']
os: [ubuntu-latest] os: [ubuntu-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v2
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
@ -33,7 +30,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.9-$(date +'%Y%m%d%H%M%S')" TAG="v0.0.8-$(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

View File

@ -9,19 +9,16 @@ on:
# types: [published] # types: [published]
workflow_dispatch: workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs: jobs:
build: build:
name: Build and Test name: Build and Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v3
with: with:
go-version: 'stable' go-version: 'stable'
@ -47,10 +44,10 @@ jobs:
needs: build needs: build
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v3
with: with:
go-version: 'stable' go-version: 'stable'
@ -58,7 +55,7 @@ jobs:
run: | run: |
mkdir -p bin mkdir -p bin
cd cmd cd cmd
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} GOARM=${{ matrix.goarm }} go build \ CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build \
-o ../bin/backtrace-${{ matrix.goos }}-${{ matrix.goarch }} \ -o ../bin/backtrace-${{ matrix.goos }}-${{ matrix.goarch }} \
-v \ -v \
-ldflags="-extldflags=-static -s -w" \ -ldflags="-extldflags=-static -s -w" \
@ -92,6 +89,9 @@ jobs:
goarch: amd64 goarch: amd64
- goos: windows - goos: windows
goarch: arm64 goarch: arm64
- goos: windows
goarch: arm
goarm: 7
- goos: darwin - goos: darwin
goarch: arm64 goarch: arm64
- goos: linux - goos: linux

View File

@ -75,7 +75,7 @@ rm -rf /usr/bin/backtrace
## 在Golang中使用 ## 在Golang中使用
``` ```
go get github.com/oneclickvirt/backtrace@v0.0.9-20260521161358 go get github.com/oneclickvirt/backtrace@v0.0.8-20251109090457
``` ```
## 概览图 ## 概览图

View File

@ -117,10 +117,7 @@ func getSVGPath(ip string) (string, error) {
client := req.C().ImpersonateChrome() client := req.C().ImpersonateChrome()
url := fmt.Sprintf("https://bgp.tools/prefix/%s#connectivity", ip) url := fmt.Sprintf("https://bgp.tools/prefix/%s#connectivity", ip)
resp, err := executeWithRetry(client, url, defaultRetryConfig) resp, err := executeWithRetry(client, url, defaultRetryConfig)
if err == nil && resp != nil { if err == nil {
if resp.Body != nil {
defer resp.Body.Close()
}
body := resp.String() body := resp.String()
re := regexp.MustCompile(`<img[^>]+id="pathimg"[^>]+src="([^"]+)"`) re := regexp.MustCompile(`<img[^>]+id="pathimg"[^>]+src="([^"]+)"`)
matches := re.FindStringSubmatch(body) matches := re.FindStringSubmatch(body)
@ -145,8 +142,7 @@ func downloadSVG(svgPath string) (string, error) {
uuid := uuid.NewString() uuid := uuid.NewString()
url := fmt.Sprintf("https://bgp.tools%s?%s&loggedin", svgPath, uuid) url := fmt.Sprintf("https://bgp.tools%s?%s&loggedin", svgPath, uuid)
resp, err := executeWithRetry(client, url, defaultRetryConfig) resp, err := executeWithRetry(client, url, defaultRetryConfig)
if err == nil && resp != nil && resp.Body != nil { if err == nil {
defer resp.Body.Close()
bodyBytes, err := io.ReadAll(resp.Body) bodyBytes, err := io.ReadAll(resp.Body)
if err == nil { if err == nil {
return string(bodyBytes), nil return string(bodyBytes), nil

View File

@ -7,14 +7,6 @@ import (
"github.com/oneclickvirt/backtrace/model" "github.com/oneclickvirt/backtrace/model"
) )
func safeTraceCall(fn func()) {
defer func() {
if r := recover(); r != nil {
}
}()
fn()
}
func BackTrace(enableIpv6 bool) string { 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)
@ -34,16 +26,10 @@ func BackTrace(enableIpv6 bool) string {
t = time.After(time.Second * 10) t = time.After(time.Second * 10)
) )
for i := range model.Ipv4s { for i := range model.Ipv4s {
idx := i go trace(c, i)
go safeTraceCall(func() {
trace(c, idx)
})
} }
for i := range model.Ipv6s { for i := range model.Ipv6s {
idx := i go traceIPv6(c, i, ipv4Count)
go safeTraceCall(func() {
traceIPv6(c, idx, ipv4Count)
})
} }
loopIPv4v6: loopIPv4v6:
for range s { for range s {
@ -76,10 +62,7 @@ func BackTrace(enableIpv6 bool) string {
t = time.After(time.Second * 10) t = time.After(time.Second * 10)
) )
for i := range model.Ipv4s { for i := range model.Ipv4s {
idx := i go trace(c, i)
go safeTraceCall(func() {
trace(c, idx)
})
} }
loopIPv4: loopIPv4:
for range s { for range s {

View File

@ -2,6 +2,7 @@
2400:9380:9009 2400:9380:9009
2400:9380:9020 2400:9380:9020
2400:9380:9021 2400:9380:9021
2400:9380:9040
2400:9380:9050 2400:9380:9050
2400:9380:9051 2400:9380:9051
2400:9380:9060 2400:9380:9060
@ -18,6 +19,7 @@
2400:9380:9121 2400:9380:9121
2400:9380:9220 2400:9380:9220
2400:9380:9221 2400:9380:9221
2400:9380:9240
2400:9380:9250 2400:9380:9250
2400:9380:9251 2400:9380:9251
2400:9380:9260 2400:9380:9260
@ -96,8 +98,6 @@
240e:649:dc0f 240e:649:dc0f
240e:64e 240e:64e
240e:64e:de0 240e:64e:de0
240e:64e:dec
240e:64e:ded
240e:650 240e:650
240e:659:f100 240e:659:f100
240e:65f 240e:65f

View File

@ -15,5 +15,3 @@
2620:107:4008:d23c 2620:107:4008:d23c
2620:107:4008:d23d 2620:107:4008:d23d
2620:107:4008:d261 2620:107:4008:d261
2620:107:4008:d270
2620:107:4008:d271

View File

@ -862,7 +862,6 @@
2409:8734:2451 2409:8734:2451
2409:8734:c01 2409:8734:c01
2409:8734:c10 2409:8734:c10
2409:8735
2409:874c 2409:874c
2409:874c:c10 2409:874c:c10
2409:874d 2409:874d

View File

@ -233,10 +233,7 @@ func (t *Tracer) serveData(from net.IP, b []byte) error {
return err return err
} }
if msg.Type == ipv4.ICMPTypeEchoReply { if msg.Type == ipv4.ICMPTypeEchoReply {
echo, ok := msg.Body.(*icmp.Echo) echo := msg.Body.(*icmp.Echo)
if !ok || echo == nil {
return errUnsupportedProtocol
}
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()}) return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
} }
b = getReplyData(msg) b = getReplyData(msg)

View File

@ -58,10 +58,6 @@ func extractIpv4ASNsFromHops(hops []*Hop, enableLogger bool) []string {
// trace IPv4追踪函数 // trace IPv4追踪函数
func trace(ch chan Result, i int) { func trace(ch chan Result, i int) {
defer func() {
if r := recover(); r != nil {
}
}()
if model.EnableLoger { if model.EnableLoger {
InitLogger() InitLogger()
defer Logger.Sync() defer Logger.Sync()
@ -76,10 +72,6 @@ func trace(ch chan Result, i int) {
wg.Add(1) wg.Add(1)
go func(attemptNum int) { go func(attemptNum int) {
defer wg.Done() defer wg.Done()
defer func() {
if r := recover(); r != nil {
}
}()
if model.EnableLoger { if model.EnableLoger {
Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv4Names[i], model.Ipv4s[i])) Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv4Names[i], model.Ipv4s[i]))
} }

View File

@ -43,21 +43,10 @@ func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error {
} }
return err return err
} }
srcAddr, ok := src.(*net.IPAddr)
if !ok || srcAddr == nil {
continue
}
hopLimit := 0
if cm != nil {
hopLimit = cm.HopLimit
}
if model.EnableLoger { if model.EnableLoger {
Logger.Info(fmt.Sprintf("收到IPv6响应: 来源=%v, 跳数=%d", srcAddr, hopLimit)) Logger.Info(fmt.Sprintf("收到IPv6响应: 来源=%v, 跳数=%d", src, cm.HopLimit))
}
fromIP := srcAddr.IP
if fromIP == nil {
continue
} }
fromIP := src.(*net.IPAddr).IP
err = t.serveData(fromIP, buf[:n]) err = t.serveData(fromIP, buf[:n])
if err != nil && model.EnableLoger { if err != nil && model.EnableLoger {
Logger.Warn("处理IPv6数据失败: " + err.Error()) Logger.Warn("处理IPv6数据失败: " + err.Error())
@ -84,10 +73,6 @@ func extractIpv6ASNsFromHops(hops []*Hop, enableLogger bool) []string {
// traceIPv6 IPv6追踪函数 // traceIPv6 IPv6追踪函数
func traceIPv6(ch chan Result, i int, offset int) { func traceIPv6(ch chan Result, i int, offset int) {
defer func() {
if r := recover(); r != nil {
}
}()
if model.EnableLoger { if model.EnableLoger {
InitLogger() InitLogger()
defer Logger.Sync() defer Logger.Sync()
@ -102,10 +87,6 @@ func traceIPv6(ch chan Result, i int, offset int) {
wg.Add(1) wg.Add(1)
go func(attemptNum int) { go func(attemptNum int) {
defer wg.Done() defer wg.Done()
defer func() {
if r := recover(); r != nil {
}
}()
if model.EnableLoger { if model.EnableLoger {
Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv6Names[i], model.Ipv6s[i])) Logger.Info(fmt.Sprintf("第%d次尝试追踪 %s (%s)", attemptNum, model.Ipv6Names[i], model.Ipv6s[i]))
} }

View File

@ -47,7 +47,7 @@ func checkCdn(testUrl string) string {
Logger.Info(fmt.Sprintf("Testing CDN: %s", url)) Logger.Info(fmt.Sprintf("Testing CDN: %s", url))
} }
resp, err := client.R().Get(url) resp, err := client.R().Get(url)
if err == nil && resp != nil && resp.Body != nil { if err == nil {
b, err := io.ReadAll(resp.Body) b, err := io.ReadAll(resp.Body)
resp.Body.Close() resp.Body.Close()
if err == nil && strings.Contains(string(b), "success") { if err == nil && strings.Contains(string(b), "success") {
@ -92,7 +92,7 @@ func getData(endpoint string) string {
Logger.Info(fmt.Sprintf("Using CDN: %s", url)) Logger.Info(fmt.Sprintf("Using CDN: %s", url))
} }
resp, err := client.R().Get(url) resp, err := client.R().Get(url)
if err == nil && resp != nil && resp.Body != nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
b, err := io.ReadAll(resp.Body) b, err := io.ReadAll(resp.Body)
if err == nil && !strings.Contains(string(b), "error") { if err == nil && !strings.Contains(string(b), "error") {
@ -112,7 +112,7 @@ func getData(endpoint string) string {
Logger.Info(fmt.Sprintf("Trying direct connection: %s", endpoint)) Logger.Info(fmt.Sprintf("Trying direct connection: %s", endpoint))
} }
resp, err := client.R().Get(endpoint) resp, err := client.R().Get(endpoint)
if err == nil && resp != nil && resp.Body != nil { if err == nil {
defer resp.Body.Close() defer resp.Body.Close()
b, err := io.ReadAll(resp.Body) b, err := io.ReadAll(resp.Body)
if err == nil { if err == nil {

View File

@ -32,23 +32,9 @@ type ConcurrentResults struct {
// backtraceError error // backtraceError error
} }
func safeGo(wg *sync.WaitGroup, fn func()) {
go func() {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
}
}()
fn()
}()
}
func main() { func main() {
go func() { go func() {
resp, err := 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")
if err == nil && resp != nil && resp.Body != nil {
resp.Body.Close()
}
}() }()
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
@ -76,7 +62,6 @@ func main() {
if err != nil { if err != nil {
fmt.Printf("get ip info err %v \n", err.Error()) fmt.Printf("get ip info err %v \n", err.Error())
} else { } else {
defer rsp.Body.Close()
err = json.NewDecoder(rsp.Body).Decode(&info) err = json.NewDecoder(rsp.Body).Decode(&info)
if err != nil { if err != nil {
fmt.Printf("json decode err %v \n", err.Error()) fmt.Printf("json decode err %v \n", err.Error())
@ -121,7 +106,8 @@ func main() {
} }
if targetIP != "" { if targetIP != "" {
wg.Add(1) wg.Add(1)
safeGo(&wg, func() { go func() {
defer wg.Done()
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
result, err := bgptools.GetPoPInfo(targetIP) result, err := bgptools.GetPoPInfo(targetIP)
results.bgpError = err results.bgpError = err
@ -133,13 +119,14 @@ func main() {
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
} }
} }
}) }()
} }
wg.Add(1) wg.Add(1)
safeGo(&wg, func() { go func() {
defer wg.Done()
result := backtrace.BackTrace(useIPv6) result := backtrace.BackTrace(useIPv6)
results.backtraceResult = result results.backtraceResult = result
}) }()
wg.Wait() wg.Wait()
if results.bgpResult != "" { if results.bgpResult != "" {
fmt.Print(results.bgpResult) fmt.Print(results.bgpResult)

View File

@ -2,7 +2,7 @@ package model
import "time" import "time"
const BackTraceVersion = "v0.0.9" const BackTraceVersion = "v0.0.8"
var EnableLoger = false var EnableLoger = false