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 | |
|---|---|---|---|
|
|
88e69f7dc2 | ||
|
|
b1a66546a0 | ||
|
|
5c46e4eddb | ||
|
|
30d550753c | ||
|
|
50b3e442da | ||
|
|
ba133e3c73 | ||
|
|
3a5184b06c | ||
|
|
e825b8d092 | ||
|
|
f64934bfde | ||
|
|
9871449b30 | ||
|
|
31a9c356e1 | ||
|
|
5c0c490ae8 | ||
|
|
22660143b0 | ||
|
|
f4b5de08ca | ||
|
|
b0e1329d66 | ||
|
|
805e827e45 | ||
|
|
ed2250f811 | ||
|
|
fe18c80f83 | ||
|
|
d1c9fd6c3a | ||
|
|
c67e2d6384 | ||
|
|
309ae9d74a | ||
|
|
cf65ff5e7e | ||
|
|
eae92ebfae | ||
|
|
afe18fc4c0 | ||
|
|
cc1d6177ca | ||
|
|
c8077919ce | ||
|
|
cfc79489d4 | ||
|
|
f60e6fbc99 | ||
|
|
de0f49d01b | ||
|
|
7ae47fdb6f | ||
|
|
471412b740 | ||
|
|
8aca06fe24 | ||
|
|
003db157a9 | ||
|
|
6e88706d62 | ||
|
|
0940014b09 | ||
|
|
5a7d04ab1e | ||
|
|
c6b7db8d59 |
@@ -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 windows/amd64 windows/arm64 openbsd/amd64 openbsd/arm64 freebsd/amd64 freebsd/arm64"
|
||||
PLATFORMS="darwin/amd64 darwin/arm64 linux/386 linux/amd64 linux/arm64 linux/mips linux/mips64 linux/mipsle linux/mips64le 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')"
|
||||
|
||||
53
.github/workflows/build.yml
vendored
53
.github/workflows/build.yml
vendored
@@ -34,18 +34,43 @@ jobs:
|
||||
with: # 将下述可执行文件 release 上去
|
||||
draft: false # Release草稿
|
||||
files: |
|
||||
dist/nexttrace_darwin_amd64
|
||||
dist/nexttrace_darwin_arm64
|
||||
dist/nexttrace_linux_386
|
||||
dist/nexttrace_linux_amd64
|
||||
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
|
||||
dist/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GT_Token }}
|
||||
GITHUB_TOKEN: ${{ secrets.GT_Token }}
|
||||
|
||||
publish-new-formula:
|
||||
needs: build
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# 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' || true
|
||||
git remote set-url origin https://${{ secrets.gt_token }}@github.com/xgadget-lab/homebrew-nexttrace.git
|
||||
git push
|
||||
# env:
|
||||
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
|
||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||
|
||||
5
.github/workflows/publishNewFormula.yml
vendored
5
.github/workflows/publishNewFormula.yml
vendored
@@ -3,7 +3,6 @@ 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
|
||||
@@ -22,7 +21,7 @@ jobs:
|
||||
git config --global user.name "${{ secrets.git_name }}"
|
||||
- name: Clone repo
|
||||
run: |
|
||||
git clone https://github.com/xgadget-lab/homebrew-nexttrace.git
|
||||
git clone https://github.com/sjlleo/homebrew-nexttrace.git
|
||||
- name: Exec scipt
|
||||
run: |
|
||||
cd homebrew-nexttrace
|
||||
@@ -39,7 +38,7 @@ jobs:
|
||||
run: |
|
||||
cd homebrew-nexttrace
|
||||
git commit -am 'Publish a new version with Formula' || true
|
||||
git remote set-url origin https://${{ secrets.gt_token }}@github.com/xgadget-lab/homebrew-nexttrace.git
|
||||
git remote set-url origin https://${{ secrets.gt_token }}@github.com/sjlleo/homebrew-nexttrace.git
|
||||
git push
|
||||
# env:
|
||||
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
|
||||
|
||||
94
README.md
94
README.md
@@ -18,11 +18,11 @@ Document Language: English | [简体中文](README_zh_CN.md)
|
||||
# Linux one-click install script
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)
|
||||
|
||||
# GHPROXY 镜像(国内使用)
|
||||
bash -c "$(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)"
|
||||
|
||||
# macOS brew install command
|
||||
brew tap xgadget-lab/nexttrace && brew install nexttrace
|
||||
|
||||
# GHProxy Mirror (For China Mainland User)
|
||||
bash -c "$(curl -Ls https://ghproxy.com/https://raw.githubusercontent.com/sjlleo/nexttrace/main/nt_install.sh)"
|
||||
```
|
||||
|
||||
Windows users please go to [Release Page](https://github.com/sjlleo/nexttrace/releases/latest) directly and download exe file.
|
||||
@@ -37,6 +37,8 @@ Windows users please go to [Release Page](https://github.com/sjlleo/nexttrace/re
|
||||
```bash
|
||||
# IPv4 ICMP Trace
|
||||
nexttrace 1.0.0.1
|
||||
# URL
|
||||
nexttrace http://example.com:8080/index.html?q=1
|
||||
|
||||
# Form printing (output all hops at one time, wait 20-40 seconds)
|
||||
nexttrace --table 1.0.0.1
|
||||
@@ -44,8 +46,8 @@ nexttrace --table 1.0.0.1
|
||||
# IPv6 ICMP Trace
|
||||
nexttrace 2606:4700:4700::1111
|
||||
|
||||
# Path Visualization With the -M parameter, a map URL is returned
|
||||
nexttrace --map koreacentral.blob.core.windows.net
|
||||
# Disable Path Visualization With the -M parameter
|
||||
nexttrace koreacentral.blob.core.windows.net
|
||||
# MapTrace URL: https://api.leo.moe/tracemap/html/c14e439e-3250-5310-8965-42a1e3545266.html
|
||||
```
|
||||
|
||||
@@ -76,14 +78,14 @@ nexttrace --dev eth0 2606:4700:4700::1111
|
||||
nexttrace --source 204.98.134.56 9.9.9.9
|
||||
```
|
||||
|
||||
`NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests, but these protocols only supports `IPv4` now
|
||||
`NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests, but `UDP` protocols only supports `IPv4` now
|
||||
|
||||
```bash
|
||||
# TCP SYN Trace
|
||||
nexttrace --tcp www.bing.com
|
||||
|
||||
# You can specify the port by yourself [here is 443], the default port is 80
|
||||
nexttrace --tcp --port 443 1.0.0.1
|
||||
nexttrace --tcp --port 443 2001:4860:4860::8888
|
||||
|
||||
# UDP Trace
|
||||
nexttrace --udp 1.0.0.1
|
||||
@@ -154,15 +156,19 @@ 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]
|
||||
[-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]
|
||||
[-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
|
||||
|
||||
Arguments:
|
||||
|
||||
-h --help Print help information
|
||||
@@ -189,10 +195,13 @@ Arguments:
|
||||
-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
|
||||
-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
|
||||
-o --output Write trace result to file
|
||||
(RealTimePrinter ONLY)
|
||||
-t --table Output trace results as table
|
||||
@@ -200,8 +209,7 @@ Arguments:
|
||||
BestTrace
|
||||
-f --first Start from the first_ttl hop (instead from
|
||||
1). Default: 1
|
||||
-M --map Print Trace Map. This will return a Trace
|
||||
Map URL
|
||||
-M --map Disable Print Trace Map Function
|
||||
-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
|
||||
@@ -209,57 +217,31 @@ 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
|
||||
-g --language Choose the language for displaying [en,
|
||||
cn]. Default: cn
|
||||
```
|
||||
|
||||
## Project screenshot
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
## NextTrace Enhanced
|
||||
|
||||
`NextTrace Enhanced` is an enhanced version for enthusiasts, `Enhanced` provides trace route calls in the form of Web API and a simple Looking Glass webpage with built-in visualization.
|
||||
|
||||
The `Enhanced` version supports many functions that the `lite` version does not have, such as the ability to customize the timeout period, and the ability to specify TTL as the starting point for route tracking, etc. For ordinary users, the `lite` version is usually enough.
|
||||
Please Notice that `NextTrace Enhanced` is currently not supported in English.
|
||||
|
||||
https://github.com/OwO-Network/nexttrace-enhanced
|
||||
|
||||
## 公告
|
||||
|
||||
我今天看到了一些非常难过的事情,一些用户在 BestTrace 和 WorstTrace 下面宣传 NextTrace 的完全可替代性。
|
||||
|
||||
这么做是不正确的,NextTrace 从来都不是一个从零开始的软件,NextTrace 之所以能够拥有某些功能特性,是因为吸取了 BestTrace 、WorstTrace 的一些想法。
|
||||
|
||||
我们希望您在使用的时候知晓这一点,**我们是站在巨人的肩膀上,而尊重其他软件作者,向他们或者是我们提交 Bug 或贡献代码,才是推动整个 traceroute 工具的软件多样化发展的最好方式**。
|
||||
|
||||
NextTrace 并不追求成为一个替代者,同类软件越多样化,才能满足更多人的需求,这才是我们希望看到的,而去诋毁其他软件,这违背了我们对于开发 NextTrace 的初衷。
|
||||
|
||||
我们希望看到这条公告的朋友应该主动删除自己过激的言论,如果您有任何问题或建议,请随时在我们的社区中发表。
|
||||
|
||||
## LeoMoeAPI Credit
|
||||
|
||||
NextTrace 重点在于研究 Go 语言 Traceroute 的实现,其 LeoMoeAPI 的地理位置信息并没有原始数据的支撑,故也不可能有商用版本。
|
||||
|
||||
LeoMoeAPI 存在部分社区贡献者校准的数据,也包含了部分其他第三方数据库的数据,这些数据的所有权归校准者、第三方数据库所有,**仅供路由跟踪地理位置的展示参考使用**,我们不对数据提供准度做任何保证,请尊重他们的成果,如用于其他用途后果自负,特此告知。
|
||||
|
||||
1. 对于辛勤提供马来西亚地区节点的 samleong123、全球节点的 TOHUNET Looking Glass 以及来自 Misaka 的 Ping.sx 表示感谢,目前 80% 以上的可靠校准数据出自这些节点的 ping / mtr 报告。
|
||||
|
||||
2. 同时感谢 isyekong 在基于 rDNS 校准上思路以及数据上做出的贡献,LeoMoeAPI 正在加快对 rDNS 的解析功能研发,目前已经做到部分骨干网的地理位置自动化解析,但存在一定误判。
|
||||
我们希望 NextTrace 在未来能成为对 One-Man ISP 友好的 Traceroute 工具,我们也在尽可能完善对这些 ASN 的微型骨干网的校准。
|
||||
|
||||
3. 在开发上,我要由衷感谢 missuo 以及 zhshch 在 Go 交叉编译、设计理念以及 TCP/UDP Traceroute 重构上的帮助、tsosunchia 在 TraceMap 上的倾力支持。
|
||||
|
||||
4. 我还要感谢 FFEE_CO、TheresaQWQ、stydxm 和其他朋友的帮助。LeoMoeAPI自首次发布以来得到了很多各方面的支持,所以我想把他们都归功于此。
|
||||
|
||||
我们希望您能够在使用时尽可能多多反馈 IP 地理位置错误(详见 issue),这样它就能够在第一时间得到校准,他人也会因此而受益。
|
||||
|
||||
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.
|
||||
@@ -274,14 +256,6 @@ The LeoMoeAPI data is subject to copyright restrictions from multiple data sourc
|
||||
|
||||
We hope you can give us as much feedback as possible on IP geolocation errors (see issue) so that it can be calibrated in the first place and others can benefit from it.
|
||||
|
||||
## 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
|
||||
|
||||
Here is our recommended troubleshooting process:
|
||||
|
||||
1. Check if it is already in FAQ -> [Go to 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. Suspected bug or feature suggestion -> [Go to Github Issues](https://github.com/xgadget-lab/nexttrace/issues)
|
||||
|
||||
## JetBrain Support
|
||||
|
||||
@@ -309,4 +283,4 @@ Although other third-party APIs are integrated in this project, please refer to
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#xgadget-lab/nexttrace&Date)
|
||||
[](https://star-history.com/#sjlleo/nexttrace&Date)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<h4 align="center">一款追求轻量化的开源可视化路由跟踪工具。</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/zu1k/nali/actions">
|
||||
<a href="https://github.com/sjlleo/nexttrace/actions">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/sjlleo/nexttrace/build.yml?branch=main&style=flat-square" alt="Github Actions">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/sjlleo/nexttrace">
|
||||
@@ -26,6 +26,10 @@
|
||||
|
||||
## How To Use
|
||||
|
||||
### Before Using
|
||||
|
||||
使用 NextTrace 之前,我们建议您先阅读 [#IP 数据以及精准度说明](https://github.com/sjlleo/nexttrace/blob/main/README_zh_CN.md#ip-%E6%95%B0%E6%8D%AE%E4%BB%A5%E5%8F%8A%E7%B2%BE%E5%87%86%E5%BA%A6%E8%AF%B4%E6%98%8E),在了解您自己的对数据精准度需求以后再进行抉择。
|
||||
|
||||
### Automated Install
|
||||
|
||||
```bash
|
||||
@@ -51,6 +55,8 @@ Windows 用户请直接前往 [Release](https://github.com/sjlleo/nexttrace/rele
|
||||
```bash
|
||||
# IPv4 ICMP Trace
|
||||
nexttrace 1.0.0.1
|
||||
# URL
|
||||
nexttrace http://example.com:8080/index.html?q=1
|
||||
|
||||
# 表格打印,使用 --table / -t 参数,将实时显示结果
|
||||
nexttrace --table 1.0.0.1
|
||||
@@ -58,8 +64,8 @@ nexttrace --table 1.0.0.1
|
||||
# IPv6 ICMP Trace
|
||||
nexttrace 2606:4700:4700::1111
|
||||
|
||||
# 路径可视化 使用 --map / -M 参数,将返回一个地图 URL
|
||||
nexttrace --map koreacentral.blob.core.windows.net
|
||||
# 禁用路径可视化 使用 --map / -M 参数
|
||||
nexttrace koreacentral.blob.core.windows.net
|
||||
# MapTrace URL: https://api.leo.moe/tracemap/html/c14e439e-3250-5310-8965-42a1e3545266.html
|
||||
```
|
||||
|
||||
@@ -75,7 +81,7 @@ PS: 路由可视化的绘制模块由 [@tsosunchia](https://github.com/tsosunchi
|
||||
# 北上广(电信+联通+移动+教育网)IPv4 / IPv6 ICMP 快速测试
|
||||
nexttrace --fast-trace
|
||||
|
||||
# 也可以使用 TCP SYN 而非 ICMP 进行测试(不支持 IPv6)
|
||||
# 也可以使用 TCP SYN 而非 ICMP 进行测试
|
||||
nexttrace --fast-trace --tcp
|
||||
```
|
||||
|
||||
@@ -92,14 +98,14 @@ nexttrace --dev eth0 2606:4700:4700::1111
|
||||
nexttrace --source 204.98.134.56 9.9.9.9
|
||||
```
|
||||
|
||||
`NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求,不过目前只支持`IPv4`
|
||||
`NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求,不过目前`UDP`只支持`IPv4`
|
||||
|
||||
```bash
|
||||
# TCP SYN Trace
|
||||
nexttrace --tcp www.bing.com
|
||||
|
||||
# 可以自行指定端口[此处为443],默认80端口
|
||||
nexttrace --tcp --port 443 1.0.0.1
|
||||
nexttrace --tcp --port 443 2001:4860:4860::8888
|
||||
|
||||
# UDP Trace
|
||||
nexttrace --udp 1.0.0.1
|
||||
@@ -208,8 +214,7 @@ Arguments:
|
||||
BestTrace
|
||||
-f --first Start from the first_ttl hop (instead from
|
||||
1). Default: 1
|
||||
-M --map Print Trace Map. This will return a Trace
|
||||
Map URL
|
||||
-M --map Disable Print Trace Map Function
|
||||
-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,15 +227,17 @@ Arguments:
|
||||
groups by TTL. Useful when some routers
|
||||
use rate-limit for ICMP messages..
|
||||
Default: 500
|
||||
-g --language Choose the language for displaying [en,
|
||||
cn]. Default: cn
|
||||
```
|
||||
|
||||
## 项目截图
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### 第三方 IP 数据库 API 开发接口
|
||||
## 第三方 IP 数据库 API 开发接口
|
||||
|
||||
NextTrace 所有的的 IP 地理位置 `API DEMO` 可以参考[这里](https://github.com/sjlleo/nexttrace/blob/main/ipgeo/)
|
||||
|
||||
@@ -244,7 +251,7 @@ NextTrace 所有的的 IP 地理位置 `API DEMO` 可以参考[这里](https://g
|
||||
|
||||
https://github.com/OwO-Network/nexttrace-enhanced
|
||||
|
||||
## Thanks
|
||||
## Credits
|
||||
|
||||
BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢。
|
||||
|
||||
@@ -258,6 +265,60 @@ BGP.TOOLS 提供了本项目的一些数据支持,在此表示由衷地感谢
|
||||
|
||||
[FFEE_CO](https://github.com/fkx4-p)
|
||||
|
||||
### Others
|
||||
## Others
|
||||
|
||||
其他第三方 API 尽管集成在本项目内,但是具体的 TOS 以及 AUP,请详见第三方 API 官网。如遇到 IP 数据错误,也请直接联系他们纠错。
|
||||
|
||||
## IP 数据以及精准度说明
|
||||
|
||||
NextTrace 有多个数据源可以选择,目前默认使用的 LeoMoeAPI 为我们项目维护的数据源。
|
||||
|
||||
LeoMoeAPI 早期数据主要来自 IPInsight、IPInfo,随着项目发展,越来越多的志愿者参与进了这个项目。目前 LeoMoeAPI 有近一半的数据是社区提供的,而另外一半主要来自于包含 IPInfo、IPData、BigDataCloud、IPGeoLocation 在内的多个第三方数据。
|
||||
|
||||
LeoMoeAPI 的骨干网数据有近 70% 是社区自发反馈又或者是项目组成员校准的,这给本项目的路由跟踪基础功能带来了一定的保证,但是全球骨干网的体量庞大,我们并无能力如 IPIP 等商业公司拥有海量监测节点,这使得 LeoMoeAPI 的数据精准度无法和形如 BestTrace(IPIP)相提并论。
|
||||
|
||||
LeoMoeAPI 已经尽力校准了比较常见的骨干网路由,这部分在测试的时候经常会命中,但是如果遇到封闭型 ISP 的路由,大概率可以遇到错误,此类数据不仅是我们,哪怕 IPInsight、IPInfo 也无法正确定位,目前只有 IPIP 能够标记正确,如对此类数据的精确性有着非常高的要求,请务必使用 BestTrace 作为首选。
|
||||
|
||||
我们不保证我们的数据一定会及时更新,也不保证数据的精确性,我们希望您在发现数据错误的时候可以前往 issue 页面提交错误报告,谢谢。
|
||||
|
||||
当您使用 LeoMoeAPI 即视为您已经完全了解 NextTrace LeoMoeAPI 的数据精确性,并且同意如果您引用 LeoMoeAPI 其中的数据从而引发的一切问题,均由您自己承担。
|
||||
|
||||
## DN42 模式使用说明
|
||||
|
||||
使用这个模式需要您配置 2 个文件,分别是 geofeed.csv 以及 ptr.csv
|
||||
|
||||
当您初次运行 DN42 模式,NT 会为您生成 nt_config.yaml 文件,您可以自定义 2 个文件的存放位置,默认应该存放在 NT 的运行目录下
|
||||
|
||||
### GeoFeed
|
||||
|
||||
对于 geofeed.csv 来说,格式如下:
|
||||
```
|
||||
IP_CDIR,LtdCode,ISO3166-2,CityName,ASN,IPWhois
|
||||
```
|
||||
|
||||
比如,您可以这么写:
|
||||
|
||||
```
|
||||
58.215.96.0/20,CN,CN-JS,Wuxi,23650,CHINANET-JS
|
||||
```
|
||||
|
||||
如果您有一个大段作为骨干网使用,您也可以不写地理位置信息,如下:
|
||||
|
||||
```
|
||||
202.97.0.0/16,,,4134,CHINANET-BACKBONE
|
||||
```
|
||||
|
||||
### PTR
|
||||
|
||||
对于 ptr.csv 来说,格式如下:
|
||||
```
|
||||
IATA_CODE,LtdCode,RegionName,CityName
|
||||
```
|
||||
|
||||
比如对于美国洛杉矶,您可以这么写
|
||||
|
||||
```
|
||||
LAX,US,California,Los Anegles
|
||||
```
|
||||
|
||||
需要注意的是,NextTrace 支持自动匹配 CSV 中的城市名,如果您的 PTR 记录中有 `losangeles`,您可以只添加上面一条记录就可以正常识别并读取。
|
||||
|
||||
58
cmd/cmd.go
58
cmd/cmd.go
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/akamensky/argparse"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"github.com/xgadget-lab/nexttrace/config"
|
||||
fastTrace "github.com/xgadget-lab/nexttrace/fast_trace"
|
||||
"github.com/xgadget-lab/nexttrace/ipgeo"
|
||||
"github.com/xgadget-lab/nexttrace/printer"
|
||||
@@ -38,21 +39,27 @@ func Excute() {
|
||||
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]"})
|
||||
noRdns := parser.Flag("n", "no-rdns", &argparse.Options{Help: " Do not resolve IP addresses to their domain names"})
|
||||
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"})
|
||||
report := parser.Flag("r", "report", &argparse.Options{Help: "output using report mode"})
|
||||
dn42 := parser.Flag("", "dn42", &argparse.Options{Help: "DN42 Mode"})
|
||||
output := parser.Flag("o", "output", &argparse.Options{Help: "Write trace result to file (RealTimePrinter ONLY)"})
|
||||
tablePrint := parser.Flag("t", "table", &argparse.Options{Help: "Output trace results as table"})
|
||||
classicPrint := parser.Flag("c", "classic", &argparse.Options{Help: "Classic Output trace results like BestTrace"})
|
||||
beginHop := parser.Int("f", "first", &argparse.Options{Default: 1, Help: "Start from the first_ttl hop (instead from 1)"})
|
||||
maptrace := parser.Flag("M", "map", &argparse.Options{Help: "Print Trace Map. This will return a Trace Map URL"})
|
||||
maptrace := parser.Flag("M", "map", &argparse.Options{Help: "Disable Print Trace Map"})
|
||||
ver := parser.Flag("v", "version", &argparse.Options{Help: "Print version info and exit"})
|
||||
src_addr := parser.String("s", "source", &argparse.Options{Help: "Use source src_addr for outgoing packets"})
|
||||
src_dev := parser.String("D", "dev", &argparse.Options{Help: "Use the following Network Devices as the source address in outgoing packets"})
|
||||
router := parser.Flag("R", "route", &argparse.Options{Help: "Show Routing Table [Provided By BGP.Tools]"})
|
||||
packet_interval := parser.Int("z", "send-time", &argparse.Options{Default: 0, 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."})
|
||||
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",
|
||||
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]"})
|
||||
|
||||
err := parser.Parse(os.Args)
|
||||
if err != nil {
|
||||
@@ -87,6 +94,18 @@ func Excute() {
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(domain, "/") {
|
||||
domain = strings.Split(domain, "/")[2]
|
||||
}
|
||||
|
||||
if strings.Contains(domain, "]") {
|
||||
domain = strings.Split(strings.Split(domain, "]")[0], "[")[1]
|
||||
} else if strings.Contains(domain, ":") {
|
||||
if strings.Count(domain, ":") == 1 {
|
||||
domain = strings.Split(domain, ":")[0]
|
||||
}
|
||||
}
|
||||
|
||||
capabilities_check()
|
||||
// return
|
||||
|
||||
@@ -96,10 +115,10 @@ func Excute() {
|
||||
fmt.Println("NextTrace 基于 Windows 的路由跟踪还在早期开发阶段,目前还存在诸多问题,TCP/UDP SYN 包请求可能不能正常运行")
|
||||
}
|
||||
|
||||
if *tcp || *udp {
|
||||
ip = util.DomainLookUp(domain, true)
|
||||
if *udp {
|
||||
ip = util.DomainLookUp(domain, true, *dot)
|
||||
} else {
|
||||
ip = util.DomainLookUp(domain, false)
|
||||
ip = util.DomainLookUp(domain, false, *dot)
|
||||
}
|
||||
|
||||
if *src_dev != "" {
|
||||
@@ -114,6 +133,13 @@ func Excute() {
|
||||
}
|
||||
}
|
||||
|
||||
if *dn42 {
|
||||
// 初始化配置
|
||||
config.InitConfig()
|
||||
*dataOrigin = "DN42"
|
||||
*maptrace = true
|
||||
}
|
||||
|
||||
if strings.ToUpper(*dataOrigin) == "LEOMOEAPI" {
|
||||
w := wshandle.New()
|
||||
w.Interrupt = make(chan os.Signal, 1)
|
||||
@@ -141,6 +167,7 @@ func Excute() {
|
||||
}
|
||||
|
||||
var conf = trace.Config{
|
||||
DN42: *dn42,
|
||||
SrcAddr: *src_addr,
|
||||
BeginHop: *beginHop,
|
||||
DestIP: ip,
|
||||
@@ -150,7 +177,9 @@ func Excute() {
|
||||
TTLInterval: *ttl_interval,
|
||||
NumMeasurements: *numMeasurements,
|
||||
ParallelRequests: *parallelRequests,
|
||||
Lang: *lang,
|
||||
RDns: !*noRdns,
|
||||
AlwaysWaitRDNS: *alwaysRdns,
|
||||
IPGeoSource: ipgeo.GetSource(*dataOrigin),
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
@@ -189,7 +218,7 @@ func Excute() {
|
||||
r.Print()
|
||||
}
|
||||
|
||||
if *maptrace {
|
||||
if !*maptrace {
|
||||
r, _ := json.Marshal(res)
|
||||
tracemap.GetMapUrl(string(r))
|
||||
}
|
||||
@@ -221,7 +250,12 @@ func capabilities_check() {
|
||||
// NewPid 已经被废弃了,这里改用 NewPid2 方法
|
||||
caps, err := capability.NewPid2(0)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
// 判断是否为macOS
|
||||
if runtime.GOOS == "darwin" {
|
||||
// macOS下报错有问题
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -238,8 +272,8 @@ func capabilities_check() {
|
||||
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` 查看")
|
||||
fmt.Println("您正在以普通用户权限运行 NextTrace,但 NextTrace 未被赋予监听网络套接字的ICMP消息包、修改IP头信息(TTL)等路由跟踪所需的权限")
|
||||
fmt.Println("请使用管理员用户执行 `sudo setcap cap_net_raw,cap_net_admin+eip ${your_nexttrace_path}/nexttrace` 命令,赋予相关权限后再运行~")
|
||||
fmt.Println("什么?为什么 ping 普通用户执行不要 root 权限?因为这些工具在管理员安装时就已经被赋予了一些必要的权限,具体请使用 `getcap /usr/bin/ping` 查看")
|
||||
}
|
||||
}
|
||||
|
||||
34
config/viper.go
Normal file
34
config/viper.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func InitConfig() {
|
||||
|
||||
// 配置文件名, 不加扩展
|
||||
viper.SetConfigName("nt_config") // name of config file (without extension)
|
||||
// 设置文件的扩展名
|
||||
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
|
||||
// 查找配置文件所在路径
|
||||
viper.AddConfigPath("/etc/bin/nexttrace/")
|
||||
viper.AddConfigPath("/usr/local/bin/nexttrace/")
|
||||
// 在当前路径进行查找
|
||||
viper.AddConfigPath(".")
|
||||
// viper.AddConfigPath("./config/")
|
||||
|
||||
// 配置默认值
|
||||
viper.SetDefault("ptrPath", "./ptr.csv")
|
||||
viper.SetDefault("geoFeedPath", "./geofeed.csv")
|
||||
|
||||
// 开始查找并读取配置文件
|
||||
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")
|
||||
}
|
||||
|
||||
viper.ReadInConfig()
|
||||
}
|
||||
7
dn42/dn42.go
Normal file
7
dn42/dn42.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package dn42
|
||||
|
||||
/***
|
||||
[DN42 Package]
|
||||
谨献给 DN42 所有的小伙伴们,祝你们终有一天能有自己的公网 ASN ~
|
||||
By Leo
|
||||
***/
|
||||
101
dn42/geofeed.go
Normal file
101
dn42/geofeed.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package dn42
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"net"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type GeoFeedRow struct {
|
||||
IPNet *net.IPNet
|
||||
CIDR string
|
||||
LtdCode string
|
||||
ISO3166 string
|
||||
City string
|
||||
ASN string
|
||||
IPWhois string
|
||||
}
|
||||
|
||||
func GetGeoFeed(ip string) (GeoFeedRow, bool) {
|
||||
rows, err := ReadGeoFeed()
|
||||
if err != nil {
|
||||
// 处理错误
|
||||
panic(err)
|
||||
}
|
||||
|
||||
row, find := FindGeoFeedRow(ip, rows)
|
||||
return row, find
|
||||
|
||||
}
|
||||
|
||||
func ReadGeoFeed() ([]GeoFeedRow, error) {
|
||||
path := viper.Get("geoFeedPath").(string)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := csv.NewReader(f)
|
||||
rows, err := r.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将 CSV 中的每一行转换为 GeoFeedRow 类型,并保存到 rowsSlice 中
|
||||
var rowsSlice []GeoFeedRow
|
||||
for _, row := range rows {
|
||||
cidr := row[0] // 假设第一列是 CIDR 字段
|
||||
_, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
// 如果解析 CIDR 失败,跳过这一行
|
||||
continue
|
||||
}
|
||||
if len(row) == 4 {
|
||||
rowsSlice = append(rowsSlice, GeoFeedRow{
|
||||
IPNet: ipnet,
|
||||
CIDR: cidr,
|
||||
LtdCode: row[1],
|
||||
ISO3166: row[2],
|
||||
City: row[3],
|
||||
})
|
||||
} else {
|
||||
rowsSlice = append(rowsSlice, GeoFeedRow{
|
||||
IPNet: ipnet,
|
||||
CIDR: cidr,
|
||||
LtdCode: row[1],
|
||||
ISO3166: row[2],
|
||||
City: row[3],
|
||||
ASN: row[4],
|
||||
IPWhois: row[5],
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
// 根据 CIDR 范围从小到大排序,方便后面查找
|
||||
sort.Slice(rowsSlice, func(i, j int) bool {
|
||||
return rowsSlice[i].IPNet.Mask.String() > rowsSlice[j].IPNet.Mask.String()
|
||||
})
|
||||
|
||||
return rowsSlice, nil
|
||||
}
|
||||
|
||||
func FindGeoFeedRow(ipStr string, rows []GeoFeedRow) (GeoFeedRow, bool) {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
// 如果传入的 IP 无效,直接返回
|
||||
return GeoFeedRow{}, false
|
||||
}
|
||||
|
||||
// 遍历每个 CIDR 范围,找到第一个包含传入的 IP 的 CIDR
|
||||
for _, row := range rows {
|
||||
if row.IPNet.Contains(ip) {
|
||||
return row, true
|
||||
}
|
||||
}
|
||||
|
||||
return GeoFeedRow{}, false
|
||||
}
|
||||
17
dn42/geofeed_test.go
Normal file
17
dn42/geofeed_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package dn42
|
||||
|
||||
// func TestGeoFeed(t *testing.T) {
|
||||
// rows, err := ReadGeoFeed()
|
||||
// if err != nil {
|
||||
// // 处理错误
|
||||
// }
|
||||
|
||||
// row, found := FindGeoFeedRow("2001:0418:1403:8080::6fff", rows)
|
||||
// if found {
|
||||
// // 处理符合条件的 row
|
||||
// log.Println(row)
|
||||
// } else {
|
||||
// // 处理未找到的情况
|
||||
// }
|
||||
|
||||
// }
|
||||
83
dn42/ptr.go
Normal file
83
dn42/ptr.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package dn42
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type PtrRow struct {
|
||||
IATACode string
|
||||
LtdCode string
|
||||
Region string
|
||||
City string
|
||||
}
|
||||
|
||||
func matchesPattern(prefix string, s string) bool {
|
||||
pattern := fmt.Sprintf(`^(.*[-.\d]|^)%s[-.\d].*$`, prefix)
|
||||
|
||||
r, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
fmt.Println("Invalid regular expression:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return r.MatchString(s)
|
||||
}
|
||||
|
||||
func FindPtrRecord(ptr string) (PtrRow, error) {
|
||||
path := viper.Get("ptrPath").(string)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return PtrRow{}, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := csv.NewReader(f)
|
||||
rows, err := r.ReadAll()
|
||||
if err != nil {
|
||||
return PtrRow{}, err
|
||||
}
|
||||
// 转小写
|
||||
ptr = strings.ToLower(ptr)
|
||||
// 先查城市名
|
||||
for _, row := range rows {
|
||||
city := row[3]
|
||||
if city == "" {
|
||||
continue
|
||||
}
|
||||
city = strings.ReplaceAll(city, " ", "")
|
||||
city = strings.ToLower(city)
|
||||
|
||||
if matchesPattern(city, ptr) {
|
||||
return PtrRow{
|
||||
LtdCode: row[1],
|
||||
Region: row[2],
|
||||
City: row[3],
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
// 查 IATA Code
|
||||
for _, row := range rows {
|
||||
iata := row[0]
|
||||
if iata == "" {
|
||||
continue
|
||||
}
|
||||
iata = strings.ToLower(iata)
|
||||
if matchesPattern(iata, ptr) {
|
||||
return PtrRow{
|
||||
IATACode: iata,
|
||||
LtdCode: row[1],
|
||||
Region: row[2],
|
||||
City: row[3],
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return PtrRow{}, errors.New("ptr not found")
|
||||
}
|
||||
50
dn42/ptr_test.go
Normal file
50
dn42/ptr_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package dn42
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPTR(t *testing.T) {
|
||||
|
||||
// example_mis := []string{
|
||||
// "sloutravel.com",
|
||||
// "memeslou.org",
|
||||
// "followsloucity.net",
|
||||
// "slouslou.slou",
|
||||
// "slouslou8.slou",
|
||||
// }
|
||||
|
||||
// examples := []string{
|
||||
|
||||
// "1ge.slou.as1299.net",
|
||||
// "1ge.slou2.as1299.net",
|
||||
// "1ge-slou.as1299.net",
|
||||
// "slou-1.as1299.net",
|
||||
// "slou.as1299.com",
|
||||
// "1ge-snge-6.as1299.net",
|
||||
// "c-1.sin.sg.atlas.moeqing.com",
|
||||
// "core.hkg1.hk.atlas.moeqing.com",
|
||||
// "core.losangles.us.atlas.moeqing.com",
|
||||
// }
|
||||
|
||||
// fmt.Println("容易误匹配的 PTR")
|
||||
|
||||
// for _, s := range example_mis {
|
||||
// if r, err := FindPtrRecord("ptr.csv"); err == nil {
|
||||
// fmt.Println(s, r)
|
||||
// } else {
|
||||
// fmt.Println(s, err)
|
||||
// }
|
||||
|
||||
// }
|
||||
// fmt.Println("\n应该正常匹配的 PTR")
|
||||
// for _, s := range examples {
|
||||
// if r, err := FindPtrRecord("ptr.csv"); err == nil {
|
||||
// fmt.Println(s, r)
|
||||
// } else {
|
||||
// fmt.Println(s, err)
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ type BackBoneCollection struct {
|
||||
CU169 ISPCollection
|
||||
CU9929 ISPCollection
|
||||
CM ISPCollection
|
||||
CMIN2 ISPCollection
|
||||
EDU ISPCollection
|
||||
CST ISPCollection
|
||||
}
|
||||
@@ -32,6 +33,7 @@ const (
|
||||
CU169 string = "联通 169 AS4837"
|
||||
CU9929 string = "联通 A网 AS9929"
|
||||
CM string = "移动 骨干网 AS9808"
|
||||
CMIN2 string = "移动 CMIN2 AS58807"
|
||||
EDU string = "教育网 CERNET AS4538"
|
||||
)
|
||||
|
||||
@@ -57,12 +59,22 @@ var Beijing = BackBoneCollection{
|
||||
IPv6: "2408:8000:1010:2::10",
|
||||
},
|
||||
|
||||
CU9929: ISPCollection{
|
||||
ISPName: CU9929,
|
||||
IP: "218.105.131.125",
|
||||
},
|
||||
|
||||
CM: ISPCollection{
|
||||
ISPName: CM,
|
||||
IP: "211.136.25.153",
|
||||
IPv6: "2409:8000:3800:8::3",
|
||||
},
|
||||
|
||||
CMIN2: ISPCollection{
|
||||
ISPName: CMIN2,
|
||||
IP: "223.70.155.55",
|
||||
},
|
||||
|
||||
EDU: ISPCollection{
|
||||
ISPName: EDU,
|
||||
IP: "101.6.15.130",
|
||||
@@ -74,7 +86,7 @@ var Shanghai = BackBoneCollection{
|
||||
Location: "上海",
|
||||
CT163: ISPCollection{
|
||||
ISPName: CT163,
|
||||
IP: "101.226.28.198",
|
||||
IP: "202.101.21.178",
|
||||
IPv6: "240e:18:2:153::89",
|
||||
},
|
||||
|
||||
@@ -101,6 +113,11 @@ var Shanghai = BackBoneCollection{
|
||||
IPv6: "2409:801e:f0:1::4e1",
|
||||
},
|
||||
|
||||
CMIN2: ISPCollection{
|
||||
ISPName: CMIN2,
|
||||
IP: "183.194.134.1",
|
||||
},
|
||||
|
||||
EDU: ISPCollection{
|
||||
ISPName: EDU,
|
||||
IP: "202.120.58.155",
|
||||
|
||||
@@ -41,13 +41,10 @@ func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollection) {
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
if f.TracerouteMethod == trace.ICMPTrace {
|
||||
if oe {
|
||||
conf.RealtimePrinter = tracelog.RealtimePrinter
|
||||
} else {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
}
|
||||
|
||||
if oe {
|
||||
conf.RealtimePrinter = tracelog.RealtimePrinter
|
||||
} else {
|
||||
conf.RealtimePrinter = printer.RealtimePrinter
|
||||
}
|
||||
|
||||
_, err = trace.Traceroute(f.TracerouteMethod, conf)
|
||||
@@ -115,7 +112,12 @@ func FastTestv6(tm bool, outEnable bool) {
|
||||
w.Conn.Close()
|
||||
}()
|
||||
|
||||
ft.TracerouteMethod = trace.ICMPTrace
|
||||
if !tm {
|
||||
ft.TracerouteMethod = trace.ICMPTrace
|
||||
fmt.Println("您将默认使用ICMP协议进行路由跟踪,如果您想使用TCP SYN进行路由跟踪,可以加入 -T 参数")
|
||||
} else {
|
||||
ft.TracerouteMethod = trace.TCPTrace
|
||||
}
|
||||
|
||||
switch c {
|
||||
case "1":
|
||||
|
||||
@@ -43,6 +43,8 @@ func (f *FastTracer) tracert(location string, ispCollection ISPCollection) {
|
||||
NumMeasurements: 3,
|
||||
ParallelRequests: 18,
|
||||
RDns: true,
|
||||
PacketInterval: 100,
|
||||
TTLInterval: 500,
|
||||
IPGeoSource: ipgeo.GetSource("LeoMoeAPI"),
|
||||
Timeout: 1 * time.Second,
|
||||
}
|
||||
@@ -81,6 +83,7 @@ func (f *FastTracer) testCT() {
|
||||
|
||||
func (f *FastTracer) testCU() {
|
||||
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU169)
|
||||
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CU9929)
|
||||
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CU169)
|
||||
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CU9929)
|
||||
f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.CU169)
|
||||
@@ -89,7 +92,9 @@ func (f *FastTracer) testCU() {
|
||||
|
||||
func (f *FastTracer) testCM() {
|
||||
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CM)
|
||||
f.tracert(TestIPsCollection.Beijing.Location, TestIPsCollection.Beijing.CMIN2)
|
||||
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CM)
|
||||
f.tracert(TestIPsCollection.Shanghai.Location, TestIPsCollection.Shanghai.CMIN2)
|
||||
f.tracert(TestIPsCollection.Hangzhou.Location, TestIPsCollection.Hangzhou.CM)
|
||||
f.tracert(TestIPsCollection.Guangzhou.Location, TestIPsCollection.Guangzhou.CM)
|
||||
}
|
||||
@@ -106,7 +111,7 @@ func FastTest(tm bool, outEnable bool) {
|
||||
var c string
|
||||
|
||||
oe = outEnable
|
||||
|
||||
fmt.Println("Hi,欢迎使用 Fast Trace 功能,请注意 Fast Trace 功能只适合新手使用\n因为国内网络复杂,我们设置的测试目标有限,建议普通用户自测以获得更加精准的路由情况")
|
||||
fmt.Println("请您选择要测试的 IP 类型\n1. IPv4\n2. IPv6")
|
||||
fmt.Print("请选择选项:")
|
||||
fmt.Scanln(&c)
|
||||
|
||||
3
geofeed.example.csv
Normal file
3
geofeed.example.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
154.48.0.0/12,,,,174,COGENT-NET
|
||||
200.15.12.0/22,BR,BR-SP,Sao Paulo,2914,NTT-BACKBONE
|
||||
2001:0418:1403::/48,US,US-VA,Ashburn,2914,NTT-BACKBONE
|
||||
|
27
go.mod
27
go.mod
@@ -1,30 +1,41 @@
|
||||
module github.com/xgadget-lab/nexttrace
|
||||
|
||||
go 1.19
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/akamensky/argparse v1.4.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/spf13/viper v1.15.0
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
|
||||
golang.org/x/net v0.5.0
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/sync v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fatih/color v1.14.1
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/lionsoul2014/ip2region v2.11.0+incompatible
|
||||
github.com/lionsoul2014/ip2region v2.11.1+incompatible
|
||||
github.com/rodaine/table v1.1.0
|
||||
github.com/stretchr/testify v1.7.1 // indirect
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
476
go.sum
476
go.sum
@@ -1,36 +1,193 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
|
||||
github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
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/lionsoul2014/ip2region v2.11.0+incompatible h1:+L3q50qdDztfPfwKFukSWoOFTpbPhiYRXMmr2cYPPdM=
|
||||
github.com/lionsoul2014/ip2region v2.11.0+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/lionsoul2014/ip2region v2.11.1+incompatible h1:FEqj5PvIP6YwnGt3RYndGQaiftEIJJGpw4BCB76nvfM=
|
||||
github.com/lionsoul2014/ip2region v2.11.1+incompatible/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
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/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=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rodaine/table v1.1.0 h1:/fUlCSdjamMY8VifdQRIu3VWZXYLY7QHFkVorS8NTr4=
|
||||
github.com/rodaine/table v1.1.0/go.mod h1:Qu3q5wi1jTQD6B6HsP6szie/S4w1QUQ8pq22pz9iL8g=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
|
||||
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
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.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
@@ -40,29 +197,316 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
62
ipgeo/dn42.go
Normal file
62
ipgeo/dn42.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package ipgeo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/xgadget-lab/nexttrace/dn42"
|
||||
)
|
||||
|
||||
func LtdCodeToCountryOrAreaName(Code string) string {
|
||||
countryName := []string{"United States", "Afghanistan", "Åland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", " Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada ", "Cape Verde", "Cayman Islands", "Central Africa", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo (Brazzaville)", "DRC", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", " Denmark", "Djibouti", "Dominica", "Dominica", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia", " French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Vatican", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "British Isles of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "North Korea", "South Korea", " Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "FYROM", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", " Marshall Islands", "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia (Federated States of)", "Moldova", "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "Northern Mariana", "Norway", "Oman", "Pakistan", "Palau", "Palestine", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda", "St. Helena", "St. Kitts and Nevis", "St. Lucia", "St. Pierre and Miquelon", "St. Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen Islands", "Swaziland", "Sweden ", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", " United Kingdom", "U.S. Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "British Virgin Islands", "U.S. Virgin Islands", "Wallis and Futuna", "Western Sahara", "Yemen", "Zambia", "Zimbabwe"}
|
||||
countryCode := []string{"us", "af", "ax", "al", "dz", "as", "ad", "ao", "ai", "aq", "ag", "ar", "am", "aw", "au", "at", "az", "bs", "bh", "bd", "bb", "by", "be", "bz", "bj", "bm", "bt", "bo", "ba", "bw", "bv", "br", "io", "bn", "bg", "bf", "bi", "kh", "cm", "ca", "cv", "ky", "cf", "td", "cl", "cn", "cx", "cc", "co", "km", "cg", "cd", "ck", "cr", "ci", "hr", "cu", "cy", "cz", "dk", "dj", "dm", "do", "ec", "eg", "sv", "gq", "er", "ee", "et", "fk", "fo", "fj", "fi", "fr", "gf", "pf", "tf", "ga", "gm", "ge", "de", "gh", "gi", "gr", "gl", "gd", "gp", "gu", "gt", "gg", "gn", "gw", "gy", "ht", "hm", "va", "hn", "hk", "hu", "is", "in", "id", "ir", "iq", "ie", "im", "il", "it", "jm", "jp", "je", "jo", "kz", "ke", "ki", "kp", "kr", "kw", "kg", "la", "lv", "lb", "ls", "lr", "ly", "li", "lt", "lu", "mo", "mk", "mg", "mw", "my", "mv", "ml", "mt", "mh", "mq", "mr", "mu", "yt", "mx", "fm", "md", "mc", "mn", "me", "ms", "ma", "mz", "mm", "na", "nr", "np", "nl", "an", "nc", "nz", "ni", "ne", "ng", "nu", "nf", "mp", "no", "om", "pk", "pw", "ps", "pa", "pg", "py", "pe", "ph", "pn", "pl", "pt", "pr", "qa", "re", "ro", "ru", "rw", "sh", "kn", "lc", "pm", "vc", "ws", "sm", "st", "sa", "sn", "rs", "sc", "sl", "sg", "sk", "si", "sb", "so", "za", "gs", "es", "lk", "sd", "sr", "sj", "sz", "se", "ch", "sy", "tw", "tj", "tz", "th", "tl", "tg", "tk", "to", "tt", "tn", "tr", "tm", "tc", "tv", "ug", "ua", "ae", "gb", "um", "uy", "uz", "vu", "ve", "vn", "vg", "vi", "wf", "eh", "ye", "zm", "zw"}
|
||||
Code = strings.ToLower(Code)
|
||||
for i, v := range countryCode {
|
||||
if strings.Contains(Code, v) {
|
||||
return countryName[i]
|
||||
}
|
||||
}
|
||||
return Code
|
||||
}
|
||||
|
||||
func DN42(ip string) (*IPGeoData, error) {
|
||||
data := &IPGeoData{}
|
||||
// 先解析传入过来的数据
|
||||
ipTmp := strings.Split(ip, ",")
|
||||
if len(ipTmp) > 1 {
|
||||
ip = ipTmp[0]
|
||||
}
|
||||
// 先查找 GeoFeed
|
||||
if geo, find := dn42.GetGeoFeed(ip); find {
|
||||
data.Country = geo.LtdCode
|
||||
data.City = geo.City
|
||||
data.Asnumber = geo.ASN
|
||||
data.Whois = geo.IPWhois
|
||||
}
|
||||
// 如果没找到,查找 PTR
|
||||
if len(ipTmp) > 1 {
|
||||
// 存在 PTR 记录
|
||||
if res, err := dn42.FindPtrRecord(ipTmp[1]); err == nil && res.LtdCode != "" {
|
||||
data.Country = res.LtdCode
|
||||
data.Prov = res.Region
|
||||
data.City = res.City
|
||||
}
|
||||
}
|
||||
|
||||
data.Country = LtdCodeToCountryOrAreaName(data.Country)
|
||||
|
||||
switch data.Country {
|
||||
case "Hong Kong":
|
||||
data.Country = "China"
|
||||
data.Prov = "Hong Kong"
|
||||
case "Taiwan":
|
||||
data.Country = "China"
|
||||
data.Prov = "Taiwan"
|
||||
case "Macao":
|
||||
data.Country = "China"
|
||||
data.Prov = "Macao"
|
||||
case "":
|
||||
data.Country = "Unknown"
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
5
ipgeo/dn42_test.go
Normal file
5
ipgeo/dn42_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package ipgeo
|
||||
|
||||
// func TestDN42(t *testing.T) {
|
||||
// DN42("")
|
||||
// }
|
||||
@@ -29,6 +29,8 @@ type Source = func(ip string) (*IPGeoData, error)
|
||||
|
||||
func GetSource(s string) Source {
|
||||
switch strings.ToUpper(s) {
|
||||
case "DN42":
|
||||
return DN42
|
||||
case "LEOMOEAPI":
|
||||
return LeoIP
|
||||
case "IP.SB":
|
||||
|
||||
2
nt_config.yaml
Normal file
2
nt_config.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
geofeedpath: ./geofeed.csv
|
||||
ptrpath: ./ptr.csv
|
||||
@@ -21,7 +21,44 @@ func Version() {
|
||||
}
|
||||
|
||||
func CopyRight() {
|
||||
fmt.Println("XGadget-lab Leo (leo.moe) & Tso (tsosunchia@gmail.com) & Vincent (vincent.moe) & zhshch (xzhsh.ch)")
|
||||
fmt.Fprintf(color.Output, "\n%s\n%s\n%s %s\n\n%s\n%s %s\n%s %s\n%s %s\n\n%s\n%s\n%s %s\n\n",
|
||||
color.New(color.FgCyan, color.Bold).Sprintf("%s", "NextTrace CopyRight"),
|
||||
color.New(color.FgGreen, color.Bold).Sprintf("%s", "NextTrace Project Creator"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Leo"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "i@leo.moe"),
|
||||
color.New(color.FgGreen, color.Bold).Sprintf("%s", "NextTrace Project Maintainer"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Tso"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "tsosunchia@gmail.com"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Vincent"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "i@vincent.moe"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Leo"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "i@leo.moe"),
|
||||
color.New(color.FgCyan, color.Bold).Sprintf("%s", "Special Acknowledgement List"),
|
||||
color.New(color.FgGreen, color.Bold).Sprintf("%s", "NextTrace Major Contributor"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "zhshch"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "zhshch@athorx.com"),
|
||||
)
|
||||
|
||||
MoeQingOrgCopyRight()
|
||||
PluginCopyRight()
|
||||
}
|
||||
|
||||
func MoeQingOrgCopyRight() {
|
||||
fmt.Fprintf(color.Output, "%s\n%s %s\n%s %s\n\n",
|
||||
color.New(color.FgHiYellow, color.Bold).Sprintf("%s", "MoeQing Network"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "YekongTAT"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "yekongtat@gmail.com"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Haima"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "haima@peers.cloud"),
|
||||
)
|
||||
}
|
||||
|
||||
func PluginCopyRight() {
|
||||
fmt.Fprintf(color.Output, "%s\n%s %s\n\n",
|
||||
color.New(color.FgGreen, color.Bold).Sprintf("%s", "NextTrace Map Plugin Author"),
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("%s", "Tso"),
|
||||
color.New(color.FgHiBlack, color.Bold).Sprintf("%s", "tsosunchia@gmail.com"),
|
||||
)
|
||||
}
|
||||
|
||||
func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string) {
|
||||
|
||||
@@ -120,8 +120,30 @@ func RealtimePrinter(res *trace.Result, ttl int) {
|
||||
fmt.Fprintf(color.Output, " %s", color.New(color.FgHiGreen, color.Bold).Sprintf("%-16s", whoisFormat[0]))
|
||||
}
|
||||
}
|
||||
|
||||
if len(res.Hops[ttl][i].Geo.Country) <= 1 {
|
||||
res.Hops[ttl][i].Geo.Country = "LAN Address"
|
||||
res.Hops[ttl][i].Geo.Country = "局域网"
|
||||
res.Hops[ttl][i].Geo.CountryEn = "LAN Address"
|
||||
}
|
||||
|
||||
if res.Hops[ttl][i].Lang == "en" {
|
||||
if res.Hops[ttl][i].Geo.Country == "Anycast" {
|
||||
|
||||
} else if res.Hops[ttl][i].Geo.Prov == "骨干网" {
|
||||
res.Hops[ttl][i].Geo.Prov = "BackBone"
|
||||
} else if res.Hops[ttl][i].Geo.ProvEn == "" {
|
||||
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.CountryEn
|
||||
} else {
|
||||
if res.Hops[ttl][i].Geo.CityEn == "" {
|
||||
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.ProvEn
|
||||
res.Hops[ttl][i].Geo.Prov = res.Hops[ttl][i].Geo.CountryEn
|
||||
res.Hops[ttl][i].Geo.City = ""
|
||||
} else {
|
||||
res.Hops[ttl][i].Geo.Country = res.Hops[ttl][i].Geo.CityEn
|
||||
res.Hops[ttl][i].Geo.Prov = res.Hops[ttl][i].Geo.ProvEn
|
||||
res.Hops[ttl][i].Geo.City = res.Hops[ttl][i].Geo.CountryEn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if net.ParseIP(ip).To4() != nil {
|
||||
|
||||
4
ptr.example.csv
Normal file
4
ptr.example.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
snge,SG,,Singapore
|
||||
CXS,CN,Hunan,Changsha
|
||||
LAX,US,California,Los Angeles
|
||||
SJC,US,California,San Jose
|
||||
|
@@ -18,14 +18,14 @@ import (
|
||||
|
||||
type ICMPTracer struct {
|
||||
Config
|
||||
wg sync.WaitGroup
|
||||
res Result
|
||||
ctx context.Context
|
||||
inflightRequest map[int]chan Hop
|
||||
inflightRequestLock sync.Mutex
|
||||
icmpListen net.PacketConn
|
||||
final int
|
||||
finalLock sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
res Result
|
||||
ctx context.Context
|
||||
inflightRequest map[int]chan Hop
|
||||
inflightRequestRWLock sync.RWMutex
|
||||
icmpListen net.PacketConn
|
||||
final int
|
||||
finalLock sync.Mutex
|
||||
}
|
||||
|
||||
func (t *ICMPTracer) PrintFunc() {
|
||||
@@ -52,7 +52,9 @@ func (t *ICMPTracer) PrintFunc() {
|
||||
}
|
||||
|
||||
func (t *ICMPTracer) Execute() (*Result, error) {
|
||||
t.inflightRequestRWLock.Lock()
|
||||
t.inflightRequest = make(map[int]chan Hop)
|
||||
t.inflightRequestRWLock.Unlock()
|
||||
|
||||
if len(t.res.Hops) > 0 {
|
||||
return &t.res, ErrTracerouteExecuted
|
||||
@@ -75,9 +77,9 @@ func (t *ICMPTracer) Execute() (*Result, error) {
|
||||
t.wg.Add(1)
|
||||
go t.PrintFunc()
|
||||
for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ {
|
||||
t.inflightRequestLock.Lock()
|
||||
t.inflightRequestRWLock.Lock()
|
||||
t.inflightRequest[ttl] = make(chan Hop, t.NumMeasurements)
|
||||
t.inflightRequestLock.Unlock()
|
||||
t.inflightRequestRWLock.Unlock()
|
||||
if t.final != -1 && ttl > t.final {
|
||||
break
|
||||
}
|
||||
@@ -169,8 +171,8 @@ func (t *ICMPTracer) listenICMP() {
|
||||
}
|
||||
|
||||
func (t *ICMPTracer) handleICMPMessage(msg ReceivedMessage, icmpType int8, data []byte, ttl int) {
|
||||
t.inflightRequestLock.Lock()
|
||||
defer t.inflightRequestLock.Unlock()
|
||||
t.inflightRequestRWLock.RLock()
|
||||
defer t.inflightRequestRWLock.RUnlock()
|
||||
if _, ok := t.inflightRequest[ttl]; ok {
|
||||
t.inflightRequest[ttl] <- Hop{
|
||||
Success: true,
|
||||
@@ -270,7 +272,6 @@ func (t *ICMPTracer) send(ttl int) error {
|
||||
if err := t.icmpListen.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
return nil
|
||||
|
||||
@@ -16,15 +16,15 @@ import (
|
||||
|
||||
type ICMPTracerv6 struct {
|
||||
Config
|
||||
wg sync.WaitGroup
|
||||
res Result
|
||||
ctx context.Context
|
||||
resCh chan Hop
|
||||
inflightRequest map[int]chan Hop
|
||||
inflightRequestLock sync.Mutex
|
||||
icmpListen net.PacketConn
|
||||
final int
|
||||
finalLock sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
res Result
|
||||
ctx context.Context
|
||||
resCh chan Hop
|
||||
inflightRequest map[int]chan Hop
|
||||
inflightRequestRWLock sync.RWMutex
|
||||
icmpListen net.PacketConn
|
||||
final int
|
||||
finalLock sync.Mutex
|
||||
}
|
||||
|
||||
func (t *ICMPTracerv6) PrintFunc() {
|
||||
@@ -53,7 +53,9 @@ func (t *ICMPTracerv6) PrintFunc() {
|
||||
}
|
||||
|
||||
func (t *ICMPTracerv6) Execute() (*Result, error) {
|
||||
t.inflightRequestRWLock.Lock()
|
||||
t.inflightRequest = make(map[int]chan Hop)
|
||||
t.inflightRequestRWLock.Unlock()
|
||||
|
||||
if len(t.res.Hops) > 0 {
|
||||
return &t.res, ErrTracerouteExecuted
|
||||
@@ -76,9 +78,9 @@ func (t *ICMPTracerv6) Execute() (*Result, error) {
|
||||
go t.listenICMP()
|
||||
go t.PrintFunc()
|
||||
for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ {
|
||||
t.inflightRequestLock.Lock()
|
||||
t.inflightRequestRWLock.Lock()
|
||||
t.inflightRequest[ttl] = make(chan Hop, t.NumMeasurements)
|
||||
t.inflightRequestLock.Unlock()
|
||||
t.inflightRequestRWLock.Unlock()
|
||||
if t.final != -1 && ttl > t.final {
|
||||
break
|
||||
}
|
||||
@@ -227,8 +229,8 @@ func (t *ICMPTracerv6) listenICMP() {
|
||||
}
|
||||
|
||||
func (t *ICMPTracerv6) handleICMPMessage(msg ReceivedMessage, icmpType int8, data []byte, ttl int) {
|
||||
t.inflightRequestLock.Lock()
|
||||
defer t.inflightRequestLock.Unlock()
|
||||
t.inflightRequestRWLock.RLock()
|
||||
defer t.inflightRequestRWLock.RUnlock()
|
||||
if _, ok := t.inflightRequest[ttl]; ok {
|
||||
t.inflightRequest[ttl] <- Hop{
|
||||
Success: true,
|
||||
|
||||
@@ -60,7 +60,10 @@ func (t *TCPTracer) Execute() (*Result, error) {
|
||||
var cancel context.CancelFunc
|
||||
t.ctx, cancel = context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
t.inflightRequestLock.Lock()
|
||||
t.inflightRequest = make(map[int]chan Hop)
|
||||
t.inflightRequestLock.Unlock()
|
||||
|
||||
t.final = -1
|
||||
|
||||
go t.listenICMP()
|
||||
@@ -161,7 +164,7 @@ func (t *TCPTracer) listenTCP() {
|
||||
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
|
||||
tcp, _ := tcpLayer.(*layers.TCP)
|
||||
// 取得目标主机的Sequence Number
|
||||
|
||||
t.inflightRequestLock.Lock()
|
||||
if ch, ok := t.inflightRequest[int(tcp.Ack-1)]; ok {
|
||||
// 最后一跳
|
||||
ch <- Hop{
|
||||
@@ -169,6 +172,7 @@ func (t *TCPTracer) listenTCP() {
|
||||
Address: msg.Peer,
|
||||
}
|
||||
}
|
||||
t.inflightRequestLock.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"log"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
@@ -39,14 +39,14 @@ func (t *TCPTracerv6) Execute() (*Result, error) {
|
||||
return &t.res, ErrTracerouteExecuted
|
||||
}
|
||||
|
||||
t.SrcIP, _ = util.LocalIPPort(t.DestIP)
|
||||
log.Println(util.LocalIPPort(t.DestIP))
|
||||
t.SrcIP, _ = util.LocalIPPortv6(t.DestIP)
|
||||
// log.Println(util.LocalIPPortv6(t.DestIP))
|
||||
var err error
|
||||
t.tcp, err = net.ListenPacket("ip6:tcp", t.SrcIP.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.icmp, err = icmp.ListenPacket("ip6:53", "::")
|
||||
t.icmp, err = icmp.ListenPacket("ip6:58", "::")
|
||||
if err != nil {
|
||||
return &t.res, err
|
||||
}
|
||||
@@ -64,14 +64,36 @@ func (t *TCPTracerv6) Execute() (*Result, error) {
|
||||
t.sem = semaphore.NewWeighted(int64(t.ParallelRequests))
|
||||
|
||||
for ttl := 1; ttl <= t.MaxHops; ttl++ {
|
||||
// 如果到达最终跳,则退出
|
||||
if t.final != -1 && ttl > t.final {
|
||||
break
|
||||
}
|
||||
for i := 0; i < t.NumMeasurements; i++ {
|
||||
t.wg.Add(1)
|
||||
go t.send(ttl)
|
||||
|
||||
}
|
||||
if t.RealtimePrinter != nil {
|
||||
// 对于实时模式,应该按照TTL进行并发请求
|
||||
t.wg.Wait()
|
||||
t.RealtimePrinter(&t.res, ttl-1)
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
}
|
||||
|
||||
go func() {
|
||||
if t.AsyncPrinter != nil {
|
||||
for {
|
||||
t.AsyncPrinter(&t.res)
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
if t.RealtimePrinter == nil {
|
||||
t.wg.Wait()
|
||||
}
|
||||
t.wg.Wait()
|
||||
t.res.reduce(t.final)
|
||||
|
||||
return &t.res, nil
|
||||
@@ -85,20 +107,21 @@ func (t *TCPTracerv6) listenICMP() {
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
case msg := <-lc.Messages:
|
||||
// log.Println(msg)
|
||||
|
||||
if msg.N == nil {
|
||||
continue
|
||||
}
|
||||
rm, err := icmp.ParseMessage(53, msg.Msg[:*msg.N])
|
||||
rm, err := icmp.ParseMessage(58, msg.Msg[:*msg.N])
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
// log.Println(err)
|
||||
continue
|
||||
}
|
||||
log.Println(msg.Peer)
|
||||
switch rm.Type {
|
||||
case ipv6.ICMPTypeTimeExceeded:
|
||||
t.handleICMPMessage(msg, rm.Body.(*icmp.TimeExceeded).Data)
|
||||
t.handleICMPMessage(msg)
|
||||
case ipv6.ICMPTypeDestinationUnreachable:
|
||||
t.handleICMPMessage(msg, rm.Body.(*icmp.DstUnreach).Data)
|
||||
t.handleICMPMessage(msg)
|
||||
default:
|
||||
//log.Println("received icmp message of unknown type", rm.Type)
|
||||
}
|
||||
@@ -118,6 +141,8 @@ func (t *TCPTracerv6) listenTCP() {
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
case msg := <-lc.Messages:
|
||||
// log.Println(msg)
|
||||
// return
|
||||
if msg.N == nil {
|
||||
continue
|
||||
}
|
||||
@@ -144,23 +169,21 @@ func (t *TCPTracerv6) listenTCP() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TCPTracerv6) handleICMPMessage(msg ReceivedMessage, data []byte) {
|
||||
header, err := util.GetICMPResponsePayload(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sequenceNumber := util.GetTCPSeq(header)
|
||||
func (t *TCPTracerv6) handleICMPMessage(msg ReceivedMessage) {
|
||||
var sequenceNumber = binary.BigEndian.Uint32(msg.Msg[52:56])
|
||||
|
||||
t.inflightRequestLock.Lock()
|
||||
defer t.inflightRequestLock.Unlock()
|
||||
ch, ok := t.inflightRequest[int(sequenceNumber)]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// log.Println("发送数据", sequenceNumber)
|
||||
ch <- Hop{
|
||||
Success: true,
|
||||
Address: msg.Peer,
|
||||
}
|
||||
|
||||
// log.Println("发送成功")
|
||||
}
|
||||
|
||||
func (t *TCPTracerv6) send(ttl int) error {
|
||||
@@ -176,7 +199,7 @@ func (t *TCPTracerv6) send(ttl int) error {
|
||||
}
|
||||
// 随机种子
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
_, srcPort := util.LocalIPPort(t.DestIP)
|
||||
_, srcPort := util.LocalIPPortv6(t.DestIP)
|
||||
ipHeader := &layers.IPv6{
|
||||
SrcIP: t.SrcIP,
|
||||
DstIP: t.DestIP,
|
||||
@@ -185,6 +208,7 @@ func (t *TCPTracerv6) send(ttl int) error {
|
||||
}
|
||||
// 使用Uint16兼容32位系统,防止在rand的时候因使用int32而溢出
|
||||
sequenceNumber := uint32(r.Intn(math.MaxUint16))
|
||||
|
||||
tcpHeader := &layers.TCP{
|
||||
SrcPort: layers.TCPPort(srcPort),
|
||||
DstPort: layers.TCPPort(t.DestPort),
|
||||
@@ -212,6 +236,7 @@ func (t *TCPTracerv6) send(ttl int) error {
|
||||
if _, err := t.tcp.WriteTo(buf.Bytes(), &net.IPAddr{IP: t.DestIP}); err != nil {
|
||||
return err
|
||||
}
|
||||
// log.Println(ttl, sequenceNumber)
|
||||
t.inflightRequestLock.Lock()
|
||||
hopCh := make(chan Hop)
|
||||
t.inflightRequest[int(sequenceNumber)] = hopCh
|
||||
|
||||
@@ -27,8 +27,11 @@ type Config struct {
|
||||
Quic bool
|
||||
IPGeoSource ipgeo.Source
|
||||
RDns bool
|
||||
AlwaysWaitRDNS bool
|
||||
PacketInterval int
|
||||
TTLInterval int
|
||||
Lang string
|
||||
DN42 bool
|
||||
RealtimePrinter func(res *Result, ttl int)
|
||||
AsyncPrinter func(res *Result)
|
||||
}
|
||||
@@ -76,8 +79,8 @@ func Traceroute(method Method, config Config) (*Result, error) {
|
||||
if config.DestIP.To4() != nil {
|
||||
tracer = &TCPTracer{Config: config}
|
||||
} else {
|
||||
// tracer = &TCPTracerv6{Config: config}
|
||||
return nil, errors.New("IPv6 TCP Traceroute is not supported")
|
||||
tracer = &TCPTracerv6{Config: config}
|
||||
// return nil, errors.New("IPv6 TCP Traceroute is not supported")
|
||||
}
|
||||
default:
|
||||
return &Result{}, ErrInvalidMethod
|
||||
@@ -115,36 +118,90 @@ type Hop struct {
|
||||
RTT time.Duration
|
||||
Error error
|
||||
Geo *ipgeo.IPGeoData
|
||||
Lang string
|
||||
}
|
||||
|
||||
func (h *Hop) fetchIPData(c Config) (err error) {
|
||||
timeout := time.Millisecond * 800
|
||||
// DN42
|
||||
if c.DN42 {
|
||||
var ip string
|
||||
// 首先查找 PTR 记录
|
||||
r, err := net.LookupAddr(h.Address.String())
|
||||
if err == nil && len(r) > 0 {
|
||||
h.Hostname = r[0][:len(r[0])-1]
|
||||
ip = h.Address.String() + "," + h.Hostname
|
||||
}
|
||||
h.Geo, err = c.IPGeoSource(ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug Area
|
||||
// c.AlwaysWaitRDNS = true
|
||||
|
||||
// Initialize a rDNS Channel
|
||||
rDNSChan := make(chan []string)
|
||||
fetchDoneChan := make(chan bool)
|
||||
|
||||
if c.RDns && h.Hostname == "" {
|
||||
result := make(chan []string)
|
||||
// Create a rDNS Query go-routine
|
||||
go func() {
|
||||
r, err := net.LookupAddr(h.Address.String())
|
||||
if err != nil {
|
||||
result <- nil
|
||||
// No PTR Record
|
||||
rDNSChan <- nil
|
||||
} else {
|
||||
result <- r
|
||||
// One PTR Record is found
|
||||
rDNSChan <- r
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Create Data Fetcher go-routine
|
||||
go func() {
|
||||
// Start to fetch IP Geolocation data
|
||||
if c.IPGeoSource != nil && h.Geo == nil {
|
||||
res := false
|
||||
h.Lang = c.Lang
|
||||
h.Geo, res = ipgeo.Filter(h.Address.String())
|
||||
if !res {
|
||||
h.Geo, err = c.IPGeoSource(h.Address.String())
|
||||
}
|
||||
}
|
||||
// Fetch Done
|
||||
fetchDoneChan <- true
|
||||
}()
|
||||
|
||||
// Select Close Flag
|
||||
var selectClose bool
|
||||
if !c.AlwaysWaitRDNS {
|
||||
select {
|
||||
case ptr := <-result:
|
||||
case <-fetchDoneChan:
|
||||
// When fetch done signal recieved, stop waiting PTR record
|
||||
case ptr := <-rDNSChan:
|
||||
// process result
|
||||
if err == nil && len(ptr) > 0 {
|
||||
h.Hostname = ptr[0][:len(ptr[0])-1]
|
||||
}
|
||||
selectClose = true
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case ptr := <-rDNSChan:
|
||||
// process result
|
||||
if err == nil && len(ptr) > 0 {
|
||||
h.Hostname = ptr[0]
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
// handle timeout
|
||||
// 1 second timeout
|
||||
case <-time.After(time.Second * 1):
|
||||
}
|
||||
selectClose = true
|
||||
}
|
||||
if c.IPGeoSource != nil && h.Geo == nil {
|
||||
res := false
|
||||
h.Geo, res = ipgeo.Filter(h.Address.String())
|
||||
if !res {
|
||||
h.Geo, err = c.IPGeoSource(h.Address.String())
|
||||
}
|
||||
|
||||
// When Select Close, fetchDoneChan Reciever will also be closed
|
||||
if selectClose {
|
||||
// New a reciever to prevent channel congestion
|
||||
<-fetchDoneChan
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -121,8 +121,8 @@ func (t *UDPTracer) handleICMPMessage(msg ReceivedMessage, data []byte) {
|
||||
return
|
||||
}
|
||||
srcPort := util.GetUDPSrcPort(header)
|
||||
//t.inflightRequestLock.Lock()
|
||||
//defer t.inflightRequestLock.Unlock()
|
||||
t.inflightRequestLock.Lock()
|
||||
defer t.inflightRequestLock.Unlock()
|
||||
ch, ok := t.inflightRequest[int(srcPort)]
|
||||
if !ok {
|
||||
return
|
||||
|
||||
23
util/common.go
Normal file
23
util/common.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package util
|
||||
|
||||
import "net"
|
||||
|
||||
func Dnspod() *net.Resolver {
|
||||
return newDoTResolver("dot.pub", "dot.pub:853")
|
||||
}
|
||||
|
||||
func Aliyun() *net.Resolver {
|
||||
return newDoTResolver("dns.alidns.com", "dns.alidns.com:853")
|
||||
}
|
||||
|
||||
func DNSSB() *net.Resolver {
|
||||
return newDoTResolver("45.11.45.11", "dot.sb:853")
|
||||
}
|
||||
|
||||
func Cloudflare() *net.Resolver {
|
||||
return newDoTResolver("one.one.one.one", "one.one.one.one:853")
|
||||
}
|
||||
|
||||
func Google() *net.Resolver {
|
||||
return newDoTResolver("dns.google", "dns.google:853")
|
||||
}
|
||||
13
util/dns_test.go
Normal file
13
util/dns_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDNS(t *testing.T) {
|
||||
resolver := DNSSB()
|
||||
ips, _ := resolver.LookupHost(context.Background(), "www.google.com")
|
||||
fmt.Println(ips)
|
||||
}
|
||||
32
util/dot.go
Normal file
32
util/dot.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func newDoTResolver(serverName string, addrs string) *net.Resolver {
|
||||
|
||||
d := &net.Dialer{
|
||||
// 设置超时时间
|
||||
Timeout: 1000 * time.Millisecond,
|
||||
}
|
||||
|
||||
tls_config := &tls.Config{
|
||||
// 设置 TLS Server Name 以确保证书能和域名对应
|
||||
ServerName: serverName,
|
||||
}
|
||||
return &net.Resolver{
|
||||
// 指定使用 Go Build-in 的 DNS Resolver 来解析
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
conn, err := d.DialContext(ctx, "tcp", addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tls.Client(conn, tls_config), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
12
util/udp.go
Normal file
12
util/udp.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func newUDPResolver() *net.Resolver {
|
||||
return &net.Resolver{
|
||||
// 指定使用 Go Build-in 的 DNS Resolver 来解析
|
||||
PreferGo: true,
|
||||
}
|
||||
}
|
||||
80
util/util.go
80
util/util.go
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
@@ -27,41 +28,66 @@ func LocalIPPort(dstip net.IP) (net.IP, int) {
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
func DomainLookUp(host string, ipv4Only bool) net.IP {
|
||||
ips, err := net.LookupIP(host)
|
||||
func LocalIPPortv6(dstip net.IP) (net.IP, int) {
|
||||
serverAddr, err := net.ResolveUDPAddr("udp", "["+dstip.String()+"]:12345")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// We don't actually connect to anything, but we can determine
|
||||
// based on our destination ip what source ip we should use.
|
||||
if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
|
||||
defer con.Close()
|
||||
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
|
||||
return udpaddr.IP, udpaddr.Port
|
||||
}
|
||||
}
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
func DomainLookUp(host string, ipv4Only bool, dotServer string) net.IP {
|
||||
var (
|
||||
r *net.Resolver
|
||||
ips []net.IP
|
||||
)
|
||||
|
||||
switch dotServer {
|
||||
case "dnssb":
|
||||
r = DNSSB()
|
||||
case "aliyun":
|
||||
r = Aliyun()
|
||||
case "dnspod":
|
||||
r = Dnspod()
|
||||
case "google":
|
||||
r = Google()
|
||||
case "cloudflare":
|
||||
r = Cloudflare()
|
||||
default:
|
||||
r = newUDPResolver()
|
||||
}
|
||||
ips_str, err := r.LookupHost(context.Background(), host)
|
||||
for _, v := range ips_str {
|
||||
ips = append(ips, net.ParseIP(v))
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("Domain " + host + " Lookup Fail.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var ipSlice = []net.IP{}
|
||||
var ipv6Flag = false
|
||||
|
||||
for _, ip := range ips {
|
||||
if ipv4Only {
|
||||
// 仅返回ipv4的ip
|
||||
if ip.To4() != nil {
|
||||
ipSlice = append(ipSlice, ip)
|
||||
} else {
|
||||
ipv6Flag = true
|
||||
}
|
||||
} else {
|
||||
ipSlice = append(ipSlice, ip)
|
||||
}
|
||||
}
|
||||
|
||||
if ipv6Flag {
|
||||
fmt.Println("[Info] IPv6 TCP/UDP Traceroute is not supported right now.")
|
||||
if len(ipSlice) == 0 {
|
||||
fmt.Println("[Info] IPv6 UDP Traceroute is not supported right now.")
|
||||
if len(ips) == 0 {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipSlice) == 1 {
|
||||
return ipSlice[0]
|
||||
if len(ips) == 1 {
|
||||
return ips[0]
|
||||
} else {
|
||||
fmt.Println("Please Choose the IP You Want To TraceRoute")
|
||||
for i, ip := range ipSlice {
|
||||
for i, ip := range ips {
|
||||
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),
|
||||
@@ -70,10 +96,18 @@ func DomainLookUp(host string, ipv4Only bool) net.IP {
|
||||
var index int
|
||||
fmt.Printf("Your Option: ")
|
||||
fmt.Scanln(&index)
|
||||
if index >= len(ipSlice) || index < 0 {
|
||||
if index >= len(ips) || index < 0 {
|
||||
fmt.Println("Your Option is invalid")
|
||||
os.Exit(3)
|
||||
}
|
||||
return ipSlice[index]
|
||||
return ips[index]
|
||||
}
|
||||
}
|
||||
|
||||
func GetenvDefault(key, defVal string) string {
|
||||
val, ok := os.LookupEnv(key)
|
||||
if ok {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package wshandle
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/xgadget-lab/nexttrace/util"
|
||||
)
|
||||
|
||||
type WsConn struct {
|
||||
@@ -24,7 +29,8 @@ type WsConn struct {
|
||||
}
|
||||
|
||||
var wsconn *WsConn
|
||||
var hostP = GetenvDefault("NEXTTRACE_HOSTPORT", "api.leo.moe")
|
||||
var hostP = util.GetenvDefault("NEXTTRACE_HOSTPORT", "api.leo.moe")
|
||||
var host, port, fast_ip string
|
||||
|
||||
func (c *WsConn) keepAlive() {
|
||||
go func() {
|
||||
@@ -32,7 +38,12 @@ func (c *WsConn) keepAlive() {
|
||||
for {
|
||||
<-time.After(time.Second * 54)
|
||||
if c.Connected {
|
||||
c.Conn.WriteMessage(websocket.TextMessage, []byte("ping"))
|
||||
err := c.Conn.WriteMessage(websocket.TextMessage, []byte("ping"))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
c.Connected = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -71,12 +82,12 @@ func (c *WsConn) messageSendHandler() {
|
||||
// 循环监听发送
|
||||
select {
|
||||
case <-c.Done:
|
||||
log.Println("发送协程已经退出")
|
||||
log.Println("go-routine has been returned")
|
||||
return
|
||||
case t := <-c.MsgSendCh:
|
||||
// log.Println(t)
|
||||
if !c.Connected {
|
||||
c.MsgReceiveCh <- `{"ip":"` + t + `", "asnumber":"API服务端异常"}`
|
||||
c.MsgReceiveCh <- `{"ip":"` + t + `", "asnumber":"API Server Error"}`
|
||||
} else {
|
||||
err := c.Conn.WriteMessage(websocket.TextMessage, []byte(t))
|
||||
if err != nil {
|
||||
@@ -105,10 +116,16 @@ func (c *WsConn) messageSendHandler() {
|
||||
}
|
||||
|
||||
func (c *WsConn) recreateWsConn() {
|
||||
u := url.URL{Scheme: "wss", Host: hostP, Path: "/v2/ipGeoWs"}
|
||||
u := url.URL{Scheme: "wss", Host: fast_ip + ":" + port, Path: "/v2/ipGeoWs"}
|
||||
// log.Printf("connecting to %s", u.String())
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||
requestHeader := http.Header{
|
||||
"Host": []string{host},
|
||||
}
|
||||
dialer := websocket.DefaultDialer
|
||||
dialer.TLSClientConfig = &tls.Config{
|
||||
ServerName: host,
|
||||
}
|
||||
ws, _, err := websocket.DefaultDialer.Dial(u.String(), requestHeader)
|
||||
c.Conn = ws
|
||||
if err != nil {
|
||||
log.Println("dial:", err)
|
||||
@@ -129,11 +146,47 @@ func createWsConn() *WsConn {
|
||||
// 设置终端中断通道
|
||||
interrupt := make(chan os.Signal, 1)
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
// 解析域名
|
||||
hostArr := strings.Split(hostP, ":")
|
||||
// 判断是否有指定端口
|
||||
if len(hostArr) > 1 {
|
||||
// 判断是否为 IPv6
|
||||
if strings.HasPrefix(hostP, "[") {
|
||||
tmp := strings.Split(hostP, "]")
|
||||
host = tmp[0]
|
||||
host = host[1:]
|
||||
if port = tmp[1]; port != "" {
|
||||
port = port[1:]
|
||||
}
|
||||
} else {
|
||||
host, port = hostArr[0], hostArr[1]
|
||||
}
|
||||
} else {
|
||||
host = hostP
|
||||
}
|
||||
if port == "" {
|
||||
// 默认端口
|
||||
port = "443"
|
||||
}
|
||||
// 默认配置完成,开始寻找最优 IP
|
||||
fast_ip = GetFastIP(host, port)
|
||||
|
||||
u := url.URL{Scheme: "wss", Host: hostP, Path: "/v2/ipGeoWs"}
|
||||
// 如果 host 是一个 IP 使用默认域名
|
||||
if valid := net.ParseIP(host); valid != nil {
|
||||
host = "api.leo.moe"
|
||||
}
|
||||
// 判断是否是一个 IP
|
||||
requestHeader := http.Header{
|
||||
"Host": []string{host},
|
||||
}
|
||||
dialer := websocket.DefaultDialer
|
||||
dialer.TLSClientConfig = &tls.Config{
|
||||
ServerName: host,
|
||||
}
|
||||
u := url.URL{Scheme: "wss", Host: fast_ip + ":" + port, Path: "/v2/ipGeoWs"}
|
||||
// log.Printf("connecting to %s", u.String())
|
||||
|
||||
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
||||
c, _, err := websocket.DefaultDialer.Dial(u.String(), requestHeader)
|
||||
|
||||
wsconn = &WsConn{
|
||||
Conn: c,
|
||||
@@ -168,10 +221,3 @@ func New() *WsConn {
|
||||
func GetWsConn() *WsConn {
|
||||
return wsconn
|
||||
}
|
||||
func GetenvDefault(key, defVal string) string {
|
||||
val, ok := os.LookupEnv(key)
|
||||
if ok {
|
||||
return val
|
||||
}
|
||||
return defVal
|
||||
}
|
||||
|
||||
71
wshandle/latency.go
Normal file
71
wshandle/latency.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package wshandle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
result string
|
||||
results = make(chan string)
|
||||
)
|
||||
|
||||
func GetFastIP(domain string, port string) string {
|
||||
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err != nil {
|
||||
log.Fatal("DNS resolution failed, please check your system DNS Settings")
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
go checkLatency(ip.String(), port)
|
||||
}
|
||||
|
||||
select {
|
||||
case result = <-results:
|
||||
case <-time.After(1 * time.Second):
|
||||
|
||||
}
|
||||
if result == "" {
|
||||
log.Fatal("IP connection has been timeout, please check your network")
|
||||
}
|
||||
res := strings.Split(result, "-")
|
||||
|
||||
if len(ips) > 1 {
|
||||
_, _ = fmt.Fprintf(color.Output, "%s prefered API IP - %s - %s\n",
|
||||
color.New(color.FgWhite, color.Bold).Sprintf("[NextTrace API]"),
|
||||
color.New(color.FgGreen, color.Bold).Sprintf("%s", res[0]),
|
||||
color.New(color.FgCyan, color.Bold).Sprintf("%sms", res[1]),
|
||||
)
|
||||
}
|
||||
|
||||
return res[0]
|
||||
}
|
||||
|
||||
func checkLatency(ip string, port string) {
|
||||
start := time.Now()
|
||||
if !strings.Contains(ip, ".") {
|
||||
ip = "[" + ip + "]"
|
||||
}
|
||||
conn, err := net.DialTimeout("tcp", ip+":"+port, time.Second*1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func(conn net.Conn) {
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(conn)
|
||||
if result == "" {
|
||||
result = fmt.Sprintf("%s-%.2f", ip, float64(time.Since(start))/float64(time.Millisecond))
|
||||
results <- result
|
||||
return
|
||||
}
|
||||
}
|
||||
9
wshandle/latency_test.go
Normal file
9
wshandle/latency_test.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package wshandle
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetFastIP(t *testing.T) {
|
||||
GetFastIP("api.leo.moe", "443")
|
||||
}
|
||||
Reference in New Issue
Block a user