mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-04-20 03:02:08 +08:00
Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1bb9b848c | ||
![]() |
d975fe6906 | ||
![]() |
c550861ce5 | ||
![]() |
2d03ca1281 | ||
![]() |
d58a45dc56 | ||
![]() |
3995e1a1bd | ||
![]() |
a2a95e0444 | ||
![]() |
fa1da298d7 | ||
![]() |
9c58bb35cd | ||
![]() |
b3be692d7e | ||
![]() |
6f0fc98154 | ||
![]() |
a268e0b48b | ||
![]() |
af5dd4eb3d | ||
![]() |
211c724509 | ||
![]() |
0c7727e3dc | ||
![]() |
2adf709e63 | ||
![]() |
aad93e51f8 | ||
![]() |
a832d354da | ||
![]() |
f1ccde0ea9 | ||
![]() |
4caf507831 | ||
![]() |
ddc2f9b401 | ||
![]() |
93434aeda1 | ||
![]() |
341c21f1e5 | ||
![]() |
fcc0403612 | ||
![]() |
466c8dbe5d | ||
![]() |
16484ea6ca | ||
![]() |
ba10f8b64c | ||
![]() |
09abb17c08 | ||
![]() |
aa8bc941a6 | ||
![]() |
3b19d43eef | ||
![]() |
c9c62e86f3 | ||
![]() |
1a985cfbbe | ||
![]() |
9dc08856e0 | ||
![]() |
4c546a4239 | ||
![]() |
560b9e441e | ||
![]() |
5b416aa419 | ||
![]() |
b93b8fbb4a | ||
![]() |
7a644b403e | ||
![]() |
7efc61cbe4 | ||
![]() |
0c6b11883f | ||
![]() |
4f9603bee7 | ||
![]() |
509f6a3dd6 | ||
![]() |
8d69825c32 | ||
![]() |
153787b112 | ||
![]() |
7b1ebd3cc7 | ||
![]() |
7531a2a1c6 | ||
![]() |
68f9d70d05 | ||
![]() |
d97de33b68 | ||
![]() |
a64be2bb74 | ||
![]() |
ee429b012b | ||
![]() |
f578626489 | ||
![]() |
fae17eb727 | ||
![]() |
091df1603d | ||
![]() |
90905a19eb | ||
![]() |
9488f3cec7 | ||
![]() |
9a43a89d39 | ||
![]() |
76e4c09d37 | ||
![]() |
310b09e95b | ||
![]() |
9c658fb118 | ||
![]() |
29c7c81f9a |
48
.github/workflows/build.yml
vendored
Normal file
48
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: 创建IPv6检测的前缀
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
fetch-ipv6-prefixes:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: 获取并处理多个ASN的IPv6前缀
|
||||
run: |
|
||||
mkdir -p bk/prefix/
|
||||
for asn in AS4809 AS4134 AS9929 AS4837 AS58807 AS9808 AS58453 AS23764; do
|
||||
echo "处理 $asn..."
|
||||
curl -s -A "Mozilla/5.0" \
|
||||
"https://bgp.he.net/$asn" > "${asn}.html"
|
||||
grep -oE '[0-9a-f:]+::/[0-9]+' "${asn}.html" | sort -u > tmp_prefixes.txt
|
||||
{
|
||||
while read prefix; do
|
||||
ip_part=$(echo "$prefix" | cut -d/ -f1)
|
||||
prefix_len=$(echo "$prefix" | cut -d/ -f2)
|
||||
keep_segments=$((prefix_len / 16))
|
||||
segments=$(echo "$ip_part" | tr ':' '\n' | grep -v '^$')
|
||||
kept=$(echo "$segments" | head -n "$keep_segments" | tr '\n' ':' | sed 's/:$//')
|
||||
echo "$kept"
|
||||
done < tmp_prefixes.txt
|
||||
} | sort -u > "bk/prefix/${asn,,}.txt"
|
||||
rm -f "${asn}.html" tmp_prefixes.txt
|
||||
done
|
||||
|
||||
- name: 提交更新到仓库
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add bk/prefix/*.txt
|
||||
if git diff --cached --quiet; then
|
||||
echo "无变更,跳过提交。"
|
||||
else
|
||||
git commit -m "chore: 更新多个 ASN 的 IPv6 前缀"
|
||||
git push
|
||||
fi
|
51
.github/workflows/ci.yaml
vendored
Normal file
51
.github/workflows/ci.yaml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go: ['1.22.x']
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Test
|
||||
run: go test ./... -coverprofile=coverage.txt
|
||||
|
||||
- name: Create Tag
|
||||
if: success()
|
||||
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')"
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
echo "TAG=$TAG" >> $GITHUB_ENV
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update README.md
|
||||
if: success()
|
||||
run: |
|
||||
sed -i "s|go get github.com/oneclickvirt/backtrace@.*|go get github.com/oneclickvirt/backtrace@${TAG}|" README.md
|
||||
env:
|
||||
TAG: ${{ env.TAG }}
|
||||
|
||||
- name: Commit and Push README.md
|
||||
if: success()
|
||||
run: |
|
||||
git add README.md
|
||||
git commit -m "Update README.md with new tag ${TAG}"
|
||||
git push origin main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
2
.github/workflows/main.yaml
vendored
2
.github/workflows/main.yaml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
echo "Deleting asset with ID: $asset"
|
||||
curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/oneclickvirt/backtrace/releases/assets/$asset"
|
||||
done
|
||||
sleep 60
|
||||
sleep 30
|
||||
|
||||
release-binary:
|
||||
name: Release Go Binary
|
||||
|
72
README.md
72
README.md
@ -1,42 +1,80 @@
|
||||
# backtrace
|
||||
|
||||
[](https://hits.seeyoufarm.com) [](https://github.com/oneclickvirt/backtrace/actions/workflows/main.yaml)
|
||||
[](https://hits.spiritlhl.net)
|
||||
|
||||
[](https://github.com/oneclickvirt/backtrace/actions/workflows/main.yaml)
|
||||
|
||||
三网回程路由线路测试
|
||||
|
||||
基于 https://github.com/zhanghanyun/backtrace 的重构和优化,与原版存在很大不同
|
||||
|
||||
路由的线路判断最终还是得人工判断的才准确,本项目测试结果仅供参考
|
||||
|
||||
## 功能
|
||||
|
||||
- [x] 检测回程显示IPV4地址时的线路,不显示IP地址时显示ASN检测不到,原版[backtrace](https://github.com/zhanghanyun/backtrace)也支持
|
||||
- [x] 支持对```4837```、```9929```和```163```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)也支持
|
||||
- [x] 支持对```CN2GT```和```CN2GIA```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)不支持,原版全部识别为```CN2```了
|
||||
- [x] 支持对```CMIN2```和```CMI```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)也支持
|
||||
- [x] 支持对整个回程路由进行线路分析,与原版[backtrace](https://github.com/zhanghanyun/backtrace)仅进行一次判断不同
|
||||
- [x] 修复原版[backtrace](https://github.com/zhanghanyun/backtrace)对IPV4地址信息获取时json解析失败依然打印信息的问题,本项目忽略错误继续执行路由线路查询
|
||||
- [x] 检测回程显示IPV4/IPV6地址时的线路(使用1500字节的包),不显示IP地址时显示ASN检测不到
|
||||
- [x] 支持对```9929```、```4837```和```163```线路的判断
|
||||
- [x] 支持对```CTGNET```、```CN2GIA```和```CN2GT```线路的判断
|
||||
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
||||
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
||||
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
||||
- [x] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] 使用nexttrace进行路由检测,备用方案才使用本地路由检测
|
||||
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路
|
||||
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
||||
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
||||
|
||||
## 使用
|
||||
|
||||
更新时间:2024.06.24
|
||||
下载、安装、更新
|
||||
|
||||
```shell
|
||||
curl https://raw.githubusercontent.com/oneclickvirt/backtrace/main/backtrace_install.sh -sSf | sh
|
||||
curl https://raw.githubusercontent.com/oneclickvirt/backtrace/main/backtrace_install.sh -sSf | bash
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
curl https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/backtrace/main/backtrace_install.sh -sSf | bash
|
||||
```
|
||||
|
||||
使用
|
||||
|
||||
```
|
||||
backtrace
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```
|
||||
./backtrace
|
||||
```
|
||||
|
||||
进行测试
|
||||
|
||||
无环境依赖,理论上适配所有系统和主流架构,更多架构请查看 https://github.com/oneclickvirt/backtrace/releases/tag/output
|
||||
|
||||
```
|
||||
Usage: backtrace [options]
|
||||
-h Show help information
|
||||
-ipv6
|
||||
Enable ipv6 testing
|
||||
-log
|
||||
Enable logging
|
||||
-s Disabe show ip info (default true)
|
||||
-v Show version
|
||||
```
|
||||
|
||||
## 卸载
|
||||
|
||||
```
|
||||
rm -rf /root/backtrace
|
||||
rm -rf /usr/bin/backtrace
|
||||
```
|
||||
|
||||
## 在Golang中使用
|
||||
|
||||
```
|
||||
go get github.com/oneclickvirt/backtrace@latest
|
||||
go get github.com/oneclickvirt/backtrace@v0.0.5-20250413040820
|
||||
```
|
||||
|
||||
## 概览图
|
||||
@ -46,3 +84,9 @@ go get github.com/oneclickvirt/backtrace@latest
|
||||

|
||||
|
||||

|
||||
|
||||
## Thanks
|
||||
|
||||
部分代码基于 https://github.com/zhanghanyun/backtrace 的重构和优化,与原版存在很大不同
|
||||
|
||||
IPV4/IPV6可ICMP进行ping测试的 https://github.com/spiritLHLS/icmp_targets 收集仓库
|
||||
|
4
back/README.md
Normal file
4
back/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# 部分参考资料
|
||||
|
||||
https://blog.sunflyer.cn/archives/594
|
||||
|
@ -1,22 +1,46 @@
|
||||
#!/bin/bash
|
||||
#From https://github.com/oneclickvirt/backtrace
|
||||
#2024.05.21
|
||||
#2024.07.02
|
||||
|
||||
rm -rf /usr/bin/backtrace
|
||||
os=$(uname -s)
|
||||
arch=$(uname -m)
|
||||
|
||||
check_cdn() {
|
||||
local o_url=$1
|
||||
for cdn_url in "${cdn_urls[@]}"; do
|
||||
if curl -sL -k "$cdn_url$o_url" --max-time 6 | grep -q "success" >/dev/null 2>&1; then
|
||||
export cdn_success_url="$cdn_url"
|
||||
return
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
export cdn_success_url=""
|
||||
}
|
||||
|
||||
check_cdn_file() {
|
||||
check_cdn "https://raw.githubusercontent.com/spiritLHLS/ecs/main/back/test"
|
||||
if [ -n "$cdn_success_url" ]; then
|
||||
echo "CDN available, using CDN"
|
||||
else
|
||||
echo "No CDN available, no use CDN"
|
||||
fi
|
||||
}
|
||||
|
||||
cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/")
|
||||
check_cdn_file
|
||||
|
||||
case $os in
|
||||
Linux)
|
||||
case $arch in
|
||||
"x86_64" | "x86" | "amd64" | "x64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-amd64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-386
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-arm64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-linux-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
@ -27,13 +51,13 @@ case $os in
|
||||
Darwin)
|
||||
case $arch in
|
||||
"x86_64" | "x86" | "amd64" | "x64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-amd64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-386
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-arm64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-darwin-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
@ -44,13 +68,13 @@ case $os in
|
||||
FreeBSD)
|
||||
case $arch in
|
||||
amd64)
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-amd64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-386
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-arm64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-freebsd-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
@ -61,13 +85,13 @@ case $os in
|
||||
OpenBSD)
|
||||
case $arch in
|
||||
amd64)
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-amd64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-amd64"
|
||||
;;
|
||||
"i386" | "i686")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-386
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-386"
|
||||
;;
|
||||
"armv7l" | "armv8" | "armv8l" | "aarch64" | "arm64")
|
||||
wget -O backtrace https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-arm64
|
||||
wget -O backtrace "${cdn_success_url}https://github.com/oneclickvirt/backtrace/releases/download/output/backtrace-openbsd-arm64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $arch"
|
||||
@ -82,9 +106,4 @@ case $os in
|
||||
esac
|
||||
|
||||
chmod 777 backtrace
|
||||
if [ ! -f /usr/bin/backtrace ]; then
|
||||
mv backtrace /usr/bin/
|
||||
backtrace
|
||||
else
|
||||
./backtrace
|
||||
fi
|
||||
cp backtrace /usr/bin/backtrace
|
||||
|
155
bk/asn.go
155
bk/asn.go
@ -1,155 +0,0 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
i int
|
||||
s string
|
||||
}
|
||||
|
||||
var (
|
||||
ips = []string{
|
||||
// "219.141.136.12", "202.106.50.1",
|
||||
"219.141.140.10", "202.106.195.68", "221.179.155.161",
|
||||
"202.96.209.133", "210.22.97.1", "211.136.112.200",
|
||||
"58.60.188.222", "210.21.196.6", "120.196.165.24",
|
||||
"61.139.2.69", "119.6.6.6", "211.137.96.205",
|
||||
}
|
||||
names = []string{
|
||||
"北京电信", "北京联通", "北京移动",
|
||||
"上海电信", "上海联通", "上海移动",
|
||||
"广州电信", "广州联通", "广州移动",
|
||||
"成都电信", "成都联通", "成都移动",
|
||||
}
|
||||
m = map[string]string{
|
||||
// [] 前的字符串个数,中文占2个字符串
|
||||
"AS4809a": "电信CN2GIA [精品线路]",
|
||||
"AS4809b": "电信CN2GT [优质线路]",
|
||||
"AS4134": "电信163 [普通线路]",
|
||||
"AS9929": "联通9929 [优质线路]",
|
||||
"AS4837": "联通4837 [普通线路]",
|
||||
"AS58807": "移动CMIN2 [精品线路]",
|
||||
"AS9808": "移动CMI [普通线路]",
|
||||
"AS58453": "移动CMI [普通线路]",
|
||||
}
|
||||
)
|
||||
|
||||
func removeDuplicates(elements []string) []string {
|
||||
encountered := map[string]bool{} // 用于存储已经遇到的元素
|
||||
result := []string{} // 存储去重后的结果
|
||||
for v := range elements { // 遍历切片中的元素
|
||||
if encountered[elements[v]] == true { // 如果该元素已经遇到过
|
||||
// 存在过就不加入了
|
||||
} else {
|
||||
encountered[elements[v]] = true // 将该元素标记为已经遇到
|
||||
result = append(result, elements[v]) // 将该元素加入到结果切片中
|
||||
}
|
||||
}
|
||||
return result // 返回去重后的结果切片
|
||||
}
|
||||
|
||||
func trace(ch chan Result, i int) {
|
||||
hops, err := Trace(net.ParseIP(ips[i]))
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("%v %-15s %v", names[i], ips[i], err)
|
||||
ch <- Result{i, s}
|
||||
return
|
||||
}
|
||||
var asns []string
|
||||
for _, h := range hops {
|
||||
for _, n := range h.Nodes {
|
||||
asn := ipAsn(n.IP.String())
|
||||
if asn != "" {
|
||||
asns = append(asns, asn)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理CN2不同路线的区别
|
||||
if asns != nil && len(asns) > 0 {
|
||||
var tempText string
|
||||
asns = removeDuplicates(asns)
|
||||
tempText += fmt.Sprintf("%v ", names[i])
|
||||
hasAS4134 := false
|
||||
hasAS4809 := false
|
||||
for _, asn := range asns {
|
||||
if asn == "AS4134" {
|
||||
hasAS4134 = true
|
||||
}
|
||||
if asn == "AS4809" {
|
||||
hasAS4809 = true
|
||||
}
|
||||
}
|
||||
// 判断是否包含 AS4134 和 AS4809
|
||||
if hasAS4134 && hasAS4809 {
|
||||
// 同时包含 AS4134 和 AS4809 属于 CN2GT
|
||||
asns = append([]string{"AS4809b"}, asns...)
|
||||
} else if hasAS4809 {
|
||||
// 仅包含 AS4809 属于 CN2GIA
|
||||
asns = append([]string{"AS4809a"}, asns...)
|
||||
}
|
||||
tempText += fmt.Sprintf("%-15s ", ips[i])
|
||||
for _, asn := range asns {
|
||||
asnDescription := m[asn]
|
||||
switch asn {
|
||||
case "":
|
||||
continue
|
||||
case "AS4809": // 被 AS4809a 和 AS4809b 替代了
|
||||
continue
|
||||
case "AS9929":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809a":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809b":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
case "AS58807":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
default:
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += White(asnDescription) + " "
|
||||
}
|
||||
}
|
||||
}
|
||||
if tempText == (fmt.Sprintf("%v ", names[i]) + fmt.Sprintf("%-15s ", ips[i])) {
|
||||
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
||||
}
|
||||
ch <- Result{i, tempText}
|
||||
} else {
|
||||
s := fmt.Sprintf("%v %-15s %v", names[i], ips[i], Red("检测不到回程路由节点的IP地址"))
|
||||
ch <- Result{i, s}
|
||||
}
|
||||
}
|
||||
|
||||
func ipAsn(ip string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(ip, "59.43"):
|
||||
return "AS4809"
|
||||
case strings.HasPrefix(ip, "202.97"):
|
||||
return "AS4134"
|
||||
case strings.HasPrefix(ip, "218.105") || strings.HasPrefix(ip, "210.51"):
|
||||
return "AS9929"
|
||||
case strings.HasPrefix(ip, "219.158"):
|
||||
return "AS4837"
|
||||
case strings.HasPrefix(ip, "223.120.19") || strings.HasPrefix(ip, "223.120.17") || strings.HasPrefix(ip, "223.120.16") ||
|
||||
strings.HasPrefix(ip, "223.120.140") || strings.HasPrefix(ip, "223.120.130") || strings.HasPrefix(ip, "223.120.131") ||
|
||||
strings.HasPrefix(ip, "223.120.141"):
|
||||
return "AS58807"
|
||||
case strings.HasPrefix(ip, "223.118") || strings.HasPrefix(ip, "223.119") || strings.HasPrefix(ip, "223.120") || strings.HasPrefix(ip, "223.121"):
|
||||
return "AS58453"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
@ -3,27 +3,75 @@ package backtrace
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
)
|
||||
|
||||
func BackTrace() {
|
||||
func BackTrace(enableIpv6 bool) {
|
||||
if model.CachedIcmpData == "" || model.ParsedIcmpTargets == nil || time.Since(model.CachedIcmpDataFetchTime) > time.Hour {
|
||||
model.CachedIcmpData = getData(model.IcmpTargets)
|
||||
model.CachedIcmpDataFetchTime = time.Now()
|
||||
if model.CachedIcmpData != "" {
|
||||
model.ParsedIcmpTargets = parseIcmpTargets(model.CachedIcmpData)
|
||||
}
|
||||
}
|
||||
if enableIpv6 {
|
||||
ipv4Count := len(model.Ipv4s)
|
||||
ipv6Count := len(model.Ipv6s)
|
||||
totalCount := ipv4Count + ipv6Count
|
||||
var (
|
||||
s [12]string // 对应 ips 目标地址数量
|
||||
s = make([]string, totalCount)
|
||||
c = make(chan Result)
|
||||
t = time.After(time.Second * 10)
|
||||
)
|
||||
for i := range ips {
|
||||
for i := range model.Ipv4s {
|
||||
go trace(c, i)
|
||||
}
|
||||
loop:
|
||||
for i := range model.Ipv6s {
|
||||
go traceIPv6(c, i, ipv4Count)
|
||||
}
|
||||
loopIPv4v6:
|
||||
for range s {
|
||||
select {
|
||||
case o := <-c:
|
||||
s[o.i] = o.s
|
||||
case <-t:
|
||||
break loop
|
||||
break loopIPv4v6
|
||||
}
|
||||
}
|
||||
for i := 0; i < ipv4Count; i++ {
|
||||
if s[i] != "" {
|
||||
fmt.Println(s[i])
|
||||
}
|
||||
}
|
||||
for i := ipv4Count; i < totalCount; i++ {
|
||||
if s[i] != "" {
|
||||
fmt.Println(s[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ipCount := len(model.Ipv4s)
|
||||
var (
|
||||
s = make([]string, ipCount)
|
||||
c = make(chan Result)
|
||||
t = time.After(time.Second * 10)
|
||||
)
|
||||
for i := range model.Ipv4s {
|
||||
go trace(c, i)
|
||||
}
|
||||
loopIPv4:
|
||||
for range s {
|
||||
select {
|
||||
case o := <-c:
|
||||
s[o.i] = o.s
|
||||
case <-t:
|
||||
break loopIPv4
|
||||
}
|
||||
}
|
||||
for _, r := range s {
|
||||
if r != "" {
|
||||
fmt.Println(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,5 +16,5 @@ import (
|
||||
//}
|
||||
|
||||
func TestBackTrace(t *testing.T) {
|
||||
BackTrace()
|
||||
BackTrace(false)
|
||||
}
|
||||
|
31
bk/ipv4_asn.go
Normal file
31
bk/ipv4_asn.go
Normal file
@ -0,0 +1,31 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ipv4Asn(ip string) string {
|
||||
if strings.Contains(ip, ":") {
|
||||
return ipv6Asn(ip)
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(ip, "59.43"):
|
||||
return "AS4809"
|
||||
case strings.HasPrefix(ip, "202.97"):
|
||||
return "AS4134"
|
||||
case strings.HasPrefix(ip, "218.105") || strings.HasPrefix(ip, "210.51"):
|
||||
return "AS9929"
|
||||
case strings.HasPrefix(ip, "219.158"):
|
||||
return "AS4837"
|
||||
case strings.HasPrefix(ip, "223.120.19") || strings.HasPrefix(ip, "223.120.17") || strings.HasPrefix(ip, "223.120.16") ||
|
||||
strings.HasPrefix(ip, "223.120.140") || strings.HasPrefix(ip, "223.120.130") || strings.HasPrefix(ip, "223.120.131") ||
|
||||
strings.HasPrefix(ip, "223.120.141"):
|
||||
return "AS58807"
|
||||
case strings.HasPrefix(ip, "223.118") || strings.HasPrefix(ip, "223.119") || strings.HasPrefix(ip, "223.120") || strings.HasPrefix(ip, "223.121"):
|
||||
return "AS58453"
|
||||
case strings.HasPrefix(ip, "69.194") || strings.HasPrefix(ip, "203.22"):
|
||||
return "AS23764"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
59
bk/ipv6_asn.go
Normal file
59
bk/ipv6_asn.go
Normal file
@ -0,0 +1,59 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"strings"
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed prefix/as4809.txt
|
||||
var as4809Data string
|
||||
|
||||
//go:embed prefix/as4134.txt
|
||||
var as4134Data string
|
||||
|
||||
//go:embed prefix/as9929.txt
|
||||
var as9929Data string
|
||||
|
||||
//go:embed prefix/as4837.txt
|
||||
var as4837Data string
|
||||
|
||||
//go:embed prefix/as58807.txt
|
||||
var as58807Data string
|
||||
|
||||
//go:embed prefix/as9808.txt
|
||||
var as9808Data string
|
||||
|
||||
//go:embed prefix/as58453.txt
|
||||
var as58453Data string
|
||||
|
||||
//go:embed prefix/as23764.txt
|
||||
var as23764Data string
|
||||
|
||||
// ASN -> Prefix strings
|
||||
var asnPrefixes = map[string][]string{
|
||||
"AS4809": strings.Split(as4809Data, "\n"), // 电信 CN2 GT/GIA
|
||||
"AS4134": strings.Split(as4134Data, "\n"), // 电信 163 骨干网
|
||||
"AS9929": strings.Split(as9929Data, "\n"), // 联通 9929 优质国际线路
|
||||
"AS4837": strings.Split(as4837Data, "\n"), // 联通 AS4837 普通国际线路
|
||||
"AS58807": strings.Split(as58807Data, "\n"), // 移动 CMIN2 国际精品网
|
||||
"AS9808": strings.Split(as9808Data, "\n"), // 移动 CMI(中国移动国际公司)
|
||||
"AS58453": strings.Split(as58453Data, "\n"), // 移动国际互联网(CMI/HK)
|
||||
"AS23764": strings.Split(as23764Data, "\n"), // 电信 CTGNET/国际出口(可能是CN2-B)
|
||||
}
|
||||
|
||||
// 判断 IPv6 地址是否匹配 ASN 中的某个前缀
|
||||
func ipv6Asn(ip string) string {
|
||||
ip = strings.ToLower(ip)
|
||||
for asn, prefixes := range asnPrefixes {
|
||||
for _, prefix := range prefixes {
|
||||
prefix = strings.TrimSpace(prefix)
|
||||
if prefix == "" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(ip, prefix) {
|
||||
return asn
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
@ -1,17 +1,29 @@
|
||||
//go:build linux || freebsd || openbsd || darwin
|
||||
// +build linux freebsd openbsd darwin
|
||||
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||
conn, err := net.ListenIP(network, laddr)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
@ -19,6 +31,9 @@ func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error)
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||
})
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||
conn, err := net.ListenIP(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
_ = raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||
})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||
conn, err := net.ListenIP(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
_ = raw.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||
})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
@ -1,17 +1,33 @@
|
||||
//go:build !linux && !freebsd && !openbsd && !darwin && !windows
|
||||
// +build !linux,!freebsd,!openbsd,!darwin,!windows
|
||||
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
conn, err := net.ListenIP(network, laddr)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
@ -19,6 +35,9 @@ func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error)
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||
})
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
@ -6,21 +6,28 @@ package backtrace
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
conn, err := net.ListenIP(network, laddr)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
raw, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
@ -28,7 +35,9 @@ func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error)
|
||||
err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_HDRINCL, 1)
|
||||
})
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
23
bk/prefix/as23764.txt
Normal file
23
bk/prefix/as23764.txt
Normal file
@ -0,0 +1,23 @@
|
||||
2400:9380:9115
|
||||
2400:9380:9116
|
||||
2400:9380:9206
|
||||
2400:9380:9262
|
||||
2400:9380:a003
|
||||
2400:9380:a00a
|
||||
2400:9380:a00c
|
||||
2400:9380:a01f
|
||||
2400:9380:a022
|
||||
2400:9380:a026
|
||||
2400:9380:a028
|
||||
2400:9380:a042
|
||||
2400:9380:a110
|
||||
2804:1e48:9003
|
||||
2a04:f580:9001
|
||||
2a04:f581:110a
|
||||
2a04:f581:110b
|
||||
2a04:f581:a123
|
||||
2a04:f581:a125
|
||||
2c0f:f7a8:1
|
||||
2c0f:f7a8:29
|
||||
2c0f:f7a8:37
|
||||
2c0f:f7a8:47
|
223
bk/prefix/as4134.txt
Normal file
223
bk/prefix/as4134.txt
Normal file
@ -0,0 +1,223 @@
|
||||
2400:9380:8001
|
||||
2400:9380:8003
|
||||
2400:9380:8021
|
||||
2400:9380:8030
|
||||
2400:9380:8040
|
||||
2400:9380:8140
|
||||
2400:9380:8201
|
||||
2400:9380:8221
|
||||
2400:9380:8301
|
||||
240e
|
||||
240e:1
|
||||
240e:100
|
||||
240e:101
|
||||
240e:103
|
||||
240e:104
|
||||
240e:106
|
||||
240e:108
|
||||
240e:11:8001
|
||||
240e:12
|
||||
240e:144
|
||||
240e:16:1001
|
||||
240e:16:1008
|
||||
240e:16:1009
|
||||
240e:184
|
||||
240e:1c7
|
||||
240e:2
|
||||
240e:218
|
||||
240e:219
|
||||
240e:21a
|
||||
240e:21b
|
||||
240e:224
|
||||
240e:225
|
||||
240e:226
|
||||
240e:227
|
||||
240e:24
|
||||
240e:240
|
||||
240e:241
|
||||
240e:242
|
||||
240e:243
|
||||
240e:244
|
||||
240e:245
|
||||
240e:246
|
||||
240e:247
|
||||
240e:2c
|
||||
240e:318
|
||||
240e:319
|
||||
240e:31a
|
||||
240e:31b
|
||||
240e:324
|
||||
240e:325
|
||||
240e:326
|
||||
240e:327
|
||||
240e:340
|
||||
240e:341
|
||||
240e:342
|
||||
240e:343
|
||||
240e:350:205
|
||||
240e:41
|
||||
240e:418
|
||||
240e:419
|
||||
240e:41a
|
||||
240e:41b
|
||||
240e:42
|
||||
240e:424
|
||||
240e:425
|
||||
240e:426
|
||||
240e:427
|
||||
240e:42:4000
|
||||
240e:42:8010
|
||||
240e:43
|
||||
240e:43:8000
|
||||
240e:44
|
||||
240e:440
|
||||
240e:441
|
||||
240e:442
|
||||
240e:443
|
||||
240e:444
|
||||
240e:445
|
||||
240e:446
|
||||
240e:447
|
||||
240e:45
|
||||
240e:45:8000
|
||||
240e:46
|
||||
240e:46:5008
|
||||
240e:47
|
||||
240e:47:4
|
||||
240e:48
|
||||
240e:49
|
||||
240e:4a
|
||||
240e:4b
|
||||
240e:4b:2
|
||||
240e:4c
|
||||
240e:4c:4006
|
||||
240e:4d
|
||||
240e:4d:50ff
|
||||
240e:4e
|
||||
240e:4e:4000
|
||||
240e:4f
|
||||
240e:50
|
||||
240e:51
|
||||
240e:518
|
||||
240e:519
|
||||
240e:51a
|
||||
240e:51b
|
||||
240e:52
|
||||
240e:524
|
||||
240e:525
|
||||
240e:526
|
||||
240e:527
|
||||
240e:53
|
||||
240e:54
|
||||
240e:540
|
||||
240e:541
|
||||
240e:542
|
||||
240e:543
|
||||
240e:544
|
||||
240e:545
|
||||
240e:546
|
||||
240e:547
|
||||
240e:55
|
||||
240e:56
|
||||
240e:57
|
||||
240e:5a
|
||||
240e:5b
|
||||
240e:5c
|
||||
240e:5d
|
||||
240e:5e
|
||||
240e:5f
|
||||
240e:618
|
||||
240e:619
|
||||
240e:61a
|
||||
240e:61b
|
||||
240e:61d:1401
|
||||
240e:624
|
||||
240e:625
|
||||
240e:626
|
||||
240e:627
|
||||
240e:638
|
||||
240e:64
|
||||
240e:640
|
||||
240e:641
|
||||
240e:642
|
||||
240e:643
|
||||
240e:659:1160
|
||||
240e:7
|
||||
240e:718
|
||||
240e:719
|
||||
240e:71a
|
||||
240e:71b
|
||||
240e:724
|
||||
240e:725
|
||||
240e:726
|
||||
240e:727
|
||||
240e:740
|
||||
240e:741
|
||||
240e:742
|
||||
240e:743
|
||||
240e:767
|
||||
240e:840
|
||||
240e:841
|
||||
240e:9
|
||||
240e:918
|
||||
240e:919
|
||||
240e:91a
|
||||
240e:91b
|
||||
240e:924
|
||||
240e:925
|
||||
240e:926
|
||||
240e:927
|
||||
240e:940
|
||||
240e:941
|
||||
240e:942
|
||||
240e:943
|
||||
240e:944
|
||||
240e:945
|
||||
240e:946
|
||||
240e:947
|
||||
240e:980
|
||||
240e:981
|
||||
240e:982
|
||||
240e:983
|
||||
240e:a0c
|
||||
240e:a0d
|
||||
240e:a0e
|
||||
240e:a0f
|
||||
240e:a18
|
||||
240e:a19
|
||||
240e:a1a
|
||||
240e:a1b
|
||||
240e:a24
|
||||
240e:a25
|
||||
240e:a26
|
||||
240e:a27
|
||||
240e:a40
|
||||
240e:a41
|
||||
240e:a42
|
||||
240e:a43
|
||||
240e:a44
|
||||
240e:a45
|
||||
240e:a46
|
||||
240e:a47
|
||||
240e:a5:8000
|
||||
240e:b
|
||||
240e:cd:8000
|
||||
240e:d:100
|
||||
2605:9d80:8001
|
||||
2605:9d80:8011
|
||||
2605:9d80:8021
|
||||
2605:9d80:8031
|
||||
2605:9d80:8041
|
||||
2605:9d80:8081
|
||||
2a04:f580:8010
|
||||
2a04:f580:8011
|
||||
2a04:f580:8090
|
||||
2a04:f580:8210
|
||||
2a04:f580:8211
|
||||
2a04:f580:8290
|
||||
2c0f:f7a8:8011
|
||||
2c0f:f7a8:8050
|
||||
2c0f:f7a8:805f
|
||||
2c0f:f7a8:8150
|
||||
2c0f:f7a8:815f
|
||||
2c0f:f7a8:8211
|
160
bk/prefix/as4809.txt
Normal file
160
bk/prefix/as4809.txt
Normal file
@ -0,0 +1,160 @@
|
||||
2400:9380:9000
|
||||
2400:9380:9001
|
||||
2400:9380:9002
|
||||
2400:9380:9005
|
||||
2400:9380:9009
|
||||
2400:9380:900a
|
||||
2400:9380:9020
|
||||
2400:9380:9021
|
||||
2400:9380:9030
|
||||
2400:9380:9031
|
||||
2400:9380:9040
|
||||
2400:9380:9041
|
||||
2400:9380:9050
|
||||
2400:9380:9051
|
||||
2400:9380:9060
|
||||
2400:9380:9061
|
||||
2400:9380:9070
|
||||
2400:9380:9071
|
||||
2400:9380:9080
|
||||
2400:9380:9081
|
||||
2400:9380:90a0
|
||||
2400:9380:90a1
|
||||
2400:9380:90b0
|
||||
2400:9380:90b1
|
||||
2400:9380:90b2
|
||||
2400:9380:90b3
|
||||
2400:9380:90b4
|
||||
2400:9380:90b5
|
||||
2400:9380:90b6
|
||||
2400:9380:90b7
|
||||
2400:9380:9100
|
||||
2400:9380:9101
|
||||
2400:9380:9121
|
||||
2400:9380:9201
|
||||
2400:9380:9202
|
||||
2400:9380:9205
|
||||
2400:9380:9220
|
||||
2400:9380:9221
|
||||
2400:9380:9230
|
||||
2400:9380:9231
|
||||
2400:9380:9240
|
||||
2400:9380:9241
|
||||
2400:9380:9250
|
||||
2400:9380:9251
|
||||
2400:9380:9252
|
||||
2400:9380:9260
|
||||
2400:9380:9261
|
||||
2400:9380:9270
|
||||
2400:9380:9271
|
||||
2400:9380:9272
|
||||
2400:9380:9280
|
||||
2400:9380:9281
|
||||
2400:9380:9282
|
||||
2400:9380:92a0
|
||||
2400:9380:92a1
|
||||
2400:9380:92b0
|
||||
2400:9380:92b1
|
||||
2400:9380:92b2
|
||||
2400:9380:92b3
|
||||
2400:9380:92b4
|
||||
2400:9380:92b5
|
||||
2400:9380:92b6
|
||||
2400:9380:92b7
|
||||
240e:182:5401
|
||||
240e:182:5501
|
||||
240e:409:9000
|
||||
240e:409:9001
|
||||
240e:410:ff00
|
||||
240e:411:ff00
|
||||
240e:414
|
||||
240e:43d:fff1
|
||||
240e:43d:fff3
|
||||
240e:43d:fff4
|
||||
240e:43d:fff7
|
||||
240e:440:ac00
|
||||
240e:440:ac01
|
||||
240e:440:ac02
|
||||
240e:441:ac00
|
||||
240e:441:ac01
|
||||
240e:441:ac02
|
||||
240e:445:3f00
|
||||
240e:446:3f00
|
||||
240e:451:bfc0
|
||||
240e:451:bfe0
|
||||
240e:451:ffa0
|
||||
240e:451:ffc0
|
||||
240e:451:ffe0
|
||||
240e:456:fe00
|
||||
240e:457:fe00
|
||||
240e:469:f400
|
||||
240e:476:febf
|
||||
240e:476:feff
|
||||
240e:604:314
|
||||
240e:60e:8000
|
||||
240e:60e:8001
|
||||
240e:615
|
||||
240e:62c
|
||||
240e:638:f
|
||||
240e:63c
|
||||
240e:640:178
|
||||
240e:640:179
|
||||
240e:640:17a
|
||||
240e:640:17b
|
||||
240e:648:1e
|
||||
240e:64e
|
||||
240e:659:f100
|
||||
240e:669
|
||||
240e:699:7a00
|
||||
240e:699:7a01
|
||||
240e:713:f020
|
||||
240e:713:f021
|
||||
240e:733:4c0
|
||||
240e:f6:8002
|
||||
2605:9d80:9003
|
||||
2605:9d80:9013
|
||||
2605:9d80:9023
|
||||
2605:9d80:9033
|
||||
2605:9d80:9042
|
||||
2605:9d80:9052
|
||||
2605:9d80:9061
|
||||
2605:9d80:9071
|
||||
2605:9d80:9092
|
||||
2804:1e48
|
||||
2804:1e48:9001
|
||||
2804:1e48:9002
|
||||
2a04:f580:9000
|
||||
2a04:f580:9001
|
||||
2a04:f580:9002
|
||||
2a04:f580:9010
|
||||
2a04:f580:9012
|
||||
2a04:f580:9013
|
||||
2a04:f580:9020
|
||||
2a04:f580:9030
|
||||
2a04:f580:9040
|
||||
2a04:f580:9050
|
||||
2a04:f580:9060
|
||||
2a04:f580:9070
|
||||
2a04:f580:9080
|
||||
2a04:f580:9090
|
||||
2a04:f580:9200
|
||||
2a04:f580:9201
|
||||
2a04:f580:9202
|
||||
2a04:f580:9210
|
||||
2a04:f580:9212
|
||||
2a04:f580:9213
|
||||
2a04:f580:9220
|
||||
2a04:f580:9230
|
||||
2a04:f580:9240
|
||||
2a04:f580:9250
|
||||
2a04:f580:9260
|
||||
2a04:f580:9270
|
||||
2a04:f580:9280
|
||||
2a04:f580:9290
|
||||
2c0f:f7a8:9010
|
||||
2c0f:f7a8:9011
|
||||
2c0f:f7a8:9020
|
||||
2c0f:f7a8:9041
|
||||
2c0f:f7a8:9210
|
||||
2c0f:f7a8:9211
|
||||
2c0f:f7a8:9220
|
414
bk/prefix/as4837.txt
Normal file
414
bk/prefix/as4837.txt
Normal file
@ -0,0 +1,414 @@
|
||||
2400:73e0:201
|
||||
2402:f140:ff13
|
||||
2402:f140:ff14
|
||||
2404:6500:dcb3
|
||||
2405:1480
|
||||
2406:1e40
|
||||
2406:cac0
|
||||
2407:37c0:ffff
|
||||
2407:6c40
|
||||
2407:6c40:1500
|
||||
2408
|
||||
2408:8000
|
||||
2408:8000:10fe
|
||||
2408:8000:10ff
|
||||
2408:8000:2
|
||||
2408:8000:3
|
||||
2408:8001
|
||||
2408:802a
|
||||
2408:802c
|
||||
2408:8034
|
||||
2408:803e
|
||||
2408:8056
|
||||
2408:80c2
|
||||
2408:80c5
|
||||
2408:80e2
|
||||
2408:80e3
|
||||
2408:80e9
|
||||
2408:80f5
|
||||
2408:80f9
|
||||
2408:815f
|
||||
2408:8181
|
||||
2408:8182
|
||||
2408:8183
|
||||
2408:81a2
|
||||
2408:81a3
|
||||
2408:8210
|
||||
2408:8211
|
||||
2408:8212
|
||||
2408:8213
|
||||
2408:8214
|
||||
2408:8215
|
||||
2408:821a
|
||||
2408:821b
|
||||
2408:8220
|
||||
2408:8221
|
||||
2408:8226
|
||||
2408:822a
|
||||
2408:822b
|
||||
2408:822e
|
||||
2408:822f
|
||||
2408:8230
|
||||
2408:8231
|
||||
2408:8232
|
||||
2408:8233
|
||||
2408:8234
|
||||
2408:8235
|
||||
2408:8236
|
||||
2408:8237
|
||||
2408:8238
|
||||
2408:8239
|
||||
2408:823c
|
||||
2408:823d
|
||||
2408:8240
|
||||
2408:8248
|
||||
2408:8249
|
||||
2408:824a
|
||||
2408:824b
|
||||
2408:824c
|
||||
2408:824e
|
||||
2408:824f
|
||||
2408:8250
|
||||
2408:8251
|
||||
2408:8252
|
||||
2408:8253
|
||||
2408:8254
|
||||
2408:8255
|
||||
2408:825c
|
||||
2408:825d
|
||||
2408:8260
|
||||
2408:8262
|
||||
2408:8263
|
||||
2408:8264
|
||||
2408:8265
|
||||
2408:8266
|
||||
2408:826a
|
||||
2408:826c
|
||||
2408:826d
|
||||
2408:826e
|
||||
2408:826f
|
||||
2408:8270
|
||||
2408:8274
|
||||
2408:8275
|
||||
2408:8276
|
||||
2408:8277
|
||||
2408:8278
|
||||
2408:8279
|
||||
2408:827a
|
||||
2408:8310
|
||||
2408:8311
|
||||
2408:8312
|
||||
2408:8313
|
||||
2408:832a
|
||||
2408:832e
|
||||
2408:832f
|
||||
2408:8330
|
||||
2408:8331
|
||||
2408:8332
|
||||
2408:8333
|
||||
2408:8338
|
||||
2408:8340
|
||||
2408:8348
|
||||
2408:8349
|
||||
2408:834a
|
||||
2408:834b
|
||||
2408:834e
|
||||
2408:834f
|
||||
2408:8350
|
||||
2408:8351
|
||||
2408:8352
|
||||
2408:8353
|
||||
2408:8354
|
||||
2408:8355
|
||||
2408:8360
|
||||
2408:8361
|
||||
2408:8362
|
||||
2408:8363
|
||||
2408:8364
|
||||
2408:8365
|
||||
2408:836c
|
||||
2408:836d
|
||||
2408:836e
|
||||
2408:836f
|
||||
2408:8374
|
||||
2408:8375
|
||||
2408:8376
|
||||
2408:8377
|
||||
2408:8378
|
||||
2408:8379
|
||||
2408:837a
|
||||
2408:8410
|
||||
2408:8411
|
||||
2408:8412
|
||||
2408:8413
|
||||
2408:8414
|
||||
2408:8415
|
||||
2408:8417
|
||||
2408:8418
|
||||
2408:841a
|
||||
2408:841b
|
||||
2408:841c
|
||||
2408:841d
|
||||
2408:841e
|
||||
2408:8420
|
||||
2408:8421
|
||||
2408:8422
|
||||
2408:8426
|
||||
2408:8427
|
||||
2408:842a
|
||||
2408:842b
|
||||
2408:842c
|
||||
2408:842e
|
||||
2408:8431
|
||||
2408:8434
|
||||
2408:8435
|
||||
2408:8436
|
||||
2408:8437
|
||||
2408:8438
|
||||
2408:8439
|
||||
2408:843c
|
||||
2408:843d
|
||||
2408:843e
|
||||
2408:843f
|
||||
2408:8440
|
||||
2408:8441
|
||||
2408:8448
|
||||
2408:844b
|
||||
2408:844c
|
||||
2408:844d
|
||||
2408:844e
|
||||
2408:844f
|
||||
2408:8452
|
||||
2408:8453
|
||||
2408:8454
|
||||
2408:845c
|
||||
2408:845d
|
||||
2408:8460
|
||||
2408:8461
|
||||
2408:8462
|
||||
2408:8463
|
||||
2408:8464
|
||||
2408:8465
|
||||
2408:8466
|
||||
2408:8469
|
||||
2408:846a
|
||||
2408:846b
|
||||
2408:846c
|
||||
2408:846d
|
||||
2408:846e
|
||||
2408:846f
|
||||
2408:8470
|
||||
2408:8471
|
||||
2408:8474
|
||||
2408:8475
|
||||
2408:8476
|
||||
2408:8477
|
||||
2408:8478
|
||||
2408:8479
|
||||
2408:847a
|
||||
2408:84e3
|
||||
2408:84e4
|
||||
2408:84e5
|
||||
2408:84e6
|
||||
2408:84e7
|
||||
2408:84e9
|
||||
2408:84eb
|
||||
2408:84ec
|
||||
2408:84ed
|
||||
2408:84ee
|
||||
2408:84ef
|
||||
2408:84f0
|
||||
2408:84f1
|
||||
2408:84f2
|
||||
2408:84f4
|
||||
2408:84f5
|
||||
2408:84f6
|
||||
2408:84f7
|
||||
2408:84f8
|
||||
2408:84f9
|
||||
2408:84fa
|
||||
2408:84fb
|
||||
2408:84fc
|
||||
2408:84fd
|
||||
2408:84fe
|
||||
2408:84ff
|
||||
2408:856c
|
||||
2408:856d
|
||||
2408:8610
|
||||
2408:8611
|
||||
2408:8612
|
||||
2408:8613
|
||||
2408:8614
|
||||
2408:8615
|
||||
2408:861a
|
||||
2408:861b
|
||||
2408:861c
|
||||
2408:8620
|
||||
2408:8621
|
||||
2408:8624
|
||||
2408:8625
|
||||
2408:8626
|
||||
2408:862a
|
||||
2408:862b
|
||||
2408:862d
|
||||
2408:862e
|
||||
2408:862f
|
||||
2408:8630
|
||||
2408:8631
|
||||
2408:8632
|
||||
2408:8633
|
||||
2408:8634
|
||||
2408:8635
|
||||
2408:8636
|
||||
2408:8637
|
||||
2408:8638
|
||||
2408:8639
|
||||
2408:863c
|
||||
2408:863d
|
||||
2408:8640
|
||||
2408:8642
|
||||
2408:8648
|
||||
2408:8649
|
||||
2408:864c
|
||||
2408:864e
|
||||
2408:864f
|
||||
2408:8650
|
||||
2408:8651
|
||||
2408:8652
|
||||
2408:8653
|
||||
2408:8654
|
||||
2408:865c
|
||||
2408:865d
|
||||
2408:8660
|
||||
2408:8662
|
||||
2408:8663
|
||||
2408:8664
|
||||
2408:8665
|
||||
2408:8666
|
||||
2408:866a
|
||||
2408:866b
|
||||
2408:866c
|
||||
2408:866d
|
||||
2408:866e
|
||||
2408:866f
|
||||
2408:8670
|
||||
2408:8674
|
||||
2408:8675
|
||||
2408:8676
|
||||
2408:8677
|
||||
2408:8678
|
||||
2408:8679
|
||||
2408:867a
|
||||
2408:8710
|
||||
2408:8711
|
||||
2408:8712
|
||||
2408:8713
|
||||
2408:8719
|
||||
2408:871a
|
||||
2408:871b
|
||||
2408:8720
|
||||
2408:8721
|
||||
2408:8722
|
||||
2408:8723
|
||||
2408:8726
|
||||
2408:872b
|
||||
2408:872f
|
||||
2408:8730
|
||||
2408:8731
|
||||
2408:8732
|
||||
2408:8733
|
||||
2408:8734
|
||||
2408:8735
|
||||
2408:8736
|
||||
2408:8738
|
||||
2408:873c
|
||||
2408:873d
|
||||
2408:8740
|
||||
2408:8742
|
||||
2408:8748
|
||||
2408:8749
|
||||
2408:874a
|
||||
2408:874b
|
||||
2408:874c
|
||||
2408:874d
|
||||
2408:874e
|
||||
2408:874f
|
||||
2408:8752
|
||||
2408:875c
|
||||
2408:8760
|
||||
2408:8762
|
||||
2408:8763
|
||||
2408:8764
|
||||
2408:8765
|
||||
2408:8766
|
||||
2408:8768
|
||||
2408:876a
|
||||
2408:876c
|
||||
2408:876d
|
||||
2408:876e
|
||||
2408:876f
|
||||
2408:8770
|
||||
2408:8772
|
||||
2408:8773
|
||||
2408:8774
|
||||
2408:8776
|
||||
2408:8777
|
||||
2408:8778
|
||||
2408:8779
|
||||
2408:877a
|
||||
2408:8812
|
||||
2408:8813
|
||||
2408:8814
|
||||
2408:8815
|
||||
2408:8816
|
||||
2408:8817
|
||||
2408:8818
|
||||
2408:8819
|
||||
2408:882c
|
||||
2408:883a
|
||||
2408:8862
|
||||
2408:8863
|
||||
2408:8864
|
||||
2408:8865
|
||||
2408:8866
|
||||
2408:886e
|
||||
2408:886f
|
||||
2408:8872
|
||||
2408:8878
|
||||
2408:8879
|
||||
2408:887e
|
||||
2408:8912
|
||||
2408:8913
|
||||
2408:8914
|
||||
2408:8915
|
||||
2408:8916
|
||||
2408:8917
|
||||
2408:891c
|
||||
2408:8920
|
||||
2408:8924
|
||||
2408:892c
|
||||
2408:8936
|
||||
2408:893a
|
||||
2408:8940
|
||||
2408:8948
|
||||
2408:894c
|
||||
2408:894e
|
||||
2408:8962
|
||||
2408:8963
|
||||
2408:8964
|
||||
2408:8965
|
||||
2408:8966
|
||||
2408:896c
|
||||
2408:896e
|
||||
2408:896f
|
||||
2408:8972
|
||||
2408:8978
|
||||
2408:8979
|
||||
2408:897a
|
||||
2408:897b
|
||||
2408:897e
|
||||
2408:8a21
|
||||
2408:8a23
|
||||
2408:8a24
|
||||
2408:8a26
|
||||
2408:8a27
|
7
bk/prefix/as58453.txt
Normal file
7
bk/prefix/as58453.txt
Normal file
@ -0,0 +1,7 @@
|
||||
2400:8800:1f0e:5f
|
||||
2400:8800:1f11:13
|
||||
2401:cf80:620f:1
|
||||
2402:4f00
|
||||
2402:4f00:3000
|
||||
2402:4f00:4000:4
|
||||
2402:4f00:4003
|
2
bk/prefix/as58807.txt
Normal file
2
bk/prefix/as58807.txt
Normal file
@ -0,0 +1,2 @@
|
||||
2402:4f00
|
||||
2402:4f00:f000
|
1335
bk/prefix/as9808.txt
Normal file
1335
bk/prefix/as9808.txt
Normal file
File diff suppressed because it is too large
Load Diff
25
bk/prefix/as9929.txt
Normal file
25
bk/prefix/as9929.txt
Normal file
@ -0,0 +1,25 @@
|
||||
2408:8120
|
||||
2408:8120:1
|
||||
2408:8120:2
|
||||
2408:8610:3bff
|
||||
2408:8614:1f0
|
||||
2408:861c:1fff
|
||||
2408:8625:10fb
|
||||
2408:8626:f200
|
||||
2408:862b
|
||||
2408:862e:2ff
|
||||
2408:8638:116
|
||||
2408:8649:2a00
|
||||
2408:8656:a52
|
||||
2408:8660:100
|
||||
2408:8660:ab00
|
||||
2408:8678:1400
|
||||
2408:8756:3efd
|
||||
2408:8a00
|
||||
2408:8a01
|
||||
2408:8a02
|
||||
2408:8a04
|
||||
2408:8a06
|
||||
2408:8a06:1
|
||||
2408:8a06:100
|
||||
2408:8a06:101
|
@ -3,14 +3,19 @@ package backtrace
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
// DefaultConfig is the default configuration for Tracer.
|
||||
@ -19,7 +24,7 @@ var DefaultConfig = Config{
|
||||
Timeout: 500 * time.Millisecond,
|
||||
MaxHops: 15,
|
||||
Count: 1,
|
||||
Networks: []string{"ip4:icmp", "ip4:ip"},
|
||||
Networks: []string{"ip4:icmp", "ip4:ip", "ip6:ipv6-icmp", "ip6:ip"},
|
||||
}
|
||||
|
||||
// DefaultTracer is a tracer with DefaultConfig.
|
||||
@ -43,7 +48,8 @@ type Tracer struct {
|
||||
Config
|
||||
|
||||
once sync.Once
|
||||
conn *net.IPConn
|
||||
conn *net.IPConn // Ipv4连接
|
||||
ipv6conn *ipv6.PacketConn // IPv6连接
|
||||
err error
|
||||
|
||||
mu sync.RWMutex
|
||||
@ -113,13 +119,36 @@ func (t *Tracer) NewSession(ip net.IP) (*Session, error) {
|
||||
}
|
||||
|
||||
func (t *Tracer) init() {
|
||||
// 初始化IPv4连接
|
||||
for _, network := range t.Networks {
|
||||
if strings.HasPrefix(network, "ip4") {
|
||||
t.conn, t.err = t.listen(network, t.Addr)
|
||||
if t.err != nil {
|
||||
if t.err == nil {
|
||||
go t.serve(t.conn)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 初始化IPv6连接
|
||||
for _, network := range t.Networks {
|
||||
if strings.HasPrefix(network, "ip6") {
|
||||
conn, err := net.ListenIP(network, t.Addr)
|
||||
if err == nil {
|
||||
t.ipv6conn = ipv6.NewPacketConn(conn)
|
||||
err = t.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
Logger.Info("设置IPv6控制消息失败: " + err.Error())
|
||||
}
|
||||
t.ipv6conn.Close()
|
||||
continue
|
||||
}
|
||||
go t.serve(t.conn)
|
||||
return
|
||||
go t.serveIPv6(t.ipv6conn)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,8 +160,10 @@ func (t *Tracer) Close() {
|
||||
if t.conn != nil {
|
||||
t.conn.Close()
|
||||
}
|
||||
if t.ipv6conn != nil {
|
||||
t.ipv6conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracer) serve(conn *net.IPConn) error {
|
||||
defer conn.Close()
|
||||
buf := make([]byte, 1500)
|
||||
@ -150,17 +181,59 @@ func (t *Tracer) serve(conn *net.IPConn) error {
|
||||
|
||||
func (t *Tracer) serveData(from net.IP, b []byte) error {
|
||||
if from.To4() == nil {
|
||||
// TODO: implement ProtocolIPv6ICMP
|
||||
return errUnsupportedProtocol
|
||||
// IPv6处理
|
||||
msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Warn("解析IPv6 ICMP消息失败: " + err.Error())
|
||||
}
|
||||
now := time.Now()
|
||||
return err
|
||||
}
|
||||
// 记录所有收到的消息类型,帮助调试
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
|
||||
}
|
||||
// 处理不同类型的ICMP消息
|
||||
if msg.Type == ipv6.ICMPTypeEchoReply {
|
||||
if echo, ok := msg.Body.(*icmp.Echo); ok {
|
||||
if model.EnableLoger {
|
||||
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()})
|
||||
}
|
||||
} else if msg.Type == ipv6.ICMPTypeTimeExceeded {
|
||||
b = getReplyData(msg)
|
||||
if len(b) < ipv6.HeaderLen {
|
||||
if model.EnableLoger {
|
||||
Logger.Warn("IPv6时间超过消息太短")
|
||||
}
|
||||
return errMessageTooShort
|
||||
}
|
||||
// 解析原始IPv6包头
|
||||
if b[0]>>4 == ipv6.Version {
|
||||
ip, err := ipv6.ParseHeader(b)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Warn("解析IPv6头部失败: " + err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("处理IPv6时间超过: 目标=%v, FlowLabel=%d, HopLimit=%d",
|
||||
ip.Dst, ip.FlowLabel, ip.HopLimit))
|
||||
}
|
||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, time.Now()})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 原有的IPv4处理逻辑
|
||||
msg, err := icmp.ParseMessage(ProtocolICMP, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.Type == ipv4.ICMPTypeEchoReply {
|
||||
echo := msg.Body.(*icmp.Echo)
|
||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, now})
|
||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
||||
}
|
||||
b = getReplyData(msg)
|
||||
if len(b) < ipv4.HeaderLen {
|
||||
@ -172,28 +245,47 @@ func (t *Tracer) serveData(from net.IP, b []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, now})
|
||||
case ipv6.Version:
|
||||
ip, err := ipv6.ParseHeader(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, now})
|
||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, time.Now()})
|
||||
default:
|
||||
return errUnsupportedProtocol
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) {
|
||||
id := uint16(atomic.AddUint32(&t.seq, 1))
|
||||
b := newPacket(id, dst, ttl)
|
||||
var b []byte
|
||||
req := &packet{dst, id, ttl, time.Now()}
|
||||
if dst.To4() == nil {
|
||||
// IPv6
|
||||
b := newPacketV6(id, dst, ttl)
|
||||
if t.ipv6conn != nil {
|
||||
cm := &ipv6.ControlMessage{
|
||||
HopLimit: ttl,
|
||||
}
|
||||
_, err := t.ipv6conn.WriteTo(b, cm, &net.IPAddr{IP: dst})
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
Logger.Info("发送IPv6请求失败: " + err.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
return nil, errors.New("IPv6连接不可用")
|
||||
} else {
|
||||
// IPv4
|
||||
b = newPacketV4(id, dst, ttl)
|
||||
_, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tracer) addSession(s *Session) {
|
||||
t.mu.Lock()
|
||||
@ -217,10 +309,30 @@ func (t *Tracer) removeSession(s *Session) {
|
||||
}
|
||||
|
||||
func (t *Tracer) serveReply(dst net.IP, res *packet) error {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("处理回复: 目标=%v, 来源=%v, ID=%d, TTL=%d",
|
||||
dst, res.IP, res.ID, res.TTL))
|
||||
}
|
||||
// 确保使用正确的IP格式进行查找
|
||||
shortDst := shortIP(dst)
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
a := t.sess[string(shortIP(dst))]
|
||||
// // 调试输出会话信息
|
||||
// if model.EnableLoger && len(t.sess) > 0 {
|
||||
// for ip, sessions := range t.sess {
|
||||
// Logger.Info(fmt.Sprintf("会话信息: IP=%v, 会话数=%d",
|
||||
// net.IP([]byte(ip)), len(sessions)))
|
||||
// }
|
||||
// }
|
||||
// 查找对应的会话
|
||||
a := t.sess[string(shortDst)]
|
||||
if len(a) == 0 && model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("找不到目标IP=%v的会话", dst))
|
||||
}
|
||||
for _, s := range a {
|
||||
// if model.EnableLoger {
|
||||
// Logger.Info(fmt.Sprintf("处理会话响应: 会话目标=%v", s.ip))
|
||||
// }
|
||||
s.handle(res)
|
||||
}
|
||||
return nil
|
||||
@ -284,12 +396,32 @@ func (s *Session) handle(res *packet) {
|
||||
now := res.Time
|
||||
n := 0
|
||||
var req *packet
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("处理会话响应: 会话目标=%v, 响应源=%v, ID=%d, TTL=%d",
|
||||
s.ip, res.IP, res.ID, res.TTL))
|
||||
}
|
||||
s.mu.Lock()
|
||||
// // 打印出所有待处理的探测包
|
||||
// if model.EnableLoger && len(s.probes) > 0 {
|
||||
// Logger.Info(fmt.Sprintf("当前会话有 %d 个待处理的探测包", len(s.probes)))
|
||||
// for i, probe := range s.probes {
|
||||
// Logger.Info(fmt.Sprintf("探测包 #%d: ID=%d, TTL=%d, 时间=%v",
|
||||
// i, probe.ID, probe.TTL, probe.Time))
|
||||
// }
|
||||
// }
|
||||
// 查找匹配的请求包
|
||||
for _, r := range s.probes {
|
||||
if now.Sub(r.Time) > s.t.Timeout {
|
||||
// if model.EnableLoger {
|
||||
// Logger.Info(fmt.Sprintf("探测包超时: ID=%d, TTL=%d", r.ID, r.TTL))
|
||||
// }
|
||||
continue
|
||||
}
|
||||
if r.ID == res.ID {
|
||||
// 对于IPv6 松散匹配
|
||||
if r.ID == res.ID || res.IP.To4() == nil {
|
||||
// if model.EnableLoger {
|
||||
// Logger.Info(fmt.Sprintf("找到匹配的探测包: ID=%d, TTL=%d", r.ID, r.TTL))
|
||||
// }
|
||||
req = r
|
||||
continue
|
||||
}
|
||||
@ -299,12 +431,19 @@ func (s *Session) handle(res *packet) {
|
||||
s.probes = s.probes[:n]
|
||||
s.mu.Unlock()
|
||||
if req == nil {
|
||||
// if model.EnableLoger {
|
||||
// Logger.Warn(fmt.Sprintf("未找到匹配的探测包: 响应ID=%d", res.ID))
|
||||
// }
|
||||
return
|
||||
}
|
||||
hops := req.TTL - res.TTL + 1
|
||||
if hops < 1 {
|
||||
hops = 1
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("创建响应: IP=%v, RTT=%v, Hops=%d",
|
||||
res.IP, res.Time.Sub(req.Time), hops))
|
||||
}
|
||||
select {
|
||||
case s.ch <- &Reply{
|
||||
IP: res.IP,
|
||||
@ -312,6 +451,9 @@ func (s *Session) handle(res *packet) {
|
||||
Hops: hops,
|
||||
}:
|
||||
default:
|
||||
if model.EnableLoger {
|
||||
Logger.Warn("发送响应到通道失败,通道已满")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,33 +494,6 @@ var (
|
||||
errNoReplyData = errors.New("no reply data")
|
||||
)
|
||||
|
||||
func newPacket(id uint16, dst net.IP, ttl int) []byte {
|
||||
// TODO: reuse buffers...
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Body: &icmp.Echo{
|
||||
ID: int(id),
|
||||
Seq: int(id),
|
||||
},
|
||||
}
|
||||
p, _ := msg.Marshal(nil)
|
||||
ip := &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TotalLen: ipv4.HeaderLen + len(p),
|
||||
TOS: 16,
|
||||
ID: int(id),
|
||||
Dst: dst,
|
||||
Protocol: ProtocolICMP,
|
||||
TTL: ttl,
|
||||
}
|
||||
buf, err := ip.Marshal()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return append(buf, p...)
|
||||
}
|
||||
|
||||
// IANA Assigned Internet Protocol Numbers
|
||||
const (
|
||||
ProtocolICMP = 1
|
186
bk/trace_ipv4.go
Normal file
186
bk/trace_ipv4.go
Normal file
@ -0,0 +1,186 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
func newPacketV4(id uint16, dst net.IP, ttl int) []byte {
|
||||
// TODO: reuse buffers...
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Body: &icmp.Echo{
|
||||
ID: int(id),
|
||||
Seq: int(id),
|
||||
},
|
||||
}
|
||||
p, _ := msg.Marshal(nil)
|
||||
ip := &ipv4.Header{
|
||||
Version: ipv4.Version,
|
||||
Len: ipv4.HeaderLen,
|
||||
TotalLen: ipv4.HeaderLen + len(p),
|
||||
TOS: 16,
|
||||
ID: int(id),
|
||||
Dst: dst,
|
||||
Protocol: ProtocolICMP,
|
||||
TTL: ttl,
|
||||
}
|
||||
buf, err := ip.Marshal()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return append(buf, p...)
|
||||
}
|
||||
|
||||
// extractIpv4ASNsFromHops 从跃点中提取ASN列表
|
||||
func extractIpv4ASNsFromHops(hops []*Hop, enableLogger bool) []string {
|
||||
var asns []string
|
||||
for _, h := range hops {
|
||||
for _, n := range h.Nodes {
|
||||
asn := ipv4Asn(n.IP.String())
|
||||
if asn != "" {
|
||||
asns = append(asns, asn)
|
||||
if enableLogger {
|
||||
Logger.Info(fmt.Sprintf("IP %s 对应的ASN: %s", n.IP.String(), asn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return asns
|
||||
}
|
||||
|
||||
// trace IPv4追踪函数
|
||||
func trace(ch chan Result, i int) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||
}
|
||||
// 先尝试原始IP地址
|
||||
hops, err := Trace(net.ParseIP(model.Ipv4s[i]))
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IP地址"))
|
||||
if model.EnableLoger {
|
||||
Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", model.Ipv4Names[i], model.Ipv4s[i], err))
|
||||
}
|
||||
ch <- Result{i, s}
|
||||
}
|
||||
asns := extractIpv4ASNsFromHops(hops, model.EnableLoger)
|
||||
// 如果没有找到ASN,尝试备选IP
|
||||
if len(asns) == 0 {
|
||||
// 尝试从IcmpTargets获取备选IP
|
||||
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)
|
||||
// // 记录每个hop的信息
|
||||
// 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 {
|
||||
var tempText string
|
||||
asns = removeDuplicates(asns)
|
||||
tempText += fmt.Sprintf("%v ", model.Ipv4Names[i])
|
||||
hasAS4134 := false
|
||||
hasAS4809 := false
|
||||
for _, asn := range asns {
|
||||
if asn == "AS4134" {
|
||||
hasAS4134 = true
|
||||
}
|
||||
if asn == "AS4809" {
|
||||
hasAS4809 = true
|
||||
}
|
||||
}
|
||||
// 判断是否包含 AS4134 和 AS4809
|
||||
if hasAS4134 && hasAS4809 {
|
||||
// 同时包含 AS4134 和 AS4809 属于 CN2GT
|
||||
asns = append([]string{"AS4809b"}, asns...)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GT", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||
}
|
||||
} else if hasAS4809 {
|
||||
// 仅包含 AS4809 属于 CN2GIA
|
||||
asns = append([]string{"AS4809a"}, asns...)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||
}
|
||||
}
|
||||
tempText += fmt.Sprintf("%-24s ", model.Ipv4s[i])
|
||||
for _, asn := range asns {
|
||||
asnDescription := model.M[asn]
|
||||
switch asn {
|
||||
case "":
|
||||
continue
|
||||
case "AS4809": // 被 AS4809a 和 AS4809b 替代了
|
||||
continue
|
||||
case "AS9929":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809a":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS23764":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809b":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
case "AS58807":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
default:
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += White(asnDescription) + " "
|
||||
}
|
||||
}
|
||||
}
|
||||
if tempText == (fmt.Sprintf("%v ", model.Ipv4Names[i]) + fmt.Sprintf("%-15s ", model.Ipv4s[i])) {
|
||||
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
||||
|
||||
if model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||
}
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", model.Ipv4Names[i], model.Ipv4s[i], tempText))
|
||||
}
|
||||
ch <- Result{i, tempText}
|
||||
} else {
|
||||
s := fmt.Sprintf("%v %-15s %v", model.Ipv4Names[i], model.Ipv4s[i], Red("检测不到回程路由节点的IPV4地址"))
|
||||
|
||||
if model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IPV4地址", model.Ipv4Names[i], model.Ipv4s[i]))
|
||||
}
|
||||
ch <- Result{i, s}
|
||||
}
|
||||
}
|
199
bk/trace_ipv6.go
Normal file
199
bk/trace_ipv6.go
Normal file
@ -0,0 +1,199 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func newPacketV6(id uint16, dst net.IP, ttl int) []byte {
|
||||
// 使用ipv6包的Echo请求
|
||||
msg := icmp.Message{
|
||||
Type: ipv6.ICMPTypeEchoRequest,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: int(id),
|
||||
Seq: int(id),
|
||||
Data: []byte("HELLO-R-U-THERE"),
|
||||
},
|
||||
}
|
||||
// 序列化ICMP消息
|
||||
icmpBytes, _ := msg.Marshal(nil)
|
||||
return icmpBytes
|
||||
}
|
||||
|
||||
func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
defer conn.Close()
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
n, cm, src, err := conn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Error("读取IPv6响应失败: " + err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("收到IPv6响应: 来源=%v, 跳数=%d", src, cm.HopLimit))
|
||||
}
|
||||
fromIP := src.(*net.IPAddr).IP
|
||||
err = t.serveData(fromIP, buf[:n])
|
||||
if err != nil && model.EnableLoger {
|
||||
Logger.Warn("处理IPv6数据失败: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// extractIpv6ASNsFromHops 从跃点中提取ASN列表
|
||||
func extractIpv6ASNsFromHops(hops []*Hop, enableLogger bool) []string {
|
||||
var asns []string
|
||||
for _, h := range hops {
|
||||
for _, n := range h.Nodes {
|
||||
asn := ipv6Asn(n.IP.String())
|
||||
if asn != "" {
|
||||
asns = append(asns, asn)
|
||||
if enableLogger {
|
||||
Logger.Info(fmt.Sprintf("IP %s 对应的ASN: %s", n.IP.String(), asn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return asns
|
||||
}
|
||||
|
||||
// traceIPv6 IPv6追踪函数
|
||||
func traceIPv6(ch chan Result, i int, offset int) {
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
// 先尝试原始IP地址
|
||||
hops, err := Trace(net.ParseIP(model.Ipv6s[i]))
|
||||
if err != nil {
|
||||
s := fmt.Sprintf("%v %-24s %v", model.Ipv6Names[i], model.Ipv6s[i], Red("检测不到回程路由节点的IP地址"))
|
||||
if model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
ch <- Result{i + offset, s}
|
||||
}
|
||||
asns := extractIpv6ASNsFromHops(hops, model.EnableLoger)
|
||||
// 如果没有找到ASN,尝试备选IP
|
||||
if len(asns) == 0 {
|
||||
// 尝试从IcmpTargets获取备选IP
|
||||
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 := extractIpv6ASNsFromHops(hops, model.EnableLoger)
|
||||
asns = append(asns, newAsns...)
|
||||
if len(newAsns) > 0 {
|
||||
break // 成功找到可用IP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
asns = removeDuplicates(asns)
|
||||
// // 记录每个hop的信息
|
||||
// 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 {
|
||||
var tempText string
|
||||
asns = removeDuplicates(asns)
|
||||
tempText += fmt.Sprintf("%v ", model.Ipv6Names[i])
|
||||
hasAS4134 := false
|
||||
hasAS4809 := false
|
||||
for _, asn := range asns {
|
||||
if asn == "AS4134" {
|
||||
hasAS4134 = true
|
||||
}
|
||||
if asn == "AS4809" {
|
||||
hasAS4809 = true
|
||||
}
|
||||
}
|
||||
// 判断是否包含 AS4134 和 AS4809
|
||||
if hasAS4134 && hasAS4809 {
|
||||
// 同时包含 AS4134 和 AS4809 属于 CN2GT
|
||||
asns = append([]string{"AS4809b"}, asns...)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GT", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
} else if hasAS4809 {
|
||||
// 仅包含 AS4809 属于 CN2GIA
|
||||
asns = append([]string{"AS4809a"}, asns...)
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
}
|
||||
tempText += fmt.Sprintf("%-24s ", model.Ipv6s[i])
|
||||
for _, asn := range asns {
|
||||
asnDescription := model.M[asn]
|
||||
switch asn {
|
||||
case "":
|
||||
continue
|
||||
case "AS4809": // 被 AS4809a 和 AS4809b 替代了
|
||||
continue
|
||||
case "AS9929":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809a":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS23764":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += DarkGreen(asnDescription) + " "
|
||||
}
|
||||
case "AS4809b":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
case "AS58807":
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += Green(asnDescription) + " "
|
||||
}
|
||||
default:
|
||||
if !strings.Contains(tempText, asnDescription) {
|
||||
tempText += White(asnDescription) + " "
|
||||
}
|
||||
}
|
||||
}
|
||||
if tempText == (fmt.Sprintf("%v ", model.Ipv6Names[i]) + fmt.Sprintf("%-40s ", model.Ipv6s[i])) {
|
||||
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
||||
if model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", model.Ipv6Names[i], model.Ipv6s[i], tempText))
|
||||
}
|
||||
ch <- Result{i + offset, tempText}
|
||||
} else {
|
||||
s := fmt.Sprintf("%v %-24s %v", model.Ipv6Names[i], model.Ipv6s[i], Red("检测不到回程路由节点的IPV6地址"))
|
||||
if model.EnableLoger {
|
||||
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IPV6地址", model.Ipv6Names[i], model.Ipv6s[i]))
|
||||
}
|
||||
ch <- Result{i + offset, s}
|
||||
}
|
||||
}
|
142
bk/utils.go
Normal file
142
bk/utils.go
Normal file
@ -0,0 +1,142 @@
|
||||
package backtrace
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
i int
|
||||
s string
|
||||
}
|
||||
|
||||
// removeDuplicates 切片去重
|
||||
func removeDuplicates(elements []string) []string {
|
||||
if elements == nil {
|
||||
return nil
|
||||
}
|
||||
seen := make(map[string]struct{})
|
||||
var result []string
|
||||
for _, v := range elements {
|
||||
if _, ok := seen[v]; !ok {
|
||||
seen[v] = struct{}{}
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getData 获取目标地址的文本内容
|
||||
func getData(endpoint string) string {
|
||||
client := req.C()
|
||||
client.SetTimeout(6 * time.Second)
|
||||
client.R().
|
||||
SetRetryCount(2).
|
||||
SetRetryBackoffInterval(1*time.Second, 5*time.Second).
|
||||
SetRetryFixedInterval(2 * time.Second)
|
||||
if model.EnableLoger {
|
||||
InitLogger()
|
||||
defer Logger.Sync()
|
||||
}
|
||||
for _, baseUrl := range model.CdnList {
|
||||
url := baseUrl + endpoint
|
||||
resp, err := client.R().Get(url)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if strings.Contains(string(b), "error") {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("Received data length: %d", len(b)))
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("HTTP request failed: %v", err))
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// parseIcmpTargets 解析ICMP目标数据
|
||||
func parseIcmpTargets(jsonData string) []model.IcmpTarget {
|
||||
var targets []model.IcmpTarget
|
||||
err := json.Unmarshal([]byte(jsonData), &targets)
|
||||
if err != nil {
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("解析ICMP目标失败: %s", err.Error()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return targets
|
||||
}
|
||||
|
||||
// tryAlternativeIPs 从IcmpTargets获取备选IP地址
|
||||
func tryAlternativeIPs(targetName string, ipVersion string) []string {
|
||||
if model.ParsedIcmpTargets == nil || (model.ParsedIcmpTargets != nil && len(model.ParsedIcmpTargets) == 0) {
|
||||
return nil
|
||||
}
|
||||
if model.EnableLoger {
|
||||
Logger.Info(fmt.Sprintf("使用备选地址: %s %s", targetName, ipVersion))
|
||||
}
|
||||
// 从目标名称中提取省份和ISP信息
|
||||
var targetProvince, targetISP string
|
||||
if strings.Contains(targetName, "北京") {
|
||||
targetProvince = "北京"
|
||||
} else if strings.Contains(targetName, "上海") {
|
||||
targetProvince = "上海"
|
||||
} else if strings.Contains(targetName, "广州") {
|
||||
targetProvince = "广东"
|
||||
} else if strings.Contains(targetName, "成都") {
|
||||
targetProvince = "四川"
|
||||
}
|
||||
if strings.Contains(targetName, "电信") {
|
||||
targetISP = "电信"
|
||||
} else if strings.Contains(targetName, "联通") {
|
||||
targetISP = "联通"
|
||||
} else if strings.Contains(targetName, "移动") {
|
||||
targetISP = "移动"
|
||||
}
|
||||
// 如果没有提取到信息,返回空
|
||||
if targetProvince == "" || targetISP == "" {
|
||||
return nil
|
||||
}
|
||||
// 查找匹配条件的目标
|
||||
var result []string
|
||||
for _, target := range model.ParsedIcmpTargets {
|
||||
// 检查省份是否匹配(可能带有"省"字或不带)
|
||||
provinceMatch := (target.Province == targetProvince) || (target.Province == targetProvince+"省")
|
||||
// 检查ISP和IP版本是否匹配
|
||||
if provinceMatch && target.ISP == targetISP && target.IPVersion == ipVersion {
|
||||
// 解析IP列表
|
||||
if target.IPs != "" {
|
||||
ips := strings.Split(target.IPs, ",")
|
||||
// 最多返回3个IP地址
|
||||
count := 0
|
||||
for _, ip := range ips {
|
||||
if ip != "" {
|
||||
result = append(result, strings.TrimSpace(ip))
|
||||
count++
|
||||
if count >= 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(result) > 0 {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package backtrace
|
||||
|
||||
const BackTraceVersion = "0.0.1"
|
33
cmd/main.go
33
cmd/main.go
@ -5,8 +5,11 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
backtrace "github.com/oneclickvirt/backtrace/bk"
|
||||
"github.com/oneclickvirt/backtrace/model"
|
||||
. "github.com/oneclickvirt/defaultset"
|
||||
)
|
||||
|
||||
@ -20,16 +23,27 @@ type IpInfo struct {
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
http.Get("https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Foneclickvirt%2Fbacktrace&count_bg=%2323E01C&title_bg=%23555555&icon=sonarcloud.svg&icon_color=%23E7E7E7&title=hits&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("项目地址:"), Yellow("https://github.com/oneclickvirt/backtrace"))
|
||||
var showVersion bool
|
||||
flag.BoolVar(&showVersion, "v", false, "show version")
|
||||
flag.Parse()
|
||||
if showVersion {
|
||||
fmt.Println(backtrace.BackTraceVersion)
|
||||
var showVersion, showIpInfo, help, ipv6 bool
|
||||
backtraceFlag := flag.NewFlagSet("backtrace", flag.ContinueOnError)
|
||||
backtraceFlag.BoolVar(&help, "h", false, "Show help information")
|
||||
backtraceFlag.BoolVar(&showVersion, "v", false, "Show version")
|
||||
backtraceFlag.BoolVar(&showIpInfo, "s", true, "Disabe show ip info")
|
||||
backtraceFlag.BoolVar(&model.EnableLoger, "log", false, "Enable logging")
|
||||
backtraceFlag.BoolVar(&ipv6, "ipv6", false, "Enable ipv6 testing")
|
||||
backtraceFlag.Parse(os.Args[1:])
|
||||
if help {
|
||||
fmt.Printf("Usage: %s [options]\n", os.Args[0])
|
||||
backtraceFlag.PrintDefaults()
|
||||
return
|
||||
}
|
||||
if showVersion {
|
||||
fmt.Println(model.BackTraceVersion)
|
||||
return
|
||||
}
|
||||
if showIpInfo {
|
||||
rsp, err := http.Get("http://ipinfo.io")
|
||||
if err != nil {
|
||||
fmt.Errorf("Get ip info err %v \n", err.Error())
|
||||
@ -43,7 +57,12 @@ func main() {
|
||||
Green(" 服务商: ") + Blue(info.Org))
|
||||
}
|
||||
}
|
||||
backtrace.BackTrace()
|
||||
}
|
||||
backtrace.BackTrace(ipv6)
|
||||
fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考"))
|
||||
fmt.Println(Yellow("同一目标地址多个线路时,可能检测已越过汇聚层,除了第一个线路外,后续信息可能无效"))
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||
fmt.Println("Press Enter to exit...")
|
||||
fmt.Scanln()
|
||||
}
|
||||
}
|
||||
|
23
go.mod
23
go.mod
@ -3,12 +3,31 @@ module github.com/oneclickvirt/backtrace
|
||||
go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/imroc/req/v3 v3.50.0
|
||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/net v0.33.0
|
||||
golang.org/x/sys v0.28.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/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/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
|
||||
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
|
||||
)
|
||||
|
63
go.sum
63
go.sum
@ -1,20 +1,71 @@
|
||||
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/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/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/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/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
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/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/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/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
78
model/model.go
Normal file
78
model/model.go
Normal file
@ -0,0 +1,78 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
const BackTraceVersion = "v0.0.5"
|
||||
|
||||
var EnableLoger = false
|
||||
|
||||
// IcmpTarget 定义ICMP目标的JSON结构
|
||||
type IcmpTarget struct {
|
||||
Province string `json:"province"`
|
||||
ISP string `json:"isp"`
|
||||
IPVersion string `json:"ip_version"`
|
||||
IPs string `json:"ips"` // IP列表,以逗号分隔
|
||||
}
|
||||
|
||||
var (
|
||||
IcmpTargets = "https://raw.githubusercontent.com/spiritLHLS/icmp_targets/main/nodes.json"
|
||||
CdnList = []string{
|
||||
"http://cdn1.spiritlhl.net/",
|
||||
"http://cdn2.spiritlhl.net/",
|
||||
"http://cdn3.spiritlhl.net/",
|
||||
"http://cdn4.spiritlhl.net/",
|
||||
}
|
||||
Ipv4s = []string{
|
||||
"219.141.140.10", // 北京电信v4
|
||||
"202.106.195.68", // 北京联通v4
|
||||
"221.179.155.161", // 北京移动v4
|
||||
"202.96.209.133", // 上海电信v4
|
||||
"210.22.97.1", // 上海联通v4
|
||||
"211.136.112.200", // 上海移动v4
|
||||
"58.60.188.222", // 广州电信v4
|
||||
"210.21.196.6", // 广州联通v4
|
||||
"120.196.165.24", // 广州移动v4
|
||||
"61.139.2.69", // 成都电信v4
|
||||
"119.6.6.6", // 成都联通v4
|
||||
"211.137.96.205", // 成都移动v4
|
||||
}
|
||||
|
||||
Ipv4Names = []string{
|
||||
"北京电信v4", "北京联通v4", "北京移动v4",
|
||||
"上海电信v4", "上海联通v4", "上海移动v4",
|
||||
"广州电信v4", "广州联通v4", "广州移动v4",
|
||||
"成都电信v4", "成都联通v4", "成都移动v4",
|
||||
}
|
||||
Ipv6s = []string{
|
||||
"2400:89c0:1053:3::69", // 北京电信 IPv6
|
||||
"2400:89c0:1013:3::54", // 北京联通 IPv6
|
||||
"2409:8c00:8421:1303::55", // 北京移动 IPv6
|
||||
"240e:e1:aa00:4000::24", // 上海电信 IPV6
|
||||
"2408:80f1:21:5003::a", // 上海联通 IPv6
|
||||
"2409:8c1e:75b0:3003::26", // 上海移动 IPv6
|
||||
"240e:97c:2f:3000::44", // 广州电信 IPv6
|
||||
"2408:8756:f50:1001::c", // 广州联通 IPv6
|
||||
"2409:8c54:871:1001::12", // 广州移动 IPv6
|
||||
}
|
||||
Ipv6Names = []string{
|
||||
"北京电信v6", "北京联通v6", "北京移动v6",
|
||||
"上海电信v6", "上海联通v6", "上海移动v6",
|
||||
"广州电信v6", "广州联通v6", "广州移动v6",
|
||||
}
|
||||
M = map[string]string{
|
||||
// [] 前的字符串个数,中文占2个字符串
|
||||
"AS23764": "电信CTGNET [精品线路]",
|
||||
"AS4809a": "电信CN2GIA [精品线路]",
|
||||
"AS4809b": "电信CN2GT [优质线路]",
|
||||
"AS4809": "电信CN2 [优质线路]",
|
||||
"AS4134": "电信163 [普通线路]",
|
||||
"AS9929": "联通9929 [优质线路]",
|
||||
"AS4837": "联通4837 [普通线路]",
|
||||
"AS58807": "移动CMIN2 [精品线路]",
|
||||
"AS9808": "移动CMI [普通线路]",
|
||||
"AS58453": "移动CMI [普通线路]",
|
||||
}
|
||||
CachedIcmpData string
|
||||
CachedIcmpDataFetchTime time.Time
|
||||
ParsedIcmpTargets []IcmpTarget
|
||||
)
|
Loading…
Reference in New Issue
Block a user