mirror of
https://github.com/nxtrace/NTrace-core.git
synced 2025-08-12 06:26:39 +00:00
Compare commits
5 Commits
v0.1.5-bet
...
v0.1.5-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3aa4696fa9 | ||
|
|
b4abaffc7c | ||
|
|
c96fb4efa3 | ||
|
|
876de6bde1 | ||
|
|
7dbec0c7a1 |
71
README.md
71
README.md
@@ -13,26 +13,24 @@
|
||||
### Automated Install
|
||||
|
||||
```bash
|
||||
#下载nt_install.sh
|
||||
curl -Ls https://github.com/xgadget-lab/nexttrace/raw/main/nt_install.sh -O
|
||||
#执行nt_install.sh
|
||||
sudo bash nt_install.sh
|
||||
# Note: This Script Only Supports Linux/macOS, Other Unix-Like Systems are UNAVAILABLE
|
||||
curl -Ls https://github.com/xgadget-lab/nexttrace/raw/main/nt_install.sh -O && sudo bash nt_install.sh
|
||||
```
|
||||
|
||||
### Alternative methods
|
||||
* `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
|
||||
* 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台不可用。
|
||||
|
||||
如果你的目的只是为了快速测试服务器的到中国内地的线路,没有手动使用 NextTrace 的需求,那么建议你直接使用本仓库的 `quicklytest.sh`
|
||||
### Fast Test
|
||||
|
||||
此脚本旨在快速测试服务器的到中国内地的线路,建议新手或者没有自定义`NextTrace`功能需求的用户使用。
|
||||
|
||||
```bash
|
||||
#下载quicklytest.sh
|
||||
curl -Ls https://github.com/xgadget-lab/nexttrace/raw/main/quicklytest.sh -O
|
||||
#执行quicklytest.sh
|
||||
sudo bash quicklytest.sh
|
||||
curl -Ls https://github.com/xgadget-lab/nexttrace/raw/main/quicklytest.sh -O && sudo bash quicklytest.sh
|
||||
```
|
||||
|
||||
### Get Started
|
||||
|
||||
`NextTrace`默认使用`icmp`协议发起`TraceRoute`请求,该协议同时支持`IPv4`和`IPv6`
|
||||
`NextTrace`默认使用`ICMP`协议发起`TraceRoute`请求,该协议同时支持`IPv4`和`IPv6`
|
||||
|
||||
```bash
|
||||
# IPv4 ICMP Trace
|
||||
@@ -141,17 +139,17 @@ Options:
|
||||
|
||||
## 项目截图
|
||||
|
||||

|
||||
<img src=asset/screenshot.png alt="NextTrace Screenshot" width="683" height="688" />
|
||||
|
||||
## FAQ 常见问题
|
||||
|
||||
如果你在安装或者使用的时候遇到了问题,我们建议你不要把新建一个 `issue` 作为首选项
|
||||
|
||||
或许可以在这里找到答案 -> [前往 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)
|
||||
以下是我们推荐的排错流程:
|
||||
|
||||
如果在搜索引擎,WiKi 处还是没有解决,可以试试在本项目讨论区交流 -> [前往 Github Discussions](https://github.com/xgadget-lab/nexttrace/discussions)
|
||||
|
||||
最终如果你确认遇到的是 BUG、上述方法都不能解决的话,请按照提供好的模版在 Issues 区提出问题 -> [前往 Github Issues](https://github.com/xgadget-lab/nexttrace/issues)
|
||||
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. 不会软件的参数使用 -> [前往 Github Discussions](https://github.com/xgadget-lab/nexttrace/discussions)
|
||||
3. 疑似BUG、或者功能建议 -> [前往 Github Issues](https://github.com/xgadget-lab/nexttrace/issues)
|
||||
|
||||
## Thanks
|
||||
|
||||
@@ -159,36 +157,43 @@ Options:
|
||||
|
||||
[Sam Sam](https://github.com/samleong123) (samsam123@samsam123.name.my)
|
||||
|
||||
[waiting4new](https://github.com/waiting4new)、[FFEE_CO](https://github.com/fkx4-p)、[nsnnns](https://github.com/tsosunchia)
|
||||
[tsosunchia](https://github.com/tsosunchia)
|
||||
|
||||
[waiting4new](https://github.com/waiting4new)
|
||||
|
||||
[FFEE_CO](https://github.com/fkx4-p)
|
||||
|
||||
## IP Database Copyright
|
||||
|
||||
### IPv4 Database
|
||||
|
||||
#### China MainLand
|
||||
#### China
|
||||
|
||||
- 项目组自行维护 ~ 御三家骨干网数据 ~ 5%
|
||||
|
||||
- 埃文科技 Paid Database ~ 95%
|
||||
|
||||
**这里有朋友就要问了,为什么不全部使用埃文的付费库?**
|
||||
|
||||
埃文的库一直都不是最优选择,IPIP.NET 才是,但是因为他们不对私,所以我们只能选择价格更便宜的埃文库。
|
||||
|
||||
埃文家的数据库,在骨干网这块,准度可以说是非常糟糕,作为一款可视化的路由跟踪工具,骨干网的数据库准度非常重要。
|
||||
|
||||
所以我们选择了尝试自行去校准一部分骨干网数据,但是由于我们缺乏检测节点以及志愿者,所以这项工作可能会进展的尤其缓慢。
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :------------: | :----: | :--------------: | :--: |
|
||||
| 电信/联通/移动 | 骨干网 | NextTrace | 10% |
|
||||
| 电信/联通/移动 | 城域网 | 埃文科技 | 90% |
|
||||
|
||||
#### WorldWide
|
||||
|
||||
- 埃文科技 Paid Database ~ 15%
|
||||
| ISP | 类型 | 数据源 | 占比 |
|
||||
| :------------: | :----: | :--------------: | :--: |
|
||||
| Tier-01 | 骨干网 | IPInfo | 2% |
|
||||
| Tier-01 | 骨干网 | 埃文科技 | 3% |
|
||||
| Tier-01 | 骨干网 | IPInSight | 5% |
|
||||
| Tier-01 | 城域网 | IPInSight | 90% |
|
||||
|
||||
- IpInfo Free ~ 15%
|
||||
|
||||
- IPInSight Free ~ 70%
|
||||
| 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
|
||||
|
||||
31
config/config.go
Normal file
31
config/config.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package config
|
||||
|
||||
import "os"
|
||||
|
||||
type tracerConfig struct {
|
||||
Token `yaml:"Token"`
|
||||
Preference `yaml:"Preference"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
LeoMoeAPI string `yaml:"LeoMoeAPI"`
|
||||
IPInfo string `yaml:"IPInfo"`
|
||||
}
|
||||
|
||||
type Preference struct {
|
||||
AlwaysRoutePath bool `yaml:"AlwaysRoutePath"`
|
||||
}
|
||||
|
||||
type configPath func() (string, error)
|
||||
|
||||
func configFromRunDir() (string, error) {
|
||||
return "./", nil
|
||||
}
|
||||
|
||||
func configFromUserHomeDir() (string, error) {
|
||||
dir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return dir + "/.nexttrace/", nil
|
||||
}
|
||||
18
config/config_test.go
Normal file
18
config/config_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"log"
|
||||
)
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
if res, err := Read(); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
log.Println(res)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateConfig(t *testing.T) {
|
||||
Generate()
|
||||
}
|
||||
94
config/generate_config.go
Normal file
94
config/generate_config.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/ioutil"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func pathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func writeFile(content []byte) error {
|
||||
var err error
|
||||
var path string
|
||||
path, err = configFromUserHomeDir()
|
||||
if err != nil {
|
||||
path, err = configFromRunDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if exist, _ := pathExists(path); !exist {
|
||||
err := os.Mkdir(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(path + "ntraceConfig.yml", []byte(content), 0644); err != nil{
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Generate() (*tracerConfig, error) {
|
||||
var leotoken string
|
||||
var iPInfoToken string
|
||||
var routePathEnable string
|
||||
|
||||
fmt.Println("这是一个配置向导,我们会帮助您生成配置文件,它是一次性的,除非您主动要求重新生成,否则它将不会再出现")
|
||||
|
||||
fmt.Println("请输入您的LeoMoeAPI Token,如果您没有,请到 Telegram Bot @NextTraceBot 获取一个")
|
||||
fmt.Scanln(&leotoken)
|
||||
if leotoken == "" {
|
||||
fmt.Println("检测到您的输入为空,您将使用公共Token。这意味着您将和所有使用此Token的客户端共用每分钟150次IP查询的额度")
|
||||
leotoken = "NextTraceDemo"
|
||||
}
|
||||
|
||||
fmt.Println("请输入您的IPInfo Token,如果您不需要使用IPInfo,可以直接回车")
|
||||
fmt.Scanln(&iPInfoToken)
|
||||
|
||||
token := Token{
|
||||
LeoMoeAPI: leotoken,
|
||||
IPInfo: iPInfoToken,
|
||||
}
|
||||
|
||||
var preference Preference
|
||||
fmt.Print("您是否希望在每次Traceroute结束后显示Route-Path图? (y/n)")
|
||||
fmt.Scanln(&routePathEnable)
|
||||
if routePathEnable == "n" || routePathEnable == "N" || routePathEnable == "no" || routePathEnable == "No" || routePathEnable == "NO" {
|
||||
preference = Preference{AlwaysRoutePath: false}
|
||||
} else {
|
||||
preference = Preference{AlwaysRoutePath: true}
|
||||
}
|
||||
|
||||
finalConfig := tracerConfig{
|
||||
Token: token,
|
||||
Preference: preference,
|
||||
}
|
||||
|
||||
yamlData, err := yaml.Marshal(&finalConfig)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = writeFile(yamlData); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
fmt.Println("配置文件创建成功")
|
||||
return &finalConfig, nil
|
||||
}
|
||||
}
|
||||
47
config/read_config.go
Normal file
47
config/read_config.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func (c *tracerConfig) Parse(data []byte) error {
|
||||
return yaml.Unmarshal(data, c)
|
||||
}
|
||||
|
||||
func readFile(cp configPath) ([]byte, error) {
|
||||
var content []byte
|
||||
path, err := cp()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
content, err = ioutil.ReadFile(path + "ntraceConfig.yml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func Read() (*tracerConfig, error) {
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
data, err = readFile(configFromRunDir)
|
||||
|
||||
if err != nil {
|
||||
data, err = readFile(configFromUserHomeDir)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var config tracerConfig
|
||||
if err := config.Parse(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config, err
|
||||
}
|
||||
1
go.mod
1
go.mod
@@ -11,6 +11,7 @@ require (
|
||||
require (
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
2
go.sum
2
go.sum
@@ -49,6 +49,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||
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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -26,7 +26,9 @@ func GetSource(s string) Source {
|
||||
return IPInSight
|
||||
case "IPAPI.COM":
|
||||
return IPApiCom
|
||||
case "IPINFO":
|
||||
return IPInfo
|
||||
default:
|
||||
return nil
|
||||
return LeoIP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
)
|
||||
|
||||
func IPInfo(ip string) (*IPGeoData, error) {
|
||||
|
||||
resp, err := http.Get("https://ipinfo.io/" + ip + "?token=" + token.ipinfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package ipgeo
|
||||
|
||||
import "github.com/xgadget-lab/nexttrace/config"
|
||||
|
||||
type tokenData struct {
|
||||
ipinsight string
|
||||
ipinfo string
|
||||
@@ -11,3 +13,9 @@ var token = tokenData{
|
||||
ipinfo: "",
|
||||
ipleo: "NextTraceDemo",
|
||||
}
|
||||
|
||||
|
||||
func SetToken(c config.Token) {
|
||||
token.ipleo = c.LeoMoeAPI
|
||||
token.ipinfo = c.IPInfo
|
||||
}
|
||||
|
||||
17
main.go
17
main.go
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/config"
|
||||
"github.com/xgadget-lab/nexttrace/ipgeo"
|
||||
"github.com/xgadget-lab/nexttrace/printer"
|
||||
"github.com/xgadget-lab/nexttrace/reporter"
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
var fSet = flag.NewFlagSet("", flag.ExitOnError)
|
||||
var tcpSYNFlag = fSet.Bool("T", false, "Use TCP SYN for tracerouting (default port is 80)")
|
||||
var udpPackageFlag = fSet.Bool("U", false, "Use UDP Package for tracerouting (default port is 53 in UDP)")
|
||||
var port = flag.Int("p", 80, "Set SYN Traceroute Port")
|
||||
var port = fSet.Int("p", 80, "Set SYN Traceroute Port")
|
||||
var numMeasurements = fSet.Int("q", 3, "Set the number of probes per each hop.")
|
||||
var parallelRequests = fSet.Int("r", 18, "Set ParallelRequests number. It should be 1 when there is a multi-routing.")
|
||||
var maxHops = fSet.Int("m", 30, "Set the max number of hops (max TTL to be reached).")
|
||||
@@ -65,6 +66,16 @@ func main() {
|
||||
log.Fatalln("Traceroute requires root/sudo privileges.")
|
||||
}
|
||||
|
||||
configData, err := config.Read();
|
||||
|
||||
if err != nil {
|
||||
if configData, err = config.Generate(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ipgeo.SetToken(configData.Token)
|
||||
|
||||
ip := util.DomainLookUp(domain)
|
||||
printer.PrintTraceRouteNav(ip, domain, *dataOrigin)
|
||||
|
||||
@@ -110,7 +121,9 @@ func main() {
|
||||
printer.TraceroutePrinter(res)
|
||||
}
|
||||
|
||||
if *routePath {
|
||||
p := configData.Preference
|
||||
|
||||
if *routePath || p.AlwaysRoutePath {
|
||||
r := reporter.New(res, ip.String())
|
||||
r.Print()
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ checkSystemArch() {
|
||||
'arm64' | 'aarch64')
|
||||
archParam="arm64"
|
||||
;;
|
||||
'armv7l')
|
||||
archParam='armv7'
|
||||
;;
|
||||
'i386')
|
||||
archParam="386"
|
||||
;;
|
||||
*)
|
||||
red "未知的系统架构,请联系开发者."
|
||||
exit 1
|
||||
@@ -47,7 +53,7 @@ checkSystemDistribution() {
|
||||
downPath="/var/tmp/nexttrace"
|
||||
;;
|
||||
*)
|
||||
red "unknown: $OSTYPE"
|
||||
red "安装脚本暂不支持的操作系统: $OSTYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user