Compare commits

...

84 Commits

Author SHA1 Message Date
tsosunchia
85df0121fd UPDATE README 2023-06-03 20:45:47 +08:00
tsosunchia
4a749285be 将DNS解析与WS握手同步进行 2023-06-03 20:19:01 +08:00
tsosunchia
a92cfc7783 删除无意义文件 2023-06-03 19:52:25 +08:00
tsosunchia
268971e85b Merge pull request #128 from fakeboboliu/fix1
improve: rootless trace on macOS
2023-06-03 17:26:52 +08:00
bobo liu
2bac716bd7 improve: rootless trace on macOS 2023-06-03 16:50:21 +08:00
tsosunchia
eb64f68663 修补timeout参数 2023-06-03 06:57:44 +08:00
tsosunchia
e9ca9cf388 fixbug:tcp ipv6 trace时遵从BeginHop 2023-06-03 05:47:38 +08:00
tsosunchia
364be22383 tcp,udp模式也适用ttl-time,send-time了 2023-06-03 05:25:14 +08:00
tsosunchia
2f6a2573ae fetchipdata加mutex,以后同时仅进行一次的查询 2023-06-03 04:28:10 +08:00
tsosunchia
a25157867c fixbug: fasttrace指定网卡异常退出 2023-06-03 03:33:36 +08:00
tsosunchia
7c37598804 将GeoIPInformatinDataCache推广到所有数据源 2023-06-02 18:13:27 +08:00
tsosunchia
8d30c59c17 fasttrace增加支持SrcDev,SrcAddr,BeginHop,MaxHops,RDns,AlwaysWaitRDNS,Lang,PktSize 2023-06-02 17:32:07 +08:00
tsosunchia
e8e5c1438e Merge remote-tracking branch 'refs/remotes/origin/main' 2023-06-02 14:20:48 +08:00
tsosunchia
cb0c988eda Update bug_report.md 2023-06-02 14:20:21 +08:00
tsosunchia
b1cabbc6d4 pow_test增加计时 2023-06-02 13:57:04 +08:00
tsosunchia
2493f471dc 对pow_token也进行了缓存 2023-06-02 04:37:40 +08:00
tsosunchia
8578109243 对rdns也进行了缓存 2023-06-02 02:12:35 +08:00
tsosunchia
089250fee1 提供不间断运行环境变量 2023-06-02 01:41:11 +08:00
tsosunchia
0e87592537 增加IP查询缓存机制 2023-06-02 01:04:32 +08:00
tsosunchia
14552cd853 推介OpenTrace 2023-06-01 18:43:43 +08:00
tsosunchia
44b70cf7e7 fix typo 2023-06-01 18:24:55 +08:00
tsosunchia
3f8b043821 format readme 2023-06-01 18:12:13 +08:00
tsosunchia
fa8eb050af 更新依赖 2023-06-01 17:29:35 +08:00
tsosunchia
50582f0fd0 重构UA存放位置 2023-06-01 16:18:28 +08:00
tsosunchia
64371fb41a GetTracemap也适用优选IP 2023-06-01 15:40:04 +08:00
tsosunchia
6476c3aff3 pow模块解耦合完成 2023-06-01 14:46:52 +08:00
tsosunchia
4d7831fd29 pow使用的ip也是优选IP 2023-06-01 14:08:32 +08:00
tsosunchia
d602941722 对pow模块解耦合 2023-06-01 12:30:36 +08:00
tsosunchia
2d548fcca0 增加一个设置POWtoken的环境变量 2023-06-01 00:46:45 +08:00
tsosunchia
8a79a5dd1c 调整POW超时时间为5s 2023-05-31 22:30:31 +08:00
tsosunchia
390efdd75d Merge remote-tracking branch 'origin/main' 2023-05-31 22:20:49 +08:00
tsosunchia
d0d1511c29 增加POW机制 2023-05-31 22:20:08 +08:00
Leo
7013fb6a41 doc: maintainer 2023-05-31 20:46:10 +08:00
tsosunchia
0513ab2a1b 更新README 2023-05-31 03:19:23 +08:00
tsosunchia
11489d7027 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
2023-05-31 03:12:11 +08:00
tsosunchia
97880049f7 更新README安装指引 2023-05-31 03:10:00 +08:00
tsosunchia
781c6ccaee Merge pull request #124 from chenrui333/docs/add-homebrew-installation-note
docs: update to use homebrew-core formula
2023-05-31 03:09:34 +08:00
Rui Chen
9e84a3da65 docs: update to use homebrew-core formula
Signed-off-by: Rui Chen <rui@chenrui.dev>
2023-05-30 12:47:50 -04:00
tsosunchia
4e5cd2d053 fix bug:重构版本信息的位置解决包引用环路问题 2023-05-30 14:55:47 +08:00
tsosunchia
288aee254f 变更:获取GEOIP信息适用于timeout参数 2023-05-30 14:38:42 +08:00
tsosunchia
2d235baa53 变更:获取GEOIP信息适用于timeout参数 2023-05-30 14:37:51 +08:00
sjlleo
d23f90dd19 Merge pull request #123 from sjlleo/newargs
增加timeout和psize参数
2023-05-30 12:21:38 +08:00
tsosunchia
fdc6145087 添加一个psize参数 2023-05-30 03:37:00 +08:00
tsosunchia
1d6ce5de88 添加一个timeout参数 2023-05-30 02:24:43 +08:00
tsosunchia
86b817291d Merge pull request #122 from sjlleo/resovle_v4_v6_only
增加指定解析IPv4/IPv6的功能
2023-05-29 21:58:28 +08:00
tsosunchia
b38fc18bb4 增加指定解析IPv4/IPv6的功能 2023-05-29 20:53:07 +08:00
tsosunchia
23d20de7c8 fix bug:fasttrace也进行nslookup 2023-05-29 19:51:16 +08:00
tsosunchia
bf4ec99323 fasttraceIP改为由dns获取 2023-05-29 18:34:15 +08:00
tsosunchia
4bfe85df1b 更改为仅在使用LEOMOEAPI时尝试获取tracemap 2023-05-28 16:26:22 +08:00
tsosunchia
e48b30c47a 增加json输出模式,修正使用ipinfo API查询的IP无ASN时的异常
PS: json输出模式主要目的是方便开发者调用NEXTTRACE
2023-05-28 13:58:27 +08:00
tsosunchia
f2fbce0358 增加不输出GEOIP信息的方法
PS: 为外部程序调用预留
2023-05-26 11:13:59 +08:00
tsosunchia
98bd95d046 update readme 2023-05-25 20:54:22 +08:00
tsosunchia
b622a40022 fix bug:raw和classic模式增加语言个性化输出
注意:classic模式将会被废弃,请不要在此模式基础上开发
2023-05-25 20:40:12 +08:00
tsosunchia
6bc74e14cb 增加关于IP信息纠错的联系方式 2023-05-25 18:24:05 +08:00
tsosunchia
8233c7c303 更新新模式说明 2023-05-24 22:50:11 +08:00
tsosunchia
3084effd78 修改输出提示,显示为当前真实的maxhops设置
之前无论maxhops设置为多少,都输出为 30 hops max
2023-05-24 16:34:30 +08:00
tsosunchia
ac1ee5e08c 增加tracemap的异常处理
防止与tracemap连接出现问题时报错
2023-05-24 16:08:59 +08:00
tsosunchia
723f5c4c5e raw模式使用新参数--raw
classic模式参数保持v1.1.3版本的设置
2023-05-23 22:22:14 +08:00
Leo
308ae73728 chore: add latency 2023-05-23 21:41:16 +08:00
Leo
b88d5292da chore: Classic Printer Change 2023-05-23 20:00:42 +08:00
tsosunchia
903b6f232d Update README_zh_CN.md 2023-05-23 02:39:59 +08:00
tsosunchia
5211daf814 Update README.md 2023-05-23 02:38:56 +08:00
tsosunchia
62f817af91 Merge pull request #111 from sjlleo/dependabot/go_modules/golang.org/x/net-0.10.0 2023-05-15 20:53:18 +08:00
dependabot[bot]
5907ebcf84 chore(deps): bump golang.org/x/net from 0.9.0 to 0.10.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/net/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-15 10:02:10 +00:00
tsosunchia
825eccf986 Merge pull request #109 from sjlleo/dependabot/go_modules/golang.org/x/sync-0.2.0
chore(deps): bump golang.org/x/sync from 0.1.0 to 0.2.0
2023-05-08 19:02:51 +08:00
dependabot[bot]
a33307d746 chore(deps): bump golang.org/x/sync from 0.1.0 to 0.2.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.1.0 to 0.2.0.
- [Commits](https://github.com/golang/sync/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 10:04:38 +00:00
sjlleo
eee741d848 doc: add donate link 2023-05-04 21:08:21 +08:00
sjlleo
98344193e7 doc: add donate link 2023-05-04 21:06:12 +08:00
tsosunchia
7a74bb83c2 Update basic.go
更换北京9929IP
2023-05-02 01:21:47 +08:00
sjlleo
3e010bd9da update readme 2023-04-21 19:22:47 +08:00
tsosunchia
abc1ecd035 Merge pull request #94 from sjlleo/dependabot/go_modules/golang.org/x/net-0.9.0
chore(deps): bump golang.org/x/net from 0.8.0 to 0.9.0
2023-04-10 18:38:33 +08:00
dependabot[bot]
989dc29931 chore(deps): bump golang.org/x/net from 0.8.0 to 0.9.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-10 10:02:16 +00:00
tsosunchia
1f2b4cde1f Merge pull request #91 from sjlleo/dependabot/github_actions/actions/setup-go-4
chore(deps): bump actions/setup-go from 3 to 4
2023-03-20 18:15:33 +08:00
dependabot[bot]
939a4c7aab chore(deps): bump actions/setup-go from 3 to 4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 10:08:31 +00:00
tsosunchia
4890615a2b 增加了关于IPInfo和IPInsight API TOKEN的环境变量 2023-03-14 00:20:42 +08:00
tsosunchia
9b8fd51ef2 Merge pull request #90 from sjlleo/dependabot/go_modules/github.com/fatih/color-1.15.0
chore(deps): bump github.com/fatih/color from 1.14.1 to 1.15.0
2023-03-13 20:46:22 +08:00
dependabot[bot]
73c9d91637 chore(deps): bump github.com/fatih/color from 1.14.1 to 1.15.0
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.14.1 to 1.15.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.14.1...v1.15.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 12:40:57 +00:00
tsosunchia
06e85c11c6 修改GitHub Action 2023-03-13 20:36:55 +08:00
tsosunchia
d151416566 Merge pull request #86 from sjlleo/dependabot/go_modules/golang.org/x/net-0.8.0
chore(deps): bump golang.org/x/net from 0.7.0 to 0.8.0
2023-03-12 04:03:04 +08:00
tsosunchia
b9d9853458 Merge pull request #85 from sjlleo/dependabot/github_actions/actions/setup-go-3
chore(deps): bump actions/setup-go from 2 to 3
2023-03-12 04:00:26 +08:00
dependabot[bot]
3f177c87d2 chore(deps): bump golang.org/x/net from 0.7.0 to 0.8.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 04:52:00 +00:00
dependabot[bot]
d3a00335a1 chore(deps): bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 04:51:41 +00:00
tsosunchia
aa38ed374f Create .github/dependabot.yml 2023-03-06 12:51:25 +08:00
tsosunchia
08f87cc229 Update publishNewFormula.yml 2023-03-03 16:15:31 +08:00
47 changed files with 1352 additions and 438 deletions

View File

@@ -26,15 +26,15 @@ for pl in ${PLATFORMS}; do
echo "build => ${TARGET}"
if [ "${DEBUG_MODE}" == "debug" ]; then
go build -trimpath -gcflags "all=-N -l" -o ${TARGET} \
-ldflags "-X 'github.com/xgadget-lab/nexttrace/printer.version=${BUILD_VERSION}' \
-X 'github.com/xgadget-lab/nexttrace/printer.buildDate=${BUILD_DATE}' \
-X 'github.com/xgadget-lab/nexttrace/printer.commitID=${COMMIT_SHA1}'\
-ldflags "-X 'github.com/xgadget-lab/nexttrace/config.Version=${BUILD_VERSION}' \
-X 'github.com/xgadget-lab/nexttrace/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/xgadget-lab/nexttrace/config.CommitID=${COMMIT_SHA1}'\
-w -s"
else
go build -trimpath -o ${TARGET} \
-ldflags "-X 'github.com/xgadget-lab/nexttrace/printer.version=${BUILD_VERSION}' \
-X 'github.com/xgadget-lab/nexttrace/printer.buildDate=${BUILD_DATE}' \
-X 'github.com/xgadget-lab/nexttrace/printer.commitID=${COMMIT_SHA1}'\
-ldflags "-X 'github.com/xgadget-lab/nexttrace/config.Version=${BUILD_VERSION}' \
-X 'github.com/xgadget-lab/nexttrace/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/xgadget-lab/nexttrace/config.CommitID=${COMMIT_SHA1}'\
-w -s"
fi
done

View File

@@ -38,3 +38,7 @@ copyright: [v2fly](https://github.com/v2fly)
## 请附上出错时软件输出的错误信息
## 是否查询过本仓库wiki有没有类似错误
<!-- wiki: https://github.com/sjlleo/nexttrace/wiki -->

15
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -1,47 +1,148 @@
name: Build & Release
on:
push:
pull_request:
workflow_dispatch:
name: Test & Build Release
push:
branches:
- main
tags:
- "v*"
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
Test:
build:
runs-on: ubuntu-latest
strategy:
matrix:
# Include amd64 on all platforms.
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
goarch: [amd64, 386]
exclude:
# Exclude i386 on darwin and dragonfly.
- goarch: 386
goos: dragonfly
- goarch: 386
goos: darwin
include:
# BEIGIN MacOS ARM64
- goos: darwin
goarch: arm64
# END macOS ARM64
# BEGIN Linux ARM 5 6 7
- goos: linux
goarch: arm
goarm: 7
- goos: linux
goarch: arm
goarm: 6
- goos: linux
goarch: arm
goarm: 5
# END Linux ARM 5 6 7
# BEGIN Android ARM 8
- goos: android
goarch: arm64
# END Android ARM 8
# Windows ARM
- goos: windows
goarch: arm64
- goos: windows
goarch: arm
goarm: 7
# BEGIN Other architectures
# BEGIN riscv64 & ARM64
- goos: linux
goarch: arm64
- goos: linux
goarch: riscv64
# END riscv64 & ARM64
# BEGIN MIPS
- goos: linux
goarch: mips64
- goos: linux
goarch: mips64le
- goos: linux
goarch: mipsle
- goos: linux
goarch: mips
# END MIPS
# BEGIN PPC
- goos: linux
goarch: ppc64
- goos: linux
goarch: ppc64le
# END PPC
# BEGIN FreeBSD ARM
- goos: freebsd
goarch: arm64
- goos: freebsd
goarch: arm
goarm: 7
# END FreeBSD ARM
# BEGIN S390X
- goos: linux
goarch: s390x
# END S390X
# END Other architectures
# BEGIN OPENBSD ARM
- goos: openbsd
goarch: arm64
- goos: openbsd
goarch: arm
goarm: 7
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: 0
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
- name: Checkout codebase
uses: actions/checkout@v3
- name: Show workflow information
run: |
if [ ! -z $GOARM ]; then
export GOARM=v$GOARM
fi
export _NAME="nexttrace_${GOOS}_${GOARCH}${GOARM}"
if [ "$GOOS" == "windows" ]; then
export _NAME="$_NAME.exe"
fi
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, RELEASE_NAME: $_NAME"
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
echo "BUILD_VERSION=$(git describe --tags --always)" >> $GITHUB_ENV
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
echo "COMMIT_SHA1=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.20"
- name: Test
run: sudo go test -v -coverprofile='coverage.out' -covermode=count ./...
Build:
needs: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
with:
go-version: "1.20"
- name: compile
run: bash .cross_compile.sh
go-version: '1.20'
- name: Get project dependencies
run: go mod download
- name: Build
run: |
go build -trimpath -o dist/${ASSET_NAME} \
-ldflags "-X 'github.com/xgadget-lab/nexttrace/config.Version=${BUILD_VERSION}' \
-X 'github.com/xgadget-lab/nexttrace/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/xgadget-lab/nexttrace/config.CommitID=${COMMIT_SHA1}'\
-w -s"
- name: Upload files to Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ env.ASSET_NAME }}
path: |
dist/*
Release:
needs: Build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
dist/${{ env.ASSET_NAME }}
- name: Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v1
with: # 将下述可执行文件 release 上去
draft: false # Release草稿
@@ -51,9 +152,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GT_Token }}
publish-new-formula:
needs: Release
needs: build
# The type of runner that the job will run on
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
# Steps represent a sequence of tasks that will be executed as part of the job
steps:

View File

@@ -21,7 +21,7 @@ jobs:
git config --global user.name "${{ secrets.git_name }}"
- name: Clone repo
run: |
git clone https://github.com/sjlleo/homebrew-nexttrace.git
git clone https://github.com/xgadget-lab/homebrew-nexttrace.git
- name: Exec scipt
run: |
cd homebrew-nexttrace
@@ -38,7 +38,7 @@ jobs:
run: |
cd homebrew-nexttrace
git commit -am 'Publish a new version with Formula' || true
git remote set-url origin https://${{ secrets.gt_token }}@github.com/sjlleo/homebrew-nexttrace.git
git remote set-url origin https://${{ secrets.gt_token }}@github.com/xgadget-lab/homebrew-nexttrace.git
git push
# env:
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock

43
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Test
on:
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
workflow_dispatch:
jobs:
test:
permissions:
contents: read
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
check-latest: true
- name: Checkout codebase
uses: actions/checkout@v3
- name: Test with unix
if: ${{ matrix.os != 'windows-latest' }}
run: sudo go test -v -coverprofile='coverage.out' -covermode=count ./...
- name: Test with windows
if: ${{ matrix.os == 'windows-latest' }}
run: go test -v -coverprofile='coverage.out' -covermode=count ./...

172
README.md
View File

@@ -10,27 +10,85 @@ An open source visual routing tool that pursues light weight, developed using Go
NextTrace is part of the [OwO Network](https://github.com/OwO-Network) project. The project is a joint initiative of Leo and Vincent.
If you like this project, [Donate us](https://afdian.net/a/sjlleo/plan) to help us to provide long-lasting API cost expenses.
## How To Use
Document Language: English | [简体中文](README_zh_CN.md)
### Automated Installation
### Automated Install
```bash
# Linux one-click install script
bash <(curl -Ls https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
* Linux
* One-click installation script
* Download from GitHub
# macOS brew install command
brew tap xgadget-lab/nexttrace && brew install nexttrace
```shell
bash -c "$(curl -Ls https://github.com/sjlleo/nexttrace/raw/main/nt_install.sh)"
```
* GHPROXY mirror (For use in Mainland China)
# GHProxy Mirror (For China Mainland User)
bash -c "$(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)"
```
```shell
bash -c "$(curl -Ls https://ghproxy.com/https://github.com/sjlleo/nexttrace/raw/main/nt_install.sh)"
```
* Arch Linux AUR installation command
* Build from source
Windows users please go to [Release Page](https://github.com/sjlleo/nexttrace/releases/latest) directly and download exe file.
```shell
yay -S nexttrace
```
* Directly download bin package (only supports amd64)
```shell
yay -S nexttrace-bin
```
* The two types of AUR builds are maintained by huyz and ouuan, respectively
* Linuxbrew's installation command
Same as the macOS Homebrew's installation method (homebrew-core version only supports amd64)
* macOS
* macOS Homebrew's installation command
* Homebrew-core version
```shell
brew install nexttrace
```
* This repository's ACTIONS automatically built version (updates faster)
```shell
brew tap xgadget-lab/nexttrace && brew install nexttrace
```
* The homebrew-core build is maintained by chenrui333, please note that this version's updates may lag behind the repository Action automatically version
* Windows
* Windows Scoop installation command
* Scoop-extras version
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
* Scoop-extra is maintained by soenggam
Please note, the repositories for all of the above installation methods are maintained by open source enthusiasts. Availability and timely updates are not guaranteed. If you encounter problems, please contact the repository maintainer to solve them, or use the binary packages provided by the official build of this project.
### Manual Install
* Download the precompiled executable
For users not covered by the above methods, please go directly to [Release](https://github.com/sjlleo/nexttrace/releases/latest) to download the compiled binary executable.
* `Release` provides compiled binary executables for many systems and different architectures. If none are available, you can compile it yourself.
* Some essential dependencies of this project are not fully implemented on `Windows` by `Golang`, so currently, `NextTrace` is in an experimental support phase on the `Windows` platform.
* Install from source
After installing Go >= 1.20 yourself, you can use the following command to install
```shell
go install github.com/xgadget-lab/nexttrace@latest
```
After installation, the executable is in the `$GOPATH/bin` directory. If you have not set `GOPATH`, it is in the `$HOME/go/bin` directory.
- `Release` provides compiled executables for many systems and architectures, if not, you can compile it yourself.
- Some of the necessary dependencies of this project are not fully implemented in `Golang` on `Windows`, so currently `NextTrace` is experimental on `Windows` platform.
### Get Started
@@ -42,9 +100,17 @@ nexttrace 1.0.0.1
# URL
nexttrace http://example.com:8080/index.html?q=1
# Form printing (output all hops at one time, wait 20-40 seconds)
# Form printing
nexttrace --table 1.0.0.1
# An Output Easy to Parse
nexttrace --raw 1.0.0.1
nexttrace --json 1.0.0.1
# IPv4/IPv6 Resolve Only
nexttrace --ipv4 g.co
nexttrace --ipv6 g.co
# IPv6 ICMP Trace
nexttrace 2606:4700:4700::1111
@@ -110,6 +176,9 @@ nexttrace --first 5 --max-hops 10 www.decix.net
# Turn off the IP reverse parsing function
nexttrace --no-rdns www.bbix.net
# Set the payload size to 1024 bytes
nexttrace --psize 1024 example.com
# Feature: print Route-Path diagram
# Route-Path diagram example:
# AS6453 Tata Communication「Singapore『Singapore』」
@@ -163,27 +232,36 @@ NextTrace BackEnd is now open-source.
https://github.com/sjlleo/nexttrace-backend
NextTrace `LeoMoeAPI` now utilizes the Proof of Work (POW) mechanism to prevent abuse, where NextTrace introduces the powclient library as a client-side component. Both the POW CLIENT and SERVER are open source, and everyone is welcome to use them. (Please direct any POW module-related questions to the corresponding repositories)
- [GitHub - tsosunchia/powclient: Proof of Work CLIENT for NextTrace](https://github.com/tsosunchia/powclient)
- [GitHub - tsosunchia/powserver: Proof of Work SERVER for NextTrace](https://github.com/tsosunchia/powserver)
All NextTrace IP geolocation `API DEMO` can refer to [here](https://github.com/xgadget-lab/nexttrace/blob/main/ipgeo/)
### For full usage list, please refer to the usage menu
```shell
Usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port
<integer>] [-q|--queries <integer>] [--parallel-requests
<integer>] [-m|--max-hops <integer>] [-d|--data-provider
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen)]
Usage: nexttrace [-h|--help] [-4|--ipv4] [-6|--ipv6] [-T|--tcp] [-U|--udp]
[-F|--fast-trace] [-p|--port <integer>] [-q|--queries
<integer>] [--parallel-requests <integer>] [-m|--max-hops
<integer>] [-d|--data-provider
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen|LeoMoeAPI|leomoeapi|disable-geoip)]
[-n|--no-rdns] [-a|--always-rdns] [-P|--route-path]
[-r|--report] [--dn42] [-o|--output] [-t|--table]
[-c|--classic] [-f|--first <integer>] [-M|--map]
[-r|--report] [--dn42] [-o|--output] [-t|--table] [--raw]
[-j|--json] [-c|--classic] [-f|--first <integer>] [-M|--map]
[-v|--version] [-s|--source "<value>"] [-D|--dev "<value>"]
[-R|--route] [-z|--send-time <integer>] [-i|--ttl-time
<integer>] [_positionalArg_nexttrace_25 "<value>"]
[--dot-server (dnssb|aliyun|dnspod|google|cloudflare)]
[-g|--language (en|cn)]
<integer>] [--timeout <integer>] [--psize <integer>]
[_positionalArg_nexttrace_31 "<value>"] [--dot-server
(dnssb|aliyun|dnspod|google|cloudflare)] [-g|--language
(en|cn)]
Arguments:
-h --help Print help information
-4 --ipv4 Use IPv4 only
-6 --ipv6 Use IPv6 only
-T --tcp Use TCP SYN for tracerouting (default port
is 80)
-U --udp Use UDP SYN for tracerouting (default port
@@ -206,7 +284,8 @@ Arguments:
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com, Ip2region,
IPInfoLocal, CHUNZHEN]. Default: LeoMoeAPI
IPInfoLocal, CHUNZHEN, disable-geoip].
Default: LeoMoeAPI
-n --no-rdns Do not resolve IP addresses to their
domain names
-a --always-rdns Always resolve IP addresses to their
@@ -218,6 +297,8 @@ Arguments:
-o --output Write trace result to file
(RealTimePrinter ONLY)
-t --table Output trace results as table
--raw An Output Easy to Parse
-j --json Output trace results as JSON
-c --classic Classic Output trace results like
BestTrace
-f --first Start from the first_ttl hop (instead from
@@ -228,14 +309,20 @@ Arguments:
-D --dev Use the following Network Devices as the
source address in outgoing packets
-R --route Show Routing Table [Provided By BGP.Tools]
-z --send-time Set the time interval for sending every
packet. Useful when some routers use
rate-limit for ICMP messages. Default: 100
-i --ttl-time Set the time interval for sending packets
groups by TTL. Useful when some routers
use rate-limit for ICMP messages. Default:
500
--_positionalArg_nexttrace_25 IP Address or domain name
-z --send-time Set how many [milliseconds] between
sending each packet.. Useful when some
routers use rate-limit for ICMP messages.
Default: 100
-i --ttl-time Set how many [milliseconds] between
sending packets groups by TTL. Useful when
some routers use rate-limit for ICMP
messages. Default: 500
--timeout The number of [milliseconds] to keep probe
sockets open before giving up on the
connection.. Default: 1000
--psize Set the packet size (payload size).
Default: 52
--_positionalArg_nexttrace_31 IP Address or domain name
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
@@ -254,7 +341,15 @@ Arguments:
Please Notice that `NextTrace Enhanced` is currently not supported in English.
https://github.com/OwO-Network/nexttrace-enhanced
[https://github.com/OwO-Network/nexttrace-enhanced](https://github.com/OwO-Network/nexttrace-enhanced)
## OpenTrace
`OpenTrace` is the cross-platform `GUI` version of `NextTrace` developed by @Archeb, bringing a familiar but more powerful user experience.
This software is still in the early stages of development and may have many flaws and errors. We value your feedback.
[https://github.com/Archeb/opentrace](https://github.com/Archeb/opentrace)
## LeoMoeAPI Credit
@@ -264,7 +359,7 @@ The LeoMoeAPI data is subject to copyright restrictions from multiple data sourc
1. We would like to credit samleong123 for providing nodes in Malaysia, TOHUNET Looking Glass for global nodes, and Ping.sx from Misaka, where more than 80% of reliable calibration data comes from ping/mtr reports.
2. At the same time, we would like to credit isyekong for their contribution on rDNS-based calibration ideas and data. LeoMoeAPI is accelerating the development of rDNS resolution function, and has already achieved automated geolocation resolution for some backbone networks, but there are some misjudgments. We hope that NextTrace will become a One-Man ISP-friendly traceroute tool in the future, and we are working on improving the calibration of these ASN micro-backbones as much as possible.
2. At the same time, we would like to credit isyekong for their contribution to rDNS-based calibration ideas and data. LeoMoeAPI is accelerating the development of rDNS resolution function, and has already achieved automated geolocation resolution for some backbone networks, but there are some misjudgments. We hope that NextTrace will become a One-Man ISP-friendly traceroute tool in the future, and we are working on improving the calibration of these ASN micro-backbones as much as possible.
3. In terms of development, I would like to credit missuo and zhshch for their help with Go cross-compilation, design concepts and TCP/UDP Traceroute refactoring, and tsosunchia for their support on TraceMap.
@@ -281,7 +376,7 @@ We hope you can give us as much feedback as possible on IP geolocation errors (s
## Credits
BGP.TOOLS provided some data support for this project and we would like to express our sincere gratitude.
[BGP.TOOLS](https://bgp.tools) provided some data support for this project. And we would like to express our sincere gratitude.
[Vincent Young](https://github.com/missuo) (i@yyt.moe)
@@ -291,12 +386,19 @@ BGP.TOOLS provided some data support for this project and we would like to expre
[waiting4new](https://github.com/waiting4new)
[FFEE_CO](https://github.com/fkx4-p)
[FFEE_CO](https://github.com/fkx4-p)
### Others
Although other third-party APIs are integrated in this project, please refer to the official website of the third-party APIs for specific TOS and AUP. If you encounter IP data errors, please contact them directly to correct them.
For feedback related to corrections about IP information, we currently have two channels available:
>- [IP 错误报告汇总帖](https://github.com/sjlleo/nexttrace/issues/41) in the GITHUB ISSUES section of this project (Recommended)
>- This project's dedicated correction email: `correction@moeqing.com` (Please note that this email is only for correcting IP-related information. For other feedback, please submit an ISSUE)
How to obtain the freshly baked binary executable of the latest commit?
> Please go to the most recent [Build & Release](https://github.com/sjlleo/nexttrace/actions/workflows/build.yml) workflow in GitHub Actions.
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=sjlleo/nexttrace&type=Date)](https://star-history.com/#sjlleo/nexttrace&Date)

View File

@@ -23,6 +23,7 @@
</a>
</p>
如果您喜欢这个项目,可以通过[爱发电支持](https://afdian.net/a/sjlleo/plan)我们项目的持续发展,您的捐助将用于服务器和 API 开支,非常感谢!
## How To Use
@@ -32,21 +33,77 @@
### Automated Install
```bash
# Linux 一键安装脚本
bash <(curl -Ls https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
* Linux
* 一键安装脚本
* Github下载
# GHPROXY 镜像(国内使用)
bash <(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
```shell
bash -c "$(curl -Ls https://github.com/sjlleo/nexttrace/raw/main/nt_install.sh)"
```
* GHPROXY镜像中国大陆使用
# macOS brew 安装命令
brew tap xgadget-lab/nexttrace && brew install nexttrace
```
```shell
bash -c "$(curl -Ls https://ghproxy.com/https://github.com/sjlleo/nexttrace/raw/main/nt_install.sh)"
```
* Arch Linux AUR 安装命令
* 由源码构建
Windows 用户请直接前往 [Release](https://github.com/sjlleo/nexttrace/releases/latest) 下载编译后的二进制 exe 文件。
```shell
yay -S nexttrace
```
* 直接下载bin包(仅支持amd64)
```shell
yay -S nexttrace-bin`
```
* AUR 的2种构建分别由 huyz 和 ouuan 维护
* Linuxbrew 安装命令
同macOS Homebrew安装方法(homebrew-core版仅支持amd64)
* macOS
* macOS Homebrew 安装命令
* homebrew-core版
```shell
brew install nexttrace
```
* 本仓库ACTIONS自动构建版(更新更快)
```shell
brew tap xgadget-lab/nexttrace && brew install nexttrace
```
* homebrew-core 构建由 chenrui333 维护请注意该版本更新可能会落后仓库Action自动构建版本
* Windows
* Windows Scoop 安装命令
* scoop-extras版
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
* scoop-extra 由 soenggam 维护
请注意,以上多种安装方式的仓库均由开源爱好者自行维护,不保证可用性和及时更新,如遇到问题请联系仓库维护者解决,或使用本项目官方编译提供的二进制包。
### Manual Install
* 下载预编译的可执行程序
对于以上方法没有涵盖的用户,请直接前往 [Release](https://github.com/sjlleo/nexttrace/releases/latest) 下载编译后的二进制可执行文件。
* `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
* 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台出于实验性支持阶段。
* 从源码安装
您可在自行安装Go >= 1.20后,使用以下命令安装
```shell
go install github.com/xgadget-lab/nexttrace@latest
```
安装后可执行文件在`$GOPATH/bin`目录下,如果您没有设置`GOPATH`,则在`$HOME/go/bin`目录下。
- `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
- 一些本项目的必要依赖在`Windows``Golang`底层实现不完全,所以目前`NextTrace``Windows`平台出于实验性支持阶段。
### Get Started
@@ -61,6 +118,14 @@ nexttrace http://example.com:8080/index.html?q=1
# 表格打印,使用 --table / -t 参数,将实时显示结果
nexttrace --table 1.0.0.1
# 一个方便供机器读取转化的模式
nexttrace --raw 1.0.0.1
nexttrace --json 1.0.0.1
# 只进行IPv4/IPv6解析
nexttrace --ipv4 g.co
nexttrace --ipv6 g.co
# IPv6 ICMP Trace
nexttrace 2606:4700:4700::1111
@@ -129,6 +194,9 @@ nexttrace --first 5 --max-hops 10 www.decix.net
# 关闭IP反向解析功能
nexttrace --no-rdns www.bbix.net
# 设置载荷大小为1024字节
nexttrace --psize 1024 example.com
# 特色功能打印Route-Path图
# Route-Path图示例
# AS6453 塔塔通信「Singapore『Singapore』」
@@ -176,22 +244,26 @@ nexttrace -T -q 2 --parallel-requests 1 -t -R 2001:4860:4860::8888
### 全部用法详见 Usage 菜单
```shell
Usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port
<integer>] [-q|--queries <integer>] [--parallel-requests
<integer>] [-m|--max-hops <integer>] [-d|--data-provider
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen)]
Usage: nexttrace [-h|--help] [-4|--ipv4] [-6|--ipv6] [-T|--tcp] [-U|--udp]
[-F|--fast-trace] [-p|--port <integer>] [-q|--queries
<integer>] [--parallel-requests <integer>] [-m|--max-hops
<integer>] [-d|--data-provider
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen|LeoMoeAPI|leomoeapi|disable-geoip)]
[-n|--no-rdns] [-a|--always-rdns] [-P|--route-path]
[-r|--report] [--dn42] [-o|--output] [-t|--table]
[-c|--classic] [-f|--first <integer>] [-M|--map]
[-r|--report] [--dn42] [-o|--output] [-t|--table] [--raw]
[-j|--json] [-c|--classic] [-f|--first <integer>] [-M|--map]
[-v|--version] [-s|--source "<value>"] [-D|--dev "<value>"]
[-R|--route] [-z|--send-time <integer>] [-i|--ttl-time
<integer>] [_positionalArg_nexttrace_25 "<value>"]
[--dot-server (dnssb|aliyun|dnspod|google|cloudflare)]
[-g|--language (en|cn)]
<integer>] [--timeout <integer>] [--psize <integer>]
[_positionalArg_nexttrace_31 "<value>"] [--dot-server
(dnssb|aliyun|dnspod|google|cloudflare)] [-g|--language
(en|cn)]
Arguments:
-h --help Print help information
-4 --ipv4 Use IPv4 only
-6 --ipv6 Use IPv6 only
-T --tcp Use TCP SYN for tracerouting (default port
is 80)
-U --udp Use UDP SYN for tracerouting (default port
@@ -214,7 +286,8 @@ Arguments:
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com, Ip2region,
IPInfoLocal, CHUNZHEN]. Default: LeoMoeAPI
IPInfoLocal, CHUNZHEN, disable-geoip].
Default: LeoMoeAPI
-n --no-rdns Do not resolve IP addresses to their
domain names
-a --always-rdns Always resolve IP addresses to their
@@ -226,6 +299,8 @@ Arguments:
-o --output Write trace result to file
(RealTimePrinter ONLY)
-t --table Output trace results as table
--raw An Output Easy to Parse
-j --json Output trace results as JSON
-c --classic Classic Output trace results like
BestTrace
-f --first Start from the first_ttl hop (instead from
@@ -236,14 +311,20 @@ Arguments:
-D --dev Use the following Network Devices as the
source address in outgoing packets
-R --route Show Routing Table [Provided By BGP.Tools]
-z --send-time Set the time interval for sending every
packet. Useful when some routers use
rate-limit for ICMP messages. Default: 100
-i --ttl-time Set the time interval for sending packets
groups by TTL. Useful when some routers
use rate-limit for ICMP messages. Default:
500
--_positionalArg_nexttrace_25 IP Address or domain name
-z --send-time Set how many [milliseconds] between
sending each packet.. Useful when some
routers use rate-limit for ICMP messages.
Default: 100
-i --ttl-time Set how many [milliseconds] between
sending packets groups by TTL. Useful when
some routers use rate-limit for ICMP
messages. Default: 500
--timeout The number of [milliseconds] to keep probe
sockets open before giving up on the
connection.. Default: 1000
--psize Set the packet size (payload size).
Default: 52
--_positionalArg_nexttrace_31 IP Address or domain name
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
@@ -266,13 +347,27 @@ NextTrace 所有的的 IP 地理位置 `API DEMO` 可以参考[这里](https://g
[GitHub - sjlleo/nexttrace-backend: NextTrace BackEnd](https://github.com/sjlleo/nexttrace-backend)
NextTrace `LeoMoeAPI`现已使用Proof of Work(POW)机制来防止滥用其中NextTrace作为客户端引入了powclient库POW CLIENT/SERVER均已开源欢迎大家使用。(POW模块相关问题请发到对应的仓库)
- [GitHub - tsosunchia/powclient: Proof of Work CLIENT for NextTrace](https://github.com/tsosunchia/powclient)
- [GitHub - tsosunchia/powserver: Proof of Work SERVER for NextTrace](https://github.com/tsosunchia/powserver)
```go
## NextTrace Enhanced
https://github.com/OwO-Network/nexttrace-enhanced
[https://github.com/OwO-Network/nexttrace-enhanced](https://github.com/OwO-Network/nexttrace-enhanced)
## OpenTrace
`OpenTrace`是 @Archeb 开发的`NextTrace`的跨平台`GUI`版本,带来您熟悉但更强大的用户体验。
该软件仍然处于早期开发阶段,可能存在许多缺陷和错误,需要您宝贵的使用反馈。
[https://github.com/Archeb/opentrace](https://github.com/Archeb/opentrace)
## Credits
BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢。
[BGP.TOOLS](https://bgp.tools) 提供了本项目的一些数据支持,在此表示由衷地感谢。
[Vincent Young](https://github.com/missuo) (i@yyt.moe)
@@ -288,10 +383,21 @@ BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢
其他第三方 API 尽管集成在本项目内,但是具体的 TOS 以及 AUP请详见第三方 API 官网。如遇到 IP 数据错误,也请直接联系他们纠错。
如何获取最新commit的新鲜出炉的二进制可执行文件
>请前往GitHub Actions中最新一次 [Build & Release](https://github.com/sjlleo/nexttrace/actions/workflows/build.yml) workflow.
## IP 数据以及精准度说明
对于IP相关信息的纠错反馈我们目前开放了两个渠道
>- 本项目的GITHUB ISSUES区中的[IP 错误报告汇总帖](https://github.com/sjlleo/nexttrace/issues/41)
>- 本项目的纠错专用邮箱: `correction@moeqing.com` 请注意此邮箱仅供IP相关信息纠错专用其他反馈请发送ISSUE
NextTrace 有多个数据源可以选择,目前默认使用的 LeoMoeAPI 为我们项目维护的数据源。
该项目由 OwO Network 的 [Missuo](https://github.com/missuo) && [Leo](https://github.com/sjlleo) 发起,由 [Zhshch](https://github.com/zhshch2002/) 完成最早期架构的编写和指导,后由 Leo 完成了大部分开发工作,现主要交由 [tsosunchia](https://github.com/tsosunchia) 以及 MoeQing Network 完成后续的二开和维护工作。
LeoMoeAPI 是 [Leo](https://github.com/sjlleo) 的作品,归属于 Leo Network由 [Leo](https://github.com/sjlleo) 完成整套后端 API 编写,该接口未经允许不可用于任何第三方用途。
LeoMoeAPI 早期数据主要来自 IPInsight、IPInfo随着项目发展越来越多的志愿者参与进了这个项目。目前 LeoMoeAPI 有近一半的数据是社区提供的,而另外一半主要来自于包含 IPInfo、IPData、BigDataCloud、IPGeoLocation 在内的多个第三方数据。
LeoMoeAPI 的骨干网数据有近 70% 是社区自发反馈又或者是项目组成员校准的,这给本项目的路由跟踪基础功能带来了一定的保证,但是全球骨干网的体量庞大,我们并无能力如 IPIP 等商业公司拥有海量监测节点,这使得 LeoMoeAPI 的数据精准度无法和形如 BestTraceIPIP相提并论。

View File

@@ -9,6 +9,7 @@ import (
"os/signal"
"runtime"
"strings"
"sync"
"time"
"github.com/akamensky/argparse"
@@ -28,6 +29,8 @@ import (
func Excute() {
parser := argparse.NewParser("nexttrace", "An open source visual route tracking CLI tool")
// Create string flag
ipv4Only := parser.Flag("4", "ipv4", &argparse.Options{Help: "Use IPv4 only"})
ipv6Only := parser.Flag("6", "ipv6", &argparse.Options{Help: "Use IPv6 only"})
tcp := parser.Flag("T", "tcp", &argparse.Options{Help: "Use TCP SYN for tracerouting (default port is 80)"})
udp := parser.Flag("U", "udp", &argparse.Options{Help: "Use UDP SYN for tracerouting (default port is 53)"})
fast_trace := parser.Flag("F", "fast-trace", &argparse.Options{Help: "One-Key Fast Trace to China ISPs"})
@@ -37,8 +40,8 @@ func Excute() {
numMeasurements := parser.Int("q", "queries", &argparse.Options{Default: 3, Help: "Set the number of probes per each hop"})
parallelRequests := parser.Int("", "parallel-requests", &argparse.Options{Default: 18, Help: "Set ParallelRequests number. It should be 1 when there is a multi-routing"})
maxHops := parser.Int("m", "max-hops", &argparse.Options{Default: 30, Help: "Set the max number of hops (max TTL to be reached)"})
dataOrigin := parser.Selector("d", "data-provider", []string{"Ip2region", "ip2region", "IP.SB", "ip.sb", "IPInfo", "ipinfo", "IPInsight", "ipinsight", "IPAPI.com", "ip-api.com", "IPInfoLocal", "ipinfolocal", "chunzhen"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, IPInfoLocal, CHUNZHEN]"})
dataOrigin := parser.Selector("d", "data-provider", []string{"Ip2region", "ip2region", "IP.SB", "ip.sb", "IPInfo", "ipinfo", "IPInsight", "ipinsight", "IPAPI.com", "ip-api.com", "IPInfoLocal", "ipinfolocal", "chunzhen", "LeoMoeAPI", "leomoeapi", "disable-geoip"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, IPInfoLocal, CHUNZHEN, disable-geoip]"})
noRdns := parser.Flag("n", "no-rdns", &argparse.Options{Help: "Do not resolve IP addresses to their domain names"})
alwaysRdns := parser.Flag("a", "always-rdns", &argparse.Options{Help: "Always resolve IP addresses to their domain names"})
routePath := parser.Flag("P", "route-path", &argparse.Options{Help: "Print traceroute hop path by ASN and location"})
@@ -46,15 +49,19 @@ func Excute() {
dn42 := parser.Flag("", "dn42", &argparse.Options{Help: "DN42 Mode"})
output := parser.Flag("o", "output", &argparse.Options{Help: "Write trace result to file (RealTimePrinter ONLY)"})
tablePrint := parser.Flag("t", "table", &argparse.Options{Help: "Output trace results as table"})
rawPrint := parser.Flag("", "raw", &argparse.Options{Help: "An Output Easy to Parse"})
jsonPrint := parser.Flag("j", "json", &argparse.Options{Help: "Output trace results as JSON"})
classicPrint := parser.Flag("c", "classic", &argparse.Options{Help: "Classic Output trace results like BestTrace"})
beginHop := parser.Int("f", "first", &argparse.Options{Default: 1, Help: "Start from the first_ttl hop (instead from 1)"})
maptrace := parser.Flag("M", "map", &argparse.Options{Help: "Disable Print Trace Map"})
disableMaptrace := parser.Flag("M", "map", &argparse.Options{Help: "Disable Print Trace Map"})
ver := parser.Flag("v", "version", &argparse.Options{Help: "Print version info and exit"})
src_addr := parser.String("s", "source", &argparse.Options{Help: "Use source src_addr for outgoing packets"})
src_dev := parser.String("D", "dev", &argparse.Options{Help: "Use the following Network Devices as the source address in outgoing packets"})
srcAddr := parser.String("s", "source", &argparse.Options{Help: "Use source src_addr for outgoing packets"})
srcDev := parser.String("D", "dev", &argparse.Options{Help: "Use the following Network Devices as the source address in outgoing packets"})
router := parser.Flag("R", "route", &argparse.Options{Help: "Show Routing Table [Provided By BGP.Tools]"})
packet_interval := parser.Int("z", "send-time", &argparse.Options{Default: 100, Help: "Set the time interval for sending every packet. Useful when some routers use rate-limit for ICMP messages"})
ttl_interval := parser.Int("i", "ttl-time", &argparse.Options{Default: 500, Help: "Set the time interval for sending packets groups by TTL. Useful when some routers use rate-limit for ICMP messages"})
packetInterval := parser.Int("z", "send-time", &argparse.Options{Default: 100, Help: "Set how many [milliseconds] between sending each packet.. Useful when some routers use rate-limit for ICMP messages"})
ttlInterval := parser.Int("i", "ttl-time", &argparse.Options{Default: 500, Help: "Set how many [milliseconds] between sending packets groups by TTL. Useful when some routers use rate-limit for ICMP messages"})
timeout := parser.Int("", "timeout", &argparse.Options{Default: 1000, Help: "The number of [milliseconds] to keep probe sockets open before giving up on the connection."})
packetSize := parser.Int("", "psize", &argparse.Options{Default: 52, Help: "Set the packet size (payload size)"})
str := parser.StringPositional(&argparse.Options{Help: "IP Address or domain name"})
dot := parser.Selector("", "dot-server", []string{"dnssb", "aliyun", "dnspod", "google", "cloudflare"}, &argparse.Options{
Help: "Use DoT Server for DNS Parse [dnssb, aliyun, dnspod, google, cloudflare]"})
@@ -68,7 +75,9 @@ func Excute() {
fmt.Print(parser.Usage(err))
return
}
printer.Version()
if !*jsonPrint {
printer.Version()
}
if *ver {
printer.CopyRight()
os.Exit(0)
@@ -81,7 +90,18 @@ func Excute() {
}
if *fast_trace {
fastTrace.FastTest(*tcp, *output)
var paramsFastTrace = fastTrace.ParamsFastTrace{
SrcDev: *srcDev,
SrcAddr: *srcAddr,
BeginHop: *beginHop,
MaxHops: *maxHops,
RDns: !*noRdns,
AlwaysWaitRDNS: *alwaysRdns,
Lang: *lang,
PktSize: *packetSize,
}
fastTrace.FastTest(*tcp, *output, paramsFastTrace)
if *output {
fmt.Println("您的追踪日志已经存放在 /tmp/trace.log 中")
}
@@ -89,6 +109,7 @@ func Excute() {
os.Exit(0)
}
// DOMAIN处理开始
if domain == "" {
fmt.Print(parser.Usage(err))
return
@@ -105,6 +126,7 @@ func Excute() {
domain = strings.Split(domain, ":")[0]
}
}
// DOMAIN处理结束
capabilities_check()
// return
@@ -115,47 +137,70 @@ func Excute() {
fmt.Println("NextTrace 基于 Windows 的路由跟踪还在早期开发阶段目前还存在诸多问题TCP/UDP SYN 包请求可能不能正常运行")
}
if *udp {
ip = util.DomainLookUp(domain, true, *dot)
} else {
ip = util.DomainLookUp(domain, false, *dot)
if *dn42 {
// 初始化配置
config.InitConfig()
*dataOrigin = "DN42"
*disableMaptrace = true
}
if *src_dev != "" {
dev, _ := net.InterfaceByName(*src_dev)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
if strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
val, ok := os.LookupEnv("NEXTTRACE_DATAPROVIDER")
if ok {
*dataOrigin = val
} else {
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
}
}
}()
go func() {
defer wg.Done()
if *udp {
if *ipv6Only {
fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
os.Exit(0)
}
ip = util.DomainLookUp(domain, "4", *dot, *jsonPrint)
} else {
if *ipv6Only {
ip = util.DomainLookUp(domain, "6", *dot, *jsonPrint)
} else if *ipv4Only {
ip = util.DomainLookUp(domain, "4", *dot, *jsonPrint)
} else {
ip = util.DomainLookUp(domain, "all", *dot, *jsonPrint)
}
}
}()
wg.Wait()
if *srcDev != "" {
dev, _ := net.InterfaceByName(*srcDev)
if addrs, err := dev.Addrs(); err == nil {
for _, addr := range addrs {
if (addr.(*net.IPNet).IP.To4() == nil) == (ip.To4() == nil) {
*src_addr = addr.(*net.IPNet).IP.String()
*srcAddr = addr.(*net.IPNet).IP.String()
}
}
}
}
if *dn42 {
// 初始化配置
config.InitConfig()
*dataOrigin = "DN42"
*maptrace = true
if !*jsonPrint {
printer.PrintTraceRouteNav(ip, domain, *dataOrigin, *maxHops)
}
if strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
val, ok := os.LookupEnv("NEXTTRACE_DATAPROVIDER")
if ok {
*dataOrigin = val
} else {
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
}
}
printer.PrintTraceRouteNav(ip, domain, *dataOrigin)
var m trace.Method = ""
switch {
@@ -173,25 +218,28 @@ func Excute() {
var conf = trace.Config{
DN42: *dn42,
SrcAddr: *src_addr,
SrcAddr: *srcAddr,
BeginHop: *beginHop,
DestIP: ip,
DestPort: *port,
MaxHops: *maxHops,
PacketInterval: *packet_interval,
TTLInterval: *ttl_interval,
PacketInterval: *packetInterval,
TTLInterval: *ttlInterval,
NumMeasurements: *numMeasurements,
ParallelRequests: *parallelRequests,
Lang: *lang,
RDns: !*noRdns,
AlwaysWaitRDNS: *alwaysRdns,
IPGeoSource: ipgeo.GetSource(*dataOrigin),
Timeout: 1 * time.Second,
Timeout: time.Duration(*timeout) * time.Millisecond,
PktSize: *packetSize,
}
if !*tablePrint {
if *classicPrint {
conf.RealtimePrinter = printer.ClassicPrinter
} else if *rawPrint {
conf.RealtimePrinter = printer.EasyPrinter
} else {
if *output {
conf.RealtimePrinter = tracelog.RealtimePrinter
@@ -208,6 +256,20 @@ func Excute() {
}
}
if *jsonPrint {
conf.RealtimePrinter = nil
conf.AsyncPrinter = nil
}
if util.Uninterrupted != "" && *rawPrint {
for {
_, err := trace.Traceroute(m, conf)
if err != nil {
fmt.Println(err)
}
}
}
res, err := trace.Traceroute(m, conf)
if err != nil {
@@ -223,9 +285,28 @@ func Excute() {
r.Print()
}
if !*maptrace {
r, _ := json.Marshal(res)
tracemap.GetMapUrl(string(r))
r, err := json.Marshal(res)
if err != nil {
fmt.Println(err)
return
}
if !*disableMaptrace && strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
url, err := tracemap.GetMapUrl(string(r))
if err != nil {
log.Fatalln(err)
}
res.TraceMapUrl = url
if !*jsonPrint {
tracemap.PrintMapUrl(url)
}
}
r, err = json.Marshal(res)
if err != nil {
fmt.Println(err)
return
}
if *jsonPrint {
fmt.Println(string(r))
}
}

5
config/basic.go Normal file
View File

@@ -0,0 +1,5 @@
package config
var Version = "v0.0.0.alpha"
var BuildDate = ""
var CommitID = ""

View File

@@ -49,36 +49,36 @@ var Beijing = BackBoneCollection{
Location: "北京",
CT163: ISPCollection{
ISPName: CT163,
IP: "106.37.67.1",
IPv6: "240e:40:e002:1:a:3ee3:c00:0",
IP: "ipv4.pek-4134.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.pek-4134.nexttrace-io-fasttrace-endpoint.win.",
},
CU169: ISPCollection{
ISPName: CU169,
IP: "123.125.96.156",
IPv6: "2408:8000:1010:2::10",
IP: "ipv4.pek-4837.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.pek-4837.nexttrace-io-fasttrace-endpoint.win.",
},
CU9929: ISPCollection{
ISPName: CU9929,
IP: "218.105.131.125",
IP: "ipv4.pek-9929.nexttrace-io-fasttrace-endpoint.win.",
},
CM: ISPCollection{
ISPName: CM,
IP: "211.136.25.153",
IPv6: "2409:8000:3800:8::3",
IP: "ipv4.pek-9808.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.pek-9808.nexttrace-io-fasttrace-endpoint.win.",
},
CMIN2: ISPCollection{
ISPName: CMIN2,
IP: "223.70.155.55",
IP: "ipv4.pek-58807.nexttrace-io-fasttrace-endpoint.win.",
},
EDU: ISPCollection{
ISPName: EDU,
IP: "101.6.15.130",
IPv6: "2001:da8::666",
IP: "ipv4.pek-4538.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.pek-4538.nexttrace-io-fasttrace-endpoint.win.",
},
}
@@ -86,42 +86,42 @@ var Shanghai = BackBoneCollection{
Location: "上海",
CT163: ISPCollection{
ISPName: CT163,
IP: "202.101.21.178",
IPv6: "240e:18:2:153::89",
IP: "ipv4.sha-4134.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.sha-4134.nexttrace-io-fasttrace-endpoint.win.",
},
CTCN2: ISPCollection{
ISPName: CTCN2,
IP: "58.32.4.1",
IP: "ipv4.sha-4809.nexttrace-io-fasttrace-endpoint.win.",
},
CU169: ISPCollection{
ISPName: CU169,
IP: "139.226.206.150",
IPv6: "2408:8000:9000:0:4000::437",
IP: "ipv4.sha-4837.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.sha-4837.nexttrace-io-fasttrace-endpoint.win.",
},
CU9929: ISPCollection{
ISPName: CU9929,
IP: "210.13.86.1",
IPv6: "2408:8120:2::d6",
IP: "ipv4.sha-9929.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.sha-9929.nexttrace-io-fasttrace-endpoint.win.",
},
CM: ISPCollection{
ISPName: CM,
IP: "120.204.34.85",
IPv6: "2409:801e:f0:1::4e1",
IP: "ipv4.sha-9808.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.sha-9808.nexttrace-io-fasttrace-endpoint.win.",
},
CMIN2: ISPCollection{
ISPName: CMIN2,
IP: "183.194.134.1",
IP: "ipv4.sha-58807.nexttrace-io-fasttrace-endpoint.win.",
},
EDU: ISPCollection{
ISPName: EDU,
IP: "202.120.58.155",
IPv6: "2001:da8:8000:1:202:120:2:100",
IP: "ipv4.sha-4538.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.sha-4538.nexttrace-io-fasttrace-endpoint.win.",
},
}
@@ -129,20 +129,20 @@ var Guangzhou = BackBoneCollection{
Location: "广州",
CT163: ISPCollection{
ISPName: CT163,
IP: "14.116.225.60",
IPv6: "240e:f9:8010::3:110:1",
IP: "ipv4.can-4134.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.can-4134.nexttrace-io-fasttrace-endpoint.win.",
},
CU169: ISPCollection{
ISPName: CU169,
IP: "157.18.0.22",
IPv6: "2408:8001:3161:4::1",
IP: "ipv4.can-4837.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.can-4837.nexttrace-io-fasttrace-endpoint.win.",
},
CM: ISPCollection{
ISPName: CM,
IP: "120.198.26.254",
IPv6: "2409:8055:3008:1116::150",
IP: "ipv4.can-9808.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.can-9808.nexttrace-io-fasttrace-endpoint.win.",
},
}
@@ -150,24 +150,23 @@ var Hangzhou = BackBoneCollection{
Location: "杭州",
CT163: ISPCollection{
ISPName: CT163,
IP: "61.164.23.196",
IPv6: "240e:f3:c000:201::10",
IP: "ipv4.hgh-4134.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.hgh-4134.nexttrace-io-fasttrace-endpoint.win.",
},
CU169: ISPCollection{
ISPName: CU169,
IP: "60.12.244.1",
IPv6: "",
IP: "ipv4.hgh-4837.nexttrace-io-fasttrace-endpoint.win.",
},
CM: ISPCollection{
ISPName: CM,
IP: "112.17.224.98",
IPv6: "2409:8028:840:2::11",
IP: "ipv4.hgh-9808.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.hgh-9808.nexttrace-io-fasttrace-endpoint.win.",
},
// 浙江大学 教育网
EDU: ISPCollection{
ISPName: EDU,
IP: "210.32.2.1",
IPv6: "2001:da8:e000:1::1",
IP: "ipv4.hgh-4538.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.hgh-4538.nexttrace-io-fasttrace-endpoint.win.",
},
}
@@ -176,12 +175,12 @@ var Hefei = BackBoneCollection{
// 中国科学技术大学 教育网
EDU: ISPCollection{
ISPName: EDU,
IP: "202.38.64.1",
IPv6: "2001:da8:d805:ffff:2::1",
IP: "ipv4.hef-4538.nexttrace-io-fasttrace-endpoint.win.",
IPv6: "ipv6.hef-4538.nexttrace-io-fasttrace-endpoint.win.",
},
// 中国科学技术大学 科技网
CST: ISPCollection{
ISPName: "中国科学技术大学 科技网 AS7497",
IP: "210.72.22.2",
IP: "ipv4.hef-7497.nexttrace-io-fasttrace-endpoint.win.",
},
}

View File

@@ -2,8 +2,8 @@ package fastTrace
import (
"fmt"
"github.com/xgadget-lab/nexttrace/util"
"log"
"net"
"os"
"os/signal"
"time"
@@ -33,7 +33,7 @@ func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollection) {
log.Printf("『%s %s 』\n", location, ispCollection.ISPName)
fmt.Printf("traceroute to %s, 30 hops max, 32 byte packets\n", ispCollection.IPv6)
log.Printf("traceroute to %s, 30 hops max, 32 byte packets\n", ispCollection.IPv6)
ip := net.ParseIP(ispCollection.IPv6)
ip := util.DomainLookUp(ispCollection.IP, "6", "", true)
var conf = trace.Config{
BeginHop: 1,
DestIP: ip,

View File

@@ -2,6 +2,7 @@ package fastTrace
import (
"fmt"
"github.com/xgadget-lab/nexttrace/util"
"log"
"net"
"os"
@@ -17,6 +18,18 @@ import (
type FastTracer struct {
TracerouteMethod trace.Method
ParamsFastTrace ParamsFastTrace
}
type ParamsFastTrace struct {
SrcDev string
SrcAddr string
BeginHop int
MaxHops int
RDns bool
AlwaysWaitRDNS bool
Lang string
PktSize int
}
var oe = false
@@ -39,19 +52,23 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
log.Printf("『%s %s 』\n", location, ispCollection.ISPName)
fmt.Printf("traceroute to %s, 30 hops max, 32 byte packets\n", ispCollection.IP)
log.Printf("traceroute to %s, 30 hops max, 32 byte packets\n", ispCollection.IP)
ip := net.ParseIP(ispCollection.IP)
ip := util.DomainLookUp(ispCollection.IP, "4", "", true)
var conf = trace.Config{
BeginHop: 1,
BeginHop: f.ParamsFastTrace.BeginHop,
DestIP: ip,
DestPort: 80,
MaxHops: 30,
MaxHops: f.ParamsFastTrace.MaxHops,
NumMeasurements: 3,
ParallelRequests: 18,
RDns: true,
RDns: f.ParamsFastTrace.RDns,
AlwaysWaitRDNS: f.ParamsFastTrace.AlwaysWaitRDNS,
PacketInterval: 100,
TTLInterval: 500,
IPGeoSource: ipgeo.GetSource("LeoMoeAPI"),
Timeout: 1 * time.Second,
SrcAddr: f.ParamsFastTrace.SrcAddr,
PktSize: f.ParamsFastTrace.PktSize,
Lang: f.ParamsFastTrace.Lang,
}
if oe {
@@ -68,6 +85,75 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
println()
}
func FastTest(tm bool, outEnable bool, paramsFastTrace ParamsFastTrace) {
var c string
pFastTrace := paramsFastTrace
oe = outEnable
fmt.Println("Hi欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂我们设置的测试目标有限建议普通用户自测以获得更加精准的路由情况")
fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6")
fmt.Print("请选择选项:")
_, err := fmt.Scanln(&c)
if err != nil {
c = "1"
}
if c == "2" {
FastTestv6(tm, outEnable)
return
}
if pFastTrace.SrcDev != "" {
dev, _ := net.InterfaceByName(pFastTrace.SrcDev)
if addrs, err := dev.Addrs(); err == nil {
for _, addr := range addrs {
if addr.(*net.IPNet).IP.To4() != nil {
pFastTrace.SrcAddr = addr.(*net.IPNet).IP.String()
}
}
}
}
fmt.Println("您想测试哪些ISP的路由\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网")
fmt.Print("请选择选项:")
_, err = fmt.Scanln(&c)
if err != nil {
c = "1"
}
ft := FastTracer{
ParamsFastTrace: pFastTrace,
}
// 建立 WebSocket 连接
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
if !tm {
ft.TracerouteMethod = trace.ICMPTrace
fmt.Println("您将默认使用ICMP协议进行路由跟踪如果您想使用TCP SYN进行路由跟踪可以加入 -T 参数")
} else {
ft.TracerouteMethod = trace.TCPTrace
}
switch c {
case "1":
ft.testAll()
case "2":
ft.testCT()
case "3":
ft.testCU()
case "4":
ft.testCM()
case "5":
ft.testEDU()
default:
ft.testAll()
}
}
func (f *FastTracer) testAll() {
f.testCT()
println()
@@ -111,59 +197,3 @@ func (f *FastTracer) testEDU() {
// 科技网暂时算在EDU里面等拿到了足够多的数据再分离出去单独用于测试
f.tracert(TestIPsCollection.Hefei.Location, TestIPsCollection.Hefei.CST)
}
func FastTest(tm bool, outEnable bool) {
var c string
oe = outEnable
fmt.Println("Hi欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂我们设置的测试目标有限建议普通用户自测以获得更加精准的路由情况")
fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6")
fmt.Print("请选择选项:")
_, err := fmt.Scanln(&c)
if err != nil {
c = "1"
}
if c == "2" {
FastTestv6(tm, outEnable)
return
}
fmt.Println("您想测试哪些ISP的路由\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网")
fmt.Print("请选择选项:")
_, err = fmt.Scanln(&c)
if err != nil {
c = "1"
}
ft := FastTracer{}
// 建立 WebSocket 连接
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
if !tm {
ft.TracerouteMethod = trace.ICMPTrace
fmt.Println("您将默认使用ICMP协议进行路由跟踪如果您想使用TCP SYN进行路由跟踪可以加入 -T 参数")
} else {
ft.TracerouteMethod = trace.TCPTrace
}
switch c {
case "1":
ft.testAll()
case "2":
ft.testCT()
case "3":
ft.testCU()
case "4":
ft.testCM()
case "5":
ft.testEDU()
default:
ft.testAll()
}
}

View File

@@ -1,6 +1,7 @@
package fastTrace
import (
"fmt"
"os"
"os/signal"
"testing"
@@ -9,9 +10,18 @@ import (
"github.com/xgadget-lab/nexttrace/wshandle"
)
// ICMP Use Too Many Time to Wait So we don't test it.
func TestTCPTrace(t *testing.T) {
ft := FastTracer{}
func TestTrace(t *testing.T) {
pFastTrace := ParamsFastTrace{
SrcDev: "",
SrcAddr: "",
BeginHop: 1,
MaxHops: 30,
RDns: false,
AlwaysWaitRDNS: false,
Lang: "",
PktSize: 52,
}
ft := FastTracer{ParamsFastTrace: pFastTrace}
// 建立 WebSocket 连接
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
@@ -19,6 +29,14 @@ func TestTCPTrace(t *testing.T) {
defer func() {
w.Conn.Close()
}()
fmt.Println("TCP v4")
ft.TracerouteMethod = trace.TCPTrace
ft.testEDU()
ft.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
//fmt.Println("TCP v6")
//ft.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
//fmt.Println("ICMP v4")
//ft.TracerouteMethod = trace.ICMPTrace
//ft.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
//fmt.Println("ICMP v6")
//ft.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
}

24
go.mod
View File

@@ -6,37 +6,41 @@ require (
github.com/akamensky/argparse v1.4.0
github.com/google/gopacket v1.1.19
github.com/oschwald/maxminddb-golang v1.10.0
github.com/spf13/viper v1.15.0
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
golang.org/x/net v0.7.0
golang.org/x/sync v0.1.0
github.com/tsosunchia/powclient v0.1.1
golang.org/x/net v0.10.0
golang.org/x/sync v0.2.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
require (
github.com/fatih/color v1.14.1
github.com/fatih/color v1.15.0
github.com/gorilla/websocket v1.5.0
github.com/lionsoul2014/ip2region v2.11.1+incompatible
github.com/rodaine/table v1.1.0
github.com/tidwall/gjson v1.14.4
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/sys v0.8.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

60
go.sum
View File

@@ -57,9 +57,9 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@@ -136,7 +136,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -147,16 +147,16 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -165,17 +165,17 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/rodaine/table v1.1.0 h1:/fUlCSdjamMY8VifdQRIu3VWZXYLY7QHFkVorS8NTr4=
github.com/rodaine/table v1.1.0/go.mod h1:Qu3q5wi1jTQD6B6HsP6szie/S4w1QUQ8pq22pz9iL8g=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -186,8 +186,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
@@ -199,6 +200,8 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tsosunchia/powclient v0.1.1 h1:Llv7vFNXTvpxrd2JjnAkpGz95gjVu6A2891RQCML3Rc=
github.com/tsosunchia/powclient v0.1.1/go.mod h1:Pm4MP3QqN74SfNskPpFIEyT+NQrcABGoXkkeRwjlMEE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -215,7 +218,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -280,8 +283,9 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -301,8 +305,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -335,12 +339,14 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -348,8 +354,10 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -10,11 +10,11 @@ import (
"time"
)
func Chunzhen(ip string) (*IPGeoData, error) {
func Chunzhen(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoData, error) {
url := util.GetenvDefault("NEXTTRACE_CHUNZHENURL", "http://127.0.0.1:2060") + "?ip=" + ip
client := &http.Client{
// 2 秒超时
Timeout: 2 * time.Second,
Timeout: timeout,
}
req, _ := http.NewRequest("GET", url, nil)
content, err := client.Do(req)

View File

@@ -2,6 +2,7 @@ package ipgeo
import (
"strings"
"time"
"github.com/xgadget-lab/nexttrace/dn42"
)
@@ -18,7 +19,7 @@ func LtdCodeToCountryOrAreaName(Code string) string {
return Code
}
func DN42(ip string) (*IPGeoData, error) {
func DN42(ip string, _ time.Duration, _ string, _ bool) (*IPGeoData, error) {
data := &IPGeoData{}
// 先解析传入过来的数据
ipTmp := strings.Split(ip, ",")

View File

@@ -6,6 +6,7 @@ import (
"io"
"net/http"
"os"
"time"
"github.com/lionsoul2014/ip2region/v1.0/binding/golang/ip2region"
)
@@ -36,7 +37,7 @@ func downloadDataBase() error {
return err
}
func IP2Region(ip string) (*IPGeoData, error) {
func IP2Region(ip string, _ time.Duration, _ string, _ bool) (*IPGeoData, error) {
if _, err := os.Stat(ipDataBasePath); os.IsNotExist(err) {
if err = downloadDataBase(); err != nil {
panic("Download Failed!")

View File

@@ -11,11 +11,11 @@ import (
"github.com/tidwall/gjson"
)
func IPApiCom(ip string) (*IPGeoData, error) {
func IPApiCom(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoData, error) {
url := "http://ip-api.com/json/" + ip + "?fields=status,message,country,regionName,city,isp,as"
client := &http.Client{
// 2 秒超时
Timeout: 2 * time.Second,
Timeout: timeout,
}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0")

View File

@@ -2,6 +2,7 @@ package ipgeo
import (
"strings"
"time"
)
type IPGeoData struct {
@@ -25,7 +26,7 @@ type IPGeoData struct {
Source string `json:"source"`
}
type Source = func(ip string) (*IPGeoData, error)
type Source = func(ip string, timeout time.Duration, lang string, maptrace bool) (*IPGeoData, error)
func GetSource(s string) Source {
switch strings.ToUpper(s) {
@@ -49,7 +50,13 @@ func GetSource(s string) Source {
return IPInfoLocal
case "CHUNZHEN":
return Chunzhen
case "DISABLE-GEOIP":
return disableGeoIP
default:
return LeoIP
}
}
func disableGeoIP(string, time.Duration, string, bool) (*IPGeoData, error) {
return &IPGeoData{}, nil
}

View File

@@ -4,12 +4,19 @@ import (
"io"
"net/http"
"strings"
"time"
"github.com/tidwall/gjson"
)
func IPInfo(ip string) (*IPGeoData, error) {
resp, err := http.Get("https://ipinfo.io/" + ip + "?token=" + token.ipinfo)
func IPInfo(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoData, error) {
url := "https://ipinfo.io/" + ip + "?token=" + token.ipinfo
client := &http.Client{
// 2 秒超时
Timeout: timeout,
}
resp, err := client.Get(url)
//resp, err := http.Get("https://ipinfo.io/" + ip + "?token=" + token.ipinfo)
if err != nil {
return nil, err
}
@@ -287,8 +294,14 @@ func IPInfo(ip string) (*IPGeoData, error) {
owner = res.Get("org").String()[i:]
}
var asnumber = ""
// 有时候不返回asn或其本身没有asn
if strings.HasPrefix(res.Get("org").String(), "AS") {
asnumber = strings.Fields(strings.TrimPrefix(res.Get("org").String(), "AS"))[0]
}
return &IPGeoData{
Asnumber: strings.Fields(strings.TrimPrefix(res.Get("org").String(), "AS"))[0],
Asnumber: asnumber,
Country: country,
City: res.Get("city").String(),
Prov: res.Get("region").String(),

View File

@@ -6,13 +6,14 @@ import (
"net"
"os"
"strings"
"time"
)
const (
ipinfoDataBasePath = "./ipinfoLocal.mmdb"
)
func IPInfoLocal(ip string) (*IPGeoData, error) {
func IPInfoLocal(ip string, _ time.Duration, _ string, _ bool) (*IPGeoData, error) {
if _, err := os.Stat(ipinfoDataBasePath); os.IsNotExist(err) {
panic("Cannot find ipinfoLocal.mmdb")
}

View File

@@ -3,12 +3,17 @@ package ipgeo
import (
"io"
"net/http"
"time"
"github.com/tidwall/gjson"
)
func IPInSight(ip string) (*IPGeoData, error) {
resp, err := http.Get("https://api.ipinsight.io/ip/" + ip + "?token=" + token.ipinsight)
func IPInSight(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoData, error) {
client := &http.Client{
// 2 秒超时
Timeout: timeout,
}
resp, err := client.Get("https://api.ipinsight.io/ip/" + ip + "?token=" + token.ipinsight)
if err != nil {
return nil, err
}

View File

@@ -10,11 +10,11 @@ import (
"github.com/tidwall/gjson"
)
func IPSB(ip string) (*IPGeoData, error) {
func IPSB(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoData, error) {
url := "https://api.ip.sb/geoip/" + ip
client := &http.Client{
// 2 秒超时
Timeout: 2 * time.Second,
Timeout: timeout,
}
req, _ := http.NewRequest("GET", url, nil)
// 设置 UAip.sb 默认禁止 go-client User-Agent 的 api 请求

View File

@@ -55,7 +55,10 @@ func receiveParse() {
}
m := make(map[string][]string)
json.Unmarshal([]byte(res.Get("router").String()), &m)
err := json.Unmarshal([]byte(res.Get("router").String()), &m)
if err != nil {
// 此处是正常的因为有些IP没有路由信息
}
lat, _ := strconv.ParseFloat(res.Get("lat").String(), 32)
lng, _ := strconv.ParseFloat(res.Get("lng").String(), 32)
@@ -80,15 +83,20 @@ func receiveParse() {
}
}
func LeoIP(ip string) (*IPGeoData, error) {
// 初始化通道 - 向池子里添加IP的Channel返回IP数据是通过字典中对应键为IP的Channel来获取的
func LeoIP(ip string, timeout time.Duration, lang string, maptrace bool) (*IPGeoData, error) {
// TODO: 根据lang的值请求中文/英文API
// TODO: 根据maptrace的值决定是否请求经纬度信息
if timeout < 5*time.Second {
timeout = 5 * time.Second
}
// 缓存中没有找到IP信息需要请求API获取
IPPools.poolMux.Lock()
defer IPPools.poolMux.Unlock()
// 如果之前已经被别的协程初始化过了就不用初始化了
if IPPools.pool[ip] == nil {
IPPools.pool[ip] = make(chan IPGeoData)
}
IPPools.poolMux.Unlock()
// 发送请求
sendIPRequest(ip)
// 同步开启监听
@@ -99,10 +107,8 @@ func LeoIP(ip string) (*IPGeoData, error) {
case res := <-IPPools.pool[ip]:
return &res, nil
// 5秒后依旧没有接收到返回的IP数据不再等待超时异常处理
case <-time.After(5 * time.Second):
// default:
case <-time.After(timeout):
// 这里不可以返回一个 nil否则在访问对象内部的键值的时候会报空指针的 Fatal Error
return &IPGeoData{}, errors.New("TimeOut")
}
}

View File

@@ -1,5 +1,7 @@
package ipgeo
import "github.com/xgadget-lab/nexttrace/util"
type tokenData struct {
ipinsight string
ipinfo string
@@ -7,7 +9,7 @@ type tokenData struct {
}
var token = tokenData{
ipinsight: "",
ipinfo: "",
ipinsight: util.GetenvDefault("NEXTTRACE_IPINSIGHT_TOKEN", ""),
ipinfo: util.GetenvDefault("NEXTTRACE_IPINFO_TOKEN", ""),
ipleo: "NextTraceDemo",
}

38
pow/pow.go Normal file
View File

@@ -0,0 +1,38 @@
package pow
import (
"fmt"
"github.com/tsosunchia/powclient"
"github.com/xgadget-lab/nexttrace/util"
"net/url"
"os"
)
const (
baseURL = "/v3/challenge"
)
func GetToken(fastIp string, host string, port string) (string, error) {
getTokenParams := powclient.NewGetTokenParams()
u := url.URL{Scheme: "https", Host: fastIp + ":" + port, Path: baseURL}
getTokenParams.BaseUrl = u.String()
getTokenParams.SNI = host
getTokenParams.Host = host
getTokenParams.UserAgent = util.UserAgent
var err error
// 尝试三次RetToken如果都失败了异常退出
for i := 0; i < 3; i++ {
token, err := powclient.RetToken(getTokenParams)
if err != nil {
continue
}
//fmt.Println("GetToken success", token, getTokenParams.UserAgent)
return token, nil
}
if err != nil {
fmt.Println(err)
}
fmt.Println("RetToken failed 3 times, exit")
os.Exit(1)
return "", nil
}

19
pow/pow_test.go Normal file
View File

@@ -0,0 +1,19 @@
package pow
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestGetToken(t *testing.T) {
// 计时开始
start := time.Now()
token, err := GetToken("103.120.18.35", "api.leo.moe", "443")
// 计时结束
end := time.Now()
fmt.Println("耗时:", end.Sub(start))
fmt.Println("token:", token)
assert.NoError(t, err, "GetToken() returned an error")
}

View File

@@ -2,14 +2,16 @@ package printer
import (
"fmt"
"github.com/xgadget-lab/nexttrace/config"
"github.com/xgadget-lab/nexttrace/trace"
"net"
"github.com/fatih/color"
)
var version = "v0.0.0.alpha"
var buildDate = ""
var commitID = ""
var version = config.Version
var buildDate = config.BuildDate
var commitID = config.CommitID
func Version() {
fmt.Fprintf(color.Output, "%s %s %s %s\n",
@@ -61,12 +63,39 @@ func PluginCopyRight() {
)
}
func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string) {
func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string, maxHops int) {
fmt.Println("IP Geo Data Provider: " + dataOrigin)
if ip.String() == domain {
fmt.Printf("traceroute to %s, 30 hops max, 32 byte packets\n", ip.String())
fmt.Printf("traceroute to %s, %d hops max, 32 byte packets\n", ip.String(), maxHops)
} else {
fmt.Printf("traceroute to %s (%s), 30 hops max, 32 byte packets\n", ip.String(), domain)
fmt.Printf("traceroute to %s (%s), %d hops max, 32 byte packets\n", ip.String(), domain, maxHops)
}
}
func applyLangSetting(h *trace.Hop) {
if len(h.Geo.Country) <= 1 {
h.Geo.Country = "局域网"
h.Geo.CountryEn = "LAN Address"
}
if h.Lang == "en" {
if h.Geo.Country == "Anycast" {
} else if h.Geo.Prov == "骨干网" {
h.Geo.Prov = "BackBone"
} else if h.Geo.ProvEn == "" {
h.Geo.Country = h.Geo.CountryEn
} else {
if h.Geo.CityEn == "" {
h.Geo.Country = h.Geo.ProvEn
h.Geo.Prov = h.Geo.CountryEn
h.Geo.City = ""
} else {
h.Geo.Country = h.Geo.CityEn
h.Geo.Prov = h.Geo.ProvEn
h.Geo.City = h.Geo.CountryEn
}
}
}
}

32
printer/easy.go Normal file
View File

@@ -0,0 +1,32 @@
package printer
import (
"fmt"
"github.com/xgadget-lab/nexttrace/trace"
)
func EasyPrinter(res *trace.Result, ttl int) {
for i := range res.Hops[ttl] {
if res.Hops[ttl][i].Address == nil {
fmt.Printf("%d|*||||||\n", ttl+1)
continue
}
applyLangSetting(&res.Hops[ttl][i]) // 应用语言设置
fmt.Printf(
"%d|%s|%s|%.2f|%s|%s|%s|%s|%s|%s|%.4f|%.4f\n",
ttl+1,
res.Hops[ttl][i].Address.String(),
res.Hops[ttl][i].Hostname,
float64(res.Hops[ttl][i].RTT.Microseconds())/1000,
res.Hops[ttl][i].Geo.Asnumber,
res.Hops[ttl][i].Geo.Country,
res.Hops[ttl][i].Geo.Prov,
res.Hops[ttl][i].Geo.City,
res.Hops[ttl][i].Geo.District,
res.Hops[ttl][i].Geo.Owner,
res.Hops[ttl][i].Geo.Lat,
res.Hops[ttl][i].Geo.Lng,
)
}
}

View File

@@ -20,6 +20,8 @@ import (
// }
// }
//此文件目前仅供classic_printer使用
const (
RED_PREFIX = "\033[1;31m"
GREEN_PREFIX = "\033[1;32m"
@@ -33,6 +35,7 @@ func HopPrinter(h trace.Hop, info HopInfo) {
if h.Address == nil {
fmt.Println("\t*")
} else {
applyLangSetting(&h) // 应用语言设置
txt := "\t"
if h.Hostname == "" {

View File

@@ -62,7 +62,12 @@ func RealtimePrinter(res *trace.Result, ttl int) {
i, _ := strconv.Atoi(v[0])
if res.Hops[ttl][i].Geo.Asnumber != "" {
// CMIN2, CUII, CN2, CUG 改为壕金色高亮
/*** CMIN2, CUG, CN2, CUII, CTG 改为壕金色高亮
/* 小孩子不懂事加着玩的
/* 此处的高亮不代表任何线路质量
/* 仅代表走了这部分的ASN
/* 如果使用这些ASN的IP同样会被高亮
***/
switch {
case res.Hops[ttl][i].Geo.Asnumber == "58807":
fallthrough
@@ -121,30 +126,7 @@ func RealtimePrinter(res *trace.Result, ttl int) {
}
}
if len(res.Hops[ttl][i].Geo.Country) <= 1 {
res.Hops[ttl][i].Geo.Country = "局域网"
res.Hops[ttl][i].Geo.CountryEn = "LAN Address"
}
if res.Hops[ttl][i].Lang == "en" {
if res.Hops[ttl][i].Geo.Country == "Anycast" {
} else if res.Hops[ttl][i].Geo.Prov == "骨干网" {
res.Hops[ttl][i].Geo.Prov = "BackBone"
} else if res.Hops[ttl][i].Geo.ProvEn == "" {
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.CountryEn
} else {
if res.Hops[ttl][i].Geo.CityEn == "" {
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.ProvEn
res.Hops[ttl][i].Geo.Prov = res.Hops[ttl][i].Geo.CountryEn
res.Hops[ttl][i].Geo.City = ""
} else {
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.CityEn
res.Hops[ttl][i].Geo.Prov = res.Hops[ttl][i].Geo.ProvEn
res.Hops[ttl][i].Geo.City = res.Hops[ttl][i].Geo.CountryEn
}
}
}
applyLangSetting(&res.Hops[ttl][i]) // 应用语言设置
if net.ParseIP(ip).To4() != nil {

View File

@@ -1,6 +1,7 @@
package trace
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
@@ -11,6 +12,7 @@ import (
"sync"
"time"
"github.com/xgadget-lab/nexttrace/trace/internal"
"golang.org/x/net/context"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
@@ -26,6 +28,7 @@ type ICMPTracer struct {
icmpListen net.PacketConn
final int
finalLock sync.Mutex
fetchLock sync.Mutex
}
func (t *ICMPTracer) PrintFunc() {
@@ -62,7 +65,7 @@ func (t *ICMPTracer) Execute() (*Result, error) {
var err error
t.icmpListen, err = net.ListenPacket("ip4:1", t.SrcAddr)
t.icmpListen, err = internal.ListenICMP("ip4:1", t.SrcAddr)
if err != nil {
return &t.res, err
}
@@ -252,8 +255,9 @@ func (t *ICMPTracer) send(ttl int) error {
icmpHeader := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: id,
Data: []byte("HELLO-R-U-THERE"),
ID: id,
//Data: []byte("HELLO-R-U-THERE"),
Data: bytes.Repeat([]byte{1}, t.Config.PktSize),
Seq: ttl,
},
}
@@ -298,6 +302,8 @@ func (t *ICMPTracer) send(ttl int) error {
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
h.fetchIPData(t.Config)
t.res.add(h)

View File

@@ -1,6 +1,7 @@
package trace
import (
"bytes"
"encoding/binary"
"log"
"net"
@@ -9,6 +10,7 @@ import (
"sync"
"time"
"github.com/xgadget-lab/nexttrace/trace/internal"
"golang.org/x/net/context"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
@@ -25,6 +27,7 @@ type ICMPTracerv6 struct {
icmpListen net.PacketConn
final int
finalLock sync.Mutex
fetchLock sync.Mutex
}
func (t *ICMPTracerv6) PrintFunc() {
@@ -63,7 +66,7 @@ func (t *ICMPTracerv6) Execute() (*Result, error) {
var err error
t.icmpListen, err = net.ListenPacket("ip6:58", t.SrcAddr)
t.icmpListen, err = internal.ListenICMP("ip6:58", t.SrcAddr)
if err != nil {
return &t.res, err
}
@@ -249,8 +252,9 @@ func (t *ICMPTracerv6) send(ttl int) error {
icmpHeader := icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: id,
Data: []byte("HELLO-R-U-THERE"),
ID: id,
//Data: []byte("HELLO-R-U-THERE"),
Data: bytes.Repeat([]byte{1}, t.Config.PktSize),
Seq: ttl,
},
}
@@ -298,6 +302,8 @@ func (t *ICMPTracerv6) send(ttl int) error {
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
h.fetchIPData(t.Config)
t.res.add(h)

View File

@@ -0,0 +1,49 @@
//go:build darwin
package internal
import (
"context"
"errors"
"net"
"os"
"syscall"
"unsafe"
)
//go:linkname internetSocket net.internetSocket
func internetSocket(ctx context.Context, net string, laddr, raddr interface{}, sotype, proto int, mode string, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (fd unsafe.Pointer, err error)
//go:linkname newIPConn net.newIPConn
func newIPConn(fd unsafe.Pointer) *net.IPConn
var (
errUnknownNetwork = errors.New("unknown network type")
networkMap = map[string]string{
"ip4:icmp": "udp4",
"ip4:1": "udp4",
"ip6:icmp": "udp6",
"ip6:58": "udp6",
}
)
func ListenICMP(network string, laddr string) (net.PacketConn, error) {
if os.Getuid() == 0 { // root
return net.ListenPacket(network, laddr)
} else {
if nw, ok := networkMap[network]; ok {
proto := syscall.IPPROTO_ICMP
if nw == "udp6" {
proto = syscall.IPPROTO_ICMPV6
}
isock, err := internetSocket(context.Background(), nw, nil, nil, syscall.SOCK_DGRAM, proto, "listen", nil)
if err != nil {
panic(err)
}
return newIPConn(isock), nil
} else {
return nil, errUnknownNetwork
}
}
}

View File

@@ -0,0 +1,9 @@
//go:build !darwin
package internal
import "net"
func ListenICMP(network string, laddr string) (net.PacketConn, error) {
return net.ListenPacket(network, laddr)
}

View File

@@ -31,7 +31,8 @@ type TCPTracer struct {
final int
finalLock sync.Mutex
sem *semaphore.Weighted
sem *semaphore.Weighted
fetchLock sync.Mutex
}
func (t *TCPTracer) Execute() (*Result, error) {
@@ -79,7 +80,7 @@ func (t *TCPTracer) Execute() (*Result, error) {
for i := 0; i < t.NumMeasurements; i++ {
t.wg.Add(1)
go t.send(ttl)
<-time.After(time.Millisecond * time.Duration(t.Config.PacketInterval))
}
if t.RealtimePrinter != nil {
// 对于实时模式应该按照TTL进行并发请求
@@ -87,7 +88,7 @@ func (t *TCPTracer) Execute() (*Result, error) {
t.RealtimePrinter(&t.res, ttl-1)
}
time.Sleep(1 * time.Millisecond)
<-time.After(time.Millisecond * time.Duration(t.Config.TTLInterval))
}
go func() {
if t.AsyncPrinter != nil {
@@ -233,6 +234,11 @@ func (t *TCPTracer) send(ttl int) error {
ComputeChecksums: true,
FixLengths: true,
}
desiredPayloadSize := t.Config.PktSize
payload := make([]byte, desiredPayloadSize)
copy(buf.Bytes(), payload)
if err := gopacket.SerializeLayers(buf, opts, tcpHeader); err != nil {
return err
}
@@ -285,6 +291,8 @@ func (t *TCPTracer) send(ttl int) error {
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
h.fetchIPData(t.Config)
t.res.add(h)

View File

@@ -31,7 +31,8 @@ type TCPTracerv6 struct {
final int
finalLock sync.Mutex
sem *semaphore.Weighted
sem *semaphore.Weighted
fetchLock sync.Mutex
}
func (t *TCPTracerv6) Execute() (*Result, error) {
@@ -63,7 +64,7 @@ func (t *TCPTracerv6) Execute() (*Result, error) {
t.sem = semaphore.NewWeighted(int64(t.ParallelRequests))
for ttl := 1; ttl <= t.MaxHops; ttl++ {
for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ {
// 如果到达最终跳,则退出
if t.final != -1 && ttl > t.final {
break
@@ -71,14 +72,14 @@ func (t *TCPTracerv6) Execute() (*Result, error) {
for i := 0; i < t.NumMeasurements; i++ {
t.wg.Add(1)
go t.send(ttl)
<-time.After(time.Millisecond * time.Duration(t.Config.PacketInterval))
}
if t.RealtimePrinter != nil {
// 对于实时模式应该按照TTL进行并发请求
t.wg.Wait()
t.RealtimePrinter(&t.res, ttl-1)
}
time.Sleep(1 * time.Millisecond)
<-time.After(time.Millisecond * time.Duration(t.Config.TTLInterval))
}
go func() {
@@ -223,6 +224,11 @@ func (t *TCPTracerv6) send(ttl int) error {
ComputeChecksums: true,
FixLengths: true,
}
desiredPayloadSize := t.Config.PktSize
payload := make([]byte, desiredPayloadSize)
copy(buf.Bytes(), payload)
if err := gopacket.SerializeLayers(buf, opts, tcpHeader); err != nil {
return err
}
@@ -268,6 +274,8 @@ func (t *TCPTracerv6) send(ttl int) error {
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
h.fetchIPData(t.Config)
t.res.add(h)

View File

@@ -7,12 +7,14 @@ import (
"time"
"github.com/xgadget-lab/nexttrace/ipgeo"
"github.com/xgadget-lab/nexttrace/util"
)
var (
ErrInvalidMethod = errors.New("invalid method")
ErrTracerouteExecuted = errors.New("traceroute already executed")
ErrHopLimitTimeout = errors.New("hop timeout")
geoCache = sync.Map{}
)
type Config struct {
@@ -34,6 +36,8 @@ type Config struct {
DN42 bool
RealtimePrinter func(res *Result, ttl int)
AsyncPrinter func(res *Result)
PktSize int
Maptrace bool
}
type Method string
@@ -89,8 +93,9 @@ func Traceroute(method Method, config Config) (*Result, error) {
}
type Result struct {
Hops [][]Hop
lock sync.Mutex
Hops [][]Hop
lock sync.Mutex
TraceMapUrl string
}
func (s *Result) add(hop Hop) {
@@ -122,16 +127,17 @@ type Hop struct {
}
func (h *Hop) fetchIPData(c Config) (err error) {
// DN42
if c.DN42 {
var ip string
// 首先查找 PTR 记录
r, err := net.LookupAddr(h.Address.String())
r, err := util.LookupAddr(h.Address.String())
if err == nil && len(r) > 0 {
h.Hostname = r[0][:len(r[0])-1]
ip = h.Address.String() + "," + h.Hostname
}
h.Geo, err = c.IPGeoSource(ip)
h.Geo, err = c.IPGeoSource(ip, c.Timeout, c.Lang, c.Maptrace)
return nil
}
@@ -145,7 +151,7 @@ func (h *Hop) fetchIPData(c Config) (err error) {
if c.RDns && h.Hostname == "" {
// Create a rDNS Query go-routine
go func() {
r, err := net.LookupAddr(h.Address.String())
r, err := util.LookupAddr(h.Address.String())
if err != nil {
// No PTR Record
rDNSChan <- nil
@@ -164,7 +170,21 @@ func (h *Hop) fetchIPData(c Config) (err error) {
h.Lang = c.Lang
h.Geo, res = ipgeo.Filter(h.Address.String())
if !res {
h.Geo, err = c.IPGeoSource(h.Address.String())
timeout := c.Timeout
if c.Timeout < 2*time.Second {
timeout = 2 * time.Second
}
//h.Geo, err = c.IPGeoSource(h.Address.String(), timeout, c.Lang, c.Maptrace)
if cacheVal, ok := geoCache.Load(h.Address.String()); ok {
// 如果缓存中已有结果,直接使用
h.Geo = cacheVal.(*ipgeo.IPGeoData)
} else {
// 如果缓存中无结果,进行查询并将结果存入缓存
h.Geo, err = c.IPGeoSource(h.Address.String(), timeout, c.Lang, c.Maptrace)
if err == nil {
geoCache.Store(h.Address.String(), h.Geo)
}
}
}
}
// Fetch Done

View File

@@ -28,7 +28,8 @@ type UDPTracer struct {
final int
finalLock sync.Mutex
sem *semaphore.Weighted
sem *semaphore.Weighted
fetchLock sync.Mutex
}
func (t *UDPTracer) Execute() (*Result, error) {
@@ -60,14 +61,14 @@ func (t *UDPTracer) Execute() (*Result, error) {
for i := 0; i < t.NumMeasurements; i++ {
t.wg.Add(1)
go t.send(ttl)
<-time.After(time.Millisecond * time.Duration(t.Config.PacketInterval))
}
if t.RealtimePrinter != nil {
// 对于实时模式应该按照TTL进行并发请求
t.wg.Wait()
t.RealtimePrinter(&t.res, ttl-1)
}
time.Sleep(1 * time.Millisecond)
<-time.After(time.Millisecond * time.Duration(t.Config.TTLInterval))
}
go func() {
if t.AsyncPrinter != nil {
@@ -188,7 +189,12 @@ func (t *UDPTracer) send(ttl int) error {
ComputeChecksums: true,
FixLengths: true,
}
if err := gopacket.SerializeLayers(buf, opts, udpHeader, gopacket.Payload("HAJSFJHKAJSHFKJHAJKFHKASHKFHHKAFKHFAHSJK")); err != nil {
desiredPayloadSize := t.Config.PktSize
payload := make([]byte, desiredPayloadSize)
copy(buf.Bytes(), payload)
if err := gopacket.SerializeLayers(buf, opts, udpHeader); err != nil {
return err
}
@@ -256,6 +262,8 @@ func (t *UDPTracer) send(ttl int) error {
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
h.fetchIPData(t.Config)
t.res.add(h)

View File

@@ -1,20 +1,71 @@
package tracemap
import (
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"strings"
"github.com/fatih/color"
"github.com/xgadget-lab/nexttrace/util"
"io"
"net"
"net/http"
"net/url"
"strings"
"time"
)
func GetMapUrl(r string) {
url := "https://api.leo.moe/tracemap/api"
resp, _ := http.Post(url, "application/json", strings.NewReader(r))
body, _ := io.ReadAll(resp.Body)
fmt.Fprintf(color.Output, "%s %s\n",
color.New(color.FgWhite, color.Bold).Sprintf("%s", "MapTrace URL:"),
color.New(color.FgBlue, color.Bold).Sprintf("%s", string(body)),
)
func GetMapUrl(r string) (string, error) {
host, port := util.GetHostAndPort()
fastIp := "api.leo.moe"
// 如果 host 是一个 IP 使用默认域名
if valid := net.ParseIP(host); valid != nil {
host = "api.leo.moe"
} else {
// 默认配置完成,开始寻找最优 IP
fastIp = util.GetFastIP(host, port, false)
}
u := url.URL{Scheme: "https", Host: fastIp + ":" + port, Path: "/tracemap/api"}
tracemapUrl := u.String()
tracemapUrl = "https://api.leo.moe/tracemap/api"
client := &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
ServerName: host,
},
},
}
req, err := http.NewRequest("POST", tracemapUrl, strings.NewReader(r))
if err != nil {
return "", errors.New("an issue occurred while connecting to the tracemap API")
}
req.Header.Add("User-Agent", util.UserAgent)
req.Host = host
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
return "", errors.New("an issue occurred while connecting to the tracemap API")
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
return
}
}(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.New("an issue occurred while connecting to the tracemap API")
}
return string(body), nil
}
func PrintMapUrl(r string) {
_, err := fmt.Fprintf(color.Output, "%s %s\n",
color.New(color.FgWhite, color.Bold).Sprintf("%s", "MapTrace URL:"),
color.New(color.FgBlue, color.Bold).Sprintf("%s", string(r)),
)
if err != nil {
return
}
}

View File

@@ -8,6 +8,6 @@ import (
func TestDNS(t *testing.T) {
resolver := DNSSB()
ips, _ := resolver.LookupHost(context.Background(), "www.google.com")
ips, _ := resolver.LookupHost(context.Background(), "www.bing.com")
fmt.Println(ips)
}

View File

@@ -1,4 +1,4 @@
package wshandle
package util
import (
"fmt"
@@ -14,13 +14,16 @@ var (
result string
results = make(chan string)
)
var FastIpCache = ""
func GetFastIP(domain string, port string) string {
func GetFastIP(domain string, port string, enableOutput bool) string {
if FastIpCache != "" {
return FastIpCache
}
ips, err := net.LookupIP(domain)
if err != nil {
log.Fatal("DNS resolution failed, please check your system DNS Settings")
return ""
}
for _, ip := range ips {
@@ -30,7 +33,6 @@ func GetFastIP(domain string, port string) string {
select {
case result = <-results:
case <-time.After(1 * time.Second):
}
if result == "" {
log.Fatal("IP connection has been timeout, please check your network")
@@ -38,13 +40,15 @@ func GetFastIP(domain string, port string) string {
res := strings.Split(result, "-")
if len(ips) > 1 {
_, _ = fmt.Fprintf(color.Output, "%s prefered API IP - %s - %s\n",
color.New(color.FgWhite, color.Bold).Sprintf("[NextTrace API]"),
color.New(color.FgGreen, color.Bold).Sprintf("%s", res[0]),
color.New(color.FgCyan, color.Bold).Sprintf("%sms", res[1]),
)
if enableOutput {
_, _ = fmt.Fprintf(color.Output, "%s prefered API IP - %s - %s\n",
color.New(color.FgWhite, color.Bold).Sprintf("[NextTrace API]"),
color.New(color.FgGreen, color.Bold).Sprintf("%s", res[0]),
color.New(color.FgCyan, color.Bold).Sprintf("%sms", res[1]),
)
}
}
FastIpCache = res[0]
return res[0]
}

View File

@@ -1,9 +1,9 @@
package wshandle
package util
import (
"testing"
)
func TestGetFastIP(t *testing.T) {
GetFastIP("api.leo.moe", "443")
GetFastIP("api.leo.moe", "443", true)
}

View File

@@ -3,13 +3,40 @@ package util
import (
"context"
"fmt"
"github.com/xgadget-lab/nexttrace/config"
"log"
"net"
"os"
"runtime"
"strings"
"sync"
"github.com/fatih/color"
)
var Uninterrupted = GetenvDefault("NEXTTRACE_UNINTERRUPTED", "")
var EnvToken = GetenvDefault("NEXTTRACE_TOKEN", "")
var UserAgent = fmt.Sprintf("NextTrace %s/%s/%s", config.Version, runtime.GOOS, runtime.GOARCH)
var RdnsCache sync.Map
func LookupAddr(addr string) ([]string, error) {
// 如果在缓存中找到,直接返回
if hostname, ok := RdnsCache.Load(addr); ok {
//fmt.Println("hit RdnsCache for", addr, hostname)
return []string{hostname.(string)}, nil
}
// 如果缓存中未找到,进行 DNS 查询
names, err := net.LookupAddr(addr)
if err != nil {
return nil, err
}
// 将查询结果存入缓存
if len(names) > 0 {
RdnsCache.Store(addr, names[0])
}
return names, nil
}
// LocalIPPort get the local ip and port based on our destination ip
func LocalIPPort(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345")
@@ -45,7 +72,8 @@ func LocalIPPortv6(dstip net.IP) (net.IP, int) {
return nil, -1
}
func DomainLookUp(host string, ipv4Only bool, dotServer string) net.IP {
func DomainLookUp(host string, ipVersion string, dotServer string, disableOutput bool) net.IP {
// ipVersion: 4, 6, all
var (
r *net.Resolver
ips []net.IP
@@ -74,16 +102,29 @@ func DomainLookUp(host string, ipv4Only bool, dotServer string) net.IP {
os.Exit(1)
}
var ipv6Flag = false
//var ipv6Flag = false
//TODO: 此处代码暂无意义
//if ipv6Flag {
// fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
// if len(ips) == 0 {
// os.Exit(0)
// }
//}
if ipv6Flag {
fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
if len(ips) == 0 {
os.Exit(0)
// Filter by IPv4/IPv6
if ipVersion != "all" {
var filteredIPs []net.IP
for _, ip := range ips {
if ipVersion == "4" && ip.To4() != nil {
filteredIPs = append(filteredIPs, ip)
} else if ipVersion == "6" && strings.Contains(ip.String(), ":") {
filteredIPs = append(filteredIPs, ip)
}
}
ips = filteredIPs
}
if len(ips) == 1 {
if (len(ips) == 1) || (disableOutput) {
return ips[0]
} else {
fmt.Println("Please Choose the IP You Want To TraceRoute")
@@ -114,3 +155,30 @@ func GetenvDefault(key, defVal string) string {
}
return defVal
}
func GetHostAndPort() (host string, port string) {
var hostP = GetenvDefault("NEXTTRACE_HOSTPORT", "api.leo.moe")
// 解析域名
hostArr := strings.Split(hostP, ":")
// 判断是否有指定端口
if len(hostArr) > 1 {
// 判断是否为 IPv6
if strings.HasPrefix(hostP, "[") {
tmp := strings.Split(hostP, "]")
host = tmp[0]
host = host[1:]
if port = tmp[1]; port != "" {
port = port[1:]
}
} else {
host, port = hostArr[0], hostArr[1]
}
} else {
host = hostP
}
if port == "" {
// 默认端口
port = "443"
}
return
}

View File

@@ -2,18 +2,18 @@ package wshandle
import (
"crypto/tls"
"github.com/xgadget-lab/nexttrace/pow"
"github.com/xgadget-lab/nexttrace/util"
"log"
"net"
"net/http"
"net/url"
"os"
"os/signal"
"strings"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/xgadget-lab/nexttrace/util"
)
type WsConn struct {
@@ -29,8 +29,10 @@ type WsConn struct {
}
var wsconn *WsConn
var hostP = util.GetenvDefault("NEXTTRACE_HOSTPORT", "api.leo.moe")
var host, port, fast_ip string
var host, port, fastIp string
var envToken = util.EnvToken
var cacheToken string
var cacheTokenFailedTimes int
func (c *WsConn) keepAlive() {
go func() {
@@ -116,10 +118,31 @@ func (c *WsConn) messageSendHandler() {
}
func (c *WsConn) recreateWsConn() {
u := url.URL{Scheme: "wss", Host: fast_ip + ":" + port, Path: "/v2/ipGeoWs"}
// 尝试重新连线
u := url.URL{Scheme: "wss", Host: fastIp + ":" + port, Path: "/v3/ipGeoWs"}
// log.Printf("connecting to %s", u.String())
jwtToken, ua := envToken, []string{"Privileged Client"}
err := error(nil)
if envToken == "" {
// 无环境变量 token
if cacheToken == "" {
// 无cacheToken, 重新获取 token
jwtToken, err = pow.GetToken(fastIp, host, port)
if err != nil {
log.Println(err)
os.Exit(1)
}
} else {
// 使用 cacheToken
jwtToken = cacheToken
}
ua = []string{util.UserAgent}
}
cacheToken = jwtToken
requestHeader := http.Header{
"Host": []string{host},
"Host": []string{host},
"User-Agent": ua,
"Authorization": []string{"Bearer " + jwtToken},
}
dialer := websocket.DefaultDialer
dialer.TLSClientConfig = &tls.Config{
@@ -132,6 +155,11 @@ func (c *WsConn) recreateWsConn() {
// <-time.After(time.Second * 1)
c.Connected = false
c.Connecting = false
if cacheTokenFailedTimes > 3 {
cacheToken = ""
}
cacheTokenFailedTimes += 1
//fmt.Println("重连失败", cacheTokenFailedTimes, "次")
return
} else {
c.Connected = true
@@ -143,47 +171,40 @@ func (c *WsConn) recreateWsConn() {
}
func createWsConn() *WsConn {
//fmt.Println("正在连接 WS")
// 设置终端中断通道
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
// 解析域名
hostArr := strings.Split(hostP, ":")
// 判断是否有指定端口
if len(hostArr) > 1 {
// 判断是否为 IPv6
if strings.HasPrefix(hostP, "[") {
tmp := strings.Split(hostP, "]")
host = tmp[0]
host = host[1:]
if port = tmp[1]; port != "" {
port = port[1:]
}
} else {
host, port = hostArr[0], hostArr[1]
}
} else {
host = hostP
}
if port == "" {
// 默认端口
port = "443"
}
// 默认配置完成,开始寻找最优 IP
fast_ip = GetFastIP(host, port)
host, port = util.GetHostAndPort()
// 如果 host 是一个 IP 使用默认域名
if valid := net.ParseIP(host); valid != nil {
host = "api.leo.moe"
} else {
// 默认配置完成,开始寻找最优 IP
fastIp = util.GetFastIP(host, port, true)
}
// 判断是否是一个 IP
jwtToken, ua := envToken, []string{"Privileged Client"}
err := error(nil)
if envToken == "" {
jwtToken, err = pow.GetToken(fastIp, host, port)
if err != nil {
log.Println(err)
os.Exit(1)
}
ua = []string{util.UserAgent}
}
cacheToken = jwtToken
cacheTokenFailedTimes = 0
requestHeader := http.Header{
"Host": []string{host},
"Host": []string{host},
"User-Agent": ua,
"Authorization": []string{"Bearer " + jwtToken},
}
dialer := websocket.DefaultDialer
dialer.TLSClientConfig = &tls.Config{
ServerName: host,
}
u := url.URL{Scheme: "wss", Host: fast_ip + ":" + port, Path: "/v2/ipGeoWs"}
u := url.URL{Scheme: "wss", Host: fastIp + ":" + port, Path: "/v3/ipGeoWs"}
// log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), requestHeader)