Compare commits

...

56 Commits

Author SHA1 Message Date
tsosunchia
ac14ef4a7a 更新依赖
Signed-off-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-07-19 22:08:21 +08:00
tsosunchia
bb192699ef Merge pull request #92 from nxtrace/dependabot/go_modules/golang.org/x/net-0.42.0
chore(deps): bump golang.org/x/net from 0.41.0 to 0.42.0
2025-07-19 21:47:00 +08:00
dependabot[bot]
b0b05f476b chore(deps): bump golang.org/x/net from 0.41.0 to 0.42.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.41.0 to 0.42.0.
- [Commits](https://github.com/golang/net/compare/v0.41.0...v0.42.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-19 13:45:53 +00:00
tsosunchia
53de171bdb Merge pull request #93 from nxtrace/dependabot/go_modules/golang.org/x/sync-0.16.0
chore(deps): bump golang.org/x/sync from 0.15.0 to 0.16.0
2025-07-19 21:44:18 +08:00
dependabot[bot]
547906525a chore(deps): bump golang.org/x/sync from 0.15.0 to 0.16.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.15.0 to 0.16.0.
- [Commits](https://github.com/golang/sync/compare/v0.15.0...v0.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 18:21:07 +00:00
tsosunchia
b4d2038895 SNI和DNS不再分离,统一使用api.nxtrace.org 2025-07-08 11:30:21 +08:00
tsosunchia
adf8bb7076 更新依赖 2025-07-05 17:17:59 +08:00
tsosunchia
3defedd27c SNI和DNS不再分离,统一使用api.nxtrace.org 2025-07-05 16:48:43 +08:00
tsosunchia
4eeef8ddb8 Merge pull request #90 from nxtrace/dependabot/go_modules/github.com/go-viper/mapstructure/v2-2.3.0
chore(deps): bump github.com/go-viper/mapstructure/v2 from 2.2.1 to 2.3.0
2025-07-05 13:46:37 +08:00
dependabot[bot]
35b67d9502 chore(deps): bump github.com/go-viper/mapstructure/v2
Bumps [github.com/go-viper/mapstructure/v2](https://github.com/go-viper/mapstructure) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/go-viper/mapstructure/releases)
- [Changelog](https://github.com/go-viper/mapstructure/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-viper/mapstructure/compare/v2.2.1...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/go-viper/mapstructure/v2
  dependency-version: 2.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-27 16:53:59 +00:00
tsosunchia
4d38c38cf7 update README: AIWEN TECH Support 2025-06-26 15:22:03 +08:00
tsosunchia
d0e8e67d0a update README: AIWEN TECH Support 2025-06-26 15:14:32 +08:00
tsosunchia
26b176ccb0 Merge pull request #89 from nxtrace/dependabot/go_modules/golang.org/x/net-0.41.0
chore(deps): bump golang.org/x/net from 0.39.0 to 0.41.0
2025-06-12 21:52:21 +08:00
dependabot[bot]
e2b23bb8e0 chore(deps): bump golang.org/x/net from 0.39.0 to 0.41.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.39.0 to 0.41.0.
- [Commits](https://github.com/golang/net/compare/v0.39.0...v0.41.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-12 13:49:58 +00:00
tsosunchia
8c3a682e15 Merge pull request #88 from nxtrace/dependabot/go_modules/golang.org/x/sync-0.15.0
chore(deps): bump golang.org/x/sync from 0.13.0 to 0.15.0
2025-06-12 21:48:24 +08:00
dependabot[bot]
21e1c03596 chore(deps): bump golang.org/x/sync from 0.13.0 to 0.15.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.13.0 to 0.15.0.
- [Commits](https://github.com/golang/sync/compare/v0.13.0...v0.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 14:51:40 +00:00
tsosunchia
93c0f8558b 更新 nt_install.sh
https://github.com/nxtrace/NTrace-core/issues/300
2025-04-28 10:02:47 +08:00
SaltyFishEd
7bfccf9da4 feat(geoip): overwrite the owner field when asn.domain exists for ipdb.one datasource
feat(geoip): add asn.asname as whois field for ipdb.one datasource
2025-04-27 00:25:47 +08:00
SaltyFishEd
b5673b65a1 feat(geoip): support geoip data from ipdb.one 2025-04-18 14:43:56 +08:00
tsosunchia
946095458b update README 脚本安装命令修改 2025-04-16 17:18:52 +08:00
tsosunchia
28b329e365 update README 2025-04-16 09:44:22 +08:00
tsosunchia
c27dd3703a Merge pull request #85 from Yunlq/main
add support for custom source ports and optimize some code
2025-04-16 09:06:02 +08:00
Yunlq
b20c4b74cc add support for custom source ports and optimize some code 2025-04-16 02:54:19 +08:00
tsosunchia
deca060a9d Merge pull request #299 from nxtrace/main
Some checks failed
Build & Release / build (amd64, freebsd) (push) Has been cancelled
Build & Release / build (amd64, linux) (push) Has been cancelled
Build & Release / build (amd64, openbsd) (push) Has been cancelled
Build & Release / build (amd64, windows) (push) Has been cancelled
Build & Release / build (arm, 5, linux) (push) Has been cancelled
Build & Release / build (arm, 6, linux) (push) Has been cancelled
Build & Release / build (arm, 7, freebsd) (push) Has been cancelled
Build & Release / build (arm, 7, linux) (push) Has been cancelled
Build & Release / build (arm, 7, openbsd) (push) Has been cancelled
Build & Release / build (arm, 7, windows) (push) Has been cancelled
Build & Release / build (arm64, android) (push) Has been cancelled
Build & Release / build (arm64, darwin) (push) Has been cancelled
Build & Release / build (arm64, freebsd) (push) Has been cancelled
Build & Release / build (arm64, linux) (push) Has been cancelled
Build & Release / build (arm64, openbsd) (push) Has been cancelled
Build & Release / build (arm64, windows) (push) Has been cancelled
Build & Release / build (mips, linux) (push) Has been cancelled
Build & Release / build (mips, softfloat, linux) (push) Has been cancelled
Build & Release / build (mips64, linux) (push) Has been cancelled
Build & Release / build (mips64le, linux) (push) Has been cancelled
Build & Release / build (mipsle, linux) (push) Has been cancelled
Build & Release / build (mipsle, softfloat, linux) (push) Has been cancelled
Build & Release / build (ppc64, linux) (push) Has been cancelled
Build & Release / build (ppc64le, linux) (push) Has been cancelled
Build & Release / build (riscv64, linux) (push) Has been cancelled
Build & Release / build (s390x, linux) (push) Has been cancelled
Test / test (macos-latest) (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
Test / test (windows-latest) (push) Has been cancelled
Build & Release / publish-new-formula (push) Has been cancelled
update README
2025-04-15 16:53:14 +08:00
tsosunchia
fedf2946e0 update README
Signed-off-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-04-15 16:52:32 +08:00
tsosunchia
d0f5862258 Merge pull request #298 from nxtrace/main
SYNC
2025-04-15 16:37:57 +08:00
tsosunchia
0f8a646d71 fasttrace 增加上海/广州单独测试选项 2025-04-15 16:08:11 +08:00
tsosunchia
dccc41b995 udp mode增加mutex 以避免固定端口时的端口竞争问题 2025-04-15 15:43:41 +08:00
tsosunchia
9af629b6f9 ipgeo/leo.go 优化 receiveParse 的单例调用(WebSocket 连接的并发控制) 2025-04-15 13:36:42 +08:00
tsosunchia
d6de649e60 handleICMPMessage 采用更健壮的方案处理ICMPv6头部,之前使用了一个固定的偏移量来从 ICMPv6 错误消息中提取 UDP 源端口,现在改为动态计算偏移量 2025-04-15 13:16:15 +08:00
tsosunchia
bcd430c231 IPv6下也支持UDP Mode
Co-authored-by: Claude-3.7-Sonnet <ai@anthropic.com>
Co-authored-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>

 要提交的变更:
	修改:     cmd/cmd.go
	修改:     fast_trace/fast_trace ipv6.go
	修改:     trace/tcp_ipv6.go
	修改:     trace/trace.go
	重命名:   trace/udp.go -> trace/udp_ipv4.go
	新文件:   trace/udp_ipv6.go

Signed-off-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-04-14 23:25:18 +08:00
tsosunchia
314a4b3015 修正udp mode一些情况下的显示错误 2025-04-14 22:46:23 +08:00
tsosunchia
4d8e7e322b 固定UDP模式的源端口,改善在一些负载均衡网络环境下的效果,在使用ENV "NEXTTRACE_RANDOMPORT" 支持继续随机分配源端口。
https://github.com/nxtrace/NTrace-core/issues/296
https://github.com/nxtrace/NTrace-core/pull/297

Co-authored-by: Yunlq <vinculo025@gmail.com>
Co-authored-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-04-14 22:04:22 +08:00
tsosunchia
8fb1220f1b 更改 wshandle/client.go 超时/手动终端log显示
Signed-off-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-04-13 20:36:10 +08:00
tsosunchia
90b1a3c1ad 固定TCP模式的源端口,改善在一些负载均衡网络环境下的效果,在使用ENV "NEXTTRACE_RANDOMPORT" 支持继续随机分配源端口。
https://github.com/nxtrace/NTrace-core/issues/296
2025-04-13 20:26:54 +08:00
tsosunchia
608a2904d4 若干修改,方便其他程序调用
https://github.com/nxtrace/NTrace-V1/issues/84
 要提交的变更:
	修改:     cmd/cmd.go
	修改:     go.mod
	修改:     go.sum
	修改:     wshandle/client.go
2025-04-13 12:13:08 +08:00
tsosunchia
62ab23bdeb termux安装方法描述增加root-repo安装引导 2025-04-13 12:13:08 +08:00
tsosunchia
c095599400 upgrade go to verison 1.24
# Conflicts:
#	go.mod
2025-04-13 12:12:55 +08:00
dependabot[bot]
76d841f670 chore(deps): bump golang.org/x/sync from 0.12.0 to 0.13.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.12.0 to 0.13.0.
- [Commits](https://github.com/golang/sync/compare/v0.12.0...v0.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-09 21:38:48 +08:00
dependabot[bot]
9dd36e9625 chore(deps): bump golang.org/x/net from 0.37.0 to 0.38.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.37.0...v0.38.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>
2025-04-09 21:33:24 +08:00
dependabot[bot]
e1f4052518 chore(deps): bump github.com/spf13/viper from 1.19.0 to 1.20.0
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.19.0 to 1.20.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.19.0...v1.20.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-29 10:32:27 +08:00
dependabot[bot]
b5df3efd1b chore(deps): bump golang.org/x/net from 0.35.0 to 0.37.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.35.0 to 0.37.0.
- [Commits](https://github.com/golang/net/compare/v0.35.0...v0.37.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>
2025-03-29 10:27:37 +08:00
tsosunchia
3f9803680e 更新 README_zh_CN.md 2025-03-10 14:13:52 +08:00
tsosunchia
db2b02d5f8 更新 README.md 2025-03-10 14:13:31 +08:00
dependabot[bot]
ec634fffb3 chore(deps): bump golang.org/x/net from 0.34.0 to 0.35.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.34.0 to 0.35.0.
- [Commits](https://github.com/golang/net/compare/v0.34.0...v0.35.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>
2025-02-19 20:47:09 +08:00
dependabot[bot]
a3404cebac chore(deps): bump golang.org/x/sync from 0.10.0 to 0.11.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/sync/compare/v0.10.0...v0.11.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>
2025-02-19 10:53:18 +08:00
tsosunchia
667285a8c3 Merge pull request #291 from nxtrace/main
SYNC
2025-02-03 22:12:45 +08:00
tsosunchia
c52d5a5414 调整x-cmd位置 2025-02-03 22:11:53 +08:00
tsosunchia
6c009602b5 update readme 2025-02-03 22:09:52 +08:00
tsosunchia
a179608da0 Merge pull request #290 from nxtrace/main
Some checks failed
Build & Release / build (amd64, freebsd) (push) Has been cancelled
Build & Release / build (amd64, linux) (push) Has been cancelled
Build & Release / build (amd64, openbsd) (push) Has been cancelled
Build & Release / build (amd64, windows) (push) Has been cancelled
Build & Release / build (arm, 5, linux) (push) Has been cancelled
Build & Release / build (arm, 6, linux) (push) Has been cancelled
Build & Release / build (arm, 7, freebsd) (push) Has been cancelled
Build & Release / build (arm, 7, linux) (push) Has been cancelled
Build & Release / build (arm, 7, openbsd) (push) Has been cancelled
Build & Release / build (arm, 7, windows) (push) Has been cancelled
Build & Release / build (arm64, android) (push) Has been cancelled
Build & Release / build (arm64, darwin) (push) Has been cancelled
Build & Release / build (arm64, freebsd) (push) Has been cancelled
Build & Release / build (arm64, linux) (push) Has been cancelled
Build & Release / build (arm64, openbsd) (push) Has been cancelled
Build & Release / build (arm64, windows) (push) Has been cancelled
Build & Release / build (mips, linux) (push) Has been cancelled
Build & Release / build (mips, softfloat, linux) (push) Has been cancelled
Build & Release / build (mips64, linux) (push) Has been cancelled
Build & Release / build (mips64le, linux) (push) Has been cancelled
Build & Release / build (mipsle, linux) (push) Has been cancelled
Build & Release / build (mipsle, softfloat, linux) (push) Has been cancelled
Build & Release / build (ppc64, linux) (push) Has been cancelled
Build & Release / build (ppc64le, linux) (push) Has been cancelled
Build & Release / build (riscv64, linux) (push) Has been cancelled
Build & Release / build (s390x, linux) (push) Has been cancelled
Test / test (macos-latest) (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
Test / test (windows-latest) (push) Has been cancelled
Build & Release / publish-new-formula (push) Has been cancelled
feat: 添加触发 deb 仓库的推送
2025-02-03 19:34:07 +08:00
wcbing
5cd2962a2b feat: 添加触发 deb 仓库的推送
Signed-off-by: tsosunchia <59512455+tsosunchia@users.noreply.github.com>
2025-02-03 19:32:32 +08:00
tsosunchia
f774c0d29f Merge pull request #285 from nxtrace/main
Some checks failed
Build & Release / build (amd64, freebsd) (push) Has been cancelled
Build & Release / build (amd64, linux) (push) Has been cancelled
Build & Release / build (amd64, openbsd) (push) Has been cancelled
Build & Release / build (amd64, windows) (push) Has been cancelled
Build & Release / build (arm, 5, linux) (push) Has been cancelled
Build & Release / build (arm, 6, linux) (push) Has been cancelled
Build & Release / build (arm, 7, freebsd) (push) Has been cancelled
Build & Release / build (arm, 7, linux) (push) Has been cancelled
Build & Release / build (arm, 7, openbsd) (push) Has been cancelled
Build & Release / build (arm, 7, windows) (push) Has been cancelled
Build & Release / build (arm64, android) (push) Has been cancelled
Build & Release / build (arm64, darwin) (push) Has been cancelled
Build & Release / build (arm64, freebsd) (push) Has been cancelled
Build & Release / build (arm64, linux) (push) Has been cancelled
Build & Release / build (arm64, openbsd) (push) Has been cancelled
Build & Release / build (arm64, windows) (push) Has been cancelled
Build & Release / build (mips, linux) (push) Has been cancelled
Build & Release / build (mips, softfloat, linux) (push) Has been cancelled
Build & Release / build (mips64, linux) (push) Has been cancelled
Build & Release / build (mips64le, linux) (push) Has been cancelled
Build & Release / build (mipsle, linux) (push) Has been cancelled
Build & Release / build (mipsle, softfloat, linux) (push) Has been cancelled
Build & Release / build (ppc64, linux) (push) Has been cancelled
Build & Release / build (ppc64le, linux) (push) Has been cancelled
Build & Release / build (riscv64, linux) (push) Has been cancelled
Build & Release / build (s390x, linux) (push) Has been cancelled
Test / test (macos-latest) (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
Test / test (windows-latest) (push) Has been cancelled
Build & Release / publish-new-formula (push) Has been cancelled
SYNC
2025-01-12 11:41:06 +08:00
tsosunchia
69588b0d14 更新Golang到v1.23,此处需注意之后版本编译时需要加"-ldflags=-checklinkname=0"参数
修改:     .cross_compile.sh
	修改:     .github/workflows/build.yml
	修改:     .github/workflows/test.yml
	修改:     README.md
	修改:     README_zh_CN.md
	修改:     go.mod
	修改:     go.sum
2025-01-11 23:09:27 +08:00
tsosunchia
6c49957be8 解决网络不通时的卡死问题 2025-01-05 12:24:58 +08:00
tsosunchia
5cc08151f4 Merge pull request #279 from nxtrace/main
SYNC
2024-12-21 21:40:34 +08:00
tsosunchia
00695f32b4 Merge pull request #278 from nxtrace/main
SYNC
2024-12-20 23:14:03 +08:00
26 changed files with 1126 additions and 304 deletions

View File

@@ -29,13 +29,13 @@ for pl in ${PLATFORMS}; do
-ldflags "-X 'github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION}' \
-X 'github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1}'\
-w -s"
-w -s -checklinkname=0"
else
go build -trimpath -o ${TARGET} \
-ldflags "-X 'github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION}' \
-X 'github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1}'\
-w -s"
-w -s -checklinkname=0"
fi
done
export CGO_ENABLED=0
@@ -49,13 +49,13 @@ done
-ldflags "-X 'github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION}' \
-X 'github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1}'\
-w -s"
-w -s -checklinkname=0"
else
go build -trimpath -o ${TARGET} \
-ldflags "-X 'github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION}' \
-X 'github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1}'\
-w -s"
-w -s -checklinkname=0"
fi

View File

@@ -135,7 +135,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
go-version: '1.23'
- name: Get project dependencies
run: go mod download
- name: Build
@@ -144,7 +144,7 @@ jobs:
-ldflags "-X 'github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION}' \
-X 'github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE}' \
-X 'github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1}'\
-w -s"
-checklinkname=0 -w -s"
- name: Upload files to Artifacts
uses: actions/upload-artifact@v4
with:

View File

@@ -31,12 +31,12 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
go-version: '1.23'
- name: Checkout codebase
uses: actions/checkout@v4
- name: Test with unix
if: ${{ matrix.os != 'windows-latest' }}
run: sudo go test -v -coverprofile='coverage.out' -covermode=count ./...
run: sudo go test -v -ldflags=-checklinkname=0 -coverprofile='coverage.out' -covermode=count ./...
- name: Test with windows
if: ${{ matrix.os == 'windows-latest' }}
run: go test -v -coverprofile='coverage.out' -covermode=count ./...
run: go test -v -ldflags=-checklinkname=0 -coverprofile='coverage.out' -covermode=count ./...

15
.github/workflows/triggerDebRepo.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Trigger Deb Repo
on:
release:
types: [published]
jobs:
trigger-deb-repo:
runs-on: ubuntu-latest
steps:
- env:
GITHUB_TOKEN: ${{ secrets.GT_Token }} # 操作 deb 仓库的 PAT
run: |
curl -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/nxtrace/nexttrace-debs/actions/workflows/build.yaml/dispatches \
-d '{"ref": "main", "inputs": {"tag": "${{ github.event.release.tag_name }}"}}'

115
README.md
View File

@@ -57,67 +57,78 @@ Please note, there are exceptions to this synchronization. If a version of NTrac
* Linux
* One-click installation script
```shell
curl nxtrace.org/nt |bash
curl -sL nxtrace.org/nt |bash
```
* Install nxtrace from the APT repository
* Supports AMD64/ARM64 architectures
```shell
echo "deb [trusted=yes] https://github.com/nxtrace/nexttrace-debs/releases/latest/download ./" |
sudo tee /etc/apt/sources.list.d/nexttrace.list
sudo apt update
sudo apt install nexttrace
```
* APT repository maintained by wcbing and nxtrace
* Arch Linux AUR installation command
* Directly download bin package (only supports amd64)
```shell
yay -S nexttrace-bin
```
```shell
yay -S nexttrace-bin
```
* Build from source (only supports amd64)
```shell
yay -S nexttrace
```
```shell
yay -S nexttrace
```
* The AUR builds are maintained by ouuan, huyz
* Linuxbrew's installation command
Same as the macOS Homebrew's installation method (homebrew-core version only supports amd64)
* Linuxbrew's installation command
Same as the macOS Homebrew's installation method (homebrew-core version only supports amd64)
* Deepin installation command
```shell
apt install nexttrace
```
* Termux installation command
* [x-cmd](https://www.x-cmd.com/pkg/nexttrace) installation command
```shell
pkg install nexttrace-enhanced
x env use nexttrace
```
* Termux installation command
```shell
pkg install root-repo
pkg install nexttrace
```
* macOS
* macOS Homebrew's installation command
* Homebrew-core version
```shell
brew install nexttrace
```
```shell
brew install nexttrace
```
* This repository's ACTIONS automatically built version (updates faster)
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/nexttrace
```
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/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 WinGet installation command
* WinGet version
```powershell
winget install nexttrace
```
* WinGet build maintained by Dragon1573
* Windows Scoop installation command
* Scoop-extras version
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
* Scoop-extra is maintained by soenggam
* X-CMD
* [x-cmd](https://x-cmd.com) is a lightweight cross-platform package manager implemented in posix shell. Quickly download and execute `nexttrace` with a single command: [`x nexttrace`](https://x-cmd.com/pkg/nexttrace)
* You can also install `nexttrace` in the user level without requiring root privileges.
```shell
x env use nexttrace
```
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
@@ -128,21 +139,6 @@ Please note, the repositories for all of the above installation methods are main
* `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/nxtrace/NTrace-core@latest
```
*because of the version constraints conflict, you can not install `NTrace-V1` by this*
After installation, the executable is in the `$GOPATH/bin` directory. If you have not set `GOPATH`, it is in the `$HOME/go/bin` directory.
The binary file name is consistent with the project name. You need to replace the `nexttrace` command below with `NTrace-core`.
If you want to be consistent with the commands below, you can rename the binary after executing the `go install` command
```shell
mv $GOPATH/bin/NTrace-core $GOPATH/bin/nexttrace
```
### Get Started
`NextTrace` uses the `ICMP` protocol to perform TraceRoute requests by default, which supports both `IPv4` and `IPv6`
@@ -214,7 +210,7 @@ nexttrace --dev eth0 2606:4700:4700::1111
nexttrace --source 204.98.134.56 9.9.9.9
```
`NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests, but `UDP` protocols only supports `IPv4` now
`NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests
```bash
# TCP SYN Trace
@@ -226,7 +222,12 @@ nexttrace --tcp --port 443 2001:4860:4860::8888
# UDP Trace
nexttrace --udp 1.0.0.1
nexttrace --udp --port 53 1.0.0.1
# You can specify the target port yourself [here it is 5353], the default is port 33494
nexttrace --udp --port 5353 1.0.0.1
# For TCP/UDP Trace, you can specify the source port; by default, a fixed random port is used
# (if you need to use a different random source port for each packet, please set the ENV variable NEXTTRACE_RANDOMPORT)
nexttrace --tcp --source-port 14514 www.bing.com
```
`NextTrace` also supports some advanced functions, such as ttl control, concurrent probe packet count control, mode switching, etc.
@@ -387,6 +388,8 @@ Arguments:
-e --disable-mpls Disable MPLS
-v --version Print version info and exit
-s --source Use source src_addr for outgoing packets
--source-port Use source port src_port for outgoing
packets
-D --dev Use the following Network Devices as the
source address in outgoing packets
-z --send-time Set how many [milliseconds] between
@@ -457,6 +460,12 @@ The LeoMoeAPI data is subject to copyright restrictions from multiple data sourc
We hope you can give us as much feedback as possible on IP geolocation errors (see issue) so that it can be calibrated in the first place and others can benefit from it.
## AIWEN TECH Support
This project is sponsored by [AIWEN TECH](https://www.ipplus360.com). Were pleased to enhance the accuracy and completeness of this projects GEOIP lookups using `AIWEN TECH City-Level IP Database`, and to make it freely available to the public.
<img src="https://www.ipplus360.com/img/LOGO.c86cd0e1.svg" title="" alt="AIWEN TECH IP Geolocation Data" width="331">
## JetBrain Support
This Project uses [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport). We Proudly Develop By `Goland`.

View File

@@ -64,69 +64,78 @@ Document Language: [English](README.md) | 简体中文
* Linux
* 一键安装脚本
```shell
curl nxtrace.org/nt | bash
curl -sL nxtrace.org/nt | bash
```
* Arch Linux AUR 安装命令
* 直接下载bin包(仅支持amd64)
* 从 nxtrace的APT源安装
* 支持 AMD64/ARM64 架构
```shell
echo "deb [trusted=yes] https://github.com/nxtrace/nexttrace-debs/releases/latest/download ./" |
sudo tee /etc/apt/sources.list.d/nexttrace.list
sudo apt update
sudo apt install nexttrace
```
* APT源由 wcbing, nxtrace 维护
* Arch Linux AUR 安装命令
* 直接下载bin包(仅支持amd64)
```shell
yay -S nexttrace-bin
```
* 从源码构建(仅支持amd64)
```shell
yay -S nexttrace
```
* AUR 的构建分别由 ouuan, huyz 维护
```shell
yay -S nexttrace-bin
```
* 从源码构建(仅支持amd64)
```shell
yay -S nexttrace
```
* AUR 的构建分别由 ouuan, huyz 维护
* Linuxbrew 安装命令
同macOS Homebrew安装方法(homebrew-core版仅支持amd64)
* Deepin 安装命令
```shell
apt install nexttrace
```
* Deepin 安装命令
```shell
apt install nexttrace
```
* [x-cmd](https://cn.x-cmd.com/pkg/nexttrace) 安装命令
```shell
x env use nexttrace
```
* Termux 安装命令
```shell
pkg install nexttrace-enhanced
```
```shell
pkg install root-repo
pkg install nexttrace
```
* macOS
* macOS Homebrew 安装命令
* homebrew-core版
```shell
brew install nexttrace
```
* 本仓库ACTIONS自动构建版(更新更快)
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/nexttrace
```
* homebrew-core 构建由 chenrui333 维护请注意该版本更新可能会落后仓库Action自动构建版本
* homebrew-core版
```shell
brew install nexttrace
```
* 本仓库ACTIONS自动构建版(更新更快)
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/nexttrace
```
* homebrew-core 构建由 chenrui333 维护请注意该版本更新可能会落后仓库Action自动构建版本
* Windows
* Windows WinGet 安装命令
* WinGet 版
```powershell
winget install nexttrace
```
* WinGet 构建由 Dragon1573 维护
* Windows Scoop 安装命令
* scoop-extras版
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
* scoop-extra 由 soenggam 维护
* X-CMD
* [x-cmd](https://cn.x-cmd.com) 是一个使用 posix shell 实现的轻量级跨平台包管理器。使用单个命令快速下载并执行 `nexttrace` [`x nexttrace`](https://cn.x-cmd.com/pkg/nexttrace)
* 您还可以在用户级安装 `nexttrace`,且不需要 root 权限
```shell
x env use nexttrace
```
* scoop-extras
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
* scoop-extra 由 soenggam 维护
请注意,以上多种安装方式的仓库均由开源爱好者自行维护,不保证可用性和及时更新,如遇到问题请联系仓库维护者解决,或使用本项目官方编译提供的二进制包。
@@ -138,23 +147,6 @@ Document Language: [English](README.md) | 简体中文
* `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
* 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台出于实验性支持阶段。
* 从源码安装
您可在自行安装Go >= 1.20后,使用以下命令安装
```shell
go install github.com/nxtrace/NTrace-core@latest
```
*由于go.mod文件声明和文件目录冲突的问题你不能用go install命令安装 `NTrace-V1` 版本*
安装后可执行文件在`$GOPATH/bin`目录下,如果您没有设置`GOPATH`,则在`$HOME/go/bin`目录下。
安装后二进制文件名称与项目名称保持一致,你需要将下文中的 `nexttrace` 命令替换为 `NTrace-core` 使用
如果你希望与下文命令保持一致,可以在执行 `go install` 命令后重命名二进制文件
```shell
mv $GOPATH/bin/NTrace-core $GOPATH/bin/nexttrace
```
### Get Started
`NextTrace` 默认使用`ICMP`协议发起`TraceRoute`请求,该协议同时支持`IPv4`和`IPv6`
@@ -228,20 +220,23 @@ nexttrace --dev eth0 2606:4700:4700::1111
nexttrace --source 204.98.134.56 9.9.9.9
```
`NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求,不过目前`UDP`只支持`IPv4`
`NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求
```bash
# TCP SYN Trace
nexttrace --tcp www.bing.com
# 可以自行指定端口[此处为443]默认80端口
# 可以自行指定目标端口[此处为443]默认80端口
nexttrace --tcp --port 443 2001:4860:4860::8888
# UDP Trace
nexttrace --udp 1.0.0.1
# 可以自行指定端口[此处为5353]默认33494端口
# 可以自行指定目标端口[此处为5353]默认33494端口
nexttrace --udp --port 5353 1.0.0.1
# TCP/UDP Trace 可以自行指定源端口,默认使用随机一个固定的端口(如需每次发包随机使用不同的源端口,请设置`ENV` `NEXTTRACE_RANDOMPORT`)
nexttrace --tcp --source-port 14514 www.bing.com
```
`NextTrace`也同样支持一些进阶功能,如 TTL 控制、并发数控制、模式切换等
@@ -385,6 +380,8 @@ Arguments:
-e --disable-mpls Disable MPLS
-v --version Print version info and exit
-s --source Use source src_addr for outgoing packets
--source-port Use source port src_port for outgoing
packets
-D --dev Use the following Network Devices as the
source address in outgoing packets
-z --send-time Set how many [milliseconds] between
@@ -460,6 +457,12 @@ nexttrace --pow-provider sakura
[https://github.com/nxtrace/NextTraceroute](https://github.com/nxtrace/NextTraceroute)
<a href='https://play.google.com/store/apps/details?id=com.surfaceocean.nexttraceroute&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' width="128" height="48" src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>
## AIWEN TECH Support
本项目受 [埃文科技](https://www.ipplus360.com) 赞助。 很高兴使用`埃文科技城市级IP库`增强本项目 GEOIP 查询的准确性与完整性,并免费提供给公众。
<img src="https://www.ipplus360.com/img/LOGO.c86cd0e1.svg" title="" alt="埃文科技 IP 定位数据" width="331">
## JetBrain Support
本项目受 [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport) 支持。 很高兴使用`Goland`作为我们的开发工具。

View File

@@ -39,7 +39,7 @@ 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", "LeoMoeAPI", "leomoeapi", "disable-geoip"}, &argparse.Options{Default: "LeoMoeAPI",
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", "ipdb.one", "disable-geoip"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, IPInfoLocal, CHUNZHEN, disable-geoip]"})
powProvider := parser.Selector("", "pow-provider", []string{"api.nxtrace.org", "sakura"}, &argparse.Options{Default: "api.nxtrace.org",
Help: "Choose PoW Provider [api.nxtrace.org, sakura] For China mainland users, please use sakura"})
@@ -57,12 +57,13 @@ func Excute() {
disableMaptrace := parser.Flag("M", "map", &argparse.Options{Help: "Disable Print Trace Map"})
disableMPLS := parser.Flag("e", "disable-mpls", &argparse.Options{Help: "Disable MPLS"})
ver := parser.Flag("v", "version", &argparse.Options{Help: "Print version info and exit"})
srcAddr := parser.String("s", "source", &argparse.Options{Help: "Use source src_addr for outgoing packets"})
srcAddr := parser.String("s", "source", &argparse.Options{Help: "Use source address src_addr for outgoing packets"})
srcPort := parser.Int("", "source-port", &argparse.Options{Help: "Use source port src_port 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]"})
packetInterval := parser.Int("z", "send-time", &argparse.Options{Default: 50, Help: "Set how many [milliseconds] between sending each packet.. Useful when some routers use rate-limit for ICMP messages"})
packetInterval := parser.Int("z", "send-time", &argparse.Options{Default: 50, 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: 50, 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."})
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 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{
@@ -210,24 +211,19 @@ func Excute() {
//
//go func() {
// defer wg.Done()
if *udp {
if *ipv6Only {
fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
os.Exit(0)
}
if *ipv6Only {
ip, err = util.DomainLookUp(domain, "6", *dot, *jsonPrint)
} else if *ipv4Only {
ip, err = util.DomainLookUp(domain, "4", *dot, *jsonPrint)
} else {
if *ipv6Only {
ip, err = util.DomainLookUp(domain, "6", *dot, *jsonPrint)
} else if *ipv4Only {
ip, err = util.DomainLookUp(domain, "4", *dot, *jsonPrint)
} else {
ip, err = util.DomainLookUp(domain, "all", *dot, *jsonPrint)
}
ip, err = util.DomainLookUp(domain, "all", *dot, *jsonPrint)
}
if err != nil {
fmt.Println(err)
os.Exit(1)
//fmt.Println(err)
//os.Exit(1)
panic(err)
}
//}()
//
@@ -260,6 +256,7 @@ func Excute() {
var conf = trace.Config{
DN42: *dn42,
SrcAddr: *srcAddr,
SrcPort: *srcPort,
BeginHop: *beginHop,
DestIP: ip,
DestPort: *port,

View File

@@ -116,7 +116,7 @@ func (f *FastTracer) testEDU_v6() {
f.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CST)
}
func (f *FastTracer) testFast_v6() {
func (f *FastTracer) testFastBJ_v6() {
f.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CT163)
f.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU169)
f.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CM)
@@ -124,12 +124,24 @@ func (f *FastTracer) testFast_v6() {
//f.tracert_v6(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CST)
}
func (f *FastTracer) testFastSH_v6() {
f.tracert_v6(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CT163)
f.tracert_v6(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CU169)
f.tracert_v6(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CM)
}
func (f *FastTracer) testFastGZ_v6() {
f.tracert_v6(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CT163)
f.tracert_v6(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CU169)
f.tracert_v6(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CM)
}
func FastTestv6(traceMode trace.Method, outEnable bool, paramsFastTrace ParamsFastTrace) {
var c string
oe = outEnable
fmt.Println("您想测试哪些ISP的路由\n1. 北京三网快速测试\n2. 全国电信\n3. 全国联通\n4. 全国移动\n5. 全国教育网\n6. 全国五网")
fmt.Println("您想测试哪些ISP的路由\n1. 北京三网快速测试\n2. 上海三网快速测试\n3. 广州三网快速测试\n4. 全国电信\n5. 全国联通\n6. 全国移动\n7. 全国教育网\n8. 全国五网")
fmt.Print("请选择选项:")
_, err := fmt.Scanln(&c)
if err != nil {
@@ -154,24 +166,27 @@ func FastTestv6(traceMode trace.Method, outEnable bool, paramsFastTrace ParamsFa
case trace.TCPTrace:
ft.TracerouteMethod = trace.TCPTrace
case trace.UDPTrace:
fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
os.Exit(0)
ft.TracerouteMethod = trace.UDPTrace
}
switch c {
case "1":
ft.testFast_v6()
ft.testFastBJ_v6()
case "2":
ft.testCT_v6()
ft.testFastSH_v6()
case "3":
ft.testCU_v6()
ft.testFastGZ_v6()
case "4":
ft.testCM_v6()
ft.testCT_v6()
case "5":
ft.testEDU_v6()
ft.testCU_v6()
case "6":
ft.testCM_v6()
case "7":
ft.testEDU_v6()
case "8":
ft.testAll_v6()
default:
ft.testFast_v6()
ft.testFastBJ_v6()
}
}

View File

@@ -162,7 +162,7 @@ func FastTest(traceMode trace.Method, outEnable bool, paramsFastTrace ParamsFast
}
}
fmt.Println("您想测试哪些ISP的路由\n1. 北京三网快速测试\n2. 全国电信\n3. 全国联通\n4. 全国移动\n5. 全国教育网\n6. 全国五网")
fmt.Println("您想测试哪些ISP的路由\n1. 北京三网快速测试\n2. 上海三网快速测试\n3. 广州三网快速测试\n4. 全国电信\n5. 全国联通\n6. 全国移动\n7. 全国教育网\n8. 全国五网")
fmt.Print("请选择选项:")
_, err = fmt.Scanln(&c)
if err != nil {
@@ -192,19 +192,23 @@ func FastTest(traceMode trace.Method, outEnable bool, paramsFastTrace ParamsFast
switch c {
case "1":
ft.testFast()
ft.testFastBJ()
case "2":
ft.testCT()
ft.testFastSH()
case "3":
ft.testCU()
ft.testFastGZ()
case "4":
ft.testCM()
ft.testCT()
case "5":
ft.testEDU()
ft.testCU()
case "6":
ft.testCM()
case "7":
ft.testEDU()
case "8":
ft.testAll()
default:
ft.testFast()
ft.testFastBJ()
}
}
@@ -430,10 +434,22 @@ func (f *FastTracer) testEDU() {
f.tracert(TestIPsCollection.Hefei.Location, TestIPsCollection.Hefei.CST)
}
func (f *FastTracer) testFast() {
func (f *FastTracer) testFastBJ() {
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CT163)
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU169)
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CM)
//f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.EDU)
//f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CST)
}
func (f *FastTracer) testFastSH() {
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CT163)
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CU169)
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Beijing.CM)
}
func (f *FastTracer) testFastGZ() {
f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CT163)
f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CU169)
f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Beijing.CM)
}

33
go.mod
View File

@@ -1,40 +1,35 @@
module github.com/nxtrace/NTrace-core
go 1.22.10
go 1.24.5
require (
github.com/akamensky/argparse v1.4.0
github.com/google/gopacket v1.1.19
github.com/oschwald/maxminddb-golang v1.13.1
github.com/spf13/viper v1.19.0
github.com/spf13/viper v1.20.1
github.com/stretchr/testify v1.10.0
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
github.com/tsosunchia/powclient v0.1.5
golang.org/x/net v0.33.0
golang.org/x/sync v0.10.0
golang.org/x/net v0.42.0
golang.org/x/sync v0.16.0
)
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sagikazarmark/locafero v0.9.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.9.2 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
golang.org/x/text v0.27.0 // indirect
)
require (
@@ -45,6 +40,6 @@ require (
github.com/tidwall/gjson v1.18.0
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/sys v0.34.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

64
go.sum
View File

@@ -8,37 +8,32 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lionsoul2014/ip2region v2.11.2+incompatible h1:+VRsGcrHz8ewXI/2UzTptJlACsxD/p4xCxuql4u2nKU=
github.com/lionsoul2014/ip2region v2.11.2+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
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.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -48,20 +43,18 @@ github.com/rodaine/table v1.3.0 h1:4/3S3SVkHnVZX91EHFvAMV7K42AnJ0XuymRR2C5HlGE=
github.com/rodaine/table v1.3.0/go.mod h1:47zRsHar4zw0jgxGxL9YtFfs7EGN6B/TaS+/Dmk4WxU=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
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.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE=
github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
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=
@@ -89,33 +82,28 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

265
ipgeo/ipdbone.go Normal file
View File

@@ -0,0 +1,265 @@
package ipgeo
import (
"errors"
"io"
"net/http"
"strconv"
"sync"
"time"
"github.com/nxtrace/NTrace-core/config"
"github.com/nxtrace/NTrace-core/util"
"github.com/tidwall/gjson"
)
// Language mapping for IPDB.One API
var LangMap = map[string]string{
"en": "en",
"cn": "zh",
}
// IPDBOneConfig holds the configuration for IPDB.One service
type IPDBOneConfig struct {
BaseURL string
ApiID string
ApiKey string
}
// GetDefaultConfig returns the default configuration with fallback values
func GetDefaultConfig() *IPDBOneConfig {
return &IPDBOneConfig{
BaseURL: util.GetenvDefault("IPDBONE_BASE_URL", "https://api.ipdb.one"),
ApiID: util.GetenvDefault("IPDBONE_API_ID", ""),
ApiKey: util.GetenvDefault("IPDBONE_API_KEY", ""),
}
}
// IPDBOneTokenCache manages the caching of auth tokens
type IPDBOneTokenCache struct {
token string
expiresAt time.Time
mutex sync.RWMutex
}
// GetToken retrieves cached token if valid, otherwise returns empty string
func (c *IPDBOneTokenCache) GetToken() string {
c.mutex.RLock()
defer c.mutex.RUnlock()
if c.token == "" || time.Now().After(c.expiresAt) {
return ""
}
return c.token
}
// SetToken updates the token with its expiration time
func (c *IPDBOneTokenCache) SetToken(token string, expiresIn time.Duration) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.token = token
c.expiresAt = time.Now().Add(expiresIn)
}
// IPDBOneClient handles communication with IPDB.One API
type IPDBOneClient struct {
config *IPDBOneConfig
tokenCache *IPDBOneTokenCache
tokenInit sync.Once
httpClient *http.Client
}
// NewIPDBOneClient creates a new client for IPDB.One with default configuration
func NewIPDBOneClient() *IPDBOneClient {
return &IPDBOneClient{
config: GetDefaultConfig(),
tokenCache: &IPDBOneTokenCache{},
httpClient: &http.Client{
Timeout: 3 * time.Second,
},
}
}
// fetchToken requests a new authentication token from the API
func (c *IPDBOneClient) fetchToken() error {
authURL := c.config.BaseURL + "/auth/requestToken/query"
req, err := http.NewRequest("GET", authURL, nil)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "NextTrace/"+config.Version)
req.Header.Set("x-api-id", c.config.ApiID)
req.Header.Set("x-api-key", c.config.ApiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
statusCode := gjson.Get(string(body), "code").Int()
statusMessage := gjson.Get(string(body), "message").String()
if statusCode != 200 {
return errors.New("failed to authenticate: " + statusMessage)
}
token := gjson.Get(string(body), "data.token").String()
if token == "" {
return errors.New("authentication failed: empty token received")
}
// Cache token with a 30-second expiration
c.tokenCache.SetToken(token, 30*time.Second)
return nil
}
// ensureToken makes sure a valid token is available, fetching a new one if needed
func (c *IPDBOneClient) ensureToken() error {
var initErr error
// Ensure API credentials are set
if c.config.ApiID == "" || c.config.ApiKey == "" {
return errors.New("api id or api key is not set")
}
// Initialize token the first time this is called
c.tokenInit.Do(func() {
initErr = c.fetchToken()
})
if initErr != nil {
return initErr
}
// If token expired or not available, get a new one
if c.tokenCache.GetToken() == "" {
return c.fetchToken()
}
return nil
}
// LookupIP queries the IP information from IPDB.One
func (c *IPDBOneClient) LookupIP(ip string, lang string) (*IPGeoData, error) {
// Ensure we have a valid token
if err := c.ensureToken(); err != nil {
return &IPGeoData{}, nil
}
// Map language code if needed
langCode, ok := LangMap[lang]
if !ok {
langCode = "en" // Default to English
}
// Query the IP information
queryURL := c.config.BaseURL + "/query/" + ip + "?lang=" + langCode
req, err := http.NewRequest("GET", queryURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "NextTrace/"+config.Version)
req.Header.Set("Authorization", "Bearer "+c.tokenCache.GetToken())
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
statusCode := gjson.Get(string(body), "code").Int()
if statusCode != 200 {
return nil, errors.New("failed to get IP info: " + gjson.Get(string(body), "message").String())
}
return parseIPDBOneResponse(ip, body)
}
// parseIPDBOneResponse converts the API response to an IPGeoData struct
func parseIPDBOneResponse(ip string, responseBody []byte) (*IPGeoData, error) {
data := gjson.Get(string(responseBody), "data")
geoData := data.Get("geo")
routingData := data.Get("routing")
result := &IPGeoData{
IP: ip,
}
// Parse geo information if available
if geoData.Exists() {
coordinate := geoData.Get("coordinate")
if coordinate.Exists() && coordinate.Type != gjson.Null && coordinate.IsArray() && len(coordinate.Array()) >= 2 {
result.Lat = coordinate.Array()[0].Float()
result.Lng = coordinate.Array()[1].Float()
}
if geoData.Get("country").Exists() && geoData.Get("country").Type != gjson.Null {
result.Country = geoData.Get("country").String()
}
if geoData.Get("region").Exists() && geoData.Get("region").Type != gjson.Null {
result.Prov = geoData.Get("region").String()
}
if geoData.Get("city").Exists() && geoData.Get("city").Type != gjson.Null {
result.City = geoData.Get("city").String()
}
}
// Parse routing information if available
if routingData.Exists() {
asnData := routingData.Get("asn")
if asnData.Get("number").Exists() && asnData.Get("number").Type != gjson.Null {
result.Asnumber = strconv.FormatInt(asnData.Get("number").Int(), 10)
}
if routingData.Get("asn.name").Exists() && routingData.Get("asn.name").Type != gjson.Null {
result.Owner = routingData.Get("asn.name").String()
}
// Get domain, override owner
if routingData.Get("asn.domain").Exists() && routingData.Get("asn.domain").Type != gjson.Null {
result.Owner = routingData.Get("asn.domain").String()
}
// Get asname as Whois
if routingData.Get("asn.asname").Exists() && routingData.Get("asn.asname").Type != gjson.Null {
result.Whois = routingData.Get("asn.asname").String()
}
}
return result, nil
}
// Global client instance for backward compatibility
var defaultClient = NewIPDBOneClient()
// IPDBOne looks up IP information from IPDB.One (maintains backward compatibility)
func IPDBOne(ip string, timeout time.Duration, lang string, _ bool) (*IPGeoData, error) {
// Override timeout if specified
if timeout > 0 {
defaultClient.httpClient.Timeout = timeout
}
return defaultClient.LookupIP(ip, lang)
}

View File

@@ -52,6 +52,8 @@ func GetSource(s string) Source {
return Chunzhen
case "DISABLE-GEOIP":
return disableGeoIP
case "IPDB.ONE":
return IPDBOne
default:
return LeoIP
}

View File

@@ -83,6 +83,11 @@ func receiveParse() {
}
}
// 当前的实现中,每次调用 receiveParse() 都会锁定 WebSocket 连接
// 当前为单例模式,只启动一个 receiveParse 协程
var receiveParseOnce sync.Once
func LeoIP(ip string, timeout time.Duration, lang string, maptrace bool) (*IPGeoData, error) {
// TODO: 根据lang的值请求中文/英文API
// TODO: 根据maptrace的值决定是否请求经纬度信息
@@ -100,7 +105,10 @@ func LeoIP(ip string, timeout time.Duration, lang string, maptrace bool) (*IPGeo
// 发送请求
sendIPRequest(ip)
// 同步开启监听
go receiveParse()
// 确保 receiveParse 只启动一次
receiveParseOnce.Do(func() {
go receiveParse()
})
// 拥塞,等待数据返回
select {

View File

@@ -60,7 +60,7 @@ checkSystemDistribution() {
downloadBinrayFile() {
echo -e "${Info} 获取最新版的 NextTrace 发行版文件信息"
for i in {1..3}; do
downloadUrls=$(curl -sLf ${protocol}://www.nxtrace.org/api/dist/core/nexttrace_${osDistribution}_${archParam} --connect-timeout 1.5)
downloadUrls=$(curl -sLf ${protocol}://www.nxtrace.org/api/dist/core/nexttrace_${osDistribution}_${archParam} --connect-timeout 2)
if [ $? -eq 0 ]; then
break
fi
@@ -70,7 +70,7 @@ downloadBinrayFile() {
backupUrl=$(echo ${downloadUrls} | awk -F '|' '{print $2}')
echo -e "${Info} 正在尝试从 Primary 节点下载 NextTrace"
for i in {1..3}; do
curl -sLf ${primaryUrl} -o ${Temp_path} --connect-timeout 1.5
curl -sLf ${primaryUrl} -o ${Temp_path} --connect-timeout 2
if [ $? -eq 0 ]; then
changeMode
mv ${Temp_path} ${downPath}
@@ -84,7 +84,7 @@ downloadBinrayFile() {
fi
echo -e "${Error} 从 Primary 节点下载失败,正在尝试从 Backup 节点下载 NextTrace"
for i in {1..3}; do
curl -sLf ${backupUrl} -o ${Temp_path} --connect-timeout 1.5
curl -sLf ${backupUrl} -o ${Temp_path} --connect-timeout 2
if [ $? -eq 0 ]; then
changeMode
mv ${Temp_path} ${downPath}

View File

@@ -6,6 +6,9 @@ import (
"github.com/tsosunchia/powclient"
"net/url"
"os"
"os/signal"
"syscall"
"time"
)
const (
@@ -13,6 +16,9 @@ const (
)
func GetToken(fastIp string, host string, port string) (string, error) {
// 捕获中断信号
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
getTokenParams := powclient.NewGetTokenParams()
u := url.URL{Scheme: "https", Host: fastIp + ":" + port, Path: baseURL}
getTokenParams.BaseUrl = u.String()
@@ -26,20 +32,30 @@ func GetToken(fastIp string, host string, port string) (string, error) {
var (
token string
err error
done = make(chan bool)
)
// 尝试三次RetToken如果都失败了异常退出
for i := 0; i < 3; i++ {
token, err = powclient.RetToken(getTokenParams)
if err != nil {
continue
// 在 goroutine 中处理阻塞调用
go func() {
for i := 0; i < 3; i++ {
token, err = powclient.RetToken(getTokenParams)
if err != nil {
continue // 如果失败则重试
}
done <- true // 成功后通知主线程
return
}
//fmt.Println("GetToken success", token, getTokenParams.UserAgent)
return token, nil
done <- false // 失败后通知主线程
}()
select {
case <-sigChan: // 监听中断信号
return "", fmt.Errorf("Program interrupted by user ") // 添加返回值
case success := <-done: // 等待 goroutine 完成
if success {
return token, nil
}
return "", fmt.Errorf("RetToken failed 3 times, please try again later")
case <-time.After(10 * time.Second): // 超时处理
return "", fmt.Errorf("RetToken timed out(10s), please check your network") // 添加返回值
}
if err != nil {
fmt.Println(err)
}
fmt.Println("RetToken failed 3 times, please try again after a while, exit")
os.Exit(1)
return "", err
}

View File

@@ -13,12 +13,17 @@ type ReceivedMessage struct {
Err error
}
// PacketListener 负责监听网络数据包并通过通道传递接收到的消息
type PacketListener struct {
ctx context.Context
Conn net.PacketConn
Messages chan ReceivedMessage
}
// NewPacketListener 创建一个新的数据包监听器
// conn: 用于接收数据包的连接
// ctx: 用于控制监听器生命周期的上下文
// 返回初始化好的 PacketListener 实例
func NewPacketListener(conn net.PacketConn, ctx context.Context) *PacketListener {
results := make(chan ReceivedMessage, 50)

View File

@@ -211,7 +211,12 @@ func (t *TCPTracer) send(ttl int) error {
}
// 随机种子
r := rand.New(rand.NewSource(time.Now().UnixNano()))
_, srcPort := util.LocalIPPort(t.DestIP)
_, srcPort := func() (net.IP, int) {
if util.EnvRandomPort == "" && t.SrcPort != 0 {
return nil, t.SrcPort
}
return util.LocalIPPort(t.DestIP)
}()
ipHeader := &layers.IPv4{
SrcIP: t.SrcIP,
DstIP: t.DestIP,

View File

@@ -17,7 +17,7 @@ import (
"golang.org/x/sync/semaphore"
)
type TCPTracerv6 struct {
type TCPTracerIPv6 struct {
Config
wg sync.WaitGroup
res Result
@@ -35,7 +35,7 @@ type TCPTracerv6 struct {
fetchLock sync.Mutex
}
func (t *TCPTracerv6) Execute() (*Result, error) {
func (t *TCPTracerIPv6) Execute() (*Result, error) {
if len(t.res.Hops) > 0 {
return &t.res, ErrTracerouteExecuted
}
@@ -100,7 +100,7 @@ func (t *TCPTracerv6) Execute() (*Result, error) {
return &t.res, nil
}
func (t *TCPTracerv6) listenICMP() {
func (t *TCPTracerIPv6) listenICMP() {
lc := NewPacketListener(t.icmp, t.ctx)
go lc.Start()
for {
@@ -133,7 +133,7 @@ func (t *TCPTracerv6) listenICMP() {
// @title listenTCP
// @description 监听TCP的响应数据包
func (t *TCPTracerv6) listenTCP() {
func (t *TCPTracerIPv6) listenTCP() {
lc := NewPacketListener(t.tcp, t.ctx)
go lc.Start()
@@ -170,7 +170,7 @@ func (t *TCPTracerv6) listenTCP() {
}
}
func (t *TCPTracerv6) handleICMPMessage(msg ReceivedMessage) {
func (t *TCPTracerIPv6) handleICMPMessage(msg ReceivedMessage) {
var sequenceNumber = binary.BigEndian.Uint32(msg.Msg[52:56])
t.inflightRequestLock.Lock()
@@ -187,7 +187,7 @@ func (t *TCPTracerv6) handleICMPMessage(msg ReceivedMessage) {
// log.Println("发送成功")
}
func (t *TCPTracerv6) send(ttl int) error {
func (t *TCPTracerIPv6) send(ttl int) error {
err := t.sem.Acquire(context.Background(), 1)
if err != nil {
return err
@@ -200,7 +200,12 @@ func (t *TCPTracerv6) send(ttl int) error {
}
// 随机种子
r := rand.New(rand.NewSource(time.Now().UnixNano()))
_, srcPort := util.LocalIPPortv6(t.DestIP)
_, srcPort := func() (net.IP, int) {
if util.EnvRandomPort == "" && t.SrcPort != 0 {
return nil, t.SrcPort
}
return util.LocalIPPortv6(t.DestIP)
}()
ipHeader := &layers.IPv6{
SrcIP: t.SrcIP,
DstIP: t.DestIP,

View File

@@ -23,6 +23,7 @@ var (
type Config struct {
SrcAddr string
SrcPort int
BeginHop int
MaxHops int
NumMeasurements int
@@ -82,15 +83,13 @@ func Traceroute(method Method, config Config) (*Result, error) {
if config.DestIP.To4() != nil {
tracer = &UDPTracer{Config: config}
} else {
//TODO: IPv6 UDP trace 在做了,指新建文件夹(
return nil, errors.New("IPv6 UDP Traceroute is not supported")
tracer = &UDPTracerIPv6{Config: config}
}
case TCPTrace:
if config.DestIP.To4() != nil {
tracer = &TCPTracer{Config: config}
} else {
tracer = &TCPTracerv6{Config: config}
// return nil, errors.New("IPv6 TCP Traceroute is not supported")
tracer = &TCPTracerIPv6{Config: config}
}
default:
return &Result{}, ErrInvalidMethod

View File

@@ -4,6 +4,7 @@ import (
"log"
"math/rand"
"net"
"strconv"
"sync"
"time"
@@ -31,6 +32,7 @@ type UDPTracer struct {
sem *semaphore.Weighted
fetchLock sync.Mutex
udpMutex sync.Mutex
}
func (t *UDPTracer) Execute() (*Result, error) {
@@ -135,9 +137,10 @@ func (t *UDPTracer) handleICMPMessage(msg ReceivedMessage, data []byte) {
}
}
func (t *UDPTracer) getUDPConn(try int) (net.IP, int, net.PacketConn) {
srcIP, _ := util.LocalIPPort(t.DestIP)
var cachedLocalPort int
func (t *UDPTracer) getUDPConn(try int) (net.IP, int, net.PacketConn, error) {
srcIP, _ := util.LocalIPPort(t.DestIP)
var ipString string
if srcIP == nil {
ipString = ""
@@ -145,14 +148,40 @@ func (t *UDPTracer) getUDPConn(try int) (net.IP, int, net.PacketConn) {
ipString = srcIP.String()
}
udpConn, err := net.ListenPacket("udp", ipString+":0")
if err != nil {
if try > 3 {
log.Fatal(err)
// Check environment variable to decide caching behavior
if util.EnvRandomPort == "" {
if t.SrcPort != 0 {
cachedLocalPort = t.SrcPort
}
return t.getUDPConn(try + 1)
// Use cached random port logic
if cachedLocalPort == 0 {
// First time: listen on a random port
udpConn, err := net.ListenPacket("udp", ipString+":0")
if err != nil {
if try > 3 {
log.Fatal(err)
}
return srcIP, 0, nil, err
}
cachedLocalPort = udpConn.LocalAddr().(*net.UDPAddr).Port
// Close the initial connection after obtaining the port
udpConn.Close()
}
// Use the cached local port to establish a new connection
udpConn, err := net.ListenPacket("udp", ipString+":"+strconv.Itoa(cachedLocalPort))
if err != nil {
return srcIP, cachedLocalPort, nil, err
}
return srcIP, cachedLocalPort, udpConn, nil
} else {
// Without caching: create a new connection each time using a new random port
udpConn, err := net.ListenPacket("udp", ipString+":0")
if err != nil {
return srcIP, 0, nil, err
}
localPort := udpConn.LocalAddr().(*net.UDPAddr).Port
return srcIP, localPort, udpConn, nil
}
return srcIP, udpConn.LocalAddr().(*net.UDPAddr).Port, udpConn
}
func (t *UDPTracer) send(ttl int) error {
@@ -167,7 +196,15 @@ func (t *UDPTracer) send(ttl int) error {
return nil
}
srcIP, srcPort, udpConn := t.getUDPConn(0)
if util.EnvRandomPort == "" {
t.udpMutex.Lock()
defer t.udpMutex.Unlock()
}
srcIP, srcPort, udpConn, err := t.getUDPConn(0)
if err != nil {
return err
}
defer udpConn.Close()
//var payload []byte
@@ -244,7 +281,7 @@ func (t *UDPTracer) send(ttl int) error {
}
hopCh <- Hop{
Success: true,
Address: peer,
Address: &net.IPAddr{IP: peer.(*net.UDPAddr).IP},
}
}()
@@ -256,7 +293,6 @@ func (t *UDPTracer) send(ttl int) error {
if t.final != -1 && ttl > t.final {
return nil
}
if addr, ok := h.Address.(*net.IPAddr); ok && addr.IP.Equal(t.DestIP) {
t.finalLock.Lock()
if t.final == -1 || ttl < t.final {

394
trace/udp_ipv6.go Normal file
View File

@@ -0,0 +1,394 @@
package trace
import (
"log"
"math/rand"
"net"
"strconv"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/nxtrace/NTrace-core/util"
"golang.org/x/net/context"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
"golang.org/x/sync/semaphore"
)
type UDPTracerIPv6 struct {
Config
wg sync.WaitGroup
res Result
ctx context.Context
inflightRequest map[int]chan Hop
inflightRequestLock sync.Mutex
icmp net.PacketConn
final int
finalLock sync.Mutex
sem *semaphore.Weighted
fetchLock sync.Mutex
udpMutex sync.Mutex
}
func (t *UDPTracerIPv6) Execute() (*Result, error) {
if len(t.res.Hops) > 0 {
return &t.res, ErrTracerouteExecuted
}
var err error
t.icmp, err = icmp.ListenPacket("ip6:ipv6-icmp", "::")
if err != nil {
return &t.res, err
}
defer t.icmp.Close()
var cancel context.CancelFunc
t.ctx, cancel = context.WithCancel(context.Background())
defer cancel()
t.inflightRequest = make(map[int]chan Hop)
t.final = -1
go t.listenICMP()
t.sem = semaphore.NewWeighted(int64(t.ParallelRequests))
for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ {
// 如果到达最终跳,则退出
if t.final != -1 && ttl > t.final {
break
}
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.After(time.Millisecond * time.Duration(t.Config.TTLInterval))
}
go func() {
if t.AsyncPrinter != nil {
for {
t.AsyncPrinter(&t.res)
time.Sleep(200 * time.Millisecond)
}
}
}()
// 如果是表格模式,则一次性并发请求
if t.AsyncPrinter != nil {
t.wg.Wait()
}
t.res.reduce(t.final)
return &t.res, nil
}
func (t *UDPTracerIPv6) listenICMP() {
lc := NewPacketListener(t.icmp, t.ctx)
go lc.Start()
for {
select {
case <-t.ctx.Done():
return
case msg := <-lc.Messages:
if msg.N == nil {
continue
}
rm, err := icmp.ParseMessage(58, msg.Msg[:*msg.N])
if err != nil {
log.Println(err)
continue
}
switch rm.Type {
case ipv6.ICMPTypeTimeExceeded:
t.handleICMPMessage(msg)
case ipv6.ICMPTypeDestinationUnreachable:
t.handleICMPMessage(msg)
default:
// log.Println("received icmp message of unknown type", rm.Type)
}
}
}
}
// handleICMPMessage 处理 ICMPv6 消息并提取 UDP 源端口
//
// ICMPv6 错误消息格式:
// - ICMPv6 头部 (8 字节)
// - 原始 IPv6 包 (包含 IPv6 头部和 UDP 头部)
//
// 处理步骤:
// 1. 验证消息长度
// 2. 解析 ICMPv6 头部
// 3. 提取原始 IPv6 包
// 4. 处理可能的扩展头部
// 5. 提取 UDP 源端口
// 6. 发送结果到对应通道
func (t *UDPTracerIPv6) handleICMPMessage(msg ReceivedMessage) {
// ICMPv6 错误消息至少需要包含 IPv6 头部(40字节)和部分 UDP 头部
if len(msg.Msg) < 48 {
return
}
// 尝试解析 ICMPv6 消息中包含的原始数据包
var offset int = 8 // ICMPv6 头部长度
// 检查剩余长度是否足够包含 IPv6 头部
if len(msg.Msg) < offset+40 {
return
}
// 验证 IPv6 版本 (前4位应该是6)
if (msg.Msg[offset] >> 4) != 6 {
return
}
// 获取下一个头部类型
nextHeader := msg.Msg[offset+6]
// 跳过 IPv6 基本头部
offset += 40
// 处理可能的扩展头部
for nextHeader != 17 && offset+2 < len(msg.Msg) { // 17 是 UDP 协议号
switch nextHeader {
case 0: // Hop-by-Hop Options
case 43: // Routing
case 44: // Fragment
case 50: // ESP
case 51: // AH
case 60: // Destination Options
if offset+2 >= len(msg.Msg) {
return // 不够长,无法读取扩展头部长度
}
nextHeader = msg.Msg[offset]
headerLen := int(msg.Msg[offset+1])*8 + 8
offset += headerLen
default:
// 未知或不支持的扩展头部类型
return
}
}
// 确认下一个头部是 UDP (17)
if nextHeader != 17 {
return
}
// 确保有足够的数据来读取 UDP 源端口
if offset+2 > len(msg.Msg) {
return
}
// 从 UDP 头部提取源端口(前2字节)
srcPort := int(uint16(msg.Msg[offset])<<8 | uint16(msg.Msg[offset+1]))
t.inflightRequestLock.Lock()
defer t.inflightRequestLock.Unlock()
ch, ok := t.inflightRequest[srcPort]
if !ok {
return
}
ch <- Hop{
Success: true,
Address: msg.Peer,
}
}
var cachedLocalPortv6 int
func (t *UDPTracerIPv6) getUDPConn(try int) (net.IP, int, net.PacketConn, error) {
srcIP, _ := util.LocalIPPortv6(t.DestIP)
var ipString string
if srcIP == nil {
ipString = "::"
} else {
ipString = srcIP.String()
}
// Check environment variable to decide caching behavior
if util.EnvRandomPort == "" {
if t.SrcPort != 0 {
cachedLocalPortv6 = t.SrcPort
}
// Use cached random port logic
if cachedLocalPortv6 == 0 {
// First time: listen on a random port
udpConn, err := net.ListenPacket("udp6", "["+ipString+"]:0")
if err != nil {
if try > 3 {
log.Fatal(err)
}
return srcIP, 0, nil, err
}
cachedLocalPortv6 = udpConn.LocalAddr().(*net.UDPAddr).Port
// Close the initial connection after obtaining the port
udpConn.Close()
}
// Use the cached local port to establish a new connection
udpConn, err := net.ListenPacket("udp6", "["+ipString+"]:"+strconv.Itoa(cachedLocalPortv6))
if err != nil {
return srcIP, cachedLocalPortv6, nil, err
}
return srcIP, cachedLocalPortv6, udpConn, nil
} else {
// Without caching: create a new connection each time using a new random port
udpConn, err := net.ListenPacket("udp6", "["+ipString+"]:0")
if err != nil {
return srcIP, 0, nil, err
}
localPort := udpConn.LocalAddr().(*net.UDPAddr).Port
return srcIP, localPort, udpConn, nil
}
}
func (t *UDPTracerIPv6) send(ttl int) error {
err := t.sem.Acquire(context.Background(), 1)
if err != nil {
return err
}
defer t.sem.Release(1)
defer t.wg.Done()
if t.final != -1 && ttl > t.final {
return nil
}
if util.EnvRandomPort == "" {
t.udpMutex.Lock()
defer t.udpMutex.Unlock()
}
srcIP, srcPort, udpConn, err := t.getUDPConn(0)
if err != nil {
return err
}
defer udpConn.Close()
ipHeader := &layers.IPv6{
SrcIP: srcIP,
DstIP: t.DestIP,
NextHeader: layers.IPProtocolUDP,
HopLimit: uint8(ttl),
}
udpHeader := &layers.UDP{
SrcPort: layers.UDPPort(srcPort),
DstPort: layers.UDPPort(t.DestPort),
}
_ = udpHeader.SetNetworkLayerForChecksum(ipHeader)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
desiredPayloadSize := t.Config.PktSize
if desiredPayloadSize-8 > 0 {
desiredPayloadSize -= 8
}
payload := make([]byte, desiredPayloadSize)
// 设置随机种子
rand.Seed(time.Now().UnixNano())
// 填充随机数
for i := range payload {
payload[i] = byte(rand.Intn(256))
}
if err := gopacket.SerializeLayers(buf, opts, udpHeader, gopacket.Payload(payload)); err != nil {
return err
}
err = ipv6.NewPacketConn(udpConn).SetHopLimit(ttl)
if err != nil {
return err
}
start := time.Now()
if _, err := udpConn.WriteTo(buf.Bytes(), &net.UDPAddr{IP: t.DestIP, Port: t.DestPort}); err != nil {
return err
}
// 在对inflightRequest进行写操作的时候应该加锁保护以免多个goroutine协程试图同时写入造成panic
t.inflightRequestLock.Lock()
hopCh := make(chan Hop, 1)
t.inflightRequest[srcPort] = hopCh
t.inflightRequestLock.Unlock()
defer func() {
t.inflightRequestLock.Lock()
close(hopCh)
delete(t.inflightRequest, srcPort)
t.inflightRequestLock.Unlock()
}()
go func() {
reply := make([]byte, 1500)
_, peer, err := udpConn.ReadFrom(reply)
if err != nil {
// probably because we closed the connection
return
}
hopCh <- Hop{
Success: true,
Address: &net.IPAddr{IP: peer.(*net.UDPAddr).IP},
}
}()
select {
case <-t.ctx.Done():
return nil
case h := <-hopCh:
rtt := time.Since(start)
if t.final != -1 && ttl > t.final {
return nil
}
if addr, ok := h.Address.(*net.IPAddr); ok && addr.IP.Equal(t.DestIP) {
t.finalLock.Lock()
if t.final == -1 || ttl < t.final {
t.final = ttl
}
t.finalLock.Unlock()
} else if addr, ok := h.Address.(*net.UDPAddr); ok && addr.IP.Equal(t.DestIP) {
t.finalLock.Lock()
if t.final == -1 || ttl < t.final {
t.final = ttl
}
t.finalLock.Unlock()
}
h.TTL = ttl
h.RTT = rtt
t.fetchLock.Lock()
defer t.fetchLock.Unlock()
err := h.fetchIPData(t.Config)
if err != nil {
return err
}
t.res.add(h)
case <-time.After(t.Timeout):
if t.final != -1 && ttl > t.final {
return nil
}
t.res.add(Hop{
Success: false,
Address: nil,
TTL: ttl,
RTT: 0,
Error: ErrHopLimitTimeout,
})
}
return nil
}

View File

@@ -23,7 +23,7 @@ func GetMapUrl(r string) (string, error) {
if len(strings.Split(fastIp, ":")) > 1 {
fastIp = "[" + fastIp + "]"
}
host = "origin-fallback.nxtrace.org"
host = "api.nxtrace.org"
} else {
// 默认配置完成,开始寻找最优 IP
fastIp = util.GetFastIP(host, port, false)

View File

@@ -7,6 +7,8 @@ import (
"log"
"net"
"net/http"
"os"
"os/signal"
"strings"
"time"
@@ -28,7 +30,7 @@ var FastIpCache = ""
func GetFastIP(domain string, port string, enableOutput bool) string {
proxyUrl := GetProxy()
if proxyUrl != nil {
return "origin-fallback.nxtrace.org"
return "api.nxtrace.org"
}
if FastIpCache != "" {
return FastIpCache
@@ -36,7 +38,7 @@ func GetFastIP(domain string, port string, enableOutput bool) string {
var ips []net.IP
var err error
if domain == "origin-fallback.nxtrace.org" {
if domain == "api.nxtrace.org" {
ips, err = net.LookupIP("api.nxtrace.org")
} else {
ips, err = net.LookupIP(domain)
@@ -57,12 +59,17 @@ func GetFastIP(domain string, port string, enableOutput bool) string {
var result ResponseInfo
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
select {
case result = <-results:
//等待5s没有结果 视为连不上API了
// 正常返回结果
case <-time.After(timeout):
log.Println("IP connection has been timeout, please check your network")
log.Println("IP connection has been timeout(5s), please check your network")
case <-sigChan: // 响应中断信号
log.Println("Program interrupted by user")
os.Exit(0)
}
//if len(ips) > 0 {
@@ -115,6 +122,7 @@ func checkLatency(domain string, ip string, port string) {
return
}
req.Host = domain
req.Header.Add("User-Agent", UserAgent)
resp, err := client.Do(req)
if err != nil {
//results <- ResponseInfo{IP: ip, Latency: "error", Content: ""}

View File

@@ -16,15 +16,22 @@ import (
"github.com/fatih/color"
)
var Uninterrupted = GetenvDefault("NEXTTRACE_UNINTERRUPTED", "")
var EnvToken = GetenvDefault("NEXTTRACE_TOKEN", "")
var EnvIPInfoLocalPath = GetenvDefault("NEXTTRACE_IPINFOLOCALPATH", "")
var UserAgent = fmt.Sprintf("NextTrace %s/%s/%s", config.Version, runtime.GOOS, runtime.GOARCH)
var RdnsCache sync.Map
var PowProviderParam = ""
var DisableMPLS = GetenvDefault("NEXTTRACE_DISABLEMPLS", "")
var EnableHidDstIP = GetenvDefault("NEXTTRACE_ENABLEHIDDENDSTIP", "")
var EnvIPInfoLocalPath = GetenvDefault("NEXTTRACE_IPINFOLOCALPATH", "")
var EnvRandomPort = GetenvDefault("NEXTTRACE_RANDOMPORT", "")
var EnvToken = GetenvDefault("NEXTTRACE_TOKEN", "")
var Uninterrupted = GetenvDefault("NEXTTRACE_UNINTERRUPTED", "")
var DestIP string
var PowProviderParam = ""
var RdnsCache sync.Map
var UserAgent = fmt.Sprintf("NextTrace %s/%s/%s", config.Version, runtime.GOOS, runtime.GOARCH)
var cachedLocalIP net.IP
var cachedLocalPort int
var localIPOnce sync.Once
var cachedLocalIPv6 net.IP
var cachedLocalPort6 int
var localIPv6Once sync.Once
func LookupAddr(addr string) ([]string, error) {
// 如果在缓存中找到,直接返回
@@ -44,37 +51,69 @@ func LookupAddr(addr string) ([]string, error) {
return names, nil
}
// LocalIPPort get the local ip and port based on our destination ip
func LocalIPPort(dstip net.IP) (net.IP, int) {
// getLocalIPPort encapsulates the logic to get local IP and port via a UDP connection
func getLocalIPPort(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345")
if err != nil {
log.Fatal(err)
}
con, err := net.DialUDP("udp", nil, serverAddr)
if err != nil {
return nil, -1
}
defer con.Close()
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
return udpaddr.IP, udpaddr.Port
}
return nil, -1
}
// We don't actually connect to anything, but we can determine
// based on our destination ip what source ip we should use.
if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
defer con.Close()
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
return udpaddr.IP, udpaddr.Port
}
// getLocalIPPortv6 encapsulates the logic to get local IPv6 and port via a UDP connection
func getLocalIPPortv6(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", "["+dstip.String()+"]:12345")
if err != nil {
log.Fatal(err)
}
con, err := net.DialUDP("udp", nil, serverAddr)
if err != nil {
return nil, -1
}
defer con.Close()
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
return udpaddr.IP, udpaddr.Port
}
return nil, -1
}
// LocalIPPort returns the local IP and port based on our destination IP, with caching unless EnvRandomPort is set.
func LocalIPPort(dstip net.IP) (net.IP, int) {
// If EnvRandomPort is set, bypass caching and return a new port every time.
if EnvRandomPort != "" {
return getLocalIPPort(dstip)
}
// Otherwise, use the cached value (computed only once).
localIPOnce.Do(func() {
cachedLocalIP, cachedLocalPort = getLocalIPPort(dstip)
})
if cachedLocalIP != nil {
return cachedLocalIP, cachedLocalPort
}
return nil, -1
}
func LocalIPPortv6(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", "["+dstip.String()+"]:12345")
if err != nil {
log.Fatal(err)
// If EnvRandomPort is set, bypass caching and return a new port every time.
if EnvRandomPort != "" {
return getLocalIPPortv6(dstip)
}
// We don't actually connect to anything, but we can determine
// based on our destination ip what source ip we should use.
if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
defer con.Close()
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
return udpaddr.IP, udpaddr.Port
}
// Otherwise, use the cached value (computed only once).
localIPv6Once.Do(func() {
cachedLocalIPv6, cachedLocalPort6 = getLocalIPPortv6(dstip)
})
if cachedLocalIPv6 != nil {
return cachedLocalIPv6, cachedLocalPort6
}
return nil, -1
}
@@ -169,7 +208,7 @@ func GetenvDefault(key, defVal string) string {
}
func GetHostAndPort() (host string, port string) {
var hostP = GetenvDefault("NEXTTRACE_HOSTPORT", "origin-fallback.nxtrace.org")
var hostP = GetenvDefault("NEXTTRACE_HOSTPORT", "api.nxtrace.org")
// 解析域名
hostArr := strings.Split(hostP, ":")
// 判断是否有指定端口

View File

@@ -104,16 +104,16 @@ func (c *WsConn) messageSendHandler() {
err := c.Conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
// log.Println("write close:", err)
os.Exit(1)
//os.Exit(1)
panic(err)
}
select {
// 等到了结果,直接退出
case <-c.Done:
// 如果等待 1s 还是拿不到结果,不再等待,超时退出
case <-time.After(time.Second):
case <-time.After(1 * time.Second):
}
os.Exit(1)
// return
os.Exit(0)
}
}
}
@@ -134,8 +134,9 @@ func (c *WsConn) recreateWsConn() {
jwtToken, err = pow.GetToken(util.GetPowProvider(), util.GetPowProvider(), port)
}
if err != nil {
log.Println(err)
os.Exit(1)
//log.Println(err)
//os.Exit(1)
panic(err)
}
} else {
// 使用 cacheToken
@@ -192,7 +193,7 @@ func createWsConn() *WsConn {
if len(strings.Split(fastIp, ":")) > 1 {
fastIp = "[" + fastIp + "]"
}
host = "origin-fallback.nxtrace.org"
host = "api.nxtrace.org"
} else {
// 默认配置完成,开始寻找最优 IP
fastIp = util.GetFastIP(host, port, true)
@@ -206,8 +207,9 @@ func createWsConn() *WsConn {
jwtToken, err = pow.GetToken(util.GetPowProvider(), util.GetPowProvider(), port)
}
if err != nil {
log.Println(err)
os.Exit(1)
//log.Println(err)
//os.Exit(1)
panic(err)
}
ua = []string{util.UserAgent}
}