mirror of
https://github.com/nxtrace/NTrace-core.git
synced 2025-08-12 06:26:39 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91cd4fb8f4 | ||
|
|
336151dc1b | ||
|
|
66ee62f22b | ||
|
|
3afd28cb89 | ||
|
|
690f546ff0 | ||
|
|
d561063a7c | ||
|
|
473ce3c5f2 | ||
|
|
a1783e3563 | ||
|
|
7b9912f23f | ||
|
|
fdeaf112f5 | ||
|
|
07a2aac7c7 | ||
|
|
08f8daf9ce | ||
|
|
7872e9ee0f | ||
|
|
991f66cfe4 | ||
|
|
5b91fac860 | ||
|
|
62e877e248 | ||
|
|
9e4b2ae577 | ||
|
|
b02572d6ff | ||
|
|
e5742e1603 | ||
|
|
70a727bee6 | ||
|
|
1261e243f2 | ||
|
|
49ce0cba8e | ||
|
|
9764533c8e | ||
|
|
d752385c29 | ||
|
|
bf005fb37a | ||
|
|
8dc5960d98 | ||
|
|
ef104673b8 | ||
|
|
46545bd8d9 | ||
|
|
a4124b50aa | ||
|
|
b09d4bab74 | ||
|
|
09e493ebc3 | ||
|
|
3d665ee03c | ||
|
|
493328c7be | ||
|
|
e2d778c34d | ||
|
|
bf54b61eb8 | ||
|
|
9cec64b207 | ||
|
|
23006acd9f |
@@ -5,7 +5,7 @@ set -e
|
||||
DIST_PREFIX="nexttrace"
|
||||
DEBUG_MODE=${2}
|
||||
TARGET_DIR="dist"
|
||||
PLATFORMS="darwin/amd64 darwin/arm64 linux/386 linux/amd64 linux/arm64 linux/mips openbsd/amd64 openbsd/arm64 freebsd/amd64 freebsd/arm64"
|
||||
PLATFORMS="darwin/amd64 darwin/arm64 linux/386 linux/amd64 linux/arm64 linux/mips windows/amd64 windows/arm64 openbsd/amd64 openbsd/arm64 freebsd/amd64 freebsd/arm64"
|
||||
|
||||
BUILD_VERSION="$(git describe --tags --always)"
|
||||
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
||||
@@ -15,6 +15,7 @@ rm -rf ${TARGET_DIR}
|
||||
mkdir ${TARGET_DIR}
|
||||
|
||||
for pl in ${PLATFORMS}; do
|
||||
export CGO_ENABLED=0
|
||||
export GOOS=$(echo ${pl} | cut -d'/' -f1)
|
||||
export GOARCH=$(echo ${pl} | cut -d'/' -f2)
|
||||
export TARGET=${TARGET_DIR}/${DIST_PREFIX}_${GOOS}_${GOARCH}
|
||||
@@ -37,7 +38,7 @@ for pl in ${PLATFORMS}; do
|
||||
-w -s"
|
||||
fi
|
||||
done
|
||||
|
||||
export CGO_ENABLED=0
|
||||
export GOOS='linux'
|
||||
export GOARCH='arm'
|
||||
export GOARM='7'
|
||||
|
||||
39
.github/workflows/build.yml
vendored
39
.github/workflows/build.yml
vendored
@@ -41,44 +41,11 @@ jobs:
|
||||
dist/nexttrace_linux_arm64
|
||||
dist/nexttrace_linux_armv7
|
||||
dist/nexttrace_linux_mips
|
||||
dist/nexttrace_windows_amd64.exe
|
||||
dist/nexttrace_windows_arm64.exe
|
||||
dist/nexttrace_openbsd_amd64
|
||||
dist/nexttrace_openbsd_arm64
|
||||
dist/nexttrace_freebsd_amd64
|
||||
dist/nexttrace_freebsd_arm64
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GT_Token }}
|
||||
publish-new-formula:
|
||||
# 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:
|
||||
# Runs a single command using the runners shell
|
||||
- name: config git
|
||||
run: |
|
||||
git config --global user.email "${{ secrets.git_mail }}"
|
||||
git config --global user.name "${{ secrets.git_name }}"
|
||||
- name: Clone repo
|
||||
run: |
|
||||
git clone https://github.com/xgadget-lab/homebrew-nexttrace.git
|
||||
- name: Exec scipt
|
||||
run: |
|
||||
cd homebrew-nexttrace
|
||||
bash genFormula.sh
|
||||
# - name: setup SSH keys and known_hosts
|
||||
# run: |
|
||||
# mkdir -p ~/.ssh
|
||||
# ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
# ssh-agent -a $SSH_AUTH_SOCK > /dev/null
|
||||
# ssh-add - <<< "${{ secrets.ID_RSA }}"
|
||||
# env:
|
||||
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
|
||||
- name: Git Push
|
||||
run: |
|
||||
cd homebrew-nexttrace
|
||||
git commit -am 'Publish a new version with Formula'
|
||||
git remote set-url origin https://${{ secrets.gt_token }}@github.com/xgadget-lab/homebrew-nexttrace.git
|
||||
git push || 1
|
||||
# env:
|
||||
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
|
||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||
GITHUB_TOKEN: ${{ secrets.GT_Token }}
|
||||
1
.github/workflows/publishNewFormula.yml
vendored
1
.github/workflows/publishNewFormula.yml
vendored
@@ -3,6 +3,7 @@ name: Publish New Formula
|
||||
# Controls when the action will run. Workflow runs when manually triggered using the UI
|
||||
# or API.
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
|
||||
84
README.md
84
README.md
@@ -12,20 +12,34 @@ An open source visual routing tool that pursues light weight, developed using Go
|
||||
|
||||
NextTrace has a total of 2 versions, the Lite version focusing on lightweight and the [Enhanced version](#nexttrace-enhanced) which is more enthusiast-oriented.
|
||||
|
||||
PS: Our Lite version does not provide OSM based geolocation visualization, we provide this parameter in the enhanced version if needed.
|
||||
|
||||
## IP Data Copyright
|
||||
|
||||
NextTrace 重点在于研究 Go 语言 Traceroute 的实现,其 LeoMoeAPI 的地理位置信息并没有原始数据的支撑,故也不可能有商用版本。
|
||||
|
||||
LeoMoeAPI 的数据受到多家数据源的版权限制,**仅供路由跟踪地理位置的展示参考使用**,我们不对数据提供准度做任何保证,如用于其他用途后果自负,特此告知。
|
||||
|
||||
NextTrace focuses on Golang Traceroute implementations, and its LeoMoeAPI geolocation information is not supported by raw data, so a commercial version is not possible.
|
||||
|
||||
The LeoMoeAPI data is subject to copyright restrictions from multiple data sources, and is only used for the purpose of displaying the geolocation of route tracing.
|
||||
|
||||
## How To Use
|
||||
|
||||
### Automated Installation
|
||||
|
||||
```bash
|
||||
# Linux one-click install script
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/xgadget-lab/nexttrace/main/nt_install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
|
||||
|
||||
# macOS brew install command
|
||||
brew tap xgadget-lab/nexttrace && brew install nexttrace
|
||||
```
|
||||
|
||||
Windows users please go to [Release Page](https://github.com/sjlleo/nexttrace/releases/latest) directly and download exe file.
|
||||
|
||||
- `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 not available on `Windows` platform.
|
||||
- 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
|
||||
|
||||
@@ -52,6 +66,17 @@ nexttrace -f
|
||||
nexttrace -f -T
|
||||
```
|
||||
|
||||
`NextTrace` already supports route tracing for specified Network Devices
|
||||
|
||||
```bash
|
||||
# Use eth0 network interface
|
||||
nexttrace -D eth0 2606:4700:4700::1111
|
||||
|
||||
# Use eth0 network interface's IP
|
||||
# When using the network interface's IP for route tracing, note that the IP type to be traced should be the same as network interface's IP type (e.g. both IPv4)
|
||||
nexttrace -S 204.98.134.56 9.9.9.9
|
||||
```
|
||||
|
||||
`NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests, but these protocols only supports `IPv4` now
|
||||
|
||||
```bash
|
||||
@@ -115,9 +140,11 @@ nexttrace -T -q 2 -r 1 -table -report 2001:4860:4860::8888
|
||||
|
||||
### IP Database
|
||||
|
||||
The IP database is set to our own API service by default. If we encounter abuse, we may choose to close it.
|
||||
#### We use [bgp.tools](https://bgp.tools) as a data provider for routing tables.
|
||||
|
||||
We will also open-source the source code of the server in the near future, therefore you can also build your own API server according to the source code of the project by then.
|
||||
NextTrace BackEnd is now open-source.
|
||||
|
||||
https://github.com/sjlleo/nexttrace-backend
|
||||
|
||||
All NextTrace IP geolocation `API DEMO` can refer to [here](https://github.com/xgadget-lab/nexttrace/blob/main/ipgeo/)
|
||||
|
||||
@@ -152,7 +179,7 @@ Options:
|
||||
|
||||
## Project screenshot
|
||||
|
||||

|
||||

|
||||
|
||||
## NextTrace Enhanced
|
||||
|
||||
@@ -162,6 +189,8 @@ The `Enhanced` version supports many functions that the `lite` version does not
|
||||
|
||||
https://github.com/OwO-Network/nexttrace-enhanced
|
||||
|
||||
#
|
||||
|
||||
## FAQ Frequently Asked Questions
|
||||
|
||||
If you encounter problems while installing or using it, we do not recommend you to choose creating an `issue` as a preference
|
||||
@@ -173,12 +202,14 @@ Here is our recommended troubleshooting process:
|
||||
|
||||
## JetBrain Support
|
||||
|
||||
### This Project uses [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport). We Proudly Develop By Goland.
|
||||
#### This Project uses [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport). We Proudly Develop By Goland.
|
||||
|
||||

|
||||
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/GoLand.png" title="" alt="GoLand logo" width="331">
|
||||
|
||||
## Credits
|
||||
|
||||
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)
|
||||
|
||||
[Sam Sam](https://github.com/samleong123) (samsam123@samsam123.name.my)
|
||||
@@ -187,44 +218,7 @@ Here is our recommended troubleshooting process:
|
||||
|
||||
[waiting4new](https://github.com/waiting4new)
|
||||
|
||||
[FFEE_CO](https://github.com/fkx4-p)
|
||||
|
||||
## IP Database Copyright
|
||||
|
||||
### IPv4 Database
|
||||
|
||||
#### China
|
||||
|
||||
| ISP | Type | Data Source | Proportion |
|
||||
|:---------------------------:|:--------:|:--------------------:|:----------:|
|
||||
| China Telecom/Unicom/Mobile | Backbone | Internet Enthusiasts | 10% |
|
||||
| China Telecom/Unicom/Mobile | Local | Avon Technology | 90% |
|
||||
|
||||
#### WorldWide
|
||||
|
||||
##### Tier 1
|
||||
|
||||
| ISP | Type | Data Source | Proportion |
|
||||
|:-------:|:--------:|:---------------:|:----------:|
|
||||
| Tier 1 | Backbone | IPInfo | 2% |
|
||||
| Tier 1 | Backbone | Avon Technology | 3% |
|
||||
| Tier 1 | Backbone | IPInSight | 5% |
|
||||
| Tier 1 | Local | IPInSight | 90% |
|
||||
|
||||
##### General
|
||||
|
||||
| ISP | Type | Data Source | Proportion |
|
||||
|:------:|:--------:|:-----------:|:----------:|
|
||||
| General | Backbone | IPInSight | 5% |
|
||||
| General | Local | IPInSight | 95% |
|
||||
|
||||
### IPv6 Database
|
||||
|
||||
| ISP | Type | Data Source | Proportion |
|
||||
|:---:|:----:|:----------------:|:----------:|
|
||||
| All | All | IP2Location Lite | 100% |
|
||||
|
||||
This product includes IP2Location LITE data available from <a href="https://lite.ip2location.com">https://lite.ip2location.com</a>.
|
||||
[FFEE_CO](https://github.com/fkx4-p)
|
||||
|
||||
### Others
|
||||
|
||||
|
||||
@@ -10,23 +10,27 @@
|
||||
|
||||
NextTrace 一共有2个版本,专注于轻量的 Lite 版本以及更面向发烧友的 [Enhanced 版本](#nexttrace-enhanced)。
|
||||
|
||||
PS: Lite 版本追求轻量化,并不提供基于高德地图 / OpenStreetMap 的路由可视化功能,如有需要,请使用 Enhanced 版本。
|
||||
|
||||
## How To Use
|
||||
|
||||
### Automated Install
|
||||
|
||||
```bash
|
||||
# Linux 一键安装脚本
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/xgadget-lab/nexttrace/main/nt_install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
|
||||
|
||||
# GHPROXY 镜像(国内使用)
|
||||
bash <(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/xgadget-lab/nexttrace/main/nt_install.sh)
|
||||
bash <(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
|
||||
|
||||
# macOS brew 安装命令
|
||||
brew tap xgadget-lab/nexttrace && brew install nexttrace
|
||||
```
|
||||
|
||||
Windows 用户请直接前往 [Release](https://github.com/sjlleo/nexttrace/releases/latest) 下载编译后的二进制 exe 文件。
|
||||
|
||||
- `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
|
||||
- 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台不可用。
|
||||
- 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台出于实验性支持阶段。
|
||||
|
||||
### Get Started
|
||||
|
||||
@@ -44,6 +48,7 @@ nexttrace 2606:4700:4700::1111
|
||||
```
|
||||
|
||||
`NextTrace` 现已经支持快速测试,有一次性测试回程路由需求的朋友可以使用
|
||||
|
||||
```bash
|
||||
# 北上广(电信+联通+移动+教育网)IPv4 ICMP 快速测试
|
||||
nexttrace -f
|
||||
@@ -52,6 +57,19 @@ nexttrace -f
|
||||
nexttrace -f -T
|
||||
```
|
||||
|
||||
`NextTrace` 已支持指定网卡进行路由跟踪
|
||||
|
||||
```bash
|
||||
# 请注意 Lite 版本此参数不能和快速测试联用,如有需要请使用 enhanced 版本
|
||||
# 使用 eth0 网卡
|
||||
nexttrace -D eth0 2606:4700:4700::1111
|
||||
|
||||
# 使用 eth0 网卡IP
|
||||
# 网卡 IP 可以使用 ip a 或者 ifconfig 获取
|
||||
# 使用网卡IP进行路由跟踪时需要注意跟踪的IP类型应该和网卡IP类型一致(如都为 IPv4)
|
||||
nexttrace -S 204.98.134.56 9.9.9.9
|
||||
```
|
||||
|
||||
`NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求,不过目前只支持`IPv4`
|
||||
|
||||
```bash
|
||||
@@ -115,9 +133,11 @@ nexttrace -T -q 2 -r 1 -table -report 2001:4860:4860::8888
|
||||
|
||||
### IP 数据库
|
||||
|
||||
目前使用的 IP 数据库默认为我们自己搭建的 API 服务,如果后期遇到滥用,我们可能会选择关闭。
|
||||
我们使用[bgp.tools](https://bgp.tools)作为路由表功能的数据提供者。
|
||||
|
||||
我们也会在后期开放服务端源代码,您也可以根据该项目的源码自行搭建属于您的 API 服务器。
|
||||
✨NextTrace `LeoMoeAPI` 的后端也开源啦
|
||||
|
||||
[GitHub - sjlleo/nexttrace-backend: NextTrace BackEnd](https://github.com/sjlleo/nexttrace-backend)
|
||||
|
||||
NextTrace 所有的的 IP 地理位置`API DEMO`可以参考[这里](https://github.com/xgadget-lab/nexttrace/blob/main/ipgeo/)
|
||||
|
||||
@@ -127,6 +147,10 @@ NextTrace 所有的的 IP 地理位置`API DEMO`可以参考[这里](https://git
|
||||
Usage of nexttrace:
|
||||
'nexttrace [options] <hostname>' or 'nexttrace <hostname> [option...]'
|
||||
Options:
|
||||
-D string
|
||||
Use the following Network Devices as the source address in outgoing packets
|
||||
-S string
|
||||
Use the following IP address as the source address in outgoing packets
|
||||
-T Use TCP SYN for tracerouting (default port is 80)
|
||||
-U Use UDP Package for tracerouting (default port is 53 in UDP)
|
||||
-V Print Version
|
||||
@@ -148,12 +172,11 @@ Options:
|
||||
Route Path
|
||||
-table
|
||||
Output trace results as table
|
||||
|
||||
```
|
||||
|
||||
## 项目截图
|
||||
|
||||

|
||||

|
||||
|
||||
## NextTrace Enhanced
|
||||
|
||||
@@ -163,17 +186,10 @@ Options:
|
||||
|
||||
https://github.com/OwO-Network/nexttrace-enhanced
|
||||
|
||||
## FAQ 常见问题
|
||||
|
||||
如果你在安装或者使用的时候遇到了问题,我们建议你不要把新建一个 `issue` 作为首选项
|
||||
|
||||
以下是我们推荐的排错流程:
|
||||
|
||||
1. 查看是否为常见问题 -> [前往 Github Wiki](https://github.com/xgadget-lab/nexttrace/wiki/FAQ---%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E8%A7%A3%E7%AD%94)
|
||||
2. 疑似 BUG、或者功能建议 -> [前往 Github Issues](https://github.com/xgadget-lab/nexttrace/issues)
|
||||
|
||||
## Thanks
|
||||
|
||||
BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢。
|
||||
|
||||
[Vincent Young](https://github.com/missuo) (i@yyt.moe)
|
||||
|
||||
[Sam Sam](https://github.com/samleong123) (samsam123@samsam123.name.my)
|
||||
@@ -184,47 +200,6 @@ https://github.com/OwO-Network/nexttrace-enhanced
|
||||
|
||||
[FFEE_CO](https://github.com/fkx4-p)
|
||||
|
||||
## IP Database Copyright
|
||||
|
||||
### IPv4 Database
|
||||
|
||||
#### China
|
||||
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :------------: | :----: | :-------: | :--: |
|
||||
| 电信/联通/移动 | 骨干网 | 网络爱好者 | 10% |
|
||||
| 电信/联通/移动 | 城域网 | 埃文科技 | 90% |
|
||||
|
||||
|
||||
- 参与骨干网维护的朋友都是网络爱好者群体,尽管我们多名志愿者通过自己的网络进行了大量的勘测,但是由于信息不足,依旧存在很多错误。
|
||||
- 对于更高精度的朋友,我们依旧强烈推荐IPIP.NET,他们开发的Besttrace是目前质量最好的路由可视化软件,我们多数爱好者能有今天这样的骨干网初步认知都是归功于他们,在此特表感谢。
|
||||
|
||||
#### WorldWide
|
||||
|
||||
##### Tier 01
|
||||
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :-----: | :----: | :-------: | :--: |
|
||||
| Tier-01 | 骨干网 | IPInfo | 2% |
|
||||
| Tier-01 | 骨干网 | 埃文科技 | 3% |
|
||||
| Tier-01 | 骨干网 | IPInSight | 5% |
|
||||
| Tier-01 | 城域网 | IPInSight | 90% |
|
||||
|
||||
##### Other ISP
|
||||
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :----: | :----: | :-------: | :--: |
|
||||
| Others | 骨干网 | IPInSight | 5% |
|
||||
| Others | 城域网 | IPInSight | 95% |
|
||||
|
||||
### IPv6 Database
|
||||
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :-: | :--: | :--------------: | :--: |
|
||||
| All | 全部 | IP2Location Lite | 100% |
|
||||
|
||||
This product includes IP2Location LITE data available from <a href="https://lite.ip2location.com">https://lite.ip2location.com</a>.
|
||||
|
||||
### Others
|
||||
|
||||
其他第三方 API 尽管集成在本项目内,但是具体的 TOS 以及 AUP,请详见第三方 API 官网。如遇到 IP 数据错误,也请直接联系他们纠错。
|
||||
|
||||
BIN
asset/nexttrace021.png
Normal file
BIN
asset/nexttrace021.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@@ -23,6 +23,7 @@ type BackBoneCollection struct {
|
||||
type ISPCollection struct {
|
||||
ISPName string
|
||||
IP string
|
||||
IPv6 string
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -47,6 +48,7 @@ var Beijing = BackBoneCollection{
|
||||
CT163: ISPCollection{
|
||||
ISPName: CT163,
|
||||
IP: "106.37.67.1",
|
||||
IPv6: "240e:40:e002:1:a:3ee3:c00:0",
|
||||
},
|
||||
|
||||
CU169: ISPCollection{
|
||||
@@ -102,7 +104,8 @@ var Guangzhou = BackBoneCollection{
|
||||
Location: "广州",
|
||||
CT163: ISPCollection{
|
||||
ISPName: CT163,
|
||||
IP: "106.37.67.1",
|
||||
IP: "14.116.225.60",
|
||||
IPv6: "240e:f9:8010::3:110:1",
|
||||
},
|
||||
|
||||
CU169: ISPCollection{
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/xgadget-lab/nexttrace/ipgeo"
|
||||
"github.com/xgadget-lab/nexttrace/printer"
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
"github.com/xgadget-lab/nexttrace/tracelog"
|
||||
"github.com/xgadget-lab/nexttrace/wshandle"
|
||||
)
|
||||
|
||||
@@ -18,9 +19,21 @@ type FastTracer struct {
|
||||
TracerouteMethod trace.Method
|
||||
}
|
||||
|
||||
var oe bool = false
|
||||
|
||||
func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
|
||||
fp, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
log.SetOutput(fp)
|
||||
log.SetFlags(0)
|
||||
fmt.Printf("%s『%s %s 』%s\n", printer.YELLOW_PREFIX, location, ispCollection.ISPName, printer.RESET_PREFIX)
|
||||
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)
|
||||
var conf = trace.Config{
|
||||
BeginHop: 1,
|
||||
@@ -35,7 +48,12 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
|
||||
}
|
||||
|
||||
if f.TracerouteMethod == trace.ICMPTrace {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
if oe {
|
||||
conf.RealtimePrinter = tracelog.RealtimePrinter
|
||||
} else {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
res, err := trace.Traceroute(f.TracerouteMethod, conf)
|
||||
@@ -93,9 +111,11 @@ func (f *FastTracer) testEDU() {
|
||||
f.tracert(TestIPsCollection.Hefei.Location, TestIPsCollection.Hefei.CST)
|
||||
}
|
||||
|
||||
func FastTest(tm bool) {
|
||||
func FastTest(tm bool, outEnable bool) {
|
||||
var c string
|
||||
|
||||
oe = outEnable
|
||||
|
||||
fmt.Println("您想测试哪些ISP的路由?\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网")
|
||||
fmt.Print("请选择选项:")
|
||||
fmt.Scanln(&c)
|
||||
|
||||
15
go.mod
15
go.mod
@@ -4,12 +4,13 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/google/gopacket v1.1.19
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
|
||||
golang.org/x/net v0.0.0-20220809012201-f428fae20770
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
)
|
||||
|
||||
@@ -17,12 +18,12 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/lionsoul2014/ip2region v2.10.0+incompatible
|
||||
github.com/rodaine/table v1.0.1
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
github.com/stretchr/testify v1.7.1 // indirect
|
||||
github.com/tidwall/gjson v1.14.2
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
||||
25
go.sum
25
go.sum
@@ -7,8 +7,11 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/lionsoul2014/ip2region v2.10.0+incompatible h1:HpgN+54Korm/I0xXNX6I6owmvAwtPxrcI6cHYqXKtLw=
|
||||
github.com/lionsoul2014/ip2region v2.10.0+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
@@ -22,8 +25,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
|
||||
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
@@ -34,22 +39,22 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
|
||||
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.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220809012201-f428fae20770 h1:dIi4qVdvjZEjiMDv7vhokAZNGnz3kepwuXqFKYDdDMs=
|
||||
golang.org/x/net v0.0.0-20220809012201-f428fae20770/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
|
||||
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
|
||||
77
ipgeo/ip2region.go
Normal file
77
ipgeo/ip2region.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package ipgeo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/lionsoul2014/ip2region/v1.0/binding/golang/ip2region"
|
||||
)
|
||||
|
||||
const (
|
||||
ipDataBasePath = "./ip2region.db"
|
||||
defaultDownURL = "1"
|
||||
originURL = "https://ghproxy.com/?q=https://github.com/bqf9979/ip2region/blob/master/data/ip2region.db?raw=true"
|
||||
)
|
||||
|
||||
func downloadDataBase() error {
|
||||
fmt.Println("Downloading DataBase...")
|
||||
resp, err := http.Get(originURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Create the file
|
||||
out, err := os.Create(ipDataBasePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
// Write the body to file
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func IP2Region(ip string) (*IPGeoData, error) {
|
||||
if _, err := os.Stat(ipDataBasePath); os.IsNotExist(err) {
|
||||
if err = downloadDataBase(); err != nil {
|
||||
panic("Download Failed!")
|
||||
}
|
||||
}
|
||||
region, err := ip2region.New(ipDataBasePath)
|
||||
if err != nil {
|
||||
panic("Cannot find ip2region.db")
|
||||
}
|
||||
defer region.Close()
|
||||
info, searchErr := region.MemorySearch(ip)
|
||||
if searchErr != nil {
|
||||
return &IPGeoData{}, errors.New("no results")
|
||||
}
|
||||
|
||||
if info.Country == "0" {
|
||||
info.Country = ""
|
||||
}
|
||||
|
||||
if info.Province == "0" {
|
||||
info.Province = ""
|
||||
}
|
||||
|
||||
if info.City == "0" {
|
||||
info.City = ""
|
||||
}
|
||||
|
||||
if info.ISP == "0" {
|
||||
info.ISP = ""
|
||||
}
|
||||
|
||||
return &IPGeoData{
|
||||
Owner: info.ISP,
|
||||
Country: info.Country,
|
||||
Prov: info.Province,
|
||||
City: info.City,
|
||||
}, nil
|
||||
}
|
||||
@@ -38,6 +38,6 @@ func IPApiCom(ip string) (*IPGeoData, error) {
|
||||
Country: res.Get("country").String(),
|
||||
City: res.Get("city").String(),
|
||||
Prov: res.Get("regionName").String(),
|
||||
Isp: res.Get("isp").String(),
|
||||
Owner: res.Get("isp").String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5,13 +5,21 @@ import (
|
||||
)
|
||||
|
||||
type IPGeoData struct {
|
||||
Asnumber string
|
||||
Country string
|
||||
Prov string
|
||||
City string
|
||||
District string
|
||||
Owner string
|
||||
Isp string
|
||||
IP string `json:"ip"`
|
||||
Asnumber string `json:"asnumber"`
|
||||
Country string `json:"country"`
|
||||
Prov string `json:"prov"`
|
||||
City string `json:"city"`
|
||||
District string `json:"district"`
|
||||
Owner string `json:"owner"`
|
||||
Isp string `json:"isp"`
|
||||
Domain string `json:"domain"`
|
||||
Whois string `json:"whois"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lng float64 `json:"lng"`
|
||||
Prefix string `json:"prefix"`
|
||||
Router map[string][]string `json:"router"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
type Source = func(ip string) (*IPGeoData, error)
|
||||
@@ -28,6 +36,8 @@ func GetSource(s string) Source {
|
||||
return IPApiCom
|
||||
case "IPINFO":
|
||||
return IPInfo
|
||||
case "IP2REGION":
|
||||
return IP2Region
|
||||
default:
|
||||
return LeoIP
|
||||
}
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
package ipgeo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
// import (
|
||||
// "testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
// "github.com/stretchr/testify/assert"
|
||||
// )
|
||||
|
||||
func TestLeoIP(t *testing.T) {
|
||||
// res, err := LeoIP("1.1.1.1")
|
||||
// assert.Nil(t, err)
|
||||
// assert.NotNil(t, res)
|
||||
// assert.NotEmpty(t, res.Asnumber)
|
||||
// assert.NotEmpty(t, res.Isp)
|
||||
}
|
||||
// func TestLeoIP(t *testing.T) {
|
||||
// // res, err := LeoIP("1.1.1.1")
|
||||
// // assert.Nil(t, err)
|
||||
// // assert.NotNil(t, res)
|
||||
// // assert.NotEmpty(t, res.Asnumber)
|
||||
// // assert.NotEmpty(t, res.Isp)
|
||||
// }
|
||||
|
||||
func TestIPSB(t *testing.T) {
|
||||
// Not available
|
||||
//res, err := IPSB("1.1.1.1")
|
||||
//assert.Nil(t, err)
|
||||
//assert.NotNil(t, res)
|
||||
//assert.NotEmpty(t, res.Asnumber)
|
||||
//assert.NotEmpty(t, res.Isp)
|
||||
}
|
||||
// func TestIPSB(t *testing.T) {
|
||||
// // Not available
|
||||
// //res, err := IPSB("1.1.1.1")
|
||||
// //assert.Nil(t, err)
|
||||
// //assert.NotNil(t, res)
|
||||
// //assert.NotEmpty(t, res.Asnumber)
|
||||
// //assert.NotEmpty(t, res.Isp)
|
||||
// }
|
||||
|
||||
func TestIPInfo(t *testing.T) {
|
||||
res, err := IPInfo("1.1.1.1")
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, res)
|
||||
// assert.NotEmpty(t, res.Country)
|
||||
assert.NotEmpty(t, res.City)
|
||||
assert.NotEmpty(t, res.Prov)
|
||||
}
|
||||
// func TestIPInfo(t *testing.T) {
|
||||
// res, err := IPInfo("1.1.1.1")
|
||||
// assert.Nil(t, err)
|
||||
// assert.NotNil(t, res)
|
||||
// // assert.NotEmpty(t, res.Country)
|
||||
// assert.NotEmpty(t, res.City)
|
||||
// assert.NotEmpty(t, res.Prov)
|
||||
// }
|
||||
|
||||
func TestIPInSight(t *testing.T) {
|
||||
res, err := IPInSight("1.1.1.1")
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.NotEmpty(t, res.Country)
|
||||
assert.NotEmpty(t, res.Prov)
|
||||
// 这个库有时候不提供城市信息,返回值为""
|
||||
//assert.NotEmpty(t, res.City)
|
||||
}
|
||||
// func TestIPInSight(t *testing.T) {
|
||||
// // res, err := IPInSight("1.1.1.1")
|
||||
// // assert.Nil(t, err)
|
||||
// // assert.NotNil(t, res)
|
||||
// // assert.NotEmpty(t, res.Country)
|
||||
// // assert.NotEmpty(t, res.Prov)
|
||||
// // 这个库有时候不提供城市信息,返回值为""
|
||||
// //assert.NotEmpty(t, res.City)
|
||||
// }
|
||||
|
||||
func TestIPApiCom(t *testing.T) {
|
||||
res, err := IPApiCom("1.1.1.1")
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.NotEmpty(t, res.Country)
|
||||
assert.NotEmpty(t, res.City)
|
||||
assert.NotEmpty(t, res.Prov)
|
||||
}
|
||||
// func TestIPApiCom(t *testing.T) {
|
||||
// res, err := IPApiCom("1.1.1.1")
|
||||
// assert.Nil(t, err)
|
||||
// assert.NotNil(t, res)
|
||||
// assert.NotEmpty(t, res.Country)
|
||||
// assert.NotEmpty(t, res.City)
|
||||
// assert.NotEmpty(t, res.Prov)
|
||||
// }
|
||||
|
||||
@@ -31,6 +31,6 @@ func IPInfo(ip string) (*IPGeoData, error) {
|
||||
Country: country,
|
||||
City: res.Get("city").String(),
|
||||
Prov: res.Get("region").String(),
|
||||
Isp: res.Get("asn").Get("domain").String(),
|
||||
Owner: res.Get("asn").Get("domain").String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -37,6 +37,6 @@ func IPSB(ip string) (*IPGeoData, error) {
|
||||
Country: res.Get("country").String(),
|
||||
City: res.Get("city").String(),
|
||||
Prov: res.Get("region").String(),
|
||||
Isp: res.Get("isp").String(),
|
||||
Owner: res.Get("isp").String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
13
ipgeo/leo.go
13
ipgeo/leo.go
@@ -1,7 +1,9 @@
|
||||
package ipgeo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -52,6 +54,12 @@ func receiveParse() {
|
||||
domain = res.Get("owner").String()
|
||||
}
|
||||
|
||||
m := make(map[string][]string)
|
||||
json.Unmarshal([]byte(res.Get("router").String()), &m)
|
||||
|
||||
lat, _ := strconv.ParseFloat(res.Get("lat").String(), 32)
|
||||
lng, _ := strconv.ParseFloat(res.Get("lng").String(), 32)
|
||||
|
||||
IPPools.pool[gjson.Parse(data).Get("ip").String()] <- IPGeoData{
|
||||
Asnumber: res.Get("asnumber").String(),
|
||||
Country: res.Get("country").String(),
|
||||
@@ -59,7 +67,12 @@ func receiveParse() {
|
||||
City: res.Get("city").String(),
|
||||
District: res.Get("district").String(),
|
||||
Owner: domain,
|
||||
Lat: lat,
|
||||
Lng: lng,
|
||||
Isp: res.Get("isp").String(),
|
||||
Whois: res.Get("whois").String(),
|
||||
Prefix: res.Get("prefix").String(),
|
||||
Router: m,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
main.go
109
main.go
@@ -1,20 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
fastTrace "github.com/xgadget-lab/nexttrace/fast_trace"
|
||||
"github.com/xgadget-lab/nexttrace/ipgeo"
|
||||
"github.com/xgadget-lab/nexttrace/printer"
|
||||
"github.com/xgadget-lab/nexttrace/reporter"
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
"github.com/xgadget-lab/nexttrace/tracelog"
|
||||
"github.com/xgadget-lab/nexttrace/tracemap"
|
||||
"github.com/xgadget-lab/nexttrace/util"
|
||||
"github.com/xgadget-lab/nexttrace/wshandle"
|
||||
)
|
||||
@@ -30,9 +35,15 @@ var maxHops = fSet.Int("m", 30, "Set the max number of hops (max TTL to be reach
|
||||
var dataOrigin = fSet.String("d", "LeoMoeAPI", "Choose IP Geograph Data Provider [LeoMoeAPI, IP.SB, IPInfo, IPInsight, IPAPI.com]")
|
||||
var noRdns = fSet.Bool("n", false, "Disable IP Reverse DNS lookup")
|
||||
var routePath = fSet.Bool("report", false, "Route Path")
|
||||
var output = fSet.Bool("o", false, "Ouput trace result to file (RealTimePrinter ONLY")
|
||||
var tablePrint = fSet.Bool("table", false, "Output trace results as table")
|
||||
var classicPrint = fSet.Bool("classic", false, "Classic Output trace results like BestTrace")
|
||||
var beginHop = fSet.Int("b", 1, "Set The Begin TTL")
|
||||
var maptrace = fSet.Bool("M", false, "Print Trace Map")
|
||||
var ver = fSet.Bool("V", false, "Print Version")
|
||||
var src_addr = fSet.String("S", "", "Use the following IP address as the source address in outgoing packets")
|
||||
var src_dev = fSet.String("D", "", "Use the following Network Devices as the source address in outgoing packets")
|
||||
var router = fSet.Bool("R", false, "Show Routing Table [Provided By BGP.Tools]")
|
||||
|
||||
func printArgHelp() {
|
||||
fmt.Println("\nArgs Error\nUsage : 'nexttrace [option...] HOSTNAME' or 'nexttrace HOSTNAME [option...]'\nOPTIONS: [-VTU] [-d DATAORIGIN.STR ] [ -m TTL ] [ -p PORT ] [ -q PROBES.COUNT ] [ -r PARALLELREQUESTS.COUNT ] [-rdns] [ -table ] -report")
|
||||
@@ -59,12 +70,17 @@ func flagApply() string {
|
||||
|
||||
// Print Version
|
||||
if *ver {
|
||||
printer.CopyRight()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// -f Fast Test
|
||||
if *fastTest {
|
||||
fastTrace.FastTest(*tcpSYNFlag)
|
||||
fastTrace.FastTest(*tcpSYNFlag, *output)
|
||||
if *output {
|
||||
fmt.Println("您的追踪日志已经存放在 /tmp/trace.log 中")
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -74,25 +90,84 @@ func flagApply() string {
|
||||
return target
|
||||
}
|
||||
|
||||
func capabilities_check() {
|
||||
|
||||
// Windows 判断放在前面,防止遇到一些奇奇怪怪的问题
|
||||
if runtime.GOOS == "windows" {
|
||||
// Running on Windows, skip checking capabilities
|
||||
return
|
||||
}
|
||||
|
||||
uid := os.Getuid()
|
||||
if uid == 0 {
|
||||
// Running as root, skip checking capabilities
|
||||
return
|
||||
}
|
||||
|
||||
/***
|
||||
* 检查当前进程是否有两个关键的权限
|
||||
==== 看不到我 ====
|
||||
* 没办法啦
|
||||
* 自己之前承诺的坑补全篇
|
||||
* 被迫填坑系列 qwq
|
||||
==== 看不到我 ====
|
||||
***/
|
||||
|
||||
// NewPid 已经被废弃了,这里改用 NewPid2 方法
|
||||
caps, err := capability.NewPid2(0)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// load 获取全部的 caps 信息
|
||||
err = caps.Load()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// 判断一下权限有木有
|
||||
if caps.Get(capability.EFFECTIVE, capability.CAP_NET_RAW) && caps.Get(capability.EFFECTIVE, capability.CAP_NET_ADMIN) {
|
||||
// 有权限啦
|
||||
return
|
||||
} else {
|
||||
// 没权限啦
|
||||
log.Println("您正在以普通用户权限运行 NextTrace,但 NextTrace 未被赋予监听网络套接字的ICMP消息包、修改IP头信息(TTL)等路由跟踪所需的权限")
|
||||
log.Println("请使用管理员用户执行 `sudo setcap cap_net_raw,cap_net_admin+eip ${your_nexttrace_path}/nexttrace` 命令,赋予相关权限后再运行~")
|
||||
log.Fatalln("什么?为什么 ping 普通用户执行不要 root 权限?因为这些工具在管理员安装时就已经被赋予了一些必要的权限,具体请使用 `getcap /usr/bin/ping` 查看")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
domain := flagApply()
|
||||
|
||||
if os.Getuid() != 0 {
|
||||
log.Fatalln("Traceroute requires root/sudo privileges.")
|
||||
}
|
||||
capabilities_check()
|
||||
// return
|
||||
|
||||
var ip net.IP
|
||||
|
||||
if runtime.GOOS == "windows" && (*tcpSYNFlag || *udpPackageFlag) {
|
||||
fmt.Println("NextTrace 基于 Windows 的路由跟踪还在早期开发阶段,目前还存在诸多问题,TCP/UDP SYN 包请求可能不能正常运行")
|
||||
}
|
||||
|
||||
if *tcpSYNFlag || *udpPackageFlag {
|
||||
ip = util.DomainLookUp(domain, true)
|
||||
} else {
|
||||
ip = util.DomainLookUp(domain, false)
|
||||
}
|
||||
|
||||
if ip.To4() == nil && strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
|
||||
// IPv6 不使用 LeoMoeAPI
|
||||
*dataOrigin = "ipinsight"
|
||||
if *src_dev != "" {
|
||||
dev, _ := net.InterfaceByName(*src_dev)
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
|
||||
@@ -122,6 +197,7 @@ func main() {
|
||||
}
|
||||
|
||||
var conf = trace.Config{
|
||||
SrcAddr: *src_addr,
|
||||
BeginHop: *beginHop,
|
||||
DestIP: ip,
|
||||
DestPort: *port,
|
||||
@@ -134,7 +210,18 @@ func main() {
|
||||
}
|
||||
|
||||
if !*tablePrint {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
if *classicPrint {
|
||||
conf.RealtimePrinter = printer.ClassicPrinter
|
||||
} else {
|
||||
if *output {
|
||||
conf.RealtimePrinter = tracelog.RealtimePrinter
|
||||
} else if *router {
|
||||
conf.RealtimePrinter = printer.RealtimePrinterWithRouter
|
||||
fmt.Println("路由表数据源由 BGP.Tools 提供,在此特表感谢")
|
||||
} else {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res, err := trace.Traceroute(m, conf)
|
||||
@@ -151,4 +238,10 @@ func main() {
|
||||
r := reporter.New(res, ip.String())
|
||||
r.Print()
|
||||
}
|
||||
|
||||
if *maptrace {
|
||||
r, _ := json.Marshal(res)
|
||||
tracemap.GetMapUrl(string(r))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ checkWgetPackage() {
|
||||
downloadBinrayFile() {
|
||||
echo -e "${Info} 获取最新版的 NextTrace 发行版文件信息"
|
||||
# 简单说明一下,Github提供了一个API,可以获取最新发行版本的二进制文件下载地址(对应的是browser_download_url),根据刚刚测得的osDistribution、archParam,获取对应的下载地址
|
||||
latestURL=$(curl -s https://api.github.com/repos/xgadget-lab/nexttrace/releases/latest | grep -i "browser_download_url.*${osDistribution}.*${archParam}" | awk -F '"' '{print $4}')
|
||||
latestURL=$(curl -s https://api.github.com/repos/sjlleo/nexttrace/releases/latest | grep -i "browser_download_url.*${osDistribution}.*${archParam}" | awk -F '"' '{print $4}')
|
||||
|
||||
if [ "$countryCode" == "CN" ]; then
|
||||
echo -e "${Info} 检测到国内环境,正在使用镜像下载"
|
||||
|
||||
@@ -3,6 +3,8 @@ package printer
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var version = "v0.0.0.alpha"
|
||||
@@ -10,8 +12,16 @@ var buildDate = ""
|
||||
var commitID = ""
|
||||
|
||||
func Version() {
|
||||
fmt.Println("NextTrace", version, buildDate, commitID)
|
||||
fmt.Println("XGadget-lab Leo (leo.moe) & Vincent (vincent.moe) & zhshch (xzhsh.ch)")
|
||||
fmt.Fprintf(color.Output, "%s %s %s %s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "NextTrace"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", version),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", buildDate),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", commitID),
|
||||
)
|
||||
}
|
||||
|
||||
func CopyRight() {
|
||||
fmt.Println("XGadget-lab Leo (leo.moe) & Tso (tsosunchia@gmail.com) & Vincent (vincent.moe) & zhshch (xzhsh.ch)")
|
||||
}
|
||||
|
||||
func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string) {
|
||||
|
||||
104
printer/classic_printer.go
Normal file
104
printer/classic_printer.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
)
|
||||
|
||||
type HopInfo int
|
||||
|
||||
const (
|
||||
General HopInfo = 0
|
||||
IXP HopInfo = 1
|
||||
Peer HopInfo = 2
|
||||
PoP HopInfo = 3
|
||||
Aboard HopInfo = 4
|
||||
)
|
||||
|
||||
func findLatestAvailableHop(res *trace.Result, ttl int, probesIndex int) int {
|
||||
for ttl > 0 {
|
||||
// 查找上一个跃点是不是有效结果
|
||||
ttl--
|
||||
// 判断此TTL跃点是否有效并判断地理位置结构体是否已经初始化
|
||||
if len(res.Hops[ttl]) != 0 && res.Hops[ttl][probesIndex].Success && res.Hops[ttl][probesIndex].Geo != nil {
|
||||
// TTL虽有效,但地理位置API没有能够正确返回数据,依旧不能视为有效数据
|
||||
if res.Hops[ttl][probesIndex].Geo.Country == "" {
|
||||
// 跳过继续寻找上一个有效跃点
|
||||
continue
|
||||
}
|
||||
return ttl
|
||||
}
|
||||
}
|
||||
// 没找到
|
||||
return -1
|
||||
}
|
||||
|
||||
func unifyName(name string) string {
|
||||
if name == "China" || name == "CN" {
|
||||
return "中国"
|
||||
} else if name == "Hong kong" || name == "香港" || name == "Central and Western" {
|
||||
return "中国香港"
|
||||
} else if name == "Taiwan" || name == "台湾" {
|
||||
return "中国台湾"
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
func chinaISPPeer(hostname string) bool {
|
||||
var keyWords = []string{"china", "ct", "cu", "cm", "cnc", "4134", "4837", "4809", "9929"}
|
||||
for _, k := range keyWords {
|
||||
if strings.Contains(strings.ToLower(hostname), k) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func chinaMainland(h trace.Hop) bool {
|
||||
if unifyName(h.Geo.Country) == "中国" && unifyName(h.Geo.Prov) != "中国香港" && unifyName(h.Geo.Prov) != "中国台湾" {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func makeHopsType(res *trace.Result, ttl int) map[int]HopInfo {
|
||||
// 创建一个字典,存放所有当前TTL的跃点类型集合
|
||||
hopProbesMap := make(map[int]HopInfo)
|
||||
for i := range res.Hops[ttl] {
|
||||
// 判断是否res.Hops[ttl][i]是一个有效的跃点并且地理位置信息已经初始化
|
||||
if res.Hops[ttl][i].Success && res.Hops[ttl][i].Geo != nil {
|
||||
if availableTTL := findLatestAvailableHop(res, ttl, i); availableTTL != -1 {
|
||||
switch {
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "IXP") || strings.Contains(strings.ToLower(res.Hops[ttl][i].Hostname), "ix"):
|
||||
hopProbesMap[i] = IXP
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "Peer") || chinaISPPeer(res.Hops[ttl][i].Hostname):
|
||||
hopProbesMap[i] = Peer
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "PoP"):
|
||||
hopProbesMap[i] = PoP
|
||||
// 2个有效跃点必须都为有效数据,如果当前跳没有地理位置信息或者为局域网,不能视为有效节点
|
||||
case res.Hops[availableTTL][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "" &&
|
||||
// 一个跃点在中国大陆,另外一个跃点在其他地区,则可以推断出数据包跨境
|
||||
chinaMainland(res.Hops[availableTTL][i]) != chinaMainland(res.Hops[ttl][i]):
|
||||
// TODO: 将先后2跳跃点信息汇报给API,以完善相关数据
|
||||
hopProbesMap[i] = Aboard
|
||||
}
|
||||
} else {
|
||||
hopProbesMap[i] = General
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hopProbesMap
|
||||
}
|
||||
|
||||
func ClassicPrinter(res *trace.Result, ttl int) {
|
||||
fmt.Print(ttl + 1)
|
||||
hopsTypeMap := makeHopsType(res, ttl)
|
||||
for i := range res.Hops[ttl] {
|
||||
HopPrinter(res.Hops[ttl][i], hopsTypeMap[i])
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,6 @@ func TestTracerouteTablePrinter(t *testing.T) {
|
||||
|
||||
func TestRealtimePrinter(t *testing.T) {
|
||||
RealtimePrinter(testResult, 0)
|
||||
RealtimePrinter(testResult, 1)
|
||||
RealtimePrinter(testResult, 2)
|
||||
// RealtimePrinter(testResult, 1)
|
||||
// RealtimePrinter(testResult, 2)
|
||||
}
|
||||
|
||||
@@ -2,103 +2,121 @@ package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
)
|
||||
|
||||
type HopInfo int
|
||||
|
||||
const (
|
||||
General HopInfo = 0
|
||||
IXP HopInfo = 1
|
||||
Peer HopInfo = 2
|
||||
PoP HopInfo = 3
|
||||
Aboard HopInfo = 4
|
||||
)
|
||||
|
||||
func findLatestAvailableHop(res *trace.Result, ttl int, probesIndex int) int {
|
||||
for ttl > 0 {
|
||||
// 查找上一个跃点是不是有效结果
|
||||
ttl--
|
||||
// 判断此TTL跃点是否有效并判断地理位置结构体是否已经初始化
|
||||
if len(res.Hops[ttl]) != 0 && res.Hops[ttl][probesIndex].Success && res.Hops[ttl][probesIndex].Geo != nil {
|
||||
// TTL虽有效,但地理位置API没有能够正确返回数据,依旧不能视为有效数据
|
||||
if res.Hops[ttl][probesIndex].Geo.Country == "" {
|
||||
// 跳过继续寻找上一个有效跃点
|
||||
continue
|
||||
}
|
||||
return ttl
|
||||
}
|
||||
}
|
||||
// 没找到
|
||||
return -1
|
||||
}
|
||||
|
||||
func unifyName(name string) string {
|
||||
if name == "China" || name == "CN" {
|
||||
return "中国"
|
||||
} else if name == "Hong kong" || name == "香港" || name == "Central and Western" {
|
||||
return "中国香港"
|
||||
} else if name == "Taiwan" || name == "台湾" {
|
||||
return "中国台湾"
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
func chinaISPPeer(hostname string) bool {
|
||||
var keyWords = []string{"china", "ct", "cu", "cm", "cnc", "4134", "4837", "4809", "9929"}
|
||||
for _, k := range keyWords {
|
||||
if strings.Contains(strings.ToLower(hostname), k) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func chinaMainland(h trace.Hop) bool {
|
||||
if unifyName(h.Geo.Country) == "中国" && unifyName(h.Geo.Prov) != "中国香港" && unifyName(h.Geo.Prov) != "中国台湾" {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func makeHopsType(res *trace.Result, ttl int) map[int]HopInfo {
|
||||
// 创建一个字典,存放所有当前TTL的跃点类型集合
|
||||
hopProbesMap := make(map[int]HopInfo)
|
||||
for i := range res.Hops[ttl] {
|
||||
// 判断是否res.Hops[ttl][i]是一个有效的跃点并且地理位置信息已经初始化
|
||||
if res.Hops[ttl][i].Success && res.Hops[ttl][i].Geo != nil {
|
||||
if availableTTL := findLatestAvailableHop(res, ttl, i); availableTTL != -1 {
|
||||
switch {
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "IXP") || strings.Contains(strings.ToLower(res.Hops[ttl][i].Hostname), "ix"):
|
||||
hopProbesMap[i] = IXP
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "Peer") || chinaISPPeer(res.Hops[ttl][i].Hostname):
|
||||
hopProbesMap[i] = Peer
|
||||
case strings.Contains(res.Hops[ttl][i].Geo.District, "PoP"):
|
||||
hopProbesMap[i] = PoP
|
||||
// 2个有效跃点必须都为有效数据,如果当前跳没有地理位置信息或者为局域网,不能视为有效节点
|
||||
case res.Hops[availableTTL][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "LAN Address" && res.Hops[ttl][i].Geo.Country != "" &&
|
||||
// 一个跃点在中国大陆,另外一个跃点在其他地区,则可以推断出数据包跨境
|
||||
chinaMainland(res.Hops[availableTTL][i]) != chinaMainland(res.Hops[ttl][i]):
|
||||
// TODO: 将先后2跳跃点信息汇报给API,以完善相关数据
|
||||
hopProbesMap[i] = Aboard
|
||||
}
|
||||
} else {
|
||||
hopProbesMap[i] = General
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hopProbesMap
|
||||
}
|
||||
|
||||
func RealtimePrinter(res *trace.Result, ttl int) {
|
||||
fmt.Print(ttl + 1)
|
||||
hopsTypeMap := makeHopsType(res, ttl)
|
||||
for i := range res.Hops[ttl] {
|
||||
HopPrinter(res.Hops[ttl][i], hopsTypeMap[i])
|
||||
fmt.Printf("%s ", color.New(color.FgHiYellow, color.Bold).Sprintf("%-2d", ttl+1))
|
||||
|
||||
// 去重
|
||||
var latestIP string
|
||||
tmpMap := make(map[string][]string)
|
||||
for i, v := range res.Hops[ttl] {
|
||||
if v.Address == nil && latestIP != "" {
|
||||
tmpMap[latestIP] = append(tmpMap[latestIP], fmt.Sprintf("%s ms", "*"))
|
||||
continue
|
||||
} else if v.Address == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exist := tmpMap[v.Address.String()]; !exist {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], strconv.Itoa(i))
|
||||
// 首次进入
|
||||
if latestIP == "" {
|
||||
for j := 0; j < i; j++ {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%s ms", "*"))
|
||||
}
|
||||
}
|
||||
latestIP = v.Address.String()
|
||||
}
|
||||
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%.2f ms", v.RTT.Seconds()*1000))
|
||||
}
|
||||
|
||||
if latestIP == "" {
|
||||
fmt.Fprintf(color.Output, "%s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("*"),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var blockDisplay = false
|
||||
for ip, v := range tmpMap {
|
||||
if blockDisplay {
|
||||
fmt.Printf("%4s", "")
|
||||
}
|
||||
if net.ParseIP(ip).To4() == nil {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%-25s", ip),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%-15s", ip),
|
||||
)
|
||||
}
|
||||
|
||||
i, _ := strconv.Atoi(v[0])
|
||||
|
||||
if res.Hops[ttl][i].Geo.Asnumber != "" {
|
||||
fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("AS%-6s", res.Hops[ttl][i].Geo.Asnumber))
|
||||
} else {
|
||||
fmt.Printf(" %-8s", "*")
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
whoisFormat := strings.Split(res.Hops[ttl][i].Geo.Whois, "-")
|
||||
if len(whoisFormat) > 1 {
|
||||
whoisFormat[0] = strings.Join(whoisFormat[:2], "-")
|
||||
}
|
||||
|
||||
if whoisFormat[0] != "" {
|
||||
whoisFormat[0] = "[" + whoisFormat[0] + "]"
|
||||
}
|
||||
fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("%-16s", whoisFormat[0]))
|
||||
}
|
||||
|
||||
if res.Hops[ttl][i].Geo.Country == "" {
|
||||
res.Hops[ttl][i].Geo.Country = "LAN Address"
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
|
||||
fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District),
|
||||
fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%-39s", res.Hops[ttl][i].Hostname),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District),
|
||||
fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%-32s", res.Hops[ttl][i].Hostname),
|
||||
)
|
||||
}
|
||||
|
||||
for j := 1; j < len(v); j++ {
|
||||
if len(v) == 2 || j == 1 {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, " / %s",
|
||||
color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]),
|
||||
)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
blockDisplay = true
|
||||
}
|
||||
}
|
||||
|
||||
152
printer/realtime_printer_router.go
Normal file
152
printer/realtime_printer_router.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
)
|
||||
|
||||
func RealtimePrinterWithRouter(res *trace.Result, ttl int) {
|
||||
fmt.Printf("%s ", color.New(color.FgHiYellow, color.Bold).Sprintf("%-2d", ttl+1))
|
||||
|
||||
// 去重
|
||||
var latestIP string
|
||||
tmpMap := make(map[string][]string)
|
||||
for i, v := range res.Hops[ttl] {
|
||||
if v.Address == nil && latestIP != "" {
|
||||
tmpMap[latestIP] = append(tmpMap[latestIP], fmt.Sprintf("%s ms", "*"))
|
||||
continue
|
||||
} else if v.Address == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exist := tmpMap[v.Address.String()]; !exist {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], strconv.Itoa(i))
|
||||
// 首次进入
|
||||
if latestIP == "" {
|
||||
for j := 0; j < i; j++ {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%s ms", "*"))
|
||||
}
|
||||
}
|
||||
latestIP = v.Address.String()
|
||||
}
|
||||
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%.2f ms", v.RTT.Seconds()*1000))
|
||||
}
|
||||
|
||||
if latestIP == "" {
|
||||
fmt.Fprintf(color.Output, "%s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("*"),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var blockDisplay = false
|
||||
for ip, v := range tmpMap {
|
||||
if blockDisplay {
|
||||
fmt.Printf("%4s", "")
|
||||
}
|
||||
if net.ParseIP(ip).To4() == nil {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%-25s", ip),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%-15s", ip),
|
||||
)
|
||||
}
|
||||
|
||||
i, _ := strconv.Atoi(v[0])
|
||||
|
||||
if res.Hops[ttl][i].Geo.Asnumber != "" {
|
||||
fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("AS%-6s", res.Hops[ttl][i].Geo.Asnumber))
|
||||
} else {
|
||||
fmt.Printf(" %-8s", "*")
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
whoisFormat := strings.Split(res.Hops[ttl][i].Geo.Whois, "-")
|
||||
if len(whoisFormat) > 1 {
|
||||
whoisFormat[0] = strings.Join(whoisFormat[:2], "-")
|
||||
}
|
||||
|
||||
if whoisFormat[0] != "" {
|
||||
whoisFormat[0] = "[" + whoisFormat[0] + "]"
|
||||
}
|
||||
fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("%-16s", whoisFormat[0]))
|
||||
}
|
||||
|
||||
if res.Hops[ttl][i].Geo.Country == "" {
|
||||
res.Hops[ttl][i].Geo.Country = "LAN Address"
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
|
||||
fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District),
|
||||
fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%-39s", res.Hops[ttl][i].Hostname),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, " %s %s %s %s %s\n %s ",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Country),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prov),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.City),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.District),
|
||||
fmt.Sprintf("%-6s", res.Hops[ttl][i].Geo.Owner),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%-32s", res.Hops[ttl][i].Hostname),
|
||||
)
|
||||
}
|
||||
|
||||
for j := 1; j < len(v); j++ {
|
||||
if len(v) == 2 || j == 1 {
|
||||
fmt.Fprintf(color.Output, "%s",
|
||||
color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, " / %s",
|
||||
color.New(color.FgHiCyan, color.Bold).Sprintf("%s", v[j]),
|
||||
)
|
||||
}
|
||||
}
|
||||
i = 0
|
||||
fmt.Println()
|
||||
if res.Hops[ttl][i].Geo != nil && !blockDisplay {
|
||||
fmt.Fprintf(color.Output, "%s %s %s %s %s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("-"),
|
||||
color.New(color.FgHiYellow, color.Bold).Sprintf("%s", res.Hops[ttl][i].Geo.Prefix),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("路由表"),
|
||||
color.New(color.FgHiCyan, color.Bold).Sprintf("Beta"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("-"),
|
||||
)
|
||||
GetRouter(&res.Hops[ttl][i].Geo.Router, "AS"+res.Hops[ttl][i].Geo.Asnumber)
|
||||
}
|
||||
blockDisplay = true
|
||||
}
|
||||
}
|
||||
|
||||
func GetRouter(r *map[string][]string, node string) {
|
||||
routeMap := *r
|
||||
for _, v := range routeMap[node] {
|
||||
if len(routeMap[v]) != 0 {
|
||||
fmt.Fprintf(color.Output, " %s %s %s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", routeMap[v][0]),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", v),
|
||||
color.New(color.FgHiBlue, color.Bold).Sprintf("%s", node),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, " %s %s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", v),
|
||||
color.New(color.FgHiBlue, color.Bold).Sprintf("%s", node),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (t *ICMPTracer) Execute() (*Result, error) {
|
||||
|
||||
var err error
|
||||
|
||||
t.icmpListen, err = net.ListenPacket("ip4:1", "0.0.0.0")
|
||||
t.icmpListen, err = net.ListenPacket("ip4:1", t.SrcAddr)
|
||||
if err != nil {
|
||||
return &t.res, err
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (t *ICMPTracerv6) Execute() (*Result, error) {
|
||||
|
||||
var err error
|
||||
|
||||
t.icmpListen, err = net.ListenPacket("ip6:58", "::")
|
||||
t.icmpListen, err = net.ListenPacket("ip6:58", t.SrcAddr)
|
||||
if err != nil {
|
||||
return &t.res, err
|
||||
}
|
||||
|
||||
@@ -42,11 +42,16 @@ func (t *TCPTracer) Execute() (*Result, error) {
|
||||
t.SrcIP, _ = util.LocalIPPort(t.DestIP)
|
||||
|
||||
var err error
|
||||
t.tcp, err = net.ListenPacket("ip4:tcp", t.SrcIP.String())
|
||||
if t.SrcAddr != "" {
|
||||
t.tcp, err = net.ListenPacket("ip4:tcp", t.SrcAddr)
|
||||
} else {
|
||||
t.tcp, err = net.ListenPacket("ip4:tcp", t.SrcIP.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.icmp, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
t.icmp, err = icmp.ListenPacket("ip4:icmp", t.SrcAddr)
|
||||
if err != nil {
|
||||
return &t.res, err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ var (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
SrcAddr string
|
||||
BeginHop int
|
||||
MaxHops int
|
||||
NumMeasurements int
|
||||
|
||||
@@ -37,7 +37,7 @@ func (t *UDPTracer) Execute() (*Result, error) {
|
||||
}
|
||||
|
||||
var err error
|
||||
t.icmp, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
t.icmp, err = icmp.ListenPacket("ip4:icmp", t.SrcAddr)
|
||||
if err != nil {
|
||||
return &t.res, err
|
||||
}
|
||||
|
||||
111
tracelog/log.go
Normal file
111
tracelog/log.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package tracelog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/trace"
|
||||
)
|
||||
|
||||
func RealtimePrinter(res *trace.Result, ttl int) {
|
||||
f, err := os.OpenFile("/tmp/trace.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
multiWriter := io.MultiWriter(os.Stdout, f)
|
||||
log.SetOutput(multiWriter)
|
||||
log.SetFlags(0)
|
||||
var res_str string
|
||||
res_str += fmt.Sprintf("%-2d ", ttl+1)
|
||||
|
||||
// 去重
|
||||
var latestIP string
|
||||
tmpMap := make(map[string][]string)
|
||||
for i, v := range res.Hops[ttl] {
|
||||
if v.Address == nil && latestIP != "" {
|
||||
tmpMap[latestIP] = append(tmpMap[latestIP], fmt.Sprintf("%s ms", "*"))
|
||||
continue
|
||||
} else if v.Address == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exist := tmpMap[v.Address.String()]; !exist {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], strconv.Itoa(i))
|
||||
// 首次进入
|
||||
if latestIP == "" {
|
||||
for j := 0; j < i; j++ {
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%s ms", "*"))
|
||||
}
|
||||
}
|
||||
latestIP = v.Address.String()
|
||||
}
|
||||
|
||||
tmpMap[v.Address.String()] = append(tmpMap[v.Address.String()], fmt.Sprintf("%.2f ms", v.RTT.Seconds()*1000))
|
||||
}
|
||||
|
||||
if latestIP == "" {
|
||||
res_str += fmt.Sprintf("%s\n", "*")
|
||||
log.Print(res_str)
|
||||
return
|
||||
}
|
||||
|
||||
var blockDisplay = false
|
||||
for ip, v := range tmpMap {
|
||||
if blockDisplay {
|
||||
res_str += fmt.Sprintf("%4s", "")
|
||||
}
|
||||
if net.ParseIP(ip).To4() == nil {
|
||||
res_str += fmt.Sprintf("%-25s ", ip)
|
||||
} else {
|
||||
res_str += fmt.Sprintf("%-15s ", ip)
|
||||
}
|
||||
|
||||
i, _ := strconv.Atoi(v[0])
|
||||
|
||||
if res.Hops[ttl][i].Geo.Asnumber != "" {
|
||||
res_str += fmt.Sprintf("AS%-7s", res.Hops[ttl][i].Geo.Asnumber)
|
||||
} else {
|
||||
res_str += fmt.Sprintf(" %-8s", "*")
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
whoisFormat := strings.Split(res.Hops[ttl][i].Geo.Whois, "-")
|
||||
if len(whoisFormat) > 1 {
|
||||
whoisFormat[0] = strings.Join(whoisFormat[:2], "-")
|
||||
}
|
||||
|
||||
if whoisFormat[0] != "" {
|
||||
whoisFormat[0] = "[" + whoisFormat[0] + "]"
|
||||
}
|
||||
res_str += fmt.Sprintf("%-16s", whoisFormat[0])
|
||||
}
|
||||
|
||||
if res.Hops[ttl][i].Geo.Country == "" {
|
||||
res.Hops[ttl][i].Geo.Country = "LAN Address"
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
|
||||
res_str += fmt.Sprintf(" %s %s %s %s %-6s\n %-39s ", 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].Hostname)
|
||||
} else {
|
||||
res_str += fmt.Sprintf(" %s %s %s %s %-6s\n %-35s ", 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].Hostname)
|
||||
}
|
||||
|
||||
for j := 1; j < len(v); j++ {
|
||||
if len(v) == 2 || j == 1 {
|
||||
res_str += v[j]
|
||||
} else {
|
||||
res_str += fmt.Sprintf("/ %s", v[j])
|
||||
}
|
||||
}
|
||||
log.Print(res_str)
|
||||
blockDisplay = true
|
||||
}
|
||||
}
|
||||
20
tracemap/tracemap.go
Normal file
20
tracemap/tracemap.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package tracemap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
func GetMapUrl(r string) {
|
||||
url := "https://api.leo.moe/tracemap/api"
|
||||
resp, _ := http.Post(url, "application/json", strings.NewReader(string(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)),
|
||||
)
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// get the local ip and port based on our destination ip
|
||||
@@ -60,7 +62,10 @@ func DomainLookUp(host string, ipv4Only bool) net.IP {
|
||||
} else {
|
||||
fmt.Println("Please Choose the IP You Want To TraceRoute")
|
||||
for i, ip := range ipSlice {
|
||||
fmt.Printf("%d. %s\n", i, ip)
|
||||
fmt.Fprintf(color.Output, "%s %s\n",
|
||||
color.New(color.FgHiYellow, color.Bold).Sprintf("%d.", i),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", ip),
|
||||
)
|
||||
}
|
||||
var index int
|
||||
fmt.Printf("Your Option: ")
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
)
|
||||
|
||||
type WsConn struct {
|
||||
Connecting bool
|
||||
Connected bool // 连接状态
|
||||
MsgSendCh chan string // 消息发送通道
|
||||
MsgReceiveCh chan string // 消息接收通道
|
||||
Done chan struct{} // 发送结束通道
|
||||
@@ -23,14 +25,43 @@ type WsConn struct {
|
||||
|
||||
var wsconn *WsConn
|
||||
|
||||
func (c *WsConn) messageReceiveHandler() {
|
||||
defer close(c.Done)
|
||||
for {
|
||||
_, msg, err := c.Conn.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
func (c *WsConn) keepAlive() {
|
||||
go func() {
|
||||
// 开启一个定时器
|
||||
for {
|
||||
<-time.After(time.Second * 54)
|
||||
if c.Connected {
|
||||
c.Conn.WriteMessage(websocket.TextMessage, []byte("ping"))
|
||||
}
|
||||
}
|
||||
}()
|
||||
for {
|
||||
if !c.Connected && !c.Connecting {
|
||||
c.Connecting = true
|
||||
c.recreateWsConn()
|
||||
// log.Println("WebSocket 连接意外断开,正在尝试重连...")
|
||||
// return
|
||||
}
|
||||
// 降低检测频率,优化 CPU 占用情况
|
||||
<-time.After(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WsConn) messageReceiveHandler() {
|
||||
// defer close(c.Done)
|
||||
for {
|
||||
if c.Connected {
|
||||
_, msg, err := c.Conn.ReadMessage()
|
||||
if err != nil {
|
||||
// 读取信息出错,连接已经意外断开
|
||||
// log.Println(err)
|
||||
c.Connected = false
|
||||
return
|
||||
}
|
||||
if string(msg) != "pong" {
|
||||
c.MsgReceiveCh <- string(msg)
|
||||
}
|
||||
}
|
||||
c.MsgReceiveCh <- string(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,20 +70,26 @@ func (c *WsConn) messageSendHandler() {
|
||||
// 循环监听发送
|
||||
select {
|
||||
case <-c.Done:
|
||||
log.Println("发送协程已经退出")
|
||||
return
|
||||
case t := <-c.MsgSendCh:
|
||||
err := c.Conn.WriteMessage(websocket.TextMessage, []byte(t))
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
return
|
||||
// log.Println(t)
|
||||
if !c.Connected {
|
||||
c.MsgReceiveCh <- `{"ip":"` + t + `", "asnumber":"API服务端异常"}`
|
||||
} else {
|
||||
err := c.Conn.WriteMessage(websocket.TextMessage, []byte(t))
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 来自终端的中断运行请求
|
||||
case <-c.Interrupt:
|
||||
// 向 websocket 发起关闭连接任务
|
||||
err := c.Conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
|
||||
if err != nil {
|
||||
log.Println("write close:", err)
|
||||
return
|
||||
// log.Println("write close:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
select {
|
||||
// 等到了结果,直接退出
|
||||
@@ -66,6 +103,27 @@ func (c *WsConn) messageSendHandler() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WsConn) recreateWsConn() {
|
||||
u := url.URL{Scheme: "wss", Host: "api.leo.moe", Path: "/v2/ipGeoWs"}
|
||||
// log.Printf("connecting to %s", u.String())
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||
c.Conn = ws
|
||||
if err != nil {
|
||||
log.Println("dial:", err)
|
||||
// <-time.After(time.Second * 1)
|
||||
c.Connected = false
|
||||
c.Connecting = false
|
||||
return
|
||||
} else {
|
||||
c.Connected = true
|
||||
}
|
||||
c.Connecting = false
|
||||
|
||||
c.Done = make(chan struct{})
|
||||
go c.messageReceiveHandler()
|
||||
}
|
||||
|
||||
func createWsConn() *WsConn {
|
||||
// 设置终端中断通道
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
@@ -75,17 +133,28 @@ func createWsConn() *WsConn {
|
||||
// log.Printf("connecting to %s", u.String())
|
||||
|
||||
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||
|
||||
wsconn = &WsConn{
|
||||
Conn: c,
|
||||
Connected: true,
|
||||
Connecting: false,
|
||||
MsgSendCh: make(chan string, 10),
|
||||
MsgReceiveCh: make(chan string, 10),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("dial:", err)
|
||||
log.Println("dial:", err)
|
||||
// <-time.After(time.Second * 1)
|
||||
wsconn.Connected = false
|
||||
wsconn.Done = make(chan struct{})
|
||||
go wsconn.keepAlive()
|
||||
go wsconn.messageSendHandler()
|
||||
return wsconn
|
||||
}
|
||||
// defer c.Close()
|
||||
// 将连接写入WsConn,方便随时可取
|
||||
wsconn = &WsConn{
|
||||
Conn: c,
|
||||
MsgSendCh: make(chan string),
|
||||
MsgReceiveCh: make(chan string),
|
||||
}
|
||||
wsconn.Done = make(chan struct{})
|
||||
go wsconn.keepAlive()
|
||||
go wsconn.messageReceiveHandler()
|
||||
go wsconn.messageSendHandler()
|
||||
return wsconn
|
||||
|
||||
Reference in New Issue
Block a user