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"
|
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"
|
curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/oneclickvirt/backtrace/releases/assets/$asset"
|
||||||
done
|
done
|
||||||
sleep 60
|
sleep 30
|
||||||
|
|
||||||
release-binary:
|
release-binary:
|
||||||
name: Release Go Binary
|
name: Release Go Binary
|
||||||
|
72
README.md
72
README.md
@ -1,42 +1,80 @@
|
|||||||
# backtrace
|
# 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] 检测回程显示IPV4/IPV6地址时的线路(使用1500字节的包),不显示IP地址时显示ASN检测不到
|
||||||
- [x] 支持对```4837```、```9929```和```163```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)也支持
|
- [x] 支持对```9929```、```4837```和```163```线路的判断
|
||||||
- [x] 支持对```CN2GT```和```CN2GIA```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)不支持,原版全部识别为```CN2```了
|
- [x] 支持对```CTGNET```、```CN2GIA```和```CN2GT```线路的判断
|
||||||
- [x] 支持对```CMIN2```和```CMI```线路的判断,原版[backtrace](https://github.com/zhanghanyun/backtrace)也支持
|
- [x] 支持对```CMIN2```和```CMI```线路的判断
|
||||||
- [x] 支持对整个回程路由进行线路分析,与原版[backtrace](https://github.com/zhanghanyun/backtrace)仅进行一次判断不同
|
- [x] 支持对整个回程路由进行线路分析,一个目标IP可能会分析出多种线路
|
||||||
- [x] 修复原版[backtrace](https://github.com/zhanghanyun/backtrace)对IPV4地址信息获取时json解析失败依然打印信息的问题,本项目忽略错误继续执行路由线路查询
|
|
||||||
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
- [x] 增加对全平台的编译支持,原版[backtrace](https://github.com/zhanghanyun/backtrace)仅支持linux平台的amd64和arm64架构
|
||||||
|
- [x] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [ ] 使用nexttrace进行路由检测,备用方案才使用本地路由检测
|
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
||||||
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路
|
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
更新时间:2024.06.24
|
下载、安装、更新
|
||||||
|
|
||||||
```shell
|
```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
|
无环境依赖,理论上适配所有系统和主流架构,更多架构请查看 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中使用
|
## 在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
|
#!/bin/bash
|
||||||
#From https://github.com/oneclickvirt/backtrace
|
#From https://github.com/oneclickvirt/backtrace
|
||||||
#2024.05.21
|
#2024.07.02
|
||||||
|
|
||||||
rm -rf /usr/bin/backtrace
|
rm -rf /usr/bin/backtrace
|
||||||
os=$(uname -s)
|
os=$(uname -s)
|
||||||
arch=$(uname -m)
|
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
|
case $os in
|
||||||
Linux)
|
Linux)
|
||||||
case $arch in
|
case $arch in
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
"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")
|
"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")
|
"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"
|
echo "Unsupported architecture: $arch"
|
||||||
@ -27,13 +51,13 @@ case $os in
|
|||||||
Darwin)
|
Darwin)
|
||||||
case $arch in
|
case $arch in
|
||||||
"x86_64" | "x86" | "amd64" | "x64")
|
"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")
|
"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")
|
"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"
|
echo "Unsupported architecture: $arch"
|
||||||
@ -44,13 +68,13 @@ case $os in
|
|||||||
FreeBSD)
|
FreeBSD)
|
||||||
case $arch in
|
case $arch in
|
||||||
amd64)
|
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")
|
"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")
|
"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"
|
echo "Unsupported architecture: $arch"
|
||||||
@ -61,13 +85,13 @@ case $os in
|
|||||||
OpenBSD)
|
OpenBSD)
|
||||||
case $arch in
|
case $arch in
|
||||||
amd64)
|
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")
|
"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")
|
"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"
|
echo "Unsupported architecture: $arch"
|
||||||
@ -82,9 +106,4 @@ case $os in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
chmod 777 backtrace
|
chmod 777 backtrace
|
||||||
if [ ! -f /usr/bin/backtrace ]; then
|
cp backtrace /usr/bin/backtrace
|
||||||
mv backtrace /usr/bin/
|
|
||||||
backtrace
|
|
||||||
else
|
|
||||||
./backtrace
|
|
||||||
fi
|
|
||||||
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BackTrace() {
|
func BackTrace(enableIpv6 bool) {
|
||||||
var (
|
if model.CachedIcmpData == "" || model.ParsedIcmpTargets == nil || time.Since(model.CachedIcmpDataFetchTime) > time.Hour {
|
||||||
s [12]string // 对应 ips 目标地址数量
|
model.CachedIcmpData = getData(model.IcmpTargets)
|
||||||
c = make(chan Result)
|
model.CachedIcmpDataFetchTime = time.Now()
|
||||||
t = time.After(time.Second * 10)
|
if model.CachedIcmpData != "" {
|
||||||
)
|
model.ParsedIcmpTargets = parseIcmpTargets(model.CachedIcmpData)
|
||||||
for i := range ips {
|
|
||||||
go trace(c, i)
|
|
||||||
}
|
|
||||||
loop:
|
|
||||||
for range s {
|
|
||||||
select {
|
|
||||||
case o := <-c:
|
|
||||||
s[o.i] = o.s
|
|
||||||
case <-t:
|
|
||||||
break loop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, r := range s {
|
if enableIpv6 {
|
||||||
fmt.Println(r)
|
ipv4Count := len(model.Ipv4s)
|
||||||
|
ipv6Count := len(model.Ipv6s)
|
||||||
|
totalCount := ipv4Count + ipv6Count
|
||||||
|
var (
|
||||||
|
s = make([]string, totalCount)
|
||||||
|
c = make(chan Result)
|
||||||
|
t = time.After(time.Second * 10)
|
||||||
|
)
|
||||||
|
for i := range model.Ipv4s {
|
||||||
|
go trace(c, i)
|
||||||
|
}
|
||||||
|
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 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) {
|
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
|
package backtrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
|
. "github.com/oneclickvirt/defaultset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||||
conn, err := net.ListenIP(network, laddr)
|
conn, err := net.ListenIP(network, laddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
raw, err := conn.SyscallConn()
|
raw, err := conn.SyscallConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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)
|
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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
|
package backtrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
|
. "github.com/oneclickvirt/defaultset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
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)
|
conn, err := net.ListenIP(network, laddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
raw, err := conn.SyscallConn()
|
raw, err := conn.SyscallConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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)
|
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
@ -6,21 +6,28 @@ package backtrace
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
. "github.com/oneclickvirt/defaultset"
|
. "github.com/oneclickvirt/defaultset"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
func (t *Tracer) listen(network string, laddr *net.IPAddr) (*net.IPConn, error) {
|
||||||
InitLogger()
|
if model.EnableLoger {
|
||||||
defer Logger.Sync()
|
InitLogger()
|
||||||
|
defer Logger.Sync()
|
||||||
|
}
|
||||||
conn, err := net.ListenIP(network, laddr)
|
conn, err := net.ListenIP(network, laddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Info(err.Error())
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
raw, err := conn.SyscallConn()
|
raw, err := conn.SyscallConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Info(err.Error())
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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)
|
err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_HDRINCL, 1)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Logger.Info(err.Error())
|
if model.EnableLoger {
|
||||||
|
Logger.Info(err.Error())
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, err
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"golang.org/x/net/icmp"
|
"fmt"
|
||||||
"golang.org/x/net/ipv4"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"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.
|
// DefaultConfig is the default configuration for Tracer.
|
||||||
@ -19,7 +24,7 @@ var DefaultConfig = Config{
|
|||||||
Timeout: 500 * time.Millisecond,
|
Timeout: 500 * time.Millisecond,
|
||||||
MaxHops: 15,
|
MaxHops: 15,
|
||||||
Count: 1,
|
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.
|
// DefaultTracer is a tracer with DefaultConfig.
|
||||||
@ -42,9 +47,10 @@ type Config struct {
|
|||||||
type Tracer struct {
|
type Tracer struct {
|
||||||
Config
|
Config
|
||||||
|
|
||||||
once sync.Once
|
once sync.Once
|
||||||
conn *net.IPConn
|
conn *net.IPConn // Ipv4连接
|
||||||
err error
|
ipv6conn *ipv6.PacketConn // IPv6连接
|
||||||
|
err error
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
sess map[string][]*Session
|
sess map[string][]*Session
|
||||||
@ -113,13 +119,36 @@ func (t *Tracer) NewSession(ip net.IP) (*Session, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) init() {
|
func (t *Tracer) init() {
|
||||||
|
// 初始化IPv4连接
|
||||||
for _, network := range t.Networks {
|
for _, network := range t.Networks {
|
||||||
t.conn, t.err = t.listen(network, t.Addr)
|
if strings.HasPrefix(network, "ip4") {
|
||||||
if t.err != nil {
|
t.conn, t.err = t.listen(network, t.Addr)
|
||||||
continue
|
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.serveIPv6(t.ipv6conn)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
go t.serve(t.conn)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +160,10 @@ func (t *Tracer) Close() {
|
|||||||
if t.conn != nil {
|
if t.conn != nil {
|
||||||
t.conn.Close()
|
t.conn.Close()
|
||||||
}
|
}
|
||||||
|
if t.ipv6conn != nil {
|
||||||
|
t.ipv6conn.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) serve(conn *net.IPConn) error {
|
func (t *Tracer) serve(conn *net.IPConn) error {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
buf := make([]byte, 1500)
|
buf := make([]byte, 1500)
|
||||||
@ -150,49 +181,110 @@ func (t *Tracer) serve(conn *net.IPConn) error {
|
|||||||
|
|
||||||
func (t *Tracer) serveData(from net.IP, b []byte) error {
|
func (t *Tracer) serveData(from net.IP, b []byte) error {
|
||||||
if from.To4() == nil {
|
if from.To4() == nil {
|
||||||
// TODO: implement ProtocolIPv6ICMP
|
// IPv6处理
|
||||||
return errUnsupportedProtocol
|
msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b)
|
||||||
}
|
if err != nil {
|
||||||
now := time.Now()
|
if model.EnableLoger {
|
||||||
msg, err := icmp.ParseMessage(ProtocolICMP, b)
|
Logger.Warn("解析IPv6 ICMP消息失败: " + err.Error())
|
||||||
if err != nil {
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if msg.Type == ipv4.ICMPTypeEchoReply {
|
// 记录所有收到的消息类型,帮助调试
|
||||||
echo := msg.Body.(*icmp.Echo)
|
if model.EnableLoger {
|
||||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, now})
|
Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
|
||||||
}
|
}
|
||||||
b = getReplyData(msg)
|
// 处理不同类型的ICMP消息
|
||||||
if len(b) < ipv4.HeaderLen {
|
if msg.Type == ipv6.ICMPTypeEchoReply {
|
||||||
return errMessageTooShort
|
if echo, ok := msg.Body.(*icmp.Echo); ok {
|
||||||
}
|
if model.EnableLoger {
|
||||||
switch b[0] >> 4 {
|
Logger.Info(fmt.Sprintf("处理IPv6回显应答: ID=%d, Seq=%d", echo.ID, echo.Seq))
|
||||||
case ipv4.Version:
|
}
|
||||||
ip, err := ipv4.ParseHeader(b)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, now})
|
if msg.Type == ipv4.ICMPTypeEchoReply {
|
||||||
case ipv6.Version:
|
echo := msg.Body.(*icmp.Echo)
|
||||||
ip, err := ipv6.ParseHeader(b)
|
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
||||||
if err != nil {
|
}
|
||||||
return err
|
b = getReplyData(msg)
|
||||||
|
if len(b) < ipv4.HeaderLen {
|
||||||
|
return errMessageTooShort
|
||||||
|
}
|
||||||
|
switch b[0] >> 4 {
|
||||||
|
case ipv4.Version:
|
||||||
|
ip, err := ipv4.ParseHeader(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, time.Now()})
|
||||||
|
default:
|
||||||
|
return errUnsupportedProtocol
|
||||||
}
|
}
|
||||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, now})
|
|
||||||
default:
|
|
||||||
return errUnsupportedProtocol
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) {
|
func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) {
|
||||||
id := uint16(atomic.AddUint32(&t.seq, 1))
|
id := uint16(atomic.AddUint32(&t.seq, 1))
|
||||||
b := newPacket(id, dst, ttl)
|
var b []byte
|
||||||
req := &packet{dst, id, ttl, time.Now()}
|
req := &packet{dst, id, ttl, time.Now()}
|
||||||
_, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst})
|
if dst.To4() == nil {
|
||||||
if err != nil {
|
// IPv6
|
||||||
return nil, err
|
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
|
||||||
}
|
}
|
||||||
return req, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) addSession(s *Session) {
|
func (t *Tracer) addSession(s *Session) {
|
||||||
@ -217,10 +309,30 @@ func (t *Tracer) removeSession(s *Session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) serveReply(dst net.IP, res *packet) error {
|
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()
|
t.mu.RLock()
|
||||||
defer t.mu.RUnlock()
|
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 {
|
for _, s := range a {
|
||||||
|
// if model.EnableLoger {
|
||||||
|
// Logger.Info(fmt.Sprintf("处理会话响应: 会话目标=%v", s.ip))
|
||||||
|
// }
|
||||||
s.handle(res)
|
s.handle(res)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -284,12 +396,32 @@ func (s *Session) handle(res *packet) {
|
|||||||
now := res.Time
|
now := res.Time
|
||||||
n := 0
|
n := 0
|
||||||
var req *packet
|
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()
|
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 {
|
for _, r := range s.probes {
|
||||||
if now.Sub(r.Time) > s.t.Timeout {
|
if now.Sub(r.Time) > s.t.Timeout {
|
||||||
|
// if model.EnableLoger {
|
||||||
|
// Logger.Info(fmt.Sprintf("探测包超时: ID=%d, TTL=%d", r.ID, r.TTL))
|
||||||
|
// }
|
||||||
continue
|
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
|
req = r
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -299,12 +431,19 @@ func (s *Session) handle(res *packet) {
|
|||||||
s.probes = s.probes[:n]
|
s.probes = s.probes[:n]
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
if req == nil {
|
if req == nil {
|
||||||
|
// if model.EnableLoger {
|
||||||
|
// Logger.Warn(fmt.Sprintf("未找到匹配的探测包: 响应ID=%d", res.ID))
|
||||||
|
// }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hops := req.TTL - res.TTL + 1
|
hops := req.TTL - res.TTL + 1
|
||||||
if hops < 1 {
|
if hops < 1 {
|
||||||
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 {
|
select {
|
||||||
case s.ch <- &Reply{
|
case s.ch <- &Reply{
|
||||||
IP: res.IP,
|
IP: res.IP,
|
||||||
@ -312,6 +451,9 @@ func (s *Session) handle(res *packet) {
|
|||||||
Hops: hops,
|
Hops: hops,
|
||||||
}:
|
}:
|
||||||
default:
|
default:
|
||||||
|
if model.EnableLoger {
|
||||||
|
Logger.Warn("发送响应到通道失败,通道已满")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,33 +494,6 @@ var (
|
|||||||
errNoReplyData = errors.New("no reply data")
|
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
|
// IANA Assigned Internet Protocol Numbers
|
||||||
const (
|
const (
|
||||||
ProtocolICMP = 1
|
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"
|
|
51
cmd/main.go
51
cmd/main.go
@ -5,8 +5,11 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
backtrace "github.com/oneclickvirt/backtrace/bk"
|
backtrace "github.com/oneclickvirt/backtrace/bk"
|
||||||
|
"github.com/oneclickvirt/backtrace/model"
|
||||||
. "github.com/oneclickvirt/defaultset"
|
. "github.com/oneclickvirt/defaultset"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,30 +23,46 @@ type IpInfo struct {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go func() {
|
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"))
|
fmt.Println(Green("项目地址:"), Yellow("https://github.com/oneclickvirt/backtrace"))
|
||||||
var showVersion bool
|
var showVersion, showIpInfo, help, ipv6 bool
|
||||||
flag.BoolVar(&showVersion, "v", false, "show version")
|
backtraceFlag := flag.NewFlagSet("backtrace", flag.ContinueOnError)
|
||||||
flag.Parse()
|
backtraceFlag.BoolVar(&help, "h", false, "Show help information")
|
||||||
if showVersion {
|
backtraceFlag.BoolVar(&showVersion, "v", false, "Show version")
|
||||||
fmt.Println(backtrace.BackTraceVersion)
|
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
|
return
|
||||||
}
|
}
|
||||||
rsp, err := http.Get("http://ipinfo.io")
|
if showVersion {
|
||||||
if err != nil {
|
fmt.Println(model.BackTraceVersion)
|
||||||
fmt.Errorf("Get ip info err %v \n", err.Error())
|
return
|
||||||
} else {
|
}
|
||||||
info := IpInfo{}
|
if showIpInfo {
|
||||||
err = json.NewDecoder(rsp.Body).Decode(&info)
|
rsp, err := http.Get("http://ipinfo.io")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("json decode err %v \n", err.Error())
|
fmt.Errorf("Get ip info err %v \n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(Green("国家: ") + White(info.Country) + Green(" 城市: ") + White(info.City) +
|
info := IpInfo{}
|
||||||
Green(" 服务商: ") + Blue(info.Org))
|
err = json.NewDecoder(rsp.Body).Decode(&info)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Errorf("json decode err %v \n", err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(Green("国家: ") + White(info.Country) + Green(" 城市: ") + White(info.City) +
|
||||||
|
Green(" 服务商: ") + Blue(info.Org))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backtrace.BackTrace()
|
backtrace.BackTrace(ipv6)
|
||||||
fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考"))
|
fmt.Println(Yellow("准确线路自行查看详细路由,本测试结果仅作参考"))
|
||||||
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
|
go 1.22.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/imroc/req/v3 v3.50.0
|
||||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5
|
||||||
golang.org/x/net v0.26.0
|
golang.org/x/net v0.33.0
|
||||||
golang.org/x/sys v0.21.0
|
golang.org/x/sys v0.28.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
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/multierr v1.10.0 // indirect
|
||||||
go.uber.org/zap v1.27.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:TUM6XzOB7Z7OxyXi3fwlZY9KfuVbvUBusYiNbSfX208=
|
||||||
github.com/oneclickvirt/defaultset v0.0.0-20240624051018-30a50859e1b5/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
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 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
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 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
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 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
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/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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