diff --git a/README.md b/README.md index a5b3497..6b2f1c6 100644 --- a/README.md +++ b/README.md @@ -127,13 +127,17 @@ nexttrace --route-path www.time.com.my ```bash # 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. +## 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. +## 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 -## 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. +## 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 @@ -167,7 +171,7 @@ All NextTrace IP geolocation `API DEMO` can refer to [here](https://github.com/x Usage: nexttrace [-h|--help] [-T|--tcp] [-U|--udp] [-F|--fast-trace] [-p|--port ] [-q|--queries ] [--parallel-requests ] [-m|--max-hops ] [-d|--data-provider - (Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal)] + (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 ] [-M|--map] @@ -202,7 +206,7 @@ Arguments: reached). Default: 30 -d --data-provider Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, - IPInfoLocal]. Default: LeoMoeAPI + 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 diff --git a/README_zh_CN.md b/README_zh_CN.md index 478275b..7516602 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -141,7 +141,7 @@ nexttrace --no-rdns www.bbix.net nexttrace --route-path www.time.com.my ``` -`NextTrace`支持用户自主选择 IP 数据库(目前支持:`LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `Ip2region`, `IPInfoLocal`) +`NextTrace`支持用户自主选择 IP 数据库(目前支持:`LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `Ip2region`, `IPInfoLocal`, `CHUNZHEN`) ```bash # 可以自行指定IP数据库[此处为IP-API.com],不指定则默认为LeoMoeAPI @@ -153,6 +153,10 @@ nexttrace --data-provider ip-api.com ## 另外:由于IP.SB被滥用比较严重,会经常出现无法查询的问题,请知悉。 ## 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 ``` @@ -175,7 +179,7 @@ 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 ] [-q|--queries ] [--parallel-requests ] [-m|--max-hops ] [-d|--data-provider - (Ip2region|ip2region|IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal)] + (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 ] [-M|--map] @@ -210,7 +214,7 @@ Arguments: reached). Default: 30 -d --data-provider Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, - IPInfoLocal]. Default: LeoMoeAPI + 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 diff --git a/cmd/cmd.go b/cmd/cmd.go index 1ef4d28..b922f0c 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -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{"Ip2region", "ip2region", "IP.SB", "ip.sb", "IPInfo", "ipinfo", "IPInsight", "ipinsight", "IPAPI.com", "ip-api.com", "IPInfoLocal", "ipinfolocal"}, &argparse.Options{Default: "LeoMoeAPI", - Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, Ip2region, IPInfoLocal]"}) + 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"}) diff --git a/fast_trace/fast_trace ipv6.go b/fast_trace/fast_trace ipv6.go index 8ecf446..de85842 100644 --- a/fast_trace/fast_trace ipv6.go +++ b/fast_trace/fast_trace ipv6.go @@ -117,10 +117,7 @@ func FastTestv6(tm bool, outEnable bool) { w.Interrupt = make(chan os.Signal, 1) signal.Notify(w.Interrupt, os.Interrupt) defer func() { - err := w.Conn.Close() - if err != nil { - return - } + w.Conn.Close() }() if !tm { diff --git a/fast_trace/fast_trace.go b/fast_trace/fast_trace.go index 4284957..a52907b 100644 --- a/fast_trace/fast_trace.go +++ b/fast_trace/fast_trace.go @@ -142,10 +142,7 @@ func FastTest(tm bool, outEnable bool) { w.Interrupt = make(chan os.Signal, 1) signal.Notify(w.Interrupt, os.Interrupt) defer func() { - err := w.Conn.Close() - if err != nil { - return - } + w.Conn.Close() }() if !tm { diff --git a/fast_trace/fast_trace_test.go b/fast_trace/fast_trace_test.go index ae514d5..285c3b8 100644 --- a/fast_trace/fast_trace_test.go +++ b/fast_trace/fast_trace_test.go @@ -17,10 +17,7 @@ func TestTCPTrace(t *testing.T) { w.Interrupt = make(chan os.Signal, 1) signal.Notify(w.Interrupt, os.Interrupt) defer func() { - err := w.Conn.Close() - if err != nil { - return - } + w.Conn.Close() }() ft.TracerouteMethod = trace.TCPTrace ft.testCM() diff --git a/ipgeo/chunzhen.go b/ipgeo/chunzhen.go new file mode 100644 index 0000000..8326892 --- /dev/null +++ b/ipgeo/chunzhen.go @@ -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 +} diff --git a/ipgeo/ipgeo.go b/ipgeo/ipgeo.go index 3aca36d..78264b6 100644 --- a/ipgeo/ipgeo.go +++ b/ipgeo/ipgeo.go @@ -47,6 +47,8 @@ func GetSource(s string) Source { return IP2Region case "IPINFOLOCAL": return IPInfoLocal + case "CHUNZHEN": + return Chunzhen default: return LeoIP } diff --git a/ipgeo/ipinfo.go b/ipgeo/ipinfo.go index 6576a1b..1b34294 100644 --- a/ipgeo/ipinfo.go +++ b/ipgeo/ipinfo.go @@ -279,12 +279,19 @@ func IPInfo(ip string) (*IPGeoData, error) { "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: 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 }