Compare commits

...

19 Commits

Author SHA1 Message Date
tsosunchia
ead7ebbc25 Update fast_trace_test.go
减少TEST耗时
2023-03-03 13:42:32 +08:00
tsosunchia
7a048fa976 Update README.md 2023-03-03 13:32:55 +08:00
sjlleo
dbb844eb44 Merge pull request #84 from sjlleo/dev
多个API增加支持
2023-03-03 13:30:20 +08:00
tsosunchia
916ac3cb69 add CHUNZHEN api 2023-03-03 12:07:37 +08:00
tsosunchia
bdfba172d1 revert 2023-03-03 12:02:48 +08:00
tsosunchia
a95a741ce2 增加scanf时的默认值 2023-03-02 22:12:34 +08:00
tsosunchia
362317e95e format 2023-03-02 21:47:59 +08:00
tsosunchia
dc735b0f97 Update ipinfo.go 转换ISO3166 2023-03-02 21:21:43 +08:00
tsosunchia
fe0fce07ec Update README 2023-03-02 19:11:26 +08:00
tsosunchia
60a4454802 Update README 2023-03-02 18:56:25 +08:00
tsosunchia
525cfd8c8f merge 2023-03-02 18:47:25 +08:00
tsosunchia
c2eebca25c 修正IPInfo BUG 和增加IPInfoLocal 2023-03-02 18:38:42 +08:00
tsosunchia
110bdc27ff 修改一些第三方API信息
Update README_zh_CN.md
Update README.md
Update ipinsight.go
Update ipgeo.go
2023-03-02 12:05:32 +08:00
tsosunchia
510b0f6c32 可使用别名调用第三方API 2023-03-02 11:48:49 +08:00
tsosunchia
8a01bccbff Update ipinsight.go 2023-03-01 18:04:06 +08:00
tsosunchia
64224c905e Update ipinsight.go 2023-03-01 18:01:18 +08:00
tsosunchia
2403308c1b Update build.yml 2023-02-23 14:53:58 +08:00
sjlleo
560a1693af chore: add more detail 2023-02-20 17:11:21 +08:00
Leo
45e9fe604d chore: clean default args setting 2023-02-20 13:16:08 +08:00
23 changed files with 584 additions and 87 deletions

View File

@@ -1,6 +1,7 @@
on:
push:
pull_request:
workflow_dispatch:
name: Test & Build Release
jobs:
@@ -11,24 +12,35 @@ jobs:
- uses: actions/setup-go@v2
with:
go-version: "1.18"
go-version: "1.20"
- name: Test
run: sudo go test -v -coverprofile='coverage.out' -covermode=count ./...
Build:
needs: test
if: startsWith(github.ref, 'refs/tags/v')
needs: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
with:
go-version: "1.18"
- run: bash .cross_compile.sh
go-version: "1.20"
- name: compile
run: bash .cross_compile.sh
- name: Upload files to Artifacts
uses: actions/upload-artifact@v3
with:
path: |
dist/*
Release:
needs: Build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- name: Release
uses: softprops/action-gh-release@v1
with: # 将下述可执行文件 release 上去
@@ -39,7 +51,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GT_Token }}
publish-new-formula:
needs: build
needs: Release
# The type of runner that the job will run on
runs-on: ubuntu-latest

View File

@@ -8,6 +8,8 @@
An open source visual routing tool that pursues light weight, developed using Golang.
NextTrace is part of the [OwO Network](https://github.com/OwO-Network) project. The project is a joint initiative of Leo and Vincent.
## How To Use
Document Language: English | [简体中文](README_zh_CN.md)
@@ -120,15 +122,25 @@ nexttrace --no-rdns www.bbix.net
nexttrace --route-path www.time.com.my
```
`NextTrace` supports users to select their own IP API (currently supports: `LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`)
`NextTrace` supports users to select their own IP API (currently supports: `LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `Ip2region`, `IPInfoLocal`, `CHUNZHEN`)
```bash
# You can specify the IP database by yourself [IP.SB here], if not specified, LeoMoeAPI will be used
nexttrace --data-provider IP.SB
## Note that the ipinfo API needs users to purchase services from ipinfo. If necessary, you can clone this project, add the token provided by ipinfo and compile it yourself
# You can specify the IP database by yourself [IP-API.com here], if not specified, LeoMoeAPI will be used
nexttrace --data-provider ip-api.com
## Note There are frequency limits for free queries of the ipinfo and IPInsight APIs. You can purchase services from these providers to remove the limits
## If necessary, you can clone this project, add the token provided by ipinfo or IPInsight and compile it yourself
## Note For the offline database IPInfoLocal, please download it manually and rename it to ipinfoLocal.mmdb. (You can download it from here: https://ipinfo.io/signup?ref=free-database-downloads)
## For the offline database Ip2region, you can download it manually and rename it to ip2region.db, or let NextTrace download it automatically
## Fill the token to: ipgeo/tokens.go
## Please be aware: Due to the serious abuse of IP.SB, you will often be not able to query IP data from this source
## IPAPI.com has a stricter restiction on API calls, if you can't query IP data from this source, please try again in a few minutes.
## IP-API.com has a stricter restiction on API calls, if you can't query IP data from this source, please try again in a few minutes
# The Pure-FTPd IP database defaults to using http://127.0.0.1:2060 as the query interface. To customize it, please use environment variables
export NEXTTRACE_CHUNZHENURL=http://127.0.0.1:2060
## You can use https://github.com/freshcn/qqwry to build your own Pure-FTPd IP database service
# You can also specify the default IP database by setting an environment variable
export NEXTTRACE_DATAPROVIDER=ipinfo
```
`NextTrace` supports mixed parameters and shortened parameters
@@ -156,18 +168,18 @@ All NextTrace IP geolocation `API DEMO` can refer to [here](https://github.com/x
### For full usage list, please refer to the usage menu
```shell
usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port
Usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port
<integer>] [-q|--queries <integer>] [--parallel-requests
<integer>] [-m|--max-hops <integer>] [-d|--data-provider
(IP.SB|IPInfo|IPInsight|IPAPI.com)] [-n|--no-rdns]
[-a|--always-rdns] [-P|--route-path] [-r|--report]
[-o|--output] [-t|--table] [-c|--classic] [-f|--first
<integer>] [-M|--map] [-v|--version] [-s|--source "<value>"]
[-D|--dev "<value>"] [-R|--route] [-z|--send-time <integer>]
[-i|--ttl-time <integer>] [-g|--language (en|cn)] [IP Address
or Domain]
An open source visual route tracking CLI tool
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen)]
[-n|--no-rdns] [-a|--always-rdns] [-P|--route-path]
[-r|--report] [--dn42] [-o|--output] [-t|--table]
[-c|--classic] [-f|--first <integer>] [-M|--map]
[-v|--version] [-s|--source "<value>"] [-D|--dev "<value>"]
[-R|--route] [-z|--send-time <integer>] [-i|--ttl-time
<integer>] [_positionalArg_nexttrace_25 "<value>"]
[--dot-server (dnssb|aliyun|dnspod|google|cloudflare)]
[-g|--language (en|cn)]
Arguments:
@@ -192,9 +204,9 @@ Arguments:
18
-m --max-hops Set the max number of hops (max TTL to be
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider
[LeoMoeAPI,IP.SB, IPInfo, IPInsight,
IPAPI.com]. Default: LeoMoeAPI
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com, Ip2region,
IPInfoLocal, CHUNZHEN]. Default: LeoMoeAPI
-n --no-rdns Do not resolve IP addresses to their
domain names
-a --always-rdns Always resolve IP addresses to their
@@ -202,6 +214,7 @@ Arguments:
-P --route-path Print traceroute hop path by ASN and
location
-r --report output using report mode
--dn42 DN42 Mode
-o --output Write trace result to file
(RealTimePrinter ONLY)
-t --table Output trace results as table
@@ -209,7 +222,7 @@ Arguments:
BestTrace
-f --first Start from the first_ttl hop (instead from
1). Default: 1
-M --map Disable Print Trace Map Function
-M --map Disable Print Trace Map
-v --version Print version info and exit
-s --source Use source src_addr for outgoing packets
-D --dev Use the following Network Devices as the
@@ -222,6 +235,9 @@ Arguments:
groups by TTL. Useful when some routers
use rate-limit for ICMP messages. Default:
500
--_positionalArg_nexttrace_25 IP Address or domain name
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
cn]. Default: cn
```

View File

@@ -141,27 +141,35 @@ nexttrace --no-rdns www.bbix.net
nexttrace --route-path www.time.com.my
```
`NextTrace`支持用户自主选择 IP 数据库(目前支持:`LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`
`NextTrace`支持用户自主选择 IP 数据库(目前支持:`LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `Ip2region`, `IPInfoLocal`, `CHUNZHEN`)
```bash
# 可以自行指定IP数据库[此处为IP.SB]不指定则默认为LeoMoeAPI
nexttrace --data-provider IP.SB
## 特别的其中 ipinfo API 需要从 ipinfo 自行购买服务,如有需要可以 clone 本项目添加其提供的 token 自行编译
# 可以自行指定IP数据库[此处为IP-API.com]不指定则默认为LeoMoeAPI
nexttrace --data-provider ip-api.com
## 特别的: 其中 ipinfo 和 IPInsight API 对于免费版查询有频率限制,可从这些服务商自行购买服务以解除限制,如有需要可以 clone 本项目添加其提供的 token 自行编译
## TOKEN填写路径ipgeo/tokens.go
## 特别的: 对于离线库 IPInfoLocal请自行下载并命名为 ipinfoLocal.mmdb (可以从这里下载https://ipinfo.io/signup?ref=free-database-downloads)
## 对于离线库 Ip2region 可NextTrace自动下载也可自行下载并命名为 ip2region.db
## 另外由于IP.SB被滥用比较严重会经常出现无法查询的问题请知悉。
## IPAPI.com限制调用较为严格如有查询不到的情况请几分钟后再试。
## IP-API.com限制调用较为严格如有查询不到的情况请几分钟后再试。
# 纯真IP数据库默认使用 http://127.0.0.1:2060 作为查询接口,如需自定义请使用环境变量
export NEXTTRACE_CHUNZHENURL=http://127.0.0.1:2060
## 可使用 https://github.com/freshcn/qqwry 自行搭建纯真IP数据库服务
# 也可以通过设置环境变量来指定默认IP数据库
export NEXTTRACE_DATAPROVIDER=ipinfo
```
`NextTrace`支持使用混合参数和简略参数
```bash
Example:
nexttrace --data-provider IPAPI.com --max-hops 20 --tcp --port 443 --queries 5 --no-rdns 1.1.1.1
nexttrace --data-provider ip-api.com --max-hops 20 --tcp --port 443 --queries 5 --no-rdns 1.1.1.1
nexttrace -tcp --queries 2 --parallel-requests 1 --table --route-path 2001:4860:4860::8888
Equivalent to:
nexttrace -d IPAPI.com -m 20 -T -p 443 -q 5 -n 1.1.1.1
nexttrace -d ip-api.com -m 20 -T -p 443 -q 5 -n 1.1.1.1
nexttrace -T -q 2 --parallel-requests 1 -t -R 2001:4860:4860::8888
```
@@ -171,12 +179,16 @@ nexttrace -T -q 2 --parallel-requests 1 -t -R 2001:4860:4860::8888
Usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port
<integer>] [-q|--queries <integer>] [--parallel-requests
<integer>] [-m|--max-hops <integer>] [-d|--data-provider
(IP.SB|IPInfo|IPInsight|IPAPI.com)] [-n|--no-rdns]
[-r|--route-path] [-o|--output] [-t|--table] [-c|--classic]
[-f|--first <integer>] [-M|--map] [-v|--version] [-s|--source
"<value>"] [-D|--dev "<value>"] [-R|--route] [-z|--send-time
<integer>] [-i|--ttl-time <integer>]
[IP Address or Domain name]
(Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen)]
[-n|--no-rdns] [-a|--always-rdns] [-P|--route-path]
[-r|--report] [--dn42] [-o|--output] [-t|--table]
[-c|--classic] [-f|--first <integer>] [-M|--map]
[-v|--version] [-s|--source "<value>"] [-D|--dev "<value>"]
[-R|--route] [-z|--send-time <integer>] [-i|--ttl-time
<integer>] [_positionalArg_nexttrace_25 "<value>"]
[--dot-server (dnssb|aliyun|dnspod|google|cloudflare)]
[-g|--language (en|cn)]
Arguments:
-h --help Print help information
@@ -200,13 +212,17 @@ Arguments:
18
-m --max-hops Set the max number of hops (max TTL to be
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider
[LeoMoeAPI,IP.SB, IPInfo, IPInsight,
IPAPI.com]. Default: LeoMoeAPI
-n --no-rdns Do not resolve IP addresses to their
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com, Ip2region,
IPInfoLocal, CHUNZHEN]. Default: LeoMoeAPI
-n --no-rdns Do not resolve IP addresses to their
domain names
-r --route-path Print traceroute hop path by ASN and
-a --always-rdns Always resolve IP addresses to their
domain names
-P --route-path Print traceroute hop path by ASN and
location
-r --report output using report mode
--dn42 DN42 Mode
-o --output Write trace result to file
(RealTimePrinter ONLY)
-t --table Output trace results as table
@@ -214,7 +230,7 @@ Arguments:
BestTrace
-f --first Start from the first_ttl hop (instead from
1). Default: 1
-M --map Disable Print Trace Map Function
-M --map Disable Print Trace Map
-v --version Print version info and exit
-s --source Use source src_addr for outgoing packets
-D --dev Use the following Network Devices as the
@@ -222,11 +238,14 @@ Arguments:
-R --route Show Routing Table [Provided By BGP.Tools]
-z --send-time Set the time interval for sending every
packet. Useful when some routers use
rate-limit for ICMP messages.. Default: 0
rate-limit for ICMP messages. Default: 100
-i --ttl-time Set the time interval for sending packets
groups by TTL. Useful when some routers
use rate-limit for ICMP messages..
Default: 500
use rate-limit for ICMP messages. Default:
500
--_positionalArg_nexttrace_25 IP Address or domain name
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
cn]. Default: cn
```

View File

@@ -37,8 +37,8 @@ func Excute() {
numMeasurements := parser.Int("q", "queries", &argparse.Options{Default: 3, Help: "Set the number of probes per each hop"})
parallelRequests := parser.Int("", "parallel-requests", &argparse.Options{Default: 18, Help: "Set ParallelRequests number. It should be 1 when there is a multi-routing"})
maxHops := parser.Int("m", "max-hops", &argparse.Options{Default: 30, Help: "Set the max number of hops (max TTL to be reached)"})
dataOrigin := parser.Selector("d", "data-provider", []string{"IP.SB", "IPInfo", "IPInsight", "IPAPI.com"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [LeoMoeAPI,IP.SB, IPInfo, IPInsight, IPAPI.com]"})
dataOrigin := parser.Selector("d", "data-provider", []string{"Ip2region", "ip2region", "IP.SB", "ip.sb", "IPInfo", "ipinfo", "IPInsight", "ipinsight", "IPAPI.com", "ip-api.com", "IPInfoLocal", "ipinfolocal", "chunzhen"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, IPInfoLocal, CHUNZHEN]"})
noRdns := parser.Flag("n", "no-rdns", &argparse.Options{Help: "Do not resolve IP addresses to their domain names"})
alwaysRdns := parser.Flag("a", "always-rdns", &argparse.Options{Help: "Always resolve IP addresses to their domain names"})
routePath := parser.Flag("P", "route-path", &argparse.Options{Help: "Print traceroute hop path by ASN and location"})
@@ -56,7 +56,7 @@ func Excute() {
packet_interval := parser.Int("z", "send-time", &argparse.Options{Default: 100, Help: "Set the time interval for sending every packet. Useful when some routers use rate-limit for ICMP messages"})
ttl_interval := parser.Int("i", "ttl-time", &argparse.Options{Default: 500, Help: "Set the time interval for sending packets groups by TTL. Useful when some routers use rate-limit for ICMP messages"})
str := parser.StringPositional(&argparse.Options{Help: "IP Address or domain name"})
dot := parser.Selector("", "dot-server", []string{"dnssb", "aliyun", "dnspod", "google", "cloudflare"}, &argparse.Options{Default: "dnssb",
dot := parser.Selector("", "dot-server", []string{"dnssb", "aliyun", "dnspod", "google", "cloudflare"}, &argparse.Options{
Help: "Use DoT Server for DNS Parse [dnssb, aliyun, dnspod, google, cloudflare]"})
lang := parser.Selector("g", "language", []string{"en", "cn"}, &argparse.Options{Default: "cn",
Help: "Choose the language for displaying [en, cn]"})
@@ -141,12 +141,17 @@ func Excute() {
}
if strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
val, ok := os.LookupEnv("NEXTTRACE_DATAPROVIDER")
if ok {
*dataOrigin = val
} else {
w := wshandle.New()
w.Interrupt = make(chan os.Signal, 1)
signal.Notify(w.Interrupt, os.Interrupt)
defer func() {
w.Conn.Close()
}()
}
}
printer.PrintTraceRouteNav(ip, domain, *dataOrigin)

View File

@@ -27,8 +27,14 @@ func InitConfig() {
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
fmt.Println("未能找到配置文件,我们将在您的运行目录为您创建 nt_config.yaml 默认配置")
viper.SafeWriteConfigAs("./nt_config.yaml")
err := viper.SafeWriteConfigAs("./nt_config.yaml")
if err != nil {
return
}
}
viper.ReadInConfig()
err = viper.ReadInConfig()
if err != nil {
return
}
}

View File

@@ -20,7 +20,12 @@ func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollection) {
if err != nil {
return
}
defer fp.Close()
defer func(fp *os.File) {
err := fp.Close()
if err != nil {
log.Fatal(err)
}
}(fp)
log.SetOutput(fp)
log.SetFlags(0)
@@ -100,7 +105,10 @@ func FastTestv6(tm bool, outEnable bool) {
fmt.Println("您想测试哪些ISP的路由\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网")
fmt.Print("请选择选项:")
fmt.Scanln(&c)
_, err := fmt.Scanln(&c)
if err != nil {
c = "1"
}
ft := FastTracer{}

View File

@@ -19,14 +19,19 @@ type FastTracer struct {
TracerouteMethod trace.Method
}
var oe bool = false
var oe = 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()
defer func(fp *os.File) {
err := fp.Close()
if err != nil {
log.Fatal(err)
}
}(fp)
log.SetOutput(fp)
log.SetFlags(0)
@@ -114,7 +119,10 @@ func FastTest(tm bool, outEnable bool) {
fmt.Println("Hi欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂我们设置的测试目标有限建议普通用户自测以获得更加精准的路由情况")
fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6")
fmt.Print("请选择选项:")
fmt.Scanln(&c)
_, err := fmt.Scanln(&c)
if err != nil {
c = "1"
}
if c == "2" {
FastTestv6(tm, outEnable)
return
@@ -122,7 +130,10 @@ func FastTest(tm bool, outEnable bool) {
fmt.Println("您想测试哪些ISP的路由\n1. 国内四网\n2. 电信\n3. 联通\n4. 移动\n5. 教育网")
fmt.Print("请选择选项:")
fmt.Scanln(&c)
_, err = fmt.Scanln(&c)
if err != nil {
c = "1"
}
ft := FastTracer{}

View File

@@ -20,6 +20,5 @@ func TestTCPTrace(t *testing.T) {
w.Conn.Close()
}()
ft.TracerouteMethod = trace.TCPTrace
ft.testCM()
ft.testEDU()
}

1
go.mod
View File

@@ -5,6 +5,7 @@ go 1.20
require (
github.com/akamensky/argparse v1.4.0
github.com/google/gopacket v1.1.19
github.com/oschwald/maxminddb-golang v1.10.0
github.com/spf13/viper v1.15.0
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
golang.org/x/net v0.7.0

2
go.sum
View File

@@ -153,6 +153,8 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

91
ipgeo/chunzhen.go Normal file
View File

@@ -0,0 +1,91 @@
package ipgeo
import (
"encoding/json"
"github.com/xgadget-lab/nexttrace/util"
"io"
"log"
"net/http"
"strings"
"time"
)
func Chunzhen(ip string) (*IPGeoData, error) {
url := util.GetenvDefault("NEXTTRACE_CHUNZHENURL", "http://127.0.0.1:2060") + "?ip=" + ip
client := &http.Client{
// 2 秒超时
Timeout: 2 * time.Second,
}
req, _ := http.NewRequest("GET", url, nil)
content, err := client.Do(req)
if err != nil {
log.Println("纯真 请求超时(2s)请切换其他API使用")
return &IPGeoData{}, err
}
body, _ := io.ReadAll(content.Body)
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
return &IPGeoData{}, err
}
city := data[ip].(map[string]interface{})["area"].(string)
region := data[ip].(map[string]interface{})["country"].(string)
var asn string
if data[ip].(map[string]interface{})["asn"] != nil {
asn = data[ip].(map[string]interface{})["asn"].(string)
}
// 判断是否前两个字为香港或台湾
var country string
provinces := []string{
"北京",
"天津",
"河北",
"山西",
"内蒙古",
"辽宁",
"吉林",
"黑龙江",
"上海",
"江苏",
"浙江",
"安徽",
"福建",
"江西",
"山东",
"河南",
"湖北",
"湖南",
"广东",
"广西",
"海南",
"重庆",
"四川",
"贵州",
"云南",
"西藏",
"陕西",
"甘肃",
"青海",
"宁夏",
"新疆",
"台湾",
"香港",
"澳门",
}
for _, province := range provinces {
if strings.Contains(region, province) {
country = "中国"
city = region + city
break
}
}
if country == "" {
country = region
}
return &IPGeoData{
Asnumber: asn,
Country: country,
City: city,
}, nil
}

View File

@@ -2,7 +2,7 @@ package ipgeo
import (
"errors"
"io/ioutil"
"io"
"log"
"net/http"
"regexp"
@@ -24,7 +24,7 @@ func IPApiCom(ip string) (*IPGeoData, error) {
log.Println("ip-api.com 请求超时(2s)请切换其他API使用")
return nil, err
}
body, _ := ioutil.ReadAll(content.Body)
body, _ := io.ReadAll(content.Body)
res := gjson.ParseBytes(body)
if res.Get("status").String() != "success" {

View File

@@ -13,7 +13,7 @@ func cidrRangeContains(cidrRange string, checkIP string) bool {
return ipNet.Contains(secondIP)
}
// 被选到的返回 geodata, true 否则返回 nil, false
// Filter 被选到的返回 geodata, true 否则返回 nil, false
func Filter(ip string) (*IPGeoData, bool) {
//geodata := &IPGeoData{}
asn := ""

View File

@@ -39,10 +39,16 @@ func GetSource(s string) Source {
return IPInSight
case "IPAPI.COM":
return IPApiCom
case "IP-API.COM":
return IPApiCom
case "IPINFO":
return IPInfo
case "IP2REGION":
return IP2Region
case "IPINFOLOCAL":
return IPInfoLocal
case "CHUNZHEN":
return Chunzhen
default:
return LeoIP
}

View File

@@ -1,8 +1,9 @@
package ipgeo
import (
"io/ioutil"
"io"
"net/http"
"strings"
"github.com/tidwall/gjson"
)
@@ -13,7 +14,7 @@ func IPInfo(ip string) (*IPGeoData, error) {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@@ -21,16 +22,276 @@ func IPInfo(ip string) (*IPGeoData, error) {
res := gjson.ParseBytes(body)
var country string
country = res.Get("country").String()
if res.Get("country").String() == "HK" || res.Get("country").String() == "TW" {
country = "CN"
}
// ISO-3166 转换
var countryMap = map[string]string{
"AF": "Afghanistan",
"AX": "Åland Islands",
"AL": "Albania",
"DZ": "Algeria",
"AS": "American Samoa",
"AD": "Andorra",
"AO": "Angola",
"AI": "Anguilla",
"AQ": "Antarctica",
"AG": "Antigua and Barbuda",
"AR": "Argentina",
"AM": "Armenia",
"AW": "Aruba",
"AU": "Australia",
"AT": "Austria",
"AZ": "Azerbaijan",
"BH": "Bahrain",
"BS": "Bahamas",
"BD": "Bangladesh",
"BB": "Barbados",
"BY": "Belarus",
"BE": "Belgium",
"BZ": "Belize",
"BJ": "Benin",
"BM": "Bermuda",
"BT": "Bhutan",
"BO": "Bolivia",
"BQ": "Bonaire",
"BA": "Bosnia and Herzegovina",
"BW": "Botswana",
"BV": "Bouvet Island",
"BR": "Brazil",
"IO": "British Indian Ocean Territory",
"BN": "Brunei Darussalam",
"BG": "Bulgaria",
"BF": "Burkina Faso",
"BI": "Burundi",
"KH": "Cambodia",
"CM": "Cameroon",
"CA": "Canada",
"CV": "Cape Verde",
"KY": "Cayman Islands",
"CF": "Central African Republic",
"TD": "Chad",
"CL": "Chile",
"CN": "China",
"CX": "Christmas Island",
"CC": "Cocos (Keeling) Islands",
"CO": "Colombia",
"KM": "Comoros",
"CG": "Congo",
"CD": "Congo",
"CK": "Cook Islands",
"CR": "Costa Rica",
"CI": "Côte d'Ivoire",
"HR": "Croatia",
"CU": "Cuba",
"CW": "Curaçao",
"CY": "Cyprus",
"CZ": "Czech Republic",
"DK": "Denmark",
"DJ": "Djibouti",
"DM": "Dominica",
"DO": "Dominican Republic",
"EC": "Ecuador",
"EG": "Egypt",
"SV": "El Salvador",
"GQ": "Equatorial Guinea",
"ER": "Eritrea",
"EE": "Estonia",
"ET": "Ethiopia",
"FK": "Falkland Islands (Malvinas)",
"FO": "Faroe Islands",
"FJ": "Fiji",
"FI": "Finland",
"FR": "France",
"GF": "French Guiana",
"PF": "French Polynesia",
"TF": "French Southern Territories",
"GA": "Gabon",
"GM": "Gambia",
"GE": "Georgia",
"DE": "Germany",
"GH": "Ghana",
"GI": "Gibraltar",
"GR": "Greece",
"GL": "Greenland",
"GD": "Grenada",
"GP": "Guadeloupe",
"GU": "Guam",
"GT": "Guatemala",
"GG": "Guernsey",
"GN": "Guinea",
"GW": "Guinea-Bissau",
"GY": "Guyana",
"HT": "Haiti",
"HM": "Heard Island and McDonald Islands",
"VA": "Holy See (Vatican City State)",
"HN": "Honduras",
"HK": "Hong Kong",
"HU": "Hungary",
"IS": "Iceland",
"IN": "India",
"ID": "Indonesia",
"IR": "Iran",
"IQ": "Iraq",
"IE": "Ireland",
"IM": "Isle of Man",
"IL": "Israel",
"IT": "Italy",
"JM": "Jamaica",
"JP": "Japan",
"JE": "Jersey",
"JO": "Jordan",
"KZ": "Kazakhstan",
"KE": "Kenya",
"KI": "Kiribati",
"KP": "Korea",
"KR": "Korea",
"KW": "Kuwait",
"KG": "Kyrgyzstan",
"LA": "Lao People's Democratic Republic",
"LV": "Latvia",
"LB": "Lebanon",
"LS": "Lesotho",
"LR": "Liberia",
"LY": "Libya",
"LI": "Liechtenstein",
"LT": "Lithuania",
"LU": "Luxembourg",
"MO": "Macao",
"MK": "Macedonia",
"MG": "Madagascar",
"MW": "Malawi",
"MY": "Malaysia",
"MV": "Maldives",
"ML": "Mali",
"MT": "Malta",
"MH": "Marshall Islands",
"MQ": "Martinique",
"MR": "Mauritania",
"MU": "Mauritius",
"YT": "Mayotte",
"MX": "Mexico",
"FM": "Micronesia",
"MD": "Moldova",
"MC": "Monaco",
"MN": "Mongolia",
"ME": "Montenegro",
"MS": "Montserrat",
"MA": "Morocco",
"MZ": "Mozambique",
"MM": "Myanmar",
"NA": "Namibia",
"NR": "Nauru",
"NP": "Nepal",
"NL": "Netherlands",
"NC": "New Caledonia",
"NZ": "New Zealand",
"NI": "Nicaragua",
"NE": "Niger",
"NG": "Nigeria",
"NU": "Niue",
"NF": "Norfolk Island",
"MP": "Northern Mariana Islands",
"NO": "Norway",
"OM": "Oman",
"PK": "Pakistan",
"PW": "Palau",
"PS": "Palestine",
"PA": "Panama",
"PG": "Papua New Guinea",
"PY": "Paraguay",
"PE": "Peru",
"PH": "Philippines",
"PN": "Pitcairn",
"PL": "Poland",
"PT": "Portugal",
"PR": "Puerto Rico",
"QA": "Qatar",
"RE": "Réunion",
"RO": "Romania",
"RU": "Russian Federation",
"RW": "Rwanda",
"BL": "Saint Barthélemy",
"SH": "Saint Helena",
"KN": "Saint Kitts and Nevis",
"LC": "Saint Lucia",
"MF": "Saint Martin (French part)",
"PM": "Saint Pierre and Miquelon",
"VC": "Saint Vincent and the Grenadines",
"WS": "Samoa",
"SM": "San Marino",
"ST": "Sao Tome and Principe",
"SA": "Saudi Arabia",
"SN": "Senegal",
"RS": "Serbia",
"SC": "Seychelles",
"SL": "Sierra Leone",
"SG": "Singapore",
"SX": "Sint Maarten (Dutch part)",
"SK": "Slovakia",
"SI": "Slovenia",
"SB": "Solomon Islands",
"SO": "Somalia",
"ZA": "South Africa",
"GS": "South Georgia and the South Sandwich Islands",
"SS": "South Sudan",
"ES": "Spain",
"LK": "Sri Lanka",
"SD": "Sudan",
"SR": "Suriname",
"SJ": "Svalbard and Jan Mayen",
"SZ": "Swaziland",
"SE": "Sweden",
"CH": "Switzerland",
"SY": "Syrian Arab Republic",
"TW": "Taiwan",
"TJ": "Tajikistan",
"TZ": "Tanzania",
"TH": "Thailand",
"TL": "Timor-Leste",
"TG": "Togo",
"TK": "Tokelau",
"TO": "Tonga",
"TT": "Trinidad and Tobago",
"TN": "Tunisia",
"TR": "Turkey",
"TM": "Turkmenistan",
"TC": "Turks and Caicos Islands",
"TV": "Tuvalu",
"UG": "Uganda",
"UA": "Ukraine",
"AE": "United Arab Emirates",
"GB": "United Kingdom",
"US": "United States of America",
"UM": "United States Minor Outlying Islands",
"UY": "Uruguay",
"UZ": "Uzbekistan",
"VU": "Vanuatu",
"VE": "Venezuela",
"VN": "Viet Nam",
"VG": "Virgin Islands",
"VI": "Virgin Islands",
"WF": "Wallis and Futuna",
"EH": "Western Sahara",
"YE": "Yemen",
"ZM": "Zambia",
"ZW": "Zimbabwe",
}
country = countryMap[country]
i := strings.Index(res.Get("org").String(), " ")
var owner string
if i == -1 {
owner = ""
} else {
owner = res.Get("org").String()[i:]
}
return &IPGeoData{
Asnumber: res.Get("asn").Get("asn").String(),
Asnumber: strings.Fields(strings.TrimPrefix(res.Get("org").String(), "AS"))[0],
Country: country,
City: res.Get("city").String(),
Prov: res.Get("region").String(),
Owner: res.Get("asn").Get("domain").String(),
Owner: owner,
}, nil
}

52
ipgeo/ipinfoLocal.go Normal file
View File

@@ -0,0 +1,52 @@
package ipgeo
import (
"errors"
"github.com/oschwald/maxminddb-golang"
"net"
"os"
"strings"
)
const (
ipinfoDataBasePath = "./ipinfoLocal.mmdb"
)
func IPInfoLocal(ip string) (*IPGeoData, error) {
if _, err := os.Stat(ipinfoDataBasePath); os.IsNotExist(err) {
panic("Cannot find ipinfoLocal.mmdb")
}
region, err := maxminddb.Open(ipinfoDataBasePath)
if err != nil {
panic("Cannot find ipinfoLocal.mmdb")
}
defer func(region *maxminddb.Reader) {
err := region.Close()
if err != nil {
panic(err)
}
}(region)
var record interface{}
searchErr := region.Lookup(net.ParseIP(ip), &record)
if searchErr != nil {
return &IPGeoData{}, errors.New("no results")
}
recordMap := record.(map[string]interface{})
country_name := recordMap["country_name"].(string)
prov := ""
if recordMap["country"].(string) == "HK" {
country_name = "China"
prov = "Hong Kong"
}
if recordMap["country"].(string) == "TW" {
country_name = "China"
prov = "Taiwan"
}
return &IPGeoData{
Asnumber: strings.TrimPrefix(recordMap["asn"].(string), "AS"),
Country: country_name,
City: "",
Prov: prov,
Owner: recordMap["as_name"].(string),
}, nil
}

View File

@@ -1,18 +1,18 @@
package ipgeo
import (
"io/ioutil"
"io"
"net/http"
"github.com/tidwall/gjson"
)
func IPInSight(ip string) (*IPGeoData, error) {
resp, err := http.Get("https://ipinsight.io/query?ip=" + ip)
resp, err := http.Get("https://api.ipinsight.io/ip/" + ip + "?token=" + token.ipinsight)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

View File

@@ -1,7 +1,7 @@
package ipgeo
import (
"io/ioutil"
"io"
"log"
"net/http"
"os"
@@ -24,7 +24,7 @@ func IPSB(ip string) (*IPGeoData, error) {
log.Println("api.ip.sb 请求超时(2s)请切换其他API使用")
return nil, err
}
body, _ := ioutil.ReadAll(content.Body)
body, _ := io.ReadAll(content.Body)
res := gjson.ParseBytes(body)
if res.Get("country").String() == "" {

View File

@@ -19,7 +19,7 @@ import (
* 运作模型可以理解为一个 Node 一直在等待数据,当获得一个新的任务后,转交给下一个协程,不再关注这个 Node 的下一步处理过程,并且回到空闲状态继续等待新的任务
***/
// IP 查询池 map - ip - ip channel
// IPPool IP 查询池 map - ip - ip channel
type IPPool struct {
pool map[string]chan IPGeoData
poolMux sync.Mutex
@@ -48,7 +48,7 @@ func receiveParse() {
// json解析 -> data
res := gjson.Parse(data)
// 根据返回的IP信息发送给对应等待回复的IP通道上
var domain string = res.Get("domain").String()
var domain = res.Get("domain").String()
if res.Get("domain").String() == "" {
domain = res.Get("owner").String()

View File

@@ -45,7 +45,7 @@ func experimentTag() {
func (r *reporter) generateRouteReportNode(ip string, ipGeoData ipgeo.IPGeoData, ttl uint16) {
var success bool = true
var success = true
defer r.wg.Done()

View File

@@ -17,7 +17,12 @@ func RealtimePrinter(res *trace.Result, ttl int) {
if err != nil {
return
}
defer f.Close()
defer func(f *os.File) {
err := f.Close()
if err != nil {
log.Fatal(err)
}
}(f)
multiWriter := io.MultiWriter(os.Stdout, f)
log.SetOutput(multiWriter)

View File

@@ -11,7 +11,7 @@ import (
func GetMapUrl(r string) {
url := "https://api.leo.moe/tracemap/api"
resp, _ := http.Post(url, "application/json", strings.NewReader(string(r)))
resp, _ := http.Post(url, "application/json", strings.NewReader(r))
body, _ := io.ReadAll(resp.Body)
fmt.Fprintf(color.Output, "%s %s\n",
color.New(color.FgWhite, color.Bold).Sprintf("%s", "MapTrace URL:"),

View File

@@ -10,7 +10,7 @@ import (
"github.com/fatih/color"
)
// get the local ip and port based on our destination ip
// LocalIPPort get the local ip and port based on our destination ip
func LocalIPPort(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345")
if err != nil {
@@ -95,7 +95,10 @@ func DomainLookUp(host string, ipv4Only bool, dotServer string) net.IP {
}
var index int
fmt.Printf("Your Option: ")
fmt.Scanln(&index)
_, err := fmt.Scanln(&index)
if err != nil {
index = 0
}
if index >= len(ips) || index < 0 {
fmt.Println("Your Option is invalid")
os.Exit(3)