merge dev
2
.github/workflows/docker-image.yml
vendored
@@ -15,4 +15,4 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build the Docker image
|
||||
run: ./build_image.sh
|
||||
run: ./docker_build.sh
|
||||
|
2
.github/workflows/go.yml
vendored
@@ -22,5 +22,5 @@ jobs:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Build
|
||||
run: ./build_exec.sh
|
||||
run: ./build.sh
|
||||
|
||||
|
4
.gitignore
vendored
@@ -12,4 +12,6 @@ research
|
||||
*.tar.gz
|
||||
|
||||
docker-build/gtun/gtun*
|
||||
docker-build/gtund/gtund
|
||||
docker-build/gtund/gtund
|
||||
release
|
||||
images
|
14
README-EN.md
@@ -1,14 +0,0 @@
|
||||
## gtun
|
||||
<a href="">
|
||||
<img src="https://img.shields.io/badge/-Go-000?&logo=go">
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/ICKelin/gtun" rel="nofollow">
|
||||
<img src="https://goreportcard.com/badge/github.com/ICKelin/gtun" alt="go report">
|
||||
</a>
|
||||
|
||||
<a href="https://travis-ci.org/ICKelin/gtun" rel="nofollow">
|
||||
<img src="https://travis-ci.org/ICKelin/gtun.svg?branch=master" alt="Build Status">
|
||||
</a>
|
||||
<a href="https://github.com/ICKelin/gtun/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||
</a>
|
171
README.md
@@ -13,27 +13,18 @@
|
||||
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||
</a>
|
||||
|
||||
gtun是一款开源的ip代理加速软件,通过`tproxy`技术实现流量劫持,`quic`和`kcp`等协议优化广域网传输,gtun提供一个基础通道,所有加入`ipset`的ip,出口,入口流量都会被gtun进行拦截并代理到指定出口。
|
||||
|
||||
gtun是一款开源的ip代理加速软件,目前只支持linux,通过`tproxy`技术实现流量劫持,`quic`和`kcp`等协议优化广域网传输,gtun提供一个基础通道,所有加入`ipset`的ip的流量都会被gtun进行拦截并代理到指定出口。
|
||||
gtun支持多线路配置,可以同时对美国,日本,欧洲目的网络进行加速访问。您可以结合dnsmasq来使用,将需要配置加速的域名解析结果加入ipset,从而实现域名加速。
|
||||
|
||||
[](https://www.youtube.com/watch?v=pxv02e5EXPE "")
|
||||
|
||||
**使用场景**
|
||||
|
||||
- SaaS软件加速,加速访问Salesforce,offce365等产品
|
||||
- 云服务器加速,加速访问海外服务器,跳板机,提升操作流畅度
|
||||
- 直播加速,tiktok海外直播加速,抖音直播加速
|
||||
- 游戏加速,结合专线网络和路由盒子实现游戏加速盒
|
||||
|
||||
gtun是一个完整的加速器,**目前只支持linux**
|
||||
|
||||
同时我们也基于gtun开发了收费版本,对标阿里云的全球应用加速,ucloud的pathX等产品的功能,只是会更加灵活,支持私有化部署,独立部署,可以下沉到办公室,如果您感兴趣,可以访问[我们的网站](https://www.beyondnetwork.net)进行免费免费体验。
|
||||
同时我们也基于gtun开发了收费版本,对标阿里云的全球应用加速,ucloud的pathX等产品的功能,只是会更加灵活,支持私有化部署,独立部署,可以部署到公有云,数据中心和软路由,如果您感兴趣,可以访问[我们的网站](https://www.beyondnetwork.net)进行免费免费体验。
|
||||
|
||||
关于项目有任何问题需要咨询,可以[联系作者](#关于作者)进行交流
|
||||
|
||||
## 目录
|
||||
- [介绍](#gtun)
|
||||
- [应用场景](#应用场景)
|
||||
- [功能特性](#功能特性)
|
||||
- [技术原理](#技术原理)
|
||||
- [安装部署](#安装部署)
|
||||
@@ -42,10 +33,24 @@ gtun是一个完整的加速器,**目前只支持linux**
|
||||
- [安装运行gtun](#安装运行gtun)
|
||||
- [配置加速ip](#配置加速ip)
|
||||
- [加速效果测试](#加速效果)
|
||||
- [应用场景](#应用场景)
|
||||
- [用法玩法]()
|
||||
- [基础用法: 基于gtun+ipset实现ip代理加速和分流](doc/基础用法:基于gtun+ipset实现ip代理加速和分流.md)
|
||||
- [基础用法: 基于gtun+dnsmasq实现域名代理加速和分流](doc/基础用法:基于gtun+dnsmasq实现域名代理加速和分流.md)
|
||||
- [基础用法: openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络](doc/基础用法:openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络.md)
|
||||
- [基础用法: 基于gtun实现公有云访问外部加速](doc/基础用法:基于gtun实现公有云访问外部加速.md)
|
||||
- [玩转N1盒子:基于gtun实现的tiktok加速路由](doc/玩转N1盒子:基于gtun实现的tiktok加速路由.md)
|
||||
- [玩转N1盒子:基于gtun实现的游戏加速盒](doc/玩转N1盒子:基于gtun实现的游戏加速盒.md)
|
||||
- [有问题怎么办](#有问题怎么办)
|
||||
- [关于作者](#关于作者)
|
||||
|
||||
## 应用场景
|
||||
|
||||
- SaaS软件加速,加速访问Salesforce,offce365等产品
|
||||
- 云服务器加速,加速访问海外服务器,跳板机,提升操作流畅度
|
||||
- 直播加速,tiktok海外直播加速,抖音直播加速
|
||||
- 游戏加速,结合专线网络和路由盒子实现游戏加速盒
|
||||
- 云服务器出口加速网关,加速整个公有云内网访问外网的流量
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 纯应用层实现,不存在overlay网络,支持tcp和udp协议以及运行在其上的所有七层协议
|
||||
@@ -64,9 +69,9 @@ gtun是一款ip正向代理软件,包含代理客户端gtun和服务端gtund
|
||||
|
||||
gtun最主要的功能是流量代理,gtun经过三个版本的演变,最初基于tun网卡的vpn技术,然后优化到dnat技术,再到目前的tproxy技术,现已逐步趋于稳定。
|
||||
|
||||
gtun本身只提供流量代理通道,至于哪些流量需要被劫持,这个是由使用者定义的,使用者最终只需要将被代理的IP加入到`ipset`当中,那么该ipset的ip就会被代理
|
||||
gtun本身只提供流量代理通道,至于哪些流量需要被劫持,**这个是由使用者定义的**,使用者最终只需要将被代理的IP加入到`ipset`当中,那么该ipset的ip就会被代理
|
||||
|
||||
为了实现更加快速的代理,gtun考虑集成`kcp`或者`quic`等基于UDP实现的可靠性传输协议,以避免长链路tcp丢包严重触发拥塞控制机制,降低传输效率。
|
||||
为了实现更加快速的代理,gtun考虑集成`kcp`或者`quic`等基于UDP实现的可靠性传输协议,同时接入FEC,实时选路等机制,以避免长链路tcp丢包严重触发拥塞控制机制,降低传输效率。
|
||||
|
||||
[返回目录](#目录)
|
||||
|
||||
@@ -76,87 +81,110 @@ gtun本身只提供流量代理通道,至于哪些流量需要被劫持,这
|
||||
### 前期准备
|
||||
|
||||
- 一台公有云服务器,用于部署服务端程序gtund,区域越靠近被加速区域(源站)越好,并且确认gtund监听的端口被打开
|
||||
- 另外一台可以是公有云服务器,也可以是内网机器,用于部署客户端程序gtun,目前gtun只支持linux系统。
|
||||
- 另外一台可以是公有云服务器,也可以是内网机器,也可以是路由器,用于部署客户端程序gtun,目前gtun只支持linux系统
|
||||
|
||||
### 安装运行gtund
|
||||
gtund需要运行在公有云上,相对比较简单,原则上越靠近源站越好。
|
||||
gtund部署在美国的AWS上,支持systemd和docker两种方式进行启动。
|
||||
|
||||
首先生成配置文件,可以下载 [gtund.yaml](https://github.com/ICKelin/gtun/blob/master/etc/gtund.yaml) 进行修改
|
||||
在[release](https://github.com/ICKelin/gtun/releases)里面找到2.0.7版本的产物并进行下载,
|
||||
|
||||
```
|
||||
cd gtund
|
||||
./install.sh
|
||||
```
|
||||
install.sh 会创建gtund的运行目录,并通过systemd把gtund程序拉起。
|
||||
执行install.sh完成之后,gtund会:
|
||||
- 监听tcp的3002作为mux协议的服务端口
|
||||
- 监听udp的3002作为kcp协议的服务端口
|
||||
- 日志记录在/opt/apps/gtund/logs/gtund.log
|
||||
|
||||
gtund的默认配置为,默认情况下不需要作任何的修改即可
|
||||
|
||||
```yaml
|
||||
enable_auth: true
|
||||
auths:
|
||||
- access_token: "ICKelin:free"
|
||||
expired_ath: 0
|
||||
|
||||
trace: ":3003"
|
||||
server:
|
||||
- listen: ":3002"
|
||||
authKey: "rewrite with your auth key"
|
||||
scheme: "kcp"
|
||||
|
||||
- listen: ":3002"
|
||||
scheme: "mux"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "debug"
|
||||
path: "gtund.log"
|
||||
path: "/opt/apps/gtund/logs/gtund.log"
|
||||
|
||||
```
|
||||
|
||||
大部分情况下,如果您的端口未被占用,不需要修改任何配置
|
||||
`./gtund -c gtund.yaml`文件即可。
|
||||
您也可以使用docker-compose来进行安装:
|
||||
|
||||
```shell
|
||||
cd gtund
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
执行完之后docker ps 看是否启动成功
|
||||
|
||||
### 安装运行gtun
|
||||
gtun可以运行在内网,也可以运行在公有云,在本场景当中,gtun会被部署在内网。
|
||||
|
||||
首先生成配置文件,可以下载 [gtun.yaml](https://github.com/ICKelin/gtun/blob/master/etc/gtun.yaml) 进行修改
|
||||
gtun的安装也类似,在[release](https://github.com/ICKelin/gtun/releases)里面找到2.0.7版本的产物并进行下载,然后在本地linux上进行部署
|
||||
|
||||
```yaml
|
||||
settings:
|
||||
US:
|
||||
# 代理ip文件,可以是本地文件,也可以是网络文件,一行是一个IP或者cidr
|
||||
proxy_file: "https://www.ipdeny.com/ipblocks/data/countries/us.zone"
|
||||
route:
|
||||
# 拨测地址,需要修改US_SERVER_IP和US_SERVER_TRACE_PORT,对应gtund的公网IP和端口
|
||||
- trace_addr: ${US_SERVER_IP}:${US_SERVER_TRACE_PORT}
|
||||
scheme: "kcp"
|
||||
# 服务端地址,修改为对应gtund的IP和端口
|
||||
addr: ${US_SERVER_IP}:${US_SERVER_PORT}
|
||||
auth_key: "rewrite with your auth key"
|
||||
proxy:
|
||||
# 代理插件配置
|
||||
"tproxy_tcp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "US"
|
||||
}
|
||||
"tproxy_udp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "US"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: Debug
|
||||
path: gtun.log
|
||||
|
||||
http_server:
|
||||
listen_addr: ":9001"
|
||||
```shell
|
||||
cd gtun
|
||||
export ACCESS_TOKEN="ICKelin:free"
|
||||
export SERVER_IP="gtund所在的服务器的ip"
|
||||
./install.sh
|
||||
```
|
||||
|
||||
配置完成之后可以启动gtun程序,运行`./gtun -c gtun.yaml`即可启动。
|
||||
其中ACCESS_TOKEN为gtund配置的认证的token,SERVER_IP是gtund的公网IP
|
||||
|
||||
gtund启动时,会自动设置 iptables规则和路由表,并将需要加速的ip加入ipset当中,如果ip量比较大,启动时间会稍微长一些。
|
||||
安装完成之后查看是否有错误日志
|
||||
|
||||
同样,你也可以使用docker-compose来安装
|
||||
|
||||
```shell
|
||||
cd gtun
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
执行完成之后docker ps 看是否启动成功。
|
||||
|
||||
[返回目录](#目录)
|
||||
|
||||
### 配置加速ip
|
||||
目前支持两种方式配置IP:
|
||||
|
||||
- 基于接口的方式,我们提供HTTP接口进行动态增删IP,目前正在开发页面配置动态管理加速的IP,应用,域名,敬请期待。
|
||||
- 使用命令手动配置,手动将ip加入到ipset当中
|
||||
在上述过程中,启动了gtun和gtund程序,但是并未添加任何需要加速的信息,那么gtun如何进行加速呢?需要额外手动配置加速ip,并将该ip的tcp流量全部转发至127.0.0.1:8524端口,udp流量全部转发至127.0.0.1:8524∂端口。
|
||||
|
||||
这个过程是通过ipset和路由来配置的。以1.1.1.1为例
|
||||
|
||||
第一步,创建ipset,并将1.1.1.1加入其中
|
||||
```
|
||||
ipset create GTUN-US hash:net
|
||||
ipset add GTUN-US 1.1.1.1
|
||||
```
|
||||
|
||||
第二步,创建iptables规则,匹配目的ip为GTUN-US这个ipset内部的ip,然后做tproxy操作,将流量重定向到本地8524和8524端口
|
||||
|
||||
```
|
||||
iptables -t mangle -I PREROUTING -p tcp -m set --match-set GTUN-US dst -j TPROXY --tproxy-mark 1/1 --on-port 8524
|
||||
iptables -t mangle -I PREROUTING -p udp -m set --match-set GTUN-US dst -j TPROXY --tproxy-mark 1/1 --on-port 8524
|
||||
iptables -t mangle -I OUTPUT -m set --match-set GTUN-US dst -j MARK --set-mark 1
|
||||
```
|
||||
|
||||
第三步,添加路由表
|
||||
|
||||
```
|
||||
ip rule add fwmark 1 lookup 100
|
||||
ip ro add local default dev lo table 100
|
||||
```
|
||||
|
||||
至此所有配置都已经完成,后续需要新增代理ip,只使用以下命令将ip加入GTUN-US这个ipset当中即可,现在可以先尝试测试1.1.1.1这个ip的代理。
|
||||
|
||||
接下来以命令配置的方式进行配置,以`1.1.1.1`为例,只需要将`1.1.1.1`加入其中ipset当中`ipset add GTUN-US 1.1.1.1`即可。
|
||||
```
|
||||
root@raspberrypi:/home/pi# nslookup www.google.com 1.1.1.1
|
||||
Server: 1.1.1.1
|
||||
@@ -211,13 +239,6 @@ root@raspberrypi:/home/pi# wget http://speedtest.atlanta.linode.com/100MB-atlant
|
||||
|
||||
[返回目录](#目录)
|
||||
|
||||
## 应用场景
|
||||
|
||||
- IP加速,可用于ip,子网加速
|
||||
- 域名,站点加速,需要使用dnsmasq或者nginx/openresty等组件实现
|
||||
- k8s集群网络代理,ip加速的一个子集,可代理访问k8s的service,pod网段
|
||||
- 全球应用加速
|
||||
|
||||
## 有问题怎么办
|
||||
|
||||
- [wiki](https://github.com/ICKelin/gtun/wiki)
|
||||
|
24
build.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
rm -r release
|
||||
mkdir -p release
|
||||
mkdir -p release/gtun/etc
|
||||
mkdir -p release/gtund/etc
|
||||
|
||||
git log -n 5 > release/gtun/ChangeLog
|
||||
git log -n 5 > release/gtund/ChangeLog
|
||||
|
||||
DIR=`pwd`
|
||||
|
||||
cd src/gtun
|
||||
GOOS=linux go build -o gtun
|
||||
mv gtun $DIR/release/gtun/
|
||||
cd $DIR
|
||||
cp scripts/install_gtun.sh release/gtun/install.sh
|
||||
cp -r scripts release/gtun/scripts
|
||||
cp -r etc/gtun/* release/gtun/etc
|
||||
|
||||
cd src/gtund
|
||||
GOOS=linux GOARCH=amd64 go build -o gtund
|
||||
mv gtund $DIR/release/gtund/
|
||||
cd $DIR
|
||||
cp scripts/install_gtund.sh release/gtund/install.sh
|
||||
cp -r etc/gtund/* release/gtund/etc
|
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "building gtund...."
|
||||
GOOS=linux go build -o bin/gtund/gtund cmd/gtund/*.go
|
||||
echo "builded gtund...."
|
||||
|
||||
echo "building gtun...."
|
||||
GOOS=linux go build -o bin/gtun/gtun-linux_amd64 cmd/gtun/*.go
|
||||
GOARCH=arm GOOS=linux go build -o bin/gtun/gtun-linux_arm cmd/gtun/*.go
|
||||
echo "builded gtun...."
|
||||
|
||||
cp -r etc/gtun.yaml bin/gtun/
|
||||
cp -r etc/gtund.yaml bin/gtund/
|
||||
cp install.sh bin/gtun/
|
@@ -1,14 +0,0 @@
|
||||
WORKSPACE=`pwd`
|
||||
./build_exec.sh
|
||||
|
||||
echo "building gtund docker image"
|
||||
cd docker-build/gtund
|
||||
cp $WORKSPACE/bin/gtund/gtund .
|
||||
docker build . -t gtund
|
||||
echo "builded gtund docker image"
|
||||
|
||||
echo "building gtun docker image"
|
||||
cd $WORKSPACE/docker-build/gtun
|
||||
cp $WORKSPACE/bin/gtun/gtun-linux_amd64 .
|
||||
docker build . -t gtun
|
||||
echo "builded gtun docker image"
|
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 ICKelin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION:
|
||||
This program is a gtun client for game/ip accelator.
|
||||
|
||||
Author: ICKelin
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/gtun"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gtun.Main()
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 ICKelin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION:
|
||||
This program is a gtun server for game/ip accelator.
|
||||
|
||||
Author: ICKelin
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/ICKelin/gtun/gtund"
|
||||
|
||||
func main() {
|
||||
gtund.Main()
|
||||
}
|
BIN
doc/assets/domain_acc_topology.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
doc/assets/game_acc_topology.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
doc/assets/ip_acc_topology.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
doc/assets/public_cloud_topology.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
doc/assets/softroute_acc_step1.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
doc/assets/softroute_acc_step2.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
doc/assets/softroute_acc_step3.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
doc/assets/softroute_acc_step4.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
doc/assets/softroute_acc_step5.png
Normal file
After Width: | Height: | Size: 226 KiB |
BIN
doc/assets/softroute_acc_topology.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
doc/assets/tiktok_acc_optimize.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
doc/assets/tiktok_acc_topology.png
Normal file
After Width: | Height: | Size: 57 KiB |
3
doc/softroute.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 基于gtun+n1盒子实现软路由加速
|
||||
|
||||
|
10
doc/tk.md
Normal file
@@ -0,0 +1,10 @@
|
||||
IP选择:
|
||||
- 我有IP,需要转发加速
|
||||
- 我没有IP,需要增加IP
|
||||
|
||||
线路模式:
|
||||
- 直播线路
|
||||
- 养号线路
|
||||
|
||||
tk区域:
|
||||
|
65
doc/基础用法:openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络
|
||||
之前两篇文章都介绍的是如何加速本机的,但是实际过程中我们希望能够连接上Wi-Fi就能够进行访问加速,这个就需要用到软路由。
|
||||
|
||||
本文将详细介绍如何打造一个基于gtun加速的软路由,最终实现的效果是家里的任何一台设备,只要连上Wi-Fi,不需要任何配置就能够实现加速。
|
||||
|
||||
依照之前文章的习惯,我们首先来看一下本文的拓扑:
|
||||
|
||||

|
||||
|
||||
如图所示:
|
||||
- N1盒子,网上很多,很便宜就能买到,买了之后自己刷入openwrt,N1盒子有无线Wi-Fi功能,不需要配置旁路由,只要连上N1盒子的Wi-Fi就行
|
||||
- gtun部署在N1盒子上,由于gtun是基于iptables来匹配流量转发的,因此能够实现
|
||||
- 本机流量劫持和加速
|
||||
- 作为路由器时,经过本机路由转发的流量的加速
|
||||
- 除了N1盒子和gtun之外,由于openwrt本身就已经刷入dnsmasq了,这里不再多说,dnsmasq的域名策略还是沿用[之前文章](基础用法:基于gtun+dnsmasq实现域名代理加速和分流.md)的配置。
|
||||
|
||||
# N1盒子刷入Openwrt
|
||||
- N1盒子是从淘宝购买的
|
||||
- openwrt我刷入的是[这个固件](https://github.com/ophub/flippy-openwrt-actions/releases/download/OpenWrt_lede_save_2024.04/openwrt_s905d_n1_R24.2.2_k5.15.152-flippy-88+o.img.gz)
|
||||
|
||||
操作很简单,下载刷入u盘之后插入N1盒子(已经设置自动u盘启动),
|
||||
然后执行install-to-emmc.sh选择11刷入emmc,成功之后拔掉u盘重启,进入openwrt。
|
||||
|
||||
操作完成之后你会得到以下信息:
|
||||
- Wi-Fi名称:Phnicomm_n1
|
||||
- Wi-Fi密码:password
|
||||
- 终端用户名:root
|
||||
- 终端密码:password
|
||||
- Wi-Fi网段:192.168.1.1/24
|
||||
|
||||
接下来需要配置上网:
|
||||
- 创建wan口并且桥接到eth1
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- 去掉lan口的桥接
|
||||
|
||||

|
||||
|
||||
- 开机自启脚本加入两条命令
|
||||
```shell
|
||||
iptables -t filter -P FORWARD ACCEPT
|
||||
iptables -t filter -I FORWARD -j ACCEPT
|
||||
```
|
||||

|
||||
|
||||
操作完成之后就可以通过连接N1盒子的Wi-Fi上网了。
|
||||
|
||||
N1盒子本身有两个服务监听的udp 53端口,我们需要把named服务停掉,避免解析时候不知道使用的是哪个服务解析。
|
||||
|
||||

|
||||
|
||||
# 部署程序
|
||||
部署程序和配置没有太多特别之处,参考这两篇文章进行:
|
||||
|
||||
- [基础用法:基于gtun+ipset实现ip代理加速和分流](./基础用法:基于gtun+ipset实现ip代理加速和分流.md)
|
||||
- [基础用法:基于gtun+dnsmasq实现域名代理加速和分流](./基础用法:基于gtun+dnsmasq实现域名代理加速和分流.md)
|
||||
|
||||
# 结束语
|
||||
完成上面两个步骤之后就能连接N1盒子的Wi-Fi实现,相比较之前的而言,除了搭载硬件不一样,其他的没有太大的区别,配置几乎是一样的。
|
||||
|
||||
gtun的灵活之处在于它提供的是一个基础功能,不关注你底层跑的硬件是什么,
|
||||
底层的线路是什么,转发规则怎么配置,只要你按照我们约定好的ipset进行配置,就无脑转发。
|
84
doc/基础用法:基于gtun+dnsmasq实现域名代理加速和分流.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# 基于gtun+dnsmasq实现域名代理加速和分流.md
|
||||
|
||||
之前的文章分享了[使用gtun实现ip代理加速和分流](./基础用法:基于gtun+ipset实现ip代理加速和分流.md),实现了一个最简单的基于ip代理加速的场景,但是在实际应用当中会有两个不太优雅的地方:
|
||||
|
||||
- 基于ip的方式,如果ip发生变动,可能会出现分流策略不准的问题
|
||||
- 有时候并不需要加速这么多ip,只需要加速部分网站或者应用即可(非常典型的比如SaaS应用加速)
|
||||
- 考虑一下真正使用的时候,dns应该如何配置,如果配置成114.114.114.114,那么需要通过8.8.8.8来进行解析的ip则会被污染,如果设置成8.8.8.8,那么国内的网站可能会解析到国外的ip,这也算是一种dns污染
|
||||
|
||||
基于此我们有了基于dnsmasq的域名解析策略来实现基于域名的加速和分流,希望能够解决这三个问题,最终拓扑如下:
|
||||
|
||||

|
||||
|
||||
# 前置准备
|
||||
您可以参考[这篇文章](基础用法:基于gtun+ipset实现ip代理加速和分流.md)来安装gtund和gtun。安装完gtun和gtund之后,您需要再安装dnsmasq并且成功启动。
|
||||
|
||||
# 配置dnsmasq解析策略
|
||||
|
||||
首先还是创建好基本的运行环境,参考`gtun/scripts/redirect_all.sh`
|
||||
|
||||
然后配置dnsmasq的规则,dnsmasq的规则主要有两个:
|
||||
|
||||
- 域名解析的上游地址是多少,针对大陆地区的域名,使用114.114.114.114来进行解析,针对其他域名,使用8.8.8.8进行解析
|
||||
- 解析接入写入到哪个ipset里面,针对大陆地区的域名,写入到NOPROXY当中,海外域名不进行处理,因为在GTUN_ALL里面已经匹配除了NOPROXY之外的所有ip
|
||||
|
||||
通过这两个控制我们就能够实现dnsmasq和gtun的无缝结合,双方都不需要感知对方的存在,dnsmasq只管结果写进ipset,gtun只管匹配ipset,通过ipset来实现进程之间的默契。
|
||||
|
||||
```shell
|
||||
config_dnsmasq() {
|
||||
echo "configuring dnsmasq service"
|
||||
cp dnsmasq/dnsmasq.conf /etc/dnsmasq.conf
|
||||
cp dnsmasq/dnsmasq.resolv /etc/dnsmasq.resolv
|
||||
echo "configuring dnsmasq cn domain list"
|
||||
cp dnsmasq/cn.conf /etc/dnsmasq.d/
|
||||
cp dnsmasq/cn_set.conf /etc/dnsmasq.d/
|
||||
systemctl restart dnsmasq
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
完整命令可以参考`gtun/scripts/redirect_domains.sh`。修改完之后本机需要设置`/etc/resolv.conf`文件的`nameserver 127.0.0.1`,
|
||||
只有这样才会真正用本机的dnsmasq去解析。后面我会介绍软路由的方式,让其他机器通过配置好gtun的软路由也能使用这种代理和分流的策略。
|
||||
|
||||
# 测试
|
||||
接下来进行一轮测试,我们使用我们自己的一个域名`demo.xxxx.tech`进行测试。
|
||||
|
||||
第一步将demo.xxxx.tech配置进dnsmasq里面
|
||||
|
||||
```shell
|
||||
root@OpenWrt:~/gtun# head /etc/dnsmasq.d/cn.conf
|
||||
server=/demo.xxxx.tech/114.114.114.114
|
||||
|
||||
root@OpenWrt:~/gtun# head /etc/dnsmasq.d/cn_set.conf
|
||||
ipset=/demo.xxxx.tech/NOPROXY
|
||||
```
|
||||
|
||||
第二步nslookup解析测试
|
||||
|
||||
```shell
|
||||
root@OpenWrt:~/gtun# nslookup demo.xxxx.tech 127.0.0.1
|
||||
Server: 127.0.0.1
|
||||
Address: 127.0.0.1:53
|
||||
|
||||
Non-authoritative answer:
|
||||
Name: demo.xxxx.tech
|
||||
Address: 47.115.xx.xx
|
||||
|
||||
Non-authoritative answer:
|
||||
|
||||
root@OpenWrt:~/gtun# ipset -T NOPROXY 47.115.xx.xx
|
||||
Warning: 47.115.xx.xx is in set NOPROXY.
|
||||
```
|
||||
|
||||
demo.xxxx.tech这个域名已经被加入到NOPROXY里面了,根据之前的文章,加入到NOPROXY之后不会再走加速出口出,这里不再赘述了。
|
||||
|
||||
# 结束语
|
||||
最后我们回到文章一开始提到的三个问题。
|
||||
|
||||
首先是ip不准的问题,本文通过域名来实现控制,不是事先写入固定的cidr列表来判断的。
|
||||
|
||||
其次是部分加速的需求,这个也同样可以综合域名和IP来实现
|
||||
|
||||
最后是dns应该用哪个?本文已经给出了答案,把dns设置为127.0.0.1,交给dnsmasq来判断应该用`114.114.114.114`还是`8.8.8.8`
|
||||
|
||||
截止目前位置我们已经了解到了ip加速和域名加速,但是所有的加速都是加速本机的流量,接下来我会结合 软路由的方式,详细说明如何实现连接Wi-Fi就能实现gtun的加速。
|
214
doc/基础用法:基于gtun+ipset实现ip代理加速和分流.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 最佳实践: 基于gtun+ipset实现ip代理加速和分流
|
||||
gtun的基础功能是ip加速,本文通过具体的配置来讲解如何配置gtun的ip加速功能,最终实现的效果是除了局域网IP之外,访问其他所有IP都通过gtun转发到美国出口。
|
||||
|
||||
最终拓扑如下:
|
||||
|
||||

|
||||
|
||||
如图所示,本文会包含两个部分:
|
||||
- 本地gtun,美国gtund的部署
|
||||
- 加速流量和非加速流量的区分,这部分通过ipset和iptables来进行
|
||||
|
||||
我们可以通过iptables非常灵活的控制加速和非加速流量。
|
||||
|
||||
**本文是基于gtun的2.0.7版本。**
|
||||
|
||||
# 安装
|
||||
安装包括两个组件:
|
||||
- gtund:ip加速的服务端程序,部署在美国
|
||||
- gtun:ip加速的客户端程序,部署在本地linux
|
||||
|
||||
## 安装gtund
|
||||
gtund部署在美国的AWS上,支持systemd和docker两种方式进行启动。
|
||||
|
||||
在[release](https://github.com/ICKelin/gtun/releases)里面找到2.0.7版本的产物并进行下载,
|
||||
|
||||
```
|
||||
cd gtund
|
||||
./install.sh
|
||||
```
|
||||
install.sh 会创建gtund的运行目录,并通过systemd把gtund程序拉起。
|
||||
执行install.sh完成之后,gtund会:
|
||||
- 监听tcp的3002作为mux协议的服务端口
|
||||
- 监听udp的3002作为kcp协议的服务端口
|
||||
- 日志记录在/opt/apps/gtund/logs/gtund.log
|
||||
|
||||
gtund的默认配置为,默认情况下不需要作任何的修改即可
|
||||
|
||||
```yaml
|
||||
enable_auth: true
|
||||
auths:
|
||||
- access_token: "ICKelin:free"
|
||||
expired_ath: 0
|
||||
|
||||
trace: ":3003"
|
||||
server:
|
||||
- listen: ":3002"
|
||||
scheme: "kcp"
|
||||
|
||||
- listen: ":3002"
|
||||
scheme: "mux"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "debug"
|
||||
path: "/opt/apps/gtund/logs/gtund.log"
|
||||
|
||||
```
|
||||
|
||||
您也可以使用docker-compose来进行安装:
|
||||
|
||||
```shell
|
||||
cd gtund
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
执行完之后docker ps 看是否启动成功
|
||||
|
||||
## 安装gtun
|
||||
|
||||
gtun的安装也类似,在[release](https://github.com/ICKelin/gtun/releases)里面找到2.0.7版本的产物并进行下载,然后在本地linux上进行部署
|
||||
|
||||
```shell
|
||||
cd gtun
|
||||
export ACCESS_TOKEN="ICKelin:free"
|
||||
export SERVER_IP="gtund所在的服务器的ip"
|
||||
./install.sh
|
||||
```
|
||||
|
||||
其中ACCESS_TOKEN为gtund配置的认证的token,SERVER_IP是gtund的公网IP
|
||||
|
||||
安装完成之后查看是否有错误日志
|
||||
|
||||
```shell
|
||||
tail -f /opt/apps/gtun/logs/gtun.log
|
||||
```
|
||||
|
||||
同样,你也可以使用docker-compose来安装
|
||||
|
||||
```shell
|
||||
cd gtun
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
执行完成之后docker ps 看是否启动成功。
|
||||
|
||||
# 配置转发规则
|
||||
本文的转发规则比较简单,需要加速的地址为`0.0.0.0/0`,
|
||||
不需要加速的地址列表在`gtun/scripts/noproxy.txt`文件里面,主要包含一些局域网地址,
|
||||
需要记住的是,**一定要把gtund的公网IP加入到noproxy.txt里面**,防止自己把服务器地址拦截。
|
||||
|
||||
第一步把不需要的加速的地址配置好:
|
||||
```shell
|
||||
|
||||
noproxy_set=NOPROXY
|
||||
|
||||
clear_noproxy() {
|
||||
iptables -t mangle -D PREROUTING -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
iptables -t mangle -D OUTPUT -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
ipset destroy $noproxy_set >/dev/null
|
||||
}
|
||||
|
||||
add_noproxy() {
|
||||
ipset create $noproxy_set hash:net
|
||||
cat noproxy.txt | while read line
|
||||
do
|
||||
echo "no proxy for" $line
|
||||
ipset add $noproxy_set $line
|
||||
done
|
||||
|
||||
iptables -t mangle -A PREROUTING -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
iptables -t mangle -A OUTPUT -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
}
|
||||
|
||||
clear_noproxy
|
||||
add_noproxy
|
||||
```
|
||||
|
||||
通过创建NOPROXY的ipset并且把noproxy.txt文件的cidr列表加入进去,
|
||||
然后通过iptables匹配到NOPROXY这个ipset的地址全部ACCEPT掉,因此流量不会被劫持到gtun进程。
|
||||
|
||||
第二步把需要加速的地址配置好:
|
||||
|
||||
```shell
|
||||
setname=GTUN_ALL
|
||||
redirect_port=8524
|
||||
|
||||
add_proxy() {
|
||||
ipset create $setname hash:net
|
||||
echo "proxy for 0.0.0.0/1"
|
||||
echo "proxy for 128.0.0.0/1"
|
||||
ipset add $setname 0.0.0.0/1
|
||||
ipset add $setname 128.0.0.0/1
|
||||
|
||||
iptables -t mangle -A PREROUTING -p tcp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -A PREROUTING -p udp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -A OUTPUT -m set --match-set $setname dst -j MARK --set-mark 1
|
||||
|
||||
# redirect dns query
|
||||
# iptables -t mangle -A PREROUTING -p udp --dport 53 -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
# iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1
|
||||
|
||||
ip rule add fwmark 1 lookup 100
|
||||
ip ro add local default dev lo table 100
|
||||
}
|
||||
|
||||
add_proxy
|
||||
```
|
||||
|
||||
通过创建GTUN_ALL的ipset并且把`0.0.0.0/1`和`128.0.0.0/1`加入到其中。
|
||||
然后通过iptables打mark和策略路由来实现访问GTUN_ALL这个ipset的cidr地址的流量的劫持。
|
||||
|
||||
上面两个步骤通过控制NOPROXY和GTUN_ALL两个ipset就能实现流量是否劫持到gtun,即会不会被加速。
|
||||
|
||||
以上两个步骤的脚本已经打包进`gtun/scripts/redirect_all.sh`文件里面,有需要可以根据具体情况进行修改。
|
||||
|
||||
上面是实现的所有流量加速的,但是有时候我们需要部分不加速,比如大陆地区的ip访问不加速,
|
||||
那么只需要把大陆地区的ip加入到NOPROXY这一ipset即可。
|
||||
|
||||
```shell
|
||||
wget https://raw.githubusercontent.com/herrbischoff/country-ip-blocks/master/ipv4/cn.cidr
|
||||
cat cn.cidr | while read line
|
||||
do
|
||||
echo "no proxy for" $line
|
||||
ipset add $noproxy_set $line
|
||||
done
|
||||
```
|
||||
|
||||
用法非常多,后续文章会不断分享一些用法。
|
||||
|
||||
# 测试
|
||||
最后来进行一次简单的测试,首先是不加速的验证,这里我用我的一个服务器的ip来进行测试。
|
||||
|
||||
```shell
|
||||
# 将ip加入到NOPROXY ipset当中
|
||||
ipset add NOPROXY xx.xx.xx.xx
|
||||
|
||||
# ssh 连接ip
|
||||
ssh root@xx.xx.xx.xx
|
||||
|
||||
# 使用who命令查看当前连接的ip
|
||||
root@iZwz97kfjnf78copv1ae65Z:~# who
|
||||
root tty1 Jun 28 10:41
|
||||
root pts/0 Apr 28 09:43 (119.139.xx.xx)
|
||||
```
|
||||
|
||||
最终结果走的是本地的出口(119.139.xx.xx)。
|
||||
|
||||
同样的方式,把这个ip从NOPROXY ipset中删除,加入到GTUN_ALL这个匹配走加速的ipset当中。
|
||||
|
||||
```shell
|
||||
ipset del NOPROXY xx.xx.xx.xx
|
||||
ipset add GTUN_ALL xx.xx.xx.xx
|
||||
|
||||
root@iZwz97kfjnf78copv1ae65Z:~# who
|
||||
root tty1 Jun 28 10:41
|
||||
root pts/1 Apr 28 09:46 (3.141.xx.xx)
|
||||
```
|
||||
|
||||
最终走的是加速的出口(3.141.xx.xx)
|
||||
|
||||
# 结束语
|
||||
以上是gtun的最基本的功能,实现所有流量劫持并进行加速,同时也提了一嘴如何访问大陆地区的ip不加速,
|
||||
通过本文基本上能了解gtun是如何跑起来的,也能定制一些更加适合自己的用法。
|
||||
后续会继续介绍如何通过gtun跟dnsmasq结合实现访问域名的加速。
|
88
doc/基础用法:基于gtun实现公有云访问外部加速.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 基于gtun实现公有云访问外部加速
|
||||
之前的三篇教程都偏向于本地加速的,在云场景下也能实现类似的代理加速功能,公有云场景和旁路由非常类似,
|
||||
|
||||
本文通过配置一个部署了gtun云网关,让所有vpc的访问流量都通过这台服务器作为加速网关,能够实现两个基本的功能:
|
||||
|
||||
- vpc内访问加速,比如现在AI发展迅猛,很多企业都需要在公有云上下载大模型,那么通过配置gtun的加速网关能够解决这一场景
|
||||
- 跨vpc的单边访问,比如有大陆和美国两个公有云,通过配置对端vpc的网段加速,就能实现大陆vpc通过内网ip访问美国的vpc。
|
||||
|
||||
依照惯例,我们还是先看一看拓扑图。
|
||||
|
||||

|
||||
|
||||
- 包含大陆腾讯云和美国aws
|
||||
- 美国aws找一台云服务器部署gtund,同时内网开启一个api-server进行测试验证
|
||||
- 大陆腾讯云找一台云服务器部署gtun,同时内网有其他实例,通过配置vpc路由把流量转到gtun所在的云服务器上
|
||||
|
||||
> ⚠️
|
||||
> gtun的云服务器相当于一个路由器,如果该云服务器宕机,会影响到其他实例的网络可用性
|
||||
|
||||
那么接下来开始具体的配置。
|
||||
|
||||
# 程序安装
|
||||
这个之前的文章已经详细介绍了,并没有太多的区别,可以参考下面文章来进行配置
|
||||
|
||||
[基础用法:基于gtun+ipset实现ip代理加速和分流](./基础用法:基于gtun+ipset实现ip代理加速和分流.md)
|
||||
|
||||
# 配置
|
||||
首先清理GTUN_ALL配置的加速列表和NOPROXY的加速列表
|
||||
|
||||
```shell
|
||||
ipset -F GTUN_ALL
|
||||
ipset -F NOPROXY
|
||||
```
|
||||
|
||||
这两个操作完之后就是一个不配置任何加速的空跑的gtun服务,然后开始配置
|
||||
|
||||
配置包括两个方面:
|
||||
|
||||
- gtun所在云服务器的转发规则(ipset操作)
|
||||
- 公有云的路由表
|
||||
|
||||
本文包括两个场景:
|
||||
|
||||
- 美国公有云vpc网段的加速
|
||||
- 非vpc网段的加速
|
||||
|
||||
首先配置vpc网段的加速。
|
||||
|
||||
第一步,把对端vpc的cidr加入到GTUN_ALL这个ipset当中
|
||||
|
||||
```shell
|
||||
ipset add GTUN_ALL 172.31.0.0/16
|
||||
```
|
||||
|
||||
配置完这一步之后你就可以在gtun所在的云服务器通过对端服务器的内网地址访问到对端的服务。
|
||||
|
||||
我们启动一个http server来进行测试
|
||||
|
||||
```shell
|
||||
root@ip-172-31-3-157:~# python3 -m http.server 12590
|
||||
|
||||
# 在大陆腾讯云通过curl访问测试
|
||||
root@iZwz97kfjnf78copv1ae65Z:~# curl 172.31.3.157:12590 >/dev/null
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 835 100 835 0 0 3255 0 --:--:-- --:--:-- --:--:-- 3261
|
||||
|
||||
# 观察输出,来源IP是gtund所在服务器的内网IP(172.31.3.157)
|
||||
Serving HTTP on 0.0.0.0 port 12590 (http://0.0.0.0:12590/) ...
|
||||
172.31.3.157 - - [28/Apr/2024 10:59:31] "GET / HTTP/1.1" 200 -
|
||||
|
||||
```
|
||||
|
||||
有时候我们并不只是一台机器需要被gtun代理,因此需要配置除了gtun所在的服务器之外的其他服务器的代理,
|
||||
这里需要通过配置公有云的vpc路由来把流量导入到gtun所在服务器。
|
||||
|
||||
第二步,配置公有云的路由表,把对端vpc的cidr路由到gtun所在的云服务器实例。
|
||||
|
||||
通过公有云的路由表,能够实现其他机器也能够通过gtun访问到对端vpc的http服务。
|
||||
|
||||
非美国vpc网段的流量也是同样的配置方式,只是路由表会比较大,您也可以跟之前的文章一样,配置类似`0.0.0.0/0`的路由,把所有流量先导入到gtun所在服务器。
|
||||
|
||||
# 结束语
|
||||
gtun加速公有云访问外部流量与其他场景没有本质上的区别,唯一的区别仅仅只是需要配置公有云的路由,
|
||||
|
||||
如果要跟软路由场景对标,软路由由于本身有无线Wi-Fi,因此网关会自动设置为gtun所在机器,公有云则需要在云厂商控制台配置路由来控制。
|
||||
|
||||
本文的方式更像是旁路由的方式,旁路由通常是手动修改网关地址或者通过修改dhcp下发的地址来控制流量的流向,这里的公有云路由表类似dhcp下发。
|
63
doc/玩转N1盒子:基于gtun实现的tiktok加速路由.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# 玩转N1盒子:基于gtun实现的tiktok加速路由
|
||||
tiktok是目前出海比较火的一个场景,这个场景有以下问题需要解决:
|
||||
|
||||
- tiktok在国内访问不了,首先需要解决访问的问题
|
||||
- tiktok需要独占出口ip,不然上传视频可能会0播,直播可能会被封禁
|
||||
- 有的客户需要用本地运营商的IP,这部分我没有详细分析过不同IP带来的差异
|
||||
- 客户对成本有不一样的要求,对于直播,客户希望用专线,而且通常带宽比较固定,5mbps就能够支持一个在线直播,对于普通的刷视频,传视频,客户不一定需要专线
|
||||
|
||||
这些场景有的是可以通过gtun解决的,有的比如运营商IP,专线,这类资源型的服务则是gtun程序本身解决不了的。
|
||||
|
||||
资源型的服务我们有企业专门提供,这部分对于我们不是什么太大的问题,我们比扬云专门作这种专线,组网以及IP的业务,感兴趣的可以到[官网](https://www.beyondnetwork.net)
|
||||
了解更多。
|
||||
|
||||
言归正传,针对tiktok加速,我们提供了如下拓扑:
|
||||
|
||||

|
||||
|
||||
- 在终端还是基于N1盒子的软路由
|
||||
- 代理软件还是使用的gtun/gtund配套
|
||||
- 线路分为两块
|
||||
- 用于直播的专线线路
|
||||
- 用于养号的纯协议优化的线路,依赖的是gtun的kcp/quic这类协议
|
||||
|
||||
# 配置
|
||||
配置上与之前[基础用法:openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络](基础用法:openwrt搭载gtun打造加速软路由,连接Wi-Fi即可畅游网络.md)
|
||||
差别不大,只是底层线路上需要用到我们提供的专线,出口IP上需要用到独享的IP。
|
||||
|
||||
# 方案的缺点
|
||||
这个方案有几个非常明显的缺点:
|
||||
|
||||
- 从本地出去,经过运营商再到海外,这个走的是UDP,UDP在一些地区的运营商可能会被拦截掉,导致掉线
|
||||
- 一个软路由同时只能使用一个IP,这个是技术问题,比如同时tiktok的域名是`a.b.live.tiktok.com`,那么域名劫持的时候,结果只会写入到其中一个ipset里面,那么必然只能走一个IP出。
|
||||
|
||||
针对第一个问题,可以考虑把udp换成tcp,同时流量先经过国内公有云跳一跳,上到公有云之后再继续走的UDP协议。
|
||||
针对专线则没有这个问题,专线包含国内和国外两个机器,传输质量较好,可以全程用tcp。
|
||||
|
||||

|
||||
|
||||
针对第二个问题,目前使用软路由暂时没有太好的解决方式,如果需要解决这个问题,有两个思路:
|
||||
|
||||
- 针对不同的内网IP进行匹配
|
||||
- 使用小火箭,不实用软路由了
|
||||
|
||||
# tiktok的产品化解决方案
|
||||
|
||||
我们考虑了一段时间,还是考虑提供tiktok商家的解决方案,这个解决方案包括:
|
||||
|
||||
- IP,IP又包括运营商IP和云厂商IP
|
||||
- 代理,可以基于gtun的软路由,也可以基于小火箭
|
||||
- 线路,这个就比较复杂
|
||||
- 直连的线路,可能会被gfw封禁
|
||||
- 优化的线路,基于gtun和gtun的商业化产品[gipa](https://www.beyondnetwork.net)来提供性价比的线路
|
||||
- 部分专线线路,广港走专线,因为广港我们本身有资源,专线成本也比较低,很多客户都能接受
|
||||
- 全程专线,广港专线出,然后香港再专线到对应的国家,把出境线路收敛在广港
|
||||
|
||||
基于此思路我们做了一套tiktok解决方案
|
||||
|
||||
# 结束语
|
||||
tiktok目前是出海领域非常火的方向,tiktok的网络解决方案是很多出海工作室的刚需,我们在软件的基础之上,加上自身拥有的基础设施资源,可以非常快速的适应这一场景。
|
||||
|
||||
|
||||
|
||||
|
39
doc/玩转N1盒子:基于gtun实现的游戏加速盒.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 基于gtun实现的游戏加速盒
|
||||
之前提到tiktok出海,在跨境领域还有很多场景,游戏就是另外一块比较大的应用场景。游戏又可以细分为两个领域。
|
||||
|
||||
- ToC的游戏加速,像市面上比较常见的UU,雷神,迅游这种,除了软件之外,有些还有游戏加速盒子
|
||||
- ToB的游戏加速,针对游戏公司,游戏工作室需要海外发行游戏,但是希望给国内玩家提供服务
|
||||
|
||||
本文主要侧重在ToC的游戏加速,ToB的游戏加速有需要的客户可以先了解我们官网上的[全球加速产品](https://www.beyondnetwork.net)。
|
||||
|
||||
那么还是先来看看本文的一个简单拓扑。
|
||||

|
||||
|
||||
跟tiktok几乎是一模一样,但是游戏场景没有tiktok的养号线路,因此全程都走的专线。
|
||||
|
||||
游戏场景同样也有IP的问题,我们对接过的游戏加速器厂商普遍都希望用本地运营商IP,我们可以提供运营商IP,也可以提供数据中心的IP。
|
||||
|
||||
同样,IP可以是独享的,也可以是共享的,正常情况下游戏共享的IP问题也不是很大,但是共享一个IP池的,然后选一个线路,每条线路对应一个IP。
|
||||
|
||||
# 游戏加速的产品化解决方案
|
||||
我们的游戏解决方案提供以下服务:
|
||||
|
||||
- 基于gtun的流量劫持服务,搭载在Openwrt上做成一个游戏加速盒子
|
||||
- 提供专线加速的能力,降低丢包和延迟
|
||||
- 提供多种IP类型,包含运营商IP和BGP IP
|
||||
|
||||
以上是给普通的游戏玩家的,那么针对企业客户,我们有两个方向的合作。
|
||||
|
||||
- 如果您需要自己搭建一套这类游戏加速盒子,我们也可以提供技术支持和资源支持。
|
||||
- 如果您是游戏工作室,可以使用我们的线路来帮您实现全球同服,国内玩家加速,公有云组网的场景
|
||||
|
||||
# 结束语
|
||||
我们提供的所有的加速基本原理都是一样的,软件层面使用gtun来进行流量劫持和代理,针对不同的场景底层资源不一样。
|
||||
|
||||
针对普通的应用加速场景,不一定需要专线,只需要使用gtun然后配置kcp协议即可;
|
||||
|
||||
针对tiktok的加速,部分场景需要专线,部分场景不需要专线,但是对于gtun而言是透明的,gtun本身不需要感知是什么业务,是否使用专线;
|
||||
|
||||
针对游戏加速场景,我们强烈推荐专线,很多游戏对延迟和丢包非常敏感,而且游戏玩家能够很清楚的感知到延迟,丢包的影响。
|
||||
|
||||
|
@@ -1,65 +0,0 @@
|
||||
version: '3'
|
||||
services:
|
||||
gtun:
|
||||
build: ./gtun
|
||||
container_name: gtun
|
||||
restart: always
|
||||
network_mode: host
|
||||
privileged: true
|
||||
volumes:
|
||||
- /opt/apps/logs:/opt/logs
|
||||
environment:
|
||||
TIME_ZONE: Asia/Shanghai
|
||||
settings: |
|
||||
settings:
|
||||
CN:
|
||||
proxy_file: "https://www.ipdeny.com/ipblocks/data/countries/us.zone"
|
||||
route:
|
||||
- trace_addr: ${CN_SERVER_IP}:${CN_SERVER_TRACE_PORT}
|
||||
scheme: "kcp"
|
||||
addr: ${CN_SERVER_IP}:${CN_SERVER_PORT}
|
||||
auth_key: ""
|
||||
proxy:
|
||||
"tproxy_tcp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "CN"
|
||||
}
|
||||
"tproxy_udp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "CN"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: Debug
|
||||
path: gtun.log
|
||||
|
||||
http_server:
|
||||
listen_addr: ":9001"
|
||||
gtund:
|
||||
build: ./gtund
|
||||
container_name: gtund
|
||||
restart: always
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /opt/apps/logs:/logs
|
||||
environment:
|
||||
TIME_ZONE: Asia/Shanghai
|
||||
settings: |
|
||||
server:
|
||||
- listen: ":3002"
|
||||
authKey: "rewrite with your auth key"
|
||||
scheme: "kcp"
|
||||
trace: ":3003"
|
||||
log:
|
||||
days: 5
|
||||
level: "debug"
|
||||
path: "gtund.log"
|
2
docker-build/gtun/.env
Normal file
@@ -0,0 +1,2 @@
|
||||
ACCESS_TOKEN=ICKelin:free
|
||||
SERVER_IP=xxx.xxx.xxx.xxx
|
@@ -1,6 +1,6 @@
|
||||
FROM ubuntu:18.04
|
||||
COPY gtun-linux_amd64 /gtun
|
||||
FROM ubuntu:20.04
|
||||
RUN mkdir -p /opt/apps/gtun/logs
|
||||
COPY . /opt/apps/gtun
|
||||
COPY start.sh /
|
||||
RUN chmod +x start.sh && chmod +x gtun
|
||||
RUN mkdir /opt/logs
|
||||
RUN chmod +x start.sh && chmod +x /opt/apps/gtun/gtun
|
||||
CMD /start.sh
|
14
docker-build/gtun/docker-compose.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
version: '3'
|
||||
services:
|
||||
accelerator:
|
||||
build: .
|
||||
container_name: gtun_2.0.7
|
||||
restart: always
|
||||
network_mode: host
|
||||
privileged: true
|
||||
volumes:
|
||||
- /opt/apps/gtun/logs:/opt/apps/gtun/logs
|
||||
environment:
|
||||
TIME_ZONE: Asia/Shanghai
|
||||
ACCESS_TOKEN: $ACCESS_TOKEN
|
||||
SERVER_IP: $SERVER_IP
|
@@ -3,9 +3,4 @@ if [ "$TIME_ZONE" != "" ]; then
|
||||
ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
|
||||
fi
|
||||
|
||||
#项目的配置文件
|
||||
if [ "$settings" != "" ]; then
|
||||
echo "$settings" > /gtun.yaml
|
||||
fi
|
||||
|
||||
/gtun -c /gtun.yaml
|
||||
/opt/apps/gtun/gtun -c /opt/apps/gtun/etc/gtun.yaml
|
@@ -1,6 +1,6 @@
|
||||
FROM ubuntu:18.04
|
||||
COPY gtund /
|
||||
FROM ubuntu:20.04
|
||||
RUN mkdir -p /opt/apps/gtund/logs
|
||||
COPY . /opt/apps/gtund
|
||||
COPY start.sh /
|
||||
RUN chmod +x start.sh && chmod +x gtund
|
||||
RUN mkdir /opt/logs
|
||||
RUN chmod +x start.sh && chmod +x /opt/apps/gtund/gtund
|
||||
CMD /start.sh
|
12
docker-build/gtund/docker-compose.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
version: '3'
|
||||
services:
|
||||
accelerator:
|
||||
build: .
|
||||
container_name: gtund
|
||||
restart: always
|
||||
network_mode: host
|
||||
privileged: true
|
||||
volumes:
|
||||
- /opt/apps/gtund/logs:/opt/apps/gtund/logs
|
||||
environment:
|
||||
TIME_ZONE: Asia/Shanghai
|
@@ -3,9 +3,4 @@ if [ "$TIME_ZONE" != "" ]; then
|
||||
ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
|
||||
fi
|
||||
|
||||
#项目的配置文件
|
||||
if [ "$settings" != "" ]; then
|
||||
echo "$settings" > /gtund.yaml
|
||||
fi
|
||||
|
||||
/gtund -c /gtund.yaml
|
||||
/opt/apps/gtund/gtund -c /opt/apps/gtund/etc/gtund.yaml
|
11
docker_build.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
./build.sh
|
||||
|
||||
rm -r images
|
||||
|
||||
mkdir -p images/gtun
|
||||
cp -r release/gtun/* images/gtun/
|
||||
cp -r docker-build/gtun/* images/gtun/
|
||||
|
||||
mkdir -p images/gtund
|
||||
cp -r release/gtund/* images/gtund
|
||||
cp -r docker-build/gtund/* images/gtund/
|
@@ -1,33 +0,0 @@
|
||||
settings:
|
||||
CN:
|
||||
proxy_file: "https://www.ipdeny.com/ipblocks/data/countries/us.zone"
|
||||
route:
|
||||
- trace_addr: ${CN_SERVER_IP}:${CN_SERVER_TRACE_PORT}
|
||||
scheme: "kcp"
|
||||
addr: ${CN_SERVER_IP}:${CN_SERVER_PORT}
|
||||
auth_key: ""
|
||||
proxy:
|
||||
"tproxy_tcp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "CN"
|
||||
}
|
||||
"tproxy_udp": |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524",
|
||||
"rate_limit": 50,
|
||||
"region": "CN"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: Debug
|
||||
path: gtun.log
|
||||
|
||||
http_server:
|
||||
listen_addr: ":9001""
|
16
etc/gtun/gtun.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=gtun - ip accelerator base on tproxy
|
||||
After=network.target auditd.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/apps/gtun/gtun -c /opt/apps/gtun/etc/gtun.yaml
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartPreventExitStatus=255
|
||||
Type=simple
|
||||
LimitNOFILE=1000000
|
||||
LimitNPROC=1000000
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=gtun.service
|
28
etc/gtun/gtun.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
access_token: "${ACCESS_TOKEN}"
|
||||
accelerator:
|
||||
HK:
|
||||
routes:
|
||||
- scheme: "kcp"
|
||||
server: "${SERVER_IP}:3002"
|
||||
trace: "${SERVER_IP}:3003"
|
||||
- scheme: "mux"
|
||||
server: "${SERVER_IP}:3002"
|
||||
trace: "${SERVER_IP}:3003"
|
||||
proxy:
|
||||
tproxy_tcp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
tproxy_udp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: debug
|
||||
path: /opt/apps/gtun/logs/gtun.log
|
@@ -1,14 +0,0 @@
|
||||
trace: ":3003"
|
||||
server:
|
||||
- listen: ":3002"
|
||||
authKey: "rewrite with your auth key"
|
||||
scheme: "kcp"
|
||||
|
||||
- listen: ":3001"
|
||||
authKey: "rewrite with your auth key"
|
||||
scheme: "mux"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "debug"
|
||||
path: "gtund.log"
|
16
etc/gtund/gtund.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=gtund - ip accelerator base on tproxy
|
||||
After=network.target auditd.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/apps/gtund/gtund -c /opt/apps/gtund/etc/gtund.yaml
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartPreventExitStatus=255
|
||||
Type=simple
|
||||
LimitNOFILE=1000000
|
||||
LimitNPROC=1000000
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=gtund.service
|
17
etc/gtund/gtund.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
enable_auth: true
|
||||
auths:
|
||||
- access_token: "ICKelin:free"
|
||||
expired_ath: 0
|
||||
|
||||
trace: ":3003"
|
||||
server:
|
||||
- listen: ":3002"
|
||||
scheme: "kcp"
|
||||
|
||||
- listen: ":3002"
|
||||
scheme: "mux"
|
||||
|
||||
log:
|
||||
days: 5
|
||||
level: "debug"
|
||||
path: "/opt/apps/gtund/logs/gtund.log"
|
24
go.mod
@@ -1,10 +1,10 @@
|
||||
module github.com/ICKelin/gtun
|
||||
|
||||
go 1.16
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/ICKelin/optw v0.0.0-20211219021958-28f4d1f075ef
|
||||
github.com/agiledragon/gomonkey/v2 v2.10.1
|
||||
github.com/ICKelin/optw v0.0.0-20240428102250-612f5bb01303
|
||||
github.com/agiledragon/gomonkey/v2 v2.11.0
|
||||
github.com/astaxie/beego v1.12.3
|
||||
github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58
|
||||
@@ -13,3 +13,21 @@ require (
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/klauspost/reedsolomon v1.11.7 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
|
||||
github.com/smarty/assertions v1.15.0 // indirect
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
|
||||
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible // indirect
|
||||
github.com/xtaci/smux v1.5.24 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
)
|
||||
|
563
go.sum
@@ -1,60 +1,15 @@
|
||||
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.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.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
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=
|
||||
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/ICKelin/gtun v1.0.5-0.20211204061645-ed01445bf708/go.mod h1:lXqvFm0rxLK0HAWUJYEbrkfStUJsamURyjoIelB5FHE=
|
||||
github.com/ICKelin/optw v0.0.0-20211219021958-28f4d1f075ef h1:f2j59p1x1OG/73AaAYy3nxMCfaGilxTQdOqkueaF4FQ=
|
||||
github.com/ICKelin/optw v0.0.0-20211219021958-28f4d1f075ef/go.mod h1:G3/YSddzYP9BhFIiEeXR3H5Q5s4ykReqromA4w47fH8=
|
||||
github.com/ICKelin/optw v0.0.0-20240428102250-612f5bb01303 h1:+Ny6mSEahFVfuEXXzoxChuWUStKyW0V53wTA/v0r3ug=
|
||||
github.com/ICKelin/optw v0.0.0-20240428102250-612f5bb01303/go.mod h1:MQl8fLDhV0btvBztH05wsDamj0Rn8BDnDmCPeuIBpbY=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/agiledragon/gomonkey/v2 v2.10.1 h1:FPJJNykD1957cZlGhr9X0zjr291/lbazoZ/dmc4mS4c=
|
||||
github.com/agiledragon/gomonkey/v2 v2.10.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/agiledragon/gomonkey/v2 v2.11.0 h1:5oxSgA+tC1xuGsrIorR+sYiziYltmJyEZ9qA25b6l5U=
|
||||
github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
|
||||
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
|
||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||
@@ -64,48 +19,22 @@ github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHK
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
|
||||
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/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
|
||||
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/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
@@ -113,122 +42,42 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
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.3/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
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-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
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/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
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/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid v1.2.4 h1:EBfaK0SWSwk+fgk6efYFWdzl8MwRWoOO1gkmiaTXPW4=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/reedsolomon v1.11.7 h1:9uaHU0slncktTEEg4+7Vl7q7XUNMBUOK4R9gnKhMjAU=
|
||||
github.com/klauspost/reedsolomon v1.11.7/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -236,75 +85,44 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mmcloughlin/avo v0.0.0-20201216231306-039ef47f4f69 h1:U3a/eCFK1x5LmMPHYND8zfvAa1NS8pVK60UblgsTwmA=
|
||||
github.com/mmcloughlin/avo v0.0.0-20201216231306-039ef47f4f69/go.mod h1:6aKT4zZIrpGqB3RpFU14ByCSSyKY6LfJz4J/JJChHfI=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
|
||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
|
||||
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
|
||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
|
||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -313,22 +131,12 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS
|
||||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
|
||||
@@ -342,417 +150,78 @@ github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqI
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg=
|
||||
github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
|
||||
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
|
||||
github.com/xtaci/smux v1.5.15 h1:6hMiXswcleXj5oNfcJc+DXS8Vj36XX2LaX98udog6Kc=
|
||||
github.com/xtaci/smux v1.5.15/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY=
|
||||
github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
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=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
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=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/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/lint v0.0.0-20210508222113-6edffad5e616/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/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-20201110031124-69a78807bb2b/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-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
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/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190422165155-953cdadca894/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/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-20200106162015-b016eb3dc98e/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-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-20200615200032-f1bc736245b1/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-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
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-20181030221726-6c7e314b6563/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-20190328211700-ab21143f2384/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-20191112195655-aa38f8e97acc/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-20200619180055-7c47624df98f/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-20201105001634-bc3cf281b174/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
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/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
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-20200513103714-09dca8ec2884/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-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
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.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
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/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
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=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
@@ -1,61 +0,0 @@
|
||||
package gtun
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v2"
|
||||
"os"
|
||||
)
|
||||
|
||||
var gConfig *Config
|
||||
|
||||
type Config struct {
|
||||
Settings map[string]RegionConfig `yaml:"settings"`
|
||||
HTTPServer HTTPConfig `yaml:"http_server"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type HTTPConfig struct {
|
||||
ListenAddr string `yaml:"listen_addr"`
|
||||
}
|
||||
|
||||
type RegionConfig struct {
|
||||
Route []RouteConfig `yaml:"route"`
|
||||
ProxyFile string `yaml:"proxy_file"`
|
||||
Proxy map[string]string `yaml:"proxy"`
|
||||
}
|
||||
|
||||
type RouteConfig struct {
|
||||
Region string `yaml:"region"`
|
||||
TraceAddr string `yaml:"trace_addr"`
|
||||
Scheme string `yaml:"scheme"`
|
||||
Addr string `yaml:"addr"`
|
||||
AuthKey string `yaml:"auth_key"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (*Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseBuffer(content)
|
||||
}
|
||||
|
||||
func ParseBuffer(content []byte) (*Config, error) {
|
||||
conf := Config{}
|
||||
err := yaml.Unmarshal(content, &conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gConfig = &conf
|
||||
return &conf, err
|
||||
}
|
||||
|
||||
func GetConfig() *Config {
|
||||
return gConfig
|
||||
}
|
@@ -1,115 +0,0 @@
|
||||
package gtun
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/ICKelin/gtun/gtun/proxy"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HTTPServer struct {
|
||||
listenAddr string
|
||||
}
|
||||
|
||||
func NewHTTPServer(listenAddr string) *HTTPServer {
|
||||
return &HTTPServer{listenAddr: listenAddr}
|
||||
}
|
||||
|
||||
func (s *HTTPServer) ListenAndServe() error {
|
||||
http.HandleFunc("/meta", loadMeta)
|
||||
http.HandleFunc("/ip/add", addIP)
|
||||
http.HandleFunc("/ip/delete", delIP)
|
||||
return http.ListenAndServe(s.listenAddr, nil)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func loadMeta(w http.ResponseWriter, r *http.Request) {
|
||||
regionList := make([]string, 0)
|
||||
regions := GetConfig().Settings
|
||||
for region, _ := range regions {
|
||||
regionList = append(regionList, region)
|
||||
}
|
||||
|
||||
type replyBody struct {
|
||||
Regions []string `json:"regions"`
|
||||
Cfg *Config
|
||||
}
|
||||
|
||||
body := &replyBody{
|
||||
Regions: regionList,
|
||||
Cfg: GetConfig(),
|
||||
}
|
||||
reply(w, body)
|
||||
}
|
||||
|
||||
func addIP(w http.ResponseWriter, r *http.Request) {
|
||||
type req struct {
|
||||
Region string `json:"region"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
var form = req{}
|
||||
err := bindForm(r, &form)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// add to ipset
|
||||
err = proxy.AddIP(form.Region, form.IP)
|
||||
if err != nil {
|
||||
reply(w, &response{
|
||||
Code: -1,
|
||||
Message: err.Error(),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
reply(w, &response{Code: 0, Message: "success"})
|
||||
}
|
||||
|
||||
func delIP(w http.ResponseWriter, r *http.Request) {
|
||||
type req struct {
|
||||
Region string `json:"region"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
var form = req{}
|
||||
err := bindForm(r, &form)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// delete from ipset
|
||||
err = proxy.DelIP(form.Region, form.IP)
|
||||
if err != nil {
|
||||
reply(w, &response{
|
||||
Code: -1,
|
||||
Message: err.Error(),
|
||||
Data: nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
reply(w, &response{Code: 0, Message: "success"})
|
||||
}
|
||||
|
||||
func bindForm(r *http.Request, obj interface{}) error {
|
||||
cnt, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(cnt, obj)
|
||||
}
|
||||
|
||||
func reply(w http.ResponseWriter, obj interface{}) {
|
||||
buf, _ := json.Marshal(obj)
|
||||
_, _ = w.Write(buf)
|
||||
}
|
52
gtun/main.go
@@ -1,52 +0,0 @@
|
||||
package gtun
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/gtun/proxy"
|
||||
"github.com/ICKelin/gtun/gtun/route"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
)
|
||||
|
||||
func Main() {
|
||||
flgConf := flag.String("c", "", "config file")
|
||||
flag.Parse()
|
||||
|
||||
conf, err := ParseConfig(*flgConf)
|
||||
if err != nil {
|
||||
fmt.Printf("load config fail: %v\n", err)
|
||||
return
|
||||
}
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
|
||||
// run proxy
|
||||
for region, cfg := range conf.Settings {
|
||||
// init plugins
|
||||
err = proxy.Setup(region, cfg.ProxyFile, cfg.Proxy)
|
||||
if err != nil {
|
||||
fmt.Printf("set proxy fail: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// run route and race
|
||||
raceManager := route.GetTraceManager()
|
||||
for region, cfg := range conf.Settings {
|
||||
raceTargets := make([]string, 0)
|
||||
for _, r := range cfg.Route {
|
||||
raceTargets = append(raceTargets, r.TraceAddr)
|
||||
hopConn, err := route.CreateConnection(region, r.Scheme, r.Addr, r.AuthKey)
|
||||
if err != nil {
|
||||
fmt.Printf("connect to %s://%s fail: %v\n", r.Scheme, r.Addr, err)
|
||||
return
|
||||
}
|
||||
go hopConn.ConnectNextHop()
|
||||
}
|
||||
|
||||
regionRace := route.NewTrace(region, raceTargets)
|
||||
raceManager.AddRegionTrace(region, regionRace)
|
||||
}
|
||||
raceManager.RunRace()
|
||||
|
||||
panic(NewHTTPServer(conf.HTTPServer.ListenAddr).ListenAndServe())
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
package gtun
|
||||
|
||||
import (
|
||||
_ "github.com/ICKelin/gtun/gtun/proxy"
|
||||
)
|
@@ -1,83 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
markID = int32(1)
|
||||
routeTableID = int32(101)
|
||||
)
|
||||
|
||||
func allocateMarkID() int32 {
|
||||
return atomic.AddInt32(&markID, 1)
|
||||
}
|
||||
|
||||
func allocateRouteTableID() int32 {
|
||||
return atomic.AddInt32(&routeTableID, 1)
|
||||
}
|
||||
|
||||
func initRedirect(proto, region, redirectPort string) {
|
||||
setName := ipsetNamePrefix + region
|
||||
|
||||
out, err := utils.ExecCmd("ipset", []string{"create", setName, "hash:net"})
|
||||
if err != nil {
|
||||
logs.Warn("create ipset fail: %v %s", err, out)
|
||||
}
|
||||
|
||||
out, err = utils.ExecCmd("ipset", []string{"-F", setName})
|
||||
if err != nil {
|
||||
logs.Warn("flush ipset fail: %v %s", err, out)
|
||||
}
|
||||
|
||||
markID := allocateMarkID()
|
||||
routeTable := allocateRouteTableID()
|
||||
|
||||
args := fmt.Sprintf("-t mangle -D PREROUTING -p %s -m set --match-set %s dst -j TPROXY --tproxy-mark %d/%d --on-port %s", proto, setName, markID, markID, redirectPort)
|
||||
out, err = utils.ExecCmd("iptables", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
args = fmt.Sprintf("-t mangle -A PREROUTING -p %s -m set --match-set %s dst -j TPROXY --tproxy-mark %d/%d --on-port %s", proto, setName, markID, markID, redirectPort)
|
||||
out, err = utils.ExecCmd("iptables", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
|
||||
args = fmt.Sprintf("-t mangle -D OUTPUT -p %s -m set --match-set %s dst -j MARK --set-mark %d", proto, setName, markID)
|
||||
out, err = utils.ExecCmd("iptables", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
args = fmt.Sprintf("-t mangle -A OUTPUT -p %s -m set --match-set %s dst -j MARK --set-mark %d", proto, setName, markID)
|
||||
out, err = utils.ExecCmd("iptables", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
|
||||
args = fmt.Sprintf("rule del fwmark %d lookup %d", markID, routeTable)
|
||||
out, err = utils.ExecCmd("ip", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
args = fmt.Sprintf("rule add fwmark %d lookup %d", markID, routeTable)
|
||||
out, err = utils.ExecCmd("ip", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
|
||||
args = fmt.Sprintf("ro del local default dev lo table %d", routeTable)
|
||||
out, err = utils.ExecCmd("ip", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
args = fmt.Sprintf("ro add local default dev lo table %d", routeTable)
|
||||
out, err = utils.ExecCmd("ip", strings.Split(args, " "))
|
||||
if err != nil {
|
||||
logs.Warn("%s %s %s", args, err, out)
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type dummyConn struct {
|
||||
readBuf bytes.Buffer
|
||||
writeBuf bytes.Buffer
|
||||
}
|
||||
|
||||
func (d *dummyConn) Read(b []byte) (n int, err error) {
|
||||
n = copy(b, d.readBuf.Bytes())
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) Write(b []byte) (n int, err error) {
|
||||
return d.writeBuf.Write(b)
|
||||
}
|
||||
|
||||
func (d *dummyConn) Close() error {
|
||||
d.readBuf.Reset()
|
||||
d.writeBuf.Reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) LocalAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) RemoteAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) SetReadDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *dummyConn) SetWriteDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestTProxyTCPDoProxy(t *testing.T) {
|
||||
p := NewTProxyTCP()
|
||||
cfg := `{}`
|
||||
err := p.Setup([]byte(cfg))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
conn := &dummyConn{}
|
||||
p.(*TProxyTCP).doProxy(conn)
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/gtun/route"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/proto"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("tun_proxy", NewTunProxy)
|
||||
}
|
||||
|
||||
type TunProxyConfig struct {
|
||||
Region string `json:"region"`
|
||||
MTU int `json:"mtu"`
|
||||
WriteTimeout int `json:"write_timeout"`
|
||||
ReadTimeout int `json:"read_timeout"`
|
||||
}
|
||||
|
||||
type TunProxy struct {
|
||||
config TunProxyConfig
|
||||
dev *utils.Interface
|
||||
}
|
||||
|
||||
func NewTunProxy() Proxy {
|
||||
return &TunProxy{}
|
||||
}
|
||||
|
||||
func (p *TunProxy) Name() string {
|
||||
return "tun_proxy"
|
||||
}
|
||||
|
||||
func (p *TunProxy) Setup(cfg json.RawMessage) error {
|
||||
var config = TunProxyConfig{}
|
||||
err := json.Unmarshal(cfg, &config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.MTU <= 0 {
|
||||
return fmt.Errorf("%s invalid mtu", p.Name())
|
||||
}
|
||||
|
||||
dev, err := utils.NewInterface()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dev.SetMTU(config.MTU)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dev.Up()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.config = config
|
||||
p.dev = dev
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TunProxy) ListenAndServe() error {
|
||||
// tun proxy use only one stream for long live connection
|
||||
var nextHopStream transport.Stream
|
||||
var nextHopConn *route.HopInfo
|
||||
for {
|
||||
buf, err := p.dev.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if nextHopConn == nil || nextHopConn.IsClosed() {
|
||||
nextHopConn = route.GetRouteManager().Route(p.config.Region, "")
|
||||
if nextHopConn == nil {
|
||||
logs.Warn("route to next hop fail")
|
||||
continue
|
||||
}
|
||||
|
||||
nextHopStream, err = nextHopConn.OpenStream()
|
||||
if err != nil {
|
||||
logs.Warn("open stream fail: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// encode proxy protocol
|
||||
bytes := proto.EncodeProxyProtocol("tun_proxy", "", "0", "", "0")
|
||||
_ = nextHopStream.SetWriteDeadline(time.Now().Add(time.Duration(p.config.WriteTimeout)))
|
||||
_, err = nextHopStream.Write(bytes)
|
||||
_ = nextHopStream.SetWriteDeadline(time.Time{})
|
||||
|
||||
go p.readFromRemote(nextHopStream)
|
||||
}
|
||||
|
||||
bytes := proto.EncodeData(buf)
|
||||
nextHopStream.SetWriteDeadline(time.Now().Add(time.Duration(p.config.WriteTimeout)))
|
||||
_, err = nextHopStream.Write(bytes)
|
||||
nextHopStream.SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
nextHopStream.Close()
|
||||
nextHopConn.Close()
|
||||
logs.Error("stream write fail: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TunProxy) readFromRemote(stream transport.Stream) {
|
||||
defer stream.Close()
|
||||
hdr := make([]byte, 2)
|
||||
for {
|
||||
nr, err := stream.Read(hdr)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
logs.Error("read stream fail %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
if nr != 2 {
|
||||
logs.Error("invalid bodylen: %d", nr)
|
||||
continue
|
||||
}
|
||||
|
||||
nlen := binary.BigEndian.Uint16(hdr)
|
||||
buf := make([]byte, nlen)
|
||||
stream.SetReadDeadline(time.Now().Add(time.Duration(p.config.ReadTimeout)))
|
||||
_, err = io.ReadFull(stream, buf)
|
||||
stream.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
logs.Error("read stream body fail: %v", err)
|
||||
break
|
||||
}
|
||||
|
||||
_, err = p.dev.Write(buf)
|
||||
if err != nil {
|
||||
logs.Warn("write to dev fail: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,130 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errRegistered = fmt.Errorf("already registered")
|
||||
var errNotRegister = fmt.Errorf("proxy not register")
|
||||
var ipsetNamePrefix = "GTUN-"
|
||||
|
||||
// Proxy defines Proxies, such as tproxy_tcp, tproxy_udp,ip_tun, ip_wireguard
|
||||
type Proxy interface {
|
||||
Name() string
|
||||
Setup(cfg json.RawMessage) error
|
||||
ListenAndServe() error
|
||||
}
|
||||
|
||||
var registerProxy = make(map[string]func() Proxy)
|
||||
|
||||
func Register(name string, constructor func() Proxy) error {
|
||||
if _, ok := registerProxy[name]; ok {
|
||||
return errRegistered
|
||||
}
|
||||
registerProxy[name] = constructor
|
||||
return nil
|
||||
}
|
||||
|
||||
func Setup(region, ruleFile string, proxyConfigs map[string]string) error {
|
||||
for name, config := range proxyConfigs {
|
||||
constructor := registerProxy[name]
|
||||
if constructor == nil {
|
||||
return errNotRegister
|
||||
}
|
||||
p := constructor()
|
||||
err := p.Setup([]byte(config))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
AddFromFile(region, ruleFile)
|
||||
go p.ListenAndServe()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddIP(region string, ip string) error {
|
||||
out, err := utils.ExecCmd("ipset", []string{"add", ipsetNamePrefix + region, ip})
|
||||
if err != nil {
|
||||
return fmt.Errorf("add to ipset fail: %v %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DelIP(region, ip string) error {
|
||||
out, err := utils.ExecCmd("ipset", []string{"del", ipsetNamePrefix + region, ip})
|
||||
if err != nil {
|
||||
return fmt.Errorf("del from ipset fail: %v %s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddApp(region, appName string) error {
|
||||
AddFromFile(region, appName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddFromFile(region, file string) {
|
||||
ips := loadIPs(file)
|
||||
|
||||
for _, ip := range ips {
|
||||
AddIP(region, ip)
|
||||
}
|
||||
}
|
||||
|
||||
func loadIPs(file string) []string {
|
||||
if len(file) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ips := make([]string, 0)
|
||||
var br *bufio.Reader
|
||||
if strings.HasPrefix(file, "http://") || strings.HasPrefix(file, "https://") {
|
||||
// load from url
|
||||
req, err := http.NewRequest("GET", file, nil)
|
||||
if err != nil {
|
||||
logs.Warn("load file fail: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
cli := http.Client{
|
||||
Timeout: time.Second * 120,
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if err != nil {
|
||||
logs.Warn("load file fail: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
br = bufio.NewReader(resp.Body)
|
||||
} else {
|
||||
// load from file
|
||||
fp, err := os.Open(file)
|
||||
if err != nil {
|
||||
logs.Warn("open rule file fail: %v", err)
|
||||
return nil
|
||||
}
|
||||
defer fp.Close()
|
||||
br = bufio.NewReader(fp)
|
||||
}
|
||||
|
||||
for {
|
||||
line, _, err := br.ReadLine()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
ips = append(ips, string(line))
|
||||
}
|
||||
|
||||
return ips
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/ICKelin/optw/transport"
|
||||
)
|
||||
|
||||
var routeManager = &Manager{
|
||||
regionHops: make(map[string][]*HopInfo),
|
||||
raceManager: GetTraceManager(),
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
raceManager *TraceManager
|
||||
regionHopsMu sync.RWMutex
|
||||
regionHops map[string][]*HopInfo
|
||||
}
|
||||
|
||||
type HopInfo struct {
|
||||
transport.Conn
|
||||
}
|
||||
|
||||
func GetRouteManager() *Manager {
|
||||
return routeManager
|
||||
}
|
||||
|
||||
func (routeManager *Manager) Route(region, dip string) *HopInfo {
|
||||
routeManager.regionHopsMu.RLock()
|
||||
defer routeManager.regionHopsMu.RUnlock()
|
||||
|
||||
regionHops, ok := routeManager.regionHops[region]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(regionHops) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bestNode := routeManager.raceManager.GetBestNode(region)
|
||||
bestIP := strings.Split(bestNode, ":")[0]
|
||||
for i := 0; i < len(regionHops); i++ {
|
||||
hop := regionHops[i]
|
||||
if hop.IsClosed() {
|
||||
logs.Warn("%s %s is closed", region, hop.RemoteAddr())
|
||||
continue
|
||||
}
|
||||
|
||||
if len(bestIP) != 0 {
|
||||
// use only ip address for the same node
|
||||
// TODO: use scheme://ip:port
|
||||
hopIP := strings.Split(hop.RemoteAddr().String(), ":")[0]
|
||||
if bestIP == hopIP {
|
||||
logs.Debug("best ip match %s", bestIP)
|
||||
return hop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logs.Warn("use random hop")
|
||||
hash := 0
|
||||
for _, c := range dip {
|
||||
hash += int(c)
|
||||
}
|
||||
|
||||
hop := regionHops[hash%len(regionHops)]
|
||||
if hop == nil || hop.IsClosed() {
|
||||
return nil
|
||||
}
|
||||
return hop
|
||||
}
|
||||
|
||||
func (routeManager *Manager) AddRoute(region string, hop *HopInfo) {
|
||||
routeManager.regionHopsMu.Lock()
|
||||
defer routeManager.regionHopsMu.Unlock()
|
||||
regionHops := routeManager.regionHops[region]
|
||||
if regionHops == nil {
|
||||
regionHops = make([]*HopInfo, 0)
|
||||
}
|
||||
regionHops = append(regionHops, hop)
|
||||
routeManager.regionHops[region] = regionHops
|
||||
}
|
||||
|
||||
func (routeManager *Manager) DeleteRoute(region string, hop *HopInfo) {
|
||||
routeManager.regionHopsMu.Lock()
|
||||
defer routeManager.regionHopsMu.Unlock()
|
||||
regionHops := routeManager.regionHops[region]
|
||||
if regionHops == nil {
|
||||
return
|
||||
}
|
||||
|
||||
hops := make([]*HopInfo, 0, len(regionHops))
|
||||
for _, s := range regionHops {
|
||||
if s.RemoteAddr().String() == hop.RemoteAddr().String() {
|
||||
continue
|
||||
}
|
||||
|
||||
hops = append(hops, s)
|
||||
}
|
||||
|
||||
routeManager.regionHops[region] = hops
|
||||
}
|
@@ -1,191 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/optw/transport"
|
||||
"github.com/agiledragon/gomonkey/v2"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestManager_AddRoute(t *testing.T) {
|
||||
Convey("Test add route", t, func() {
|
||||
Convey("add first hop for region", func() {
|
||||
GetRouteManager().AddRoute("test_region1", &HopInfo{})
|
||||
So(len(GetRouteManager().regionHops), ShouldEqual, 1)
|
||||
So(len(GetRouteManager().regionHops["test_region1"]), ShouldEqual, 1)
|
||||
|
||||
})
|
||||
|
||||
Convey("add second hop", func() {
|
||||
GetRouteManager().AddRoute("test_region1", &HopInfo{})
|
||||
So(len(GetRouteManager().regionHops), ShouldEqual, 1)
|
||||
So(len(GetRouteManager().regionHops["test_region1"]), ShouldEqual, 2)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestManager_DeleteRoute(t *testing.T) {
|
||||
Convey("Test delete route", t, func() {
|
||||
Convey("delete un exist region", func() {
|
||||
GetRouteManager().DeleteRoute("not-found", nil)
|
||||
})
|
||||
|
||||
Convey("delete exist region with empty hops", func() {
|
||||
GetRouteManager().regionHops["region1"] = make([]*HopInfo, 0)
|
||||
GetRouteManager().DeleteRoute("region1", nil)
|
||||
})
|
||||
|
||||
Convey("delete exist region with hops", func() {
|
||||
newHopInfo := &HopInfo{Conn: &mockConn{}}
|
||||
gomonkey.ApplyMethod(newHopInfo.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, 0, 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
GetRouteManager().AddRoute("region1", newHopInfo)
|
||||
So(len(GetRouteManager().regionHops["region1"]), ShouldEqual, 1)
|
||||
GetRouteManager().DeleteRoute("region1", newHopInfo)
|
||||
So(len(GetRouteManager().regionHops["region1"]), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("delete not exist hops", func() {
|
||||
newHopInfo := &HopInfo{Conn: &mockConn{}}
|
||||
i := 0
|
||||
gomonkey.ApplyMethod(newHopInfo.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
i += 1
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, byte(i), 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
|
||||
deleteHopInfo := &HopInfo{Conn: &mockConn{}}
|
||||
gomonkey.ApplyMethod(deleteHopInfo.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
i += 1
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, byte(i), 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
|
||||
GetRouteManager().AddRoute("region1", newHopInfo)
|
||||
So(len(GetRouteManager().regionHops["region1"]), ShouldEqual, 1)
|
||||
|
||||
GetRouteManager().DeleteRoute("region1", deleteHopInfo)
|
||||
So(len(GetRouteManager().regionHops["region1"]), ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestManager_Route(t *testing.T) {
|
||||
Convey("Test route", t, func() {
|
||||
Convey("nil next hop region", func() {
|
||||
hop := GetRouteManager().Route("not-found", "")
|
||||
So(hop, ShouldBeNil)
|
||||
|
||||
GetRouteManager().regionHops["region1"] = make([]*HopInfo, 0)
|
||||
hop = GetRouteManager().Route("region1", "")
|
||||
So(hop, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("next hop is closed", func() {
|
||||
hop := &HopInfo{Conn: &mockConn{}}
|
||||
gomonkey.ApplyMethod(hop.Conn, "IsClosed", func(conn transport.Conn) bool {
|
||||
return true
|
||||
})
|
||||
gomonkey.ApplyMethod(hop.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, byte(0), 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
|
||||
GetRouteManager().AddRoute("region1", hop)
|
||||
routeHop := GetRouteManager().Route("region1", "")
|
||||
So(routeHop, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("best ip not match", func() {
|
||||
hop := &HopInfo{Conn: &mockConn{}}
|
||||
gomonkey.ApplyMethod(hop.Conn, "IsClosed", func(conn transport.Conn) bool {
|
||||
return false
|
||||
})
|
||||
gomonkey.ApplyMethod(hop.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, byte(0), 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
|
||||
gomonkey.ApplyMethod(GetRouteManager().raceManager, "GetBestNode", func(manager *TraceManager) string {
|
||||
return "192.168.1.1:9000"
|
||||
})
|
||||
GetRouteManager().AddRoute("region2", hop)
|
||||
routeHop := GetRouteManager().Route("region2", "")
|
||||
// use random
|
||||
So(routeHop, ShouldNotBeNil)
|
||||
So(routeHop.RemoteAddr().String(), ShouldEqual, "127.0.0.1:10000")
|
||||
})
|
||||
|
||||
Convey("best ip match", func() {
|
||||
hop := &HopInfo{Conn: &mockConn{}}
|
||||
gomonkey.ApplyMethod(hop.Conn, "IsClosed", func(conn transport.Conn) bool {
|
||||
return false
|
||||
})
|
||||
gomonkey.ApplyMethod(hop.Conn, "RemoteAddr", func(hopInfo transport.Conn) net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: net.IPv4(127, 0, byte(0), 1),
|
||||
Port: 10000,
|
||||
Zone: "",
|
||||
}
|
||||
})
|
||||
|
||||
gomonkey.ApplyMethod(GetRouteManager().raceManager, "GetBestNode", func(manager *TraceManager) string {
|
||||
return "127.0.0.1:10000"
|
||||
})
|
||||
|
||||
GetRouteManager().AddRoute("region3", hop)
|
||||
routeHop := GetRouteManager().Route("region3", "")
|
||||
So(routeHop, ShouldNotBeNil)
|
||||
So(routeHop.RemoteAddr().String(), ShouldEqual, "127.0.0.1:10000")
|
||||
})
|
||||
|
||||
Convey("random next hop", func() {})
|
||||
})
|
||||
}
|
||||
|
||||
type mockConn struct{}
|
||||
|
||||
func (m *mockConn) OpenStream() (transport.Stream, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) AcceptStream() (transport.Stream, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) Close() {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) IsClosed() bool {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) RemoteAddr() net.Addr {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
var _ transport.Conn = &mockConn{}
|
@@ -1,56 +0,0 @@
|
||||
package gtund
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/ICKelin/optw/transport/transport_api"
|
||||
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
)
|
||||
|
||||
var version = ""
|
||||
|
||||
func init() {
|
||||
go http.ListenAndServe(":6060", nil)
|
||||
}
|
||||
|
||||
func Main() {
|
||||
flgVersion := flag.Bool("v", false, "print version")
|
||||
flgConf := flag.String("c", "", "config file")
|
||||
flag.Parse()
|
||||
|
||||
if *flgVersion {
|
||||
fmt.Println(version)
|
||||
return
|
||||
}
|
||||
|
||||
conf, err := ParseConfig(*flgConf)
|
||||
if err != nil {
|
||||
fmt.Printf("parse config file fail: %s %v\n", *flgConf, err)
|
||||
return
|
||||
}
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
|
||||
logs.Debug("config: %s", conf.String())
|
||||
|
||||
if conf.Trace != "" {
|
||||
go NewTraceServer(conf.Trace).ListenAndServe()
|
||||
}
|
||||
|
||||
for _, cfg := range conf.ServerConfig {
|
||||
listener, err := transport_api.NewListen(cfg.Scheme, cfg.Listen, cfg.ListenerConfig)
|
||||
if err != nil {
|
||||
logs.Error("new listener fail: %v", err)
|
||||
return
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
s := NewServer(listener)
|
||||
go s.Run()
|
||||
}
|
||||
|
||||
select {}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
echo "add no proxy address"
|
||||
ipset create GTUN-NOPROXY hash:net
|
||||
iptables -t mangle -I PREROUTING -m set --match-set GTUN-NOPROXY dst -j ACCEPT
|
||||
iptables -t mangle -I OUTPUT -m set --match-set GTUN-NOPROXY dst -j ACCEPT
|
||||
|
||||
echo "start gtun"
|
||||
nohup ./gtun-linux-amd64 -c gtun.yaml &
|
||||
|
||||
echo "start success."
|
72967
scripts/dnsmasq/cn.conf
Normal file
72967
scripts/dnsmasq/cn_set.conf
Normal file
679
scripts/dnsmasq/dnsmasq.conf
Normal file
@@ -0,0 +1,679 @@
|
||||
# Configuration file for dnsmasq.
|
||||
#
|
||||
# Format is one option per line, legal options are the same
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Listen on this specific port instead of the standard DNS port
|
||||
# (53). Setting this to zero completely disables DNS function,
|
||||
# leaving only DHCP and/or TFTP.
|
||||
#port=5353
|
||||
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link unnecessarily.
|
||||
|
||||
# Never forward plain names (without a dot or domain part)
|
||||
#domain-needed
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
#bogus-priv
|
||||
|
||||
# Uncomment these to enable DNSSEC validation and caching:
|
||||
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
|
||||
# This option only affects forwarding, SRV records originating for
|
||||
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||
#filterwin2k
|
||||
|
||||
# Change this line if you want dns to get its upstream servers from
|
||||
# somewhere other that /etc/resolv.conf
|
||||
resolv-file=/etc/dnsmasq.resolv
|
||||
|
||||
# By default, dnsmasq will send queries to any of the upstream
|
||||
# servers it knows about and tries to favour servers to are known
|
||||
# to be up. Uncommenting this forces dnsmasq to try each query
|
||||
# with each server strictly in the order they appear in
|
||||
# /etc/resolv.conf
|
||||
#strict-order
|
||||
|
||||
# If you don't want dnsmasq to read /etc/resolv.conf or any other
|
||||
# file, getting its servers from this file instead (see below), then
|
||||
# uncomment this.
|
||||
#no-resolv
|
||||
|
||||
# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv
|
||||
# files for changes and re-read them then uncomment this.
|
||||
#no-poll
|
||||
|
||||
# Add other name servers here, with domain specs if they are for
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
# Add local-only domains here, queries in these domains are answered
|
||||
# from /etc/hosts or DHCP only.
|
||||
#local=/localnet/
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in double-click.net to a local
|
||||
# web-server.
|
||||
#address=/double-click.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
# If you want dnsmasq to change uid and gid to something other
|
||||
# than the default, edit the following lines.
|
||||
#user=
|
||||
#group=
|
||||
|
||||
# If you want dnsmasq to listen for DHCP and DNS requests only on
|
||||
# specified interfaces (and the loopback) give the name of the
|
||||
# interface (eg eth0) here.
|
||||
# Repeat the line for more than one interface.
|
||||
#interface=enp4s0
|
||||
# Or you can specify which interface _not_ to listen on
|
||||
#except-interface=
|
||||
# Or which to listen on by address (remember to include 127.0.0.1 if
|
||||
# you use this.)
|
||||
#listen-address=192.168.2.131
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP and TFTP on it.
|
||||
#no-dhcp-interface=
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
# even when it is listening on only some interfaces. It then discards
|
||||
# requests that it shouldn't reply to. This has the advantage of
|
||||
# working even when interfaces come and go and change address. If you
|
||||
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||
# uncomment this option. About the only time you may need this is when
|
||||
# running another nameserver on the same machine.
|
||||
bind-interfaces
|
||||
|
||||
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||
# following line.
|
||||
#no-hosts
|
||||
# or if you want it to read another file, as well as /etc/hosts, use
|
||||
# this.
|
||||
#addn-hosts=/etc/banner_add_hosts
|
||||
|
||||
# Set this (and domain: see below) if you want to have a domain
|
||||
# automatically added to simple names in a hosts-file.
|
||||
#expand-hosts
|
||||
|
||||
# Set the domain for dnsmasq. this is optional, but if it is set, it
|
||||
# does the following things.
|
||||
# 1) Allows DHCP hosts to have fully qualified domain names, as long
|
||||
# as the domain part matches this setting.
|
||||
# 2) Sets the "domain" DHCP option thereby potentially setting the
|
||||
# domain of all systems configured by DHCP
|
||||
# 3) Provides the domain part for "expand-hosts"
|
||||
#domain=thekelleys.org.uk
|
||||
|
||||
# Set a different domain for a particular subnet
|
||||
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
|
||||
|
||||
# Same idea, but range rather then subnet
|
||||
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
|
||||
|
||||
# Uncomment this to enable the integrated DHCP server, you need
|
||||
# to supply the range of addresses available for lease and optionally
|
||||
# a lease time. If you have more than one network, you will need to
|
||||
# repeat this for each network on which you want to supply DHCP
|
||||
# service.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# This is an example of a DHCP range where the netmask is given. This
|
||||
# is needed for networks we reach the dnsmasq DHCP server via a relay
|
||||
# agent. If you don't know what a DHCP relay agent is, you probably
|
||||
# don't need to worry about this.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
|
||||
|
||||
# This is an example of a DHCP range which sets a tag, so that
|
||||
# some DHCP options may be set only for this network.
|
||||
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# Specify a subnet which can't be used for dynamic address allocation,
|
||||
# is available for hosts with matching --dhcp-host lines. Note that
|
||||
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||
# of some type for the subnet in question.
|
||||
# In this case the netmask is implied (it comes from the network
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||
# and defaults to 64 if missing/
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||
#dhcp-range=1234::, ra-only, 48h
|
||||
|
||||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||
#dhcp-range=1234::2, 1234::500, slaac
|
||||
|
||||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||
# not get addresses from DHCP, but they will get other configuration information.
|
||||
# They will use SLAAC for addresses.
|
||||
#dhcp-range=1234::, ra-stateless
|
||||
|
||||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||
# from DHCPv4 leases.
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
# need to be on the same network. The order of the parameters in these
|
||||
# do not matter, it's permissible to give name, address and MAC in any
|
||||
# order.
|
||||
|
||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||
# The IP address 192.168.0.60
|
||||
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||
|
||||
# Always set the name of the host with hardware address
|
||||
# 11:22:33:44:55:66 to be "fred"
|
||||
#dhcp-host=11:22:33:44:55:66,fred
|
||||
|
||||
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||
# that these two Ethernet interfaces will never be in use at the same
|
||||
# time, and give the IP address to the second, even if it is already
|
||||
# in use by the first. Useful for laptops with wired and wireless
|
||||
# addresses.
|
||||
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
|
||||
|
||||
# Give the machine which says its name is "bert" IP address
|
||||
# 192.168.0.70 and an infinite lease
|
||||
#dhcp-host=bert,192.168.0.70,infinite
|
||||
|
||||
# Always give the host with client identifier 01:02:02:04
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||
|
||||
# Always give the InfiniBand interface with hardware address
|
||||
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
|
||||
# ip address 192.168.0.61. The client id is derived from the prefix
|
||||
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
|
||||
# hex digits of the hardware address.
|
||||
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
|
||||
|
||||
# Always give the host with client identifier "marjorie"
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:marjorie,192.168.0.60
|
||||
|
||||
# Enable the address given for "judge" in /etc/hosts
|
||||
# to be given to a machine presenting the name "judge" when
|
||||
# it asks for a DHCP lease.
|
||||
#dhcp-host=judge
|
||||
|
||||
# Never offer DHCP service to a machine whose Ethernet
|
||||
# address is 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,ignore
|
||||
|
||||
# Ignore any client-id presented by the machine with Ethernet
|
||||
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||
# being treated differently when running under different OS's or
|
||||
# between PXE boot and OS boot.
|
||||
#dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# the machine with Ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,set:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=tag:!known
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# DHCP vendorclass string includes the substring "Linux"
|
||||
#dhcp-vendorclass=set:red,Linux
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine one
|
||||
# of whose DHCP userclass strings includes the substring "accounts"
|
||||
#dhcp-userclass=set:red,accounts
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# MAC address matches the pattern.
|
||||
#dhcp-mac=set:red,00:60:8C:*:*:*
|
||||
|
||||
# If this line is uncommented, dnsmasq will read /etc/ethers and act
|
||||
# on the ethernet-address/IP pairs found there just as if they had
|
||||
# been given as --dhcp-host options. Useful if you keep
|
||||
# MAC-address/host mappings there for other purposes.
|
||||
#read-ethers
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
|
||||
# Override the default route supplied by dnsmasq, which assumes the
|
||||
# router is the same machine as the one running dnsmasq.
|
||||
#dhcp-option=3,1.2.3.4
|
||||
|
||||
# Do the same thing, but using the option name
|
||||
#dhcp-option=option:router,1.2.3.4
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# for all other option numbers.
|
||||
#dhcp-option=3
|
||||
|
||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1,1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2,2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
|
||||
# Set the NIS domain name to "welly"
|
||||
#dhcp-option=40,welly
|
||||
|
||||
# Set the default time-to-live to 50
|
||||
#dhcp-option=23,50
|
||||
|
||||
# Set the "all subnets are local" flag
|
||||
#dhcp-option=27,1
|
||||
|
||||
# Send the etherboot magic flag and then etherboot options (a string).
|
||||
#dhcp-option=128,e4:45:74:68:00:00
|
||||
#dhcp-option=129,NIC=eepro100
|
||||
|
||||
# Specify an option which will only be sent to the "red" network
|
||||
# (see dhcp-range for the declaration of the "red" network)
|
||||
# Note that the tag: part must precede the option: part.
|
||||
#dhcp-option = tag:red, option:ntp-server, 192.168.1.1
|
||||
|
||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||
# for the ISC dhcpcd in
|
||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# Windows clients and Samba.
|
||||
#dhcp-option=19,0 # option ip-forwarding off
|
||||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
|
||||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||
#dhcp-option=252,"\n"
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
|
||||
# Send microsoft-specific option to tell windows to release the DHCP lease
|
||||
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
|
||||
# value as a four-byte integer - that's what microsoft wants. See
|
||||
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
|
||||
#dhcp-option=vendor:MSFT,2,1i
|
||||
|
||||
# Send the Encapsulated-vendor-class ID needed by some configurations of
|
||||
# Etherboot to allow is to recognise the DHCP server.
|
||||
#dhcp-option=vendor:Etherboot,60,"Etherboot"
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
# Configuration file name
|
||||
#dhcp-option-force=209,configs/common
|
||||
# Path prefix
|
||||
#dhcp-option-force=210,/tftpboot/pxelinux/files/
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this if you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built-in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for iPXE. The idea is to send two different
|
||||
# filenames, the first loads iPXE, and the second tells iPXE what to
|
||||
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
|
||||
#dhcp-boot=undionly.kpxe
|
||||
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
|
||||
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
|
||||
|
||||
# Encapsulated options for iPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||
|
||||
# Test for the architecture of a netboot client. PXE clients are
|
||||
# supposed to send their architecture as option 93. (See RFC 4578)
|
||||
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
|
||||
# Do real PXE, rather than just booting a single file, this is an
|
||||
# alternative to dhcp-boot.
|
||||
#pxe-prompt="What system shall I netboot?"
|
||||
# or with timeout before first available action is taken:
|
||||
#pxe-prompt="Press F8 for menu.", 60
|
||||
|
||||
# Available boot services. for PXE.
|
||||
#pxe-service=x86PC, "Boot from local disk"
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||
# Beware this fails on old PXE ROMS.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
|
||||
# Use bootserver on network, found my multicast or broadcast.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||
|
||||
# Use bootserver at a known IP address.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
|
||||
|
||||
# If you have multicast-FTP available,
|
||||
# information for that can be passed in a similar way using options 1
|
||||
# to 5. See page 19 of
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Do not abort if the tftp-root is unavailable
|
||||
#tftp-no-fail
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||
# clients.
|
||||
#tftp-no-blocksize
|
||||
|
||||
# Set the boot file name only when the "red" tag is set.
|
||||
#dhcp-boot=tag:red,pxelinux.red-net
|
||||
|
||||
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||
# address of the server are given after the filename.
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||
|
||||
# If there are multiple external tftp servers having a same name
|
||||
# (using /etc/hosts) then that name can be specified as the
|
||||
# tftp_servername (the third option to dhcp-boot) and in that
|
||||
# case dnsmasq resolves this name and returns the resultant IP
|
||||
# addresses in round robin fashion. This facility can be used to
|
||||
# load balance the tftp load among a set of servers.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||
|
||||
# Set the limit on DHCP leases, the default is 150
|
||||
#dhcp-lease-max=150
|
||||
|
||||
# The DHCP server needs somewhere on disk to keep its lease database.
|
||||
# This defaults to a sane location, but if you want to change it, use
|
||||
# the line below.
|
||||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||
|
||||
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
# if there is one.
|
||||
#dhcp-script=/bin/echo
|
||||
|
||||
# Set the cachesize here.
|
||||
#cache-size=150
|
||||
|
||||
# If you want to disable negative caching, uncomment this.
|
||||
#no-negcache
|
||||
|
||||
# Normally responses which come from /etc/hosts and the DHCP lease
|
||||
# file have Time-To-Live set as zero, which conventionally means
|
||||
# do not cache further. If you are happy to trade lower load on the
|
||||
# server for potentially stale date, you can set a time-to-live (in
|
||||
# seconds) here.
|
||||
#local-ttl=
|
||||
|
||||
# If you want dnsmasq to detect attempts by Verisign to send queries
|
||||
# to unregistered .com and .net hosts to its sitefinder service and
|
||||
# have dnsmasq instead return the correct NXDOMAIN response, uncomment
|
||||
# this line. You can add similar lines to do the same for other
|
||||
# registries which have implemented wildcard A records.
|
||||
#bogus-nxdomain=64.94.110.11
|
||||
|
||||
# If you want to fix up DNS results from upstream servers, use the
|
||||
# alias option. This only works for IPv4.
|
||||
# This alias makes a result of 1.2.3.4 appear as 5.6.7.8
|
||||
#alias=1.2.3.4,5.6.7.8
|
||||
# and this maps 1.2.3.x to 5.6.7.x
|
||||
#alias=1.2.3.0,5.6.7.0,255.255.255.0
|
||||
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||
|
||||
# Change these lines if you want dnsmasq to serve MX records.
|
||||
|
||||
# Return an MX record named "maildomain.com" with target
|
||||
# servermachine.com and preference 50
|
||||
#mx-host=maildomain.com,servermachine.com,50
|
||||
|
||||
# Set the default target for MX records created using the localmx option.
|
||||
#mx-target=servermachine.com
|
||||
|
||||
# Return an MX record pointing to the mx-target for all local
|
||||
# machines.
|
||||
#localmx
|
||||
|
||||
# Return an MX record pointing to itself for all local machines.
|
||||
#selfmx
|
||||
|
||||
# Change the following lines if you want dnsmasq to serve SRV
|
||||
# records. These are useful if you want to serve ldap requests for
|
||||
# Active Directory and other windows-originated DNS requests.
|
||||
# See RFC 2782.
|
||||
# You may add multiple srv-host lines.
|
||||
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||
# If the domain part if missing from the name (so that is just has the
|
||||
# service and protocol sections) then the domain given by the domain=
|
||||
# config option is used. (Note that expand-hosts does not need to be
|
||||
# set for this to work.)
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389 (using domain=)
|
||||
#domain=example.com
|
||||
#srv-host=_ldap._tcp,ldapserver.example.com,389
|
||||
|
||||
# Two SRV records for LDAP, each with different priorities
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||
|
||||
# A SRV record indicating that there is no LDAP server for the domain
|
||||
# example.com
|
||||
#srv-host=_ldap._tcp.example.com
|
||||
|
||||
# The following line shows how to make dnsmasq serve an arbitrary PTR
|
||||
# record. This is useful for DNS-SD. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for PTR records.)
|
||||
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
|
||||
|
||||
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||
# These are used for things like SPF and zeroconf. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for TXT records.)
|
||||
|
||||
#Example SPF.
|
||||
#txt-record=example.com,"v=spf1 a -all"
|
||||
|
||||
#Example zeroconf
|
||||
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||
|
||||
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||
# "bert" another name, bertrand
|
||||
#cname=bertand,bert
|
||||
|
||||
# For debugging purposes, log each DNS query as it passes through
|
||||
# dnsmasq.
|
||||
#log-queries
|
||||
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
# Include all the files in a directory except those ending in .bak
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/,*.conf
|
||||
|
||||
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||
#dhcp-name-match=set:wpad-ignore,wpad
|
||||
#dhcp-ignore-names=tag:wpad-ignore
|
1
scripts/dnsmasq/dnsmasq.resolv
Normal file
@@ -0,0 +1 @@
|
||||
nameserver 8.8.8.8
|
7
scripts/install_gtun.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
systemctl stop gtun
|
||||
GTUN_DIR="/opt/apps/gtun"
|
||||
mkdir -p $GTUN_DIR/logs
|
||||
cp -r . $GTUN_DIR
|
||||
cp etc/gtun.service /lib/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl start gtun
|
7
scripts/install_gtund.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
systemctl stop gtund
|
||||
GTUND_DIR="/opt/apps/gtund"
|
||||
mkdir -p $GTUND_DIR/logs
|
||||
cp -r . $GTUND_DIR
|
||||
cp etc/gtund.service /lib/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl start gtund
|
17
scripts/noproxy.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
114.114.114.114
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.0.0.0/24
|
||||
192.0.2.0/24
|
||||
192.88.99.0/24
|
||||
192.168.0.0/16
|
||||
198.18.0.0/15
|
||||
198.51.100.0/24
|
||||
203.0.113.0/24
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
255.255.255.255/32
|
65
scripts/redirect_all.sh
Normal file
@@ -0,0 +1,65 @@
|
||||
setname=GTUN_ALL
|
||||
noproxy_set=NOPROXY
|
||||
redirect_port=8524
|
||||
|
||||
clear_noproxy() {
|
||||
iptables -t mangle -D PREROUTING -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
iptables -t mangle -D OUTPUT -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
ipset destroy $noproxy_set >/dev/null
|
||||
}
|
||||
|
||||
add_noproxy() {
|
||||
ipset create $noproxy_set hash:net
|
||||
cat noproxy.txt | while read line
|
||||
do
|
||||
echo "no proxy for" $line
|
||||
ipset add $noproxy_set $line
|
||||
done
|
||||
|
||||
iptables -t mangle -A PREROUTING -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
iptables -t mangle -A OUTPUT -m set --match-set $noproxy_set dst -j ACCEPT
|
||||
}
|
||||
|
||||
clear_proxy() {
|
||||
ip ro del local default dev lo table 100
|
||||
ip rule del fwmark 1 lookup 100
|
||||
iptables -t mangle -D PREROUTING -p tcp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -D PREROUTING -p udp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -D OUTPUT -m set --match-set $setname dst -j MARK --set-mark 1 >/dev/null
|
||||
ipset destroy $setname >/dev/null
|
||||
}
|
||||
|
||||
add_proxy() {
|
||||
ipset create $setname hash:net
|
||||
echo "proxy for 0.0.0.0/1"
|
||||
echo "proxy for 128.0.0.0/1"
|
||||
ipset add $setname 0.0.0.0/1
|
||||
ipset add $setname 128.0.0.0/1
|
||||
|
||||
iptables -t mangle -A PREROUTING -p tcp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -A PREROUTING -p udp -m set --match-set $setname dst -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
iptables -t mangle -A OUTPUT -m set --match-set $setname dst -j MARK --set-mark 1
|
||||
|
||||
# redirect dns query
|
||||
# iptables -t mangle -A PREROUTING -p udp --dport 53 -j TPROXY --tproxy-mark 1/1 --on-port $redirect_port
|
||||
# iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1
|
||||
|
||||
ip rule add fwmark 1 lookup 100
|
||||
ip ro add local default dev lo table 100
|
||||
}
|
||||
|
||||
sep="============================================"
|
||||
|
||||
echo "gtun accelerator redirect configure"
|
||||
clear_noproxy
|
||||
clear_proxy
|
||||
|
||||
echo "Adding noproxy cidrs"
|
||||
add_noproxy
|
||||
echo "Done."
|
||||
echo $sep
|
||||
|
||||
echo "Adding proxy cidrs"
|
||||
add_proxy
|
||||
echo "Done."
|
||||
echo $sep
|
16
scripts/redirect_domains.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
config_dnsmasq() {
|
||||
echo "configuring dnsmasq service"
|
||||
cp dnsmasq/dnsmasq.conf /etc/dnsmasq.conf
|
||||
cp dnsmasq/dnsmasq.resolv /etc/dnsmasq.resolv
|
||||
echo "configuring dnsmasq cn domain list"
|
||||
cp dnsmasq/cn.conf /etc/dnsmasq.d/
|
||||
cp dnsmasq/cn_set.conf /etc/dnsmasq.d/
|
||||
systemctl restart dnsmasq
|
||||
}
|
||||
|
||||
./redirect_all.sh
|
||||
echo "Configuring dnsmasq"
|
||||
config_dnsmasq
|
||||
echo "Done."
|
||||
echo $sep
|
65
src/gtun/config/config.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/src/internal/signature"
|
||||
"gopkg.in/yaml.v2"
|
||||
"os"
|
||||
)
|
||||
|
||||
var gConfig *Config
|
||||
var signatureKey = os.Getenv("GTUN_SIGNATURE")
|
||||
|
||||
type Config struct {
|
||||
AccessToken string `yaml:"access_token"`
|
||||
Accelerator map[string]Accelerator `yaml:"accelerator"`
|
||||
Log Log `yaml:"log"`
|
||||
}
|
||||
|
||||
type RouteConfig struct {
|
||||
Scheme string `yaml:"scheme" json:"scheme"`
|
||||
Server string `yaml:"server" json:"server"`
|
||||
Trace string `yaml:"trace" json:"trace"`
|
||||
AuthKey string `yaml:"auth_key" json:"auth_key"`
|
||||
}
|
||||
|
||||
type Accelerator struct {
|
||||
Region string `json:"region"`
|
||||
GeoSite []string `json:"geo_site"`
|
||||
GeoIP []string `json:"geo_ip"`
|
||||
Routes []*RouteConfig `json:"routes"`
|
||||
Proxy map[string]string `json:"proxy"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
Days int64 `yaml:"days"`
|
||||
Level string `yaml:"level"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
func Parse(path string) (*Config, error) {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseBuffer(content)
|
||||
}
|
||||
|
||||
func ParseBuffer(content []byte) (*Config, error) {
|
||||
configContent, err := signature.UnSign(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf := Config{}
|
||||
err = yaml.Unmarshal([]byte(os.ExpandEnv(string(configContent))), &conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gConfig = &conf
|
||||
return &conf, err
|
||||
}
|
||||
|
||||
func Default() *Config {
|
||||
return gConfig
|
||||
}
|
69
src/gtun/config/config_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/src/internal/signature"
|
||||
"github.com/smartystreets/goconvey/convey"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testConfig = `
|
||||
access_token: "${ACCESS_TOKEN}"
|
||||
accelerator:
|
||||
HK:
|
||||
routes:
|
||||
- scheme: "kcp"
|
||||
server: "${SERVER_IP}:3002"
|
||||
trace: "${SERVER_IP}:3003"
|
||||
- scheme: "mux"
|
||||
server: "${SERVER_IP}:3002"
|
||||
trace: "${SERVER_IP}:3003"
|
||||
proxy:
|
||||
tproxy_tcp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
tproxy_udp: |
|
||||
{
|
||||
"read_timeout": 30,
|
||||
"write_timeout": 30,
|
||||
"session_timeout": 30,
|
||||
"listen_addr": ":8524"
|
||||
}
|
||||
log:
|
||||
days: 5
|
||||
level: debug
|
||||
path: /opt/apps/gtun/logs/gtun.log
|
||||
|
||||
`
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
convey.Convey("test config", t, func() {
|
||||
convey.Convey("test with env var", func() {
|
||||
os.Setenv("SERVER_IP", "127.0.0.1")
|
||||
os.Setenv("ACCESS_TOKEN", "ICKelin:free")
|
||||
cfg, err := ParseBuffer([]byte(testConfig))
|
||||
convey.So(err, convey.ShouldBeNil)
|
||||
convey.So(cfg.Accelerator["HK"].Routes[0].Server, convey.ShouldEqual, "127.0.0.1:3002")
|
||||
convey.So(cfg.AccessToken, convey.ShouldEqual, "ICKelin:free")
|
||||
})
|
||||
|
||||
convey.Convey("test signature", func() {
|
||||
convey.Convey("test config without signature", func() {
|
||||
signature.SetSignature("sig")
|
||||
_, err := ParseBuffer([]byte(testConfig))
|
||||
convey.So(err, convey.ShouldNotBeNil)
|
||||
})
|
||||
|
||||
convey.Convey("test config with signature", func() {
|
||||
signature.SetSignature("sig")
|
||||
buf, err := signature.Sign([]byte(testConfig))
|
||||
convey.So(err, convey.ShouldBeNil)
|
||||
_, err = ParseBuffer(buf)
|
||||
convey.So(err, convey.ShouldBeNil)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
50
src/gtun/main.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/gtun/config"
|
||||
"github.com/ICKelin/gtun/src/gtun/proxy"
|
||||
"github.com/ICKelin/gtun/src/gtun/route"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
)
|
||||
|
||||
var logo = `
|
||||
====================================
|
||||
██████ ████████ ██ ██ ███ ██
|
||||
██ ██ ██ ██ ████ ██
|
||||
██ ███ ██ ██ ██ ██ ██ ██
|
||||
██ ██ ██ ██ ██ ██ ██ ██
|
||||
██████ ██ ██████ ██ ████
|
||||
====================================
|
||||
https://github.com/ICKelin/gtun
|
||||
`
|
||||
|
||||
func main() {
|
||||
flgConf := flag.String("c", "", "config file")
|
||||
flag.Parse()
|
||||
|
||||
conf, err := config.Parse(*flgConf)
|
||||
if err != nil {
|
||||
fmt.Printf("load config fail: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(logo)
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
logs.Info("%s", logo)
|
||||
for region, cfg := range conf.Accelerator {
|
||||
err := route.Setup(region, cfg.Routes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = proxy.Serve(region, cfg.Proxy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
route.Run()
|
||||
|
||||
// TODO: watch for config file changes
|
||||
select {}
|
||||
}
|
54
src/gtun/proxy/proxy.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
)
|
||||
|
||||
var errRegistered = fmt.Errorf("already registered")
|
||||
var errNotRegister = fmt.Errorf("proxy not register")
|
||||
|
||||
// Proxy defines Proxies, such as tproxy_tcp, tproxy_udp,ip_tun, ip_wireguard
|
||||
type Proxy interface {
|
||||
Name() string
|
||||
Setup(region string, cfg json.RawMessage) error
|
||||
ListenAndServe() error
|
||||
}
|
||||
|
||||
var registerProxy = make(map[string]func() Proxy)
|
||||
|
||||
func Register(name string, constructor func() Proxy) error {
|
||||
if _, ok := registerProxy[name]; ok {
|
||||
return errRegistered
|
||||
}
|
||||
registerProxy[name] = constructor
|
||||
return nil
|
||||
}
|
||||
|
||||
func Serve(region string, proxyConfig map[string]string) error {
|
||||
logs.Debug("region %s proxy config %s", region, proxyConfig)
|
||||
err := setup(region, proxyConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("region[%s] setup proxy fail: %v\n", region, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setup(region string, proxyConfigs map[string]string) error {
|
||||
for name, config := range proxyConfigs {
|
||||
constructor := registerProxy[name]
|
||||
if constructor == nil {
|
||||
return errNotRegister
|
||||
}
|
||||
p := constructor()
|
||||
err := p.Setup(region, json.RawMessage(config))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go p.ListenAndServe()
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -2,14 +2,11 @@ package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/gtun/route"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/proto"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"github.com/ICKelin/gtun/src/gtun/route"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/gtun/src/internal/proto"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -28,8 +25,6 @@ type TProxyTCPConfig struct {
|
||||
ReadTimeout int `json:"read_timeout"`
|
||||
WriteTimeout int `json:"write_timeout"`
|
||||
ListenAddr string `json:"listen_addr"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
type TProxyTCP struct {
|
||||
@@ -46,8 +41,6 @@ type TProxyTCP struct {
|
||||
|
||||
mempool sync.Pool
|
||||
|
||||
ratelimit *utils.RateLimit
|
||||
|
||||
routeManager *route.Manager
|
||||
}
|
||||
|
||||
@@ -59,22 +52,23 @@ func (p *TProxyTCP) Name() string {
|
||||
return "tproxy_tcp"
|
||||
}
|
||||
|
||||
func (p *TProxyTCP) Setup(cfgContent json.RawMessage) error {
|
||||
func (p *TProxyTCP) Setup(region string, cfgContent json.RawMessage) error {
|
||||
var cfg = TProxyTCPConfig{}
|
||||
err := json.Unmarshal(cfgContent, &cfg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = p.initConfig(cfg)
|
||||
logs.Debug("region[%s] proxy %s config %s", region, p.Name(), string(cfgContent))
|
||||
err = p.initConfig(region, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.initRedirect()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TProxyTCP) initConfig(cfg TProxyTCPConfig) error {
|
||||
func (p *TProxyTCP) initConfig(region string, cfg TProxyTCPConfig) error {
|
||||
tcpReadTimeout := cfg.ReadTimeout
|
||||
if tcpReadTimeout <= 0 {
|
||||
tcpReadTimeout = defaultTCPTimeout
|
||||
@@ -85,10 +79,7 @@ func (p *TProxyTCP) initConfig(cfg TProxyTCPConfig) error {
|
||||
tcpWriteTimeout = defaultTCPTimeout
|
||||
}
|
||||
|
||||
rateLimit := utils.NewRateLimit()
|
||||
rateLimit.SetRateLimit(int64(cfg.RateLimit * 1024 * 1024))
|
||||
|
||||
p.region = cfg.Region
|
||||
p.region = region
|
||||
p.listenAddr = cfg.ListenAddr
|
||||
p.writeTimeout = time.Duration(tcpWriteTimeout) * time.Second
|
||||
p.readTimeout = time.Duration(tcpReadTimeout) * time.Second
|
||||
@@ -97,39 +88,32 @@ func (p *TProxyTCP) initConfig(cfg TProxyTCPConfig) error {
|
||||
return make([]byte, 32*1024)
|
||||
},
|
||||
}
|
||||
p.ratelimit = rateLimit
|
||||
p.routeManager = route.GetRouteManager()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TProxyTCP) initRedirect() error {
|
||||
ipPort := strings.Split(p.listenAddr, ":")
|
||||
if len(ipPort) != 2 {
|
||||
return fmt.Errorf("invalid listen addr")
|
||||
}
|
||||
|
||||
initRedirect("tcp", p.region, ipPort[1])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TProxyTCP) ListenAndServe() error {
|
||||
listener, err := net.Listen("tcp", p.listenAddr)
|
||||
if err != nil {
|
||||
logs.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// set socket with ip transparent option
|
||||
file, err := listener.(*net.TCPListener).File()
|
||||
if err != nil {
|
||||
logs.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
|
||||
if err != nil {
|
||||
logs.Error("%v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
logs.Info("region[%s] %s listen %s", p.region, p.Name(), p.listenAddr)
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
@@ -185,6 +169,8 @@ func (p *TProxyTCP) doProxy(conn net.Conn) {
|
||||
io.CopyBuffer(stream, conn, buf)
|
||||
}()
|
||||
|
||||
defer stream.Close()
|
||||
defer conn.Close()
|
||||
obj := p.mempool.Get()
|
||||
defer p.mempool.Put(obj)
|
||||
buf := obj.([]byte)
|
@@ -5,14 +5,13 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/gtun/route"
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/proto"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"github.com/ICKelin/gtun/src/gtun/route"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/gtun/src/internal/proto"
|
||||
utils2 "github.com/ICKelin/gtun/src/internal/utils"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -41,8 +40,6 @@ type TProxyUDPConfig struct {
|
||||
WriteTimeout int `json:"write_timeout"`
|
||||
SessionTimeout int `json:"session_timeout"`
|
||||
ListenAddr string `json:"listen_addr"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
type TProxyUDP struct {
|
||||
@@ -59,8 +56,6 @@ type TProxyUDP struct {
|
||||
// the purpose of udpSession is to reuse stream
|
||||
udpSessions map[string]*udpSession
|
||||
udpsessLock sync.Mutex
|
||||
|
||||
ratelimit *utils.RateLimit
|
||||
}
|
||||
|
||||
func NewTProxyUDP() Proxy {
|
||||
@@ -71,22 +66,22 @@ func (p *TProxyUDP) Name() string {
|
||||
return "tproxy_udp"
|
||||
}
|
||||
|
||||
func (p *TProxyUDP) Setup(cfgContent json.RawMessage) error {
|
||||
func (p *TProxyUDP) Setup(region string, cfgContent json.RawMessage) error {
|
||||
var cfg = TProxyUDPConfig{}
|
||||
err := json.Unmarshal(cfgContent, &cfg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = p.initConfig(cfg)
|
||||
err = p.initConfig(region, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.initRedirect()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TProxyUDP) initConfig(cfg TProxyUDPConfig) error {
|
||||
func (p *TProxyUDP) initConfig(region string, cfg TProxyUDPConfig) error {
|
||||
readTimeout := cfg.ReadTimeout
|
||||
if readTimeout <= 0 {
|
||||
readTimeout = defaultUDPTimeout
|
||||
@@ -102,30 +97,16 @@ func (p *TProxyUDP) initConfig(cfg TProxyUDPConfig) error {
|
||||
sessionTimeout = defaultUDPSessionTimeout
|
||||
}
|
||||
|
||||
rateLimit := utils.NewRateLimit()
|
||||
rateLimit.SetRateLimit(int64(cfg.RateLimit * 1024 * 1024))
|
||||
|
||||
p.region = cfg.Region
|
||||
p.region = region
|
||||
p.listenAddr = cfg.ListenAddr
|
||||
p.writeTimeout = time.Duration(writeTimeout) * time.Second
|
||||
p.readTimeout = time.Duration(readTimeout) * time.Second
|
||||
p.sessionTimeout = time.Duration(sessionTimeout) * time.Second
|
||||
p.udpSessions = make(map[string]*udpSession)
|
||||
p.ratelimit = rateLimit
|
||||
p.routeManager = route.GetRouteManager()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TProxyUDP) initRedirect() error {
|
||||
ipPort := strings.Split(p.listenAddr, ":")
|
||||
if len(ipPort) != 2 {
|
||||
return fmt.Errorf("invalid listen addr")
|
||||
}
|
||||
|
||||
initRedirect("udp", p.region, ipPort[1])
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListenAndServe listens an udp port, since that we use tproxy to
|
||||
// redirect traffic to this listened udp port
|
||||
// so the socket should set to ip transparent option
|
||||
@@ -177,6 +158,7 @@ func (p *TProxyUDP) ListenAndServe() error {
|
||||
}
|
||||
|
||||
func (p *TProxyUDP) serve(lconn *net.UDPConn) error {
|
||||
logs.Info("region[%s] %s listen %s", p.region, p.Name(), p.listenAddr)
|
||||
go p.recycleSession()
|
||||
buf := make([]byte, 64*1024)
|
||||
oob := make([]byte, 1024)
|
||||
@@ -283,7 +265,7 @@ func (p *TProxyUDP) doProxy(stream transport.Stream, sessionKey string, fromaddr
|
||||
break
|
||||
}
|
||||
|
||||
err = utils.SendUDPViaRaw(p.rawfd, fromaddr, toaddr, buf)
|
||||
err = utils2.SendUDPViaRaw(p.rawfd, fromaddr, toaddr, buf)
|
||||
if err != nil {
|
||||
logs.Error("send via raw socket fail: %v", err)
|
||||
}
|
@@ -2,33 +2,43 @@ package route
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/gtun/config"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/optw/transport/transport_api"
|
||||
"time"
|
||||
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
)
|
||||
|
||||
type ConnectionConfig struct {
|
||||
Region string
|
||||
ServerAddr string
|
||||
AuthKey string
|
||||
var cm = &connManager{regionConn: map[string][]*conn{}}
|
||||
|
||||
type connManager struct {
|
||||
regionConn map[string][]*conn
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
func (cm *connManager) startConn() {
|
||||
for _, conns := range cm.regionConn {
|
||||
for _, conn := range conns {
|
||||
go conn.connect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type conn struct {
|
||||
dialer transport.Dialer
|
||||
region string
|
||||
scheme string
|
||||
serverAddr string
|
||||
}
|
||||
|
||||
func CreateConnection(region, scheme, serverAddr, authKey string) (*Connection, error) {
|
||||
func newConn(region, scheme, serverAddr, authKey string) (*conn, error) {
|
||||
dialer, err := transport_api.NewDialer(scheme, serverAddr, authKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dialer.SetAccessToken(config.Default().AccessToken)
|
||||
|
||||
return &Connection{
|
||||
return &conn{
|
||||
dialer: dialer,
|
||||
region: region,
|
||||
scheme: scheme,
|
||||
@@ -36,7 +46,7 @@ func CreateConnection(region, scheme, serverAddr, authKey string) (*Connection,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Connection) ConnectNextHop() {
|
||||
func (c *conn) connect() {
|
||||
for {
|
||||
conn, err := c.dialer.Dial()
|
||||
if err != nil {
|
||||
@@ -46,23 +56,28 @@ func (c *Connection) ConnectNextHop() {
|
||||
}
|
||||
|
||||
logs.Info("connect to %s success", c.String())
|
||||
hopConn := &HopInfo{Conn: conn}
|
||||
|
||||
// add next hop connection to route
|
||||
GetRouteManager().AddRoute(c.region, hopConn)
|
||||
routeEle := &routeItem{
|
||||
region: c.region,
|
||||
scheme: c.scheme,
|
||||
serverAddr: c.serverAddr,
|
||||
Conn: conn,
|
||||
}
|
||||
GetRouteManager().addRoute(c.region, routeEle)
|
||||
tick := time.NewTicker(time.Second * 1)
|
||||
for range tick.C {
|
||||
if hopConn.IsClosed() {
|
||||
if conn.IsClosed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// delete next hop connection to route
|
||||
GetRouteManager().DeleteRoute(c.region, hopConn)
|
||||
GetRouteManager().deleteRoute(c.region, routeEle)
|
||||
logs.Warn("reconnect %s", c.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Connection) String() string {
|
||||
func (c *conn) String() string {
|
||||
return fmt.Sprintf("regions[%s] %s://%s", c.region, c.scheme, c.serverAddr)
|
||||
}
|
149
src/gtun/route/route.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/gtun/config"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var routeManager = &Manager{
|
||||
tm: tm,
|
||||
cm: cm,
|
||||
routeTable: make(map[string][]*routeItem),
|
||||
}
|
||||
|
||||
type routeItem struct {
|
||||
region string
|
||||
scheme string
|
||||
serverAddr string
|
||||
transport.Conn
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
tm *traceManager
|
||||
cm *connManager
|
||||
|
||||
routeTableMu sync.Mutex
|
||||
routeTable map[string][]*routeItem
|
||||
}
|
||||
|
||||
func GetRouteManager() *Manager {
|
||||
return routeManager
|
||||
}
|
||||
|
||||
func (routeManager *Manager) Route(region, dip string) transport.Conn {
|
||||
regionRoutes, ok := routeManager.routeTable[region]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(regionRoutes) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
bestNode, ok := routeManager.tm.getRegionBestTarget(region)
|
||||
if ok {
|
||||
bestAddr := bestNode.serverAddr
|
||||
for i := 0; i < len(regionRoutes); i++ {
|
||||
it := regionRoutes[i]
|
||||
if it.IsClosed() {
|
||||
logs.Warn("%s %s is closed", region, it.RemoteAddr())
|
||||
continue
|
||||
}
|
||||
|
||||
if len(bestAddr) != 0 {
|
||||
// scheme://ip:port match
|
||||
if bestAddr == it.serverAddr &&
|
||||
bestNode.scheme == it.scheme {
|
||||
logs.Debug("region[%s] best node match %s://%s",
|
||||
region, it.scheme, bestAddr)
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logs.Warn("no best node for region[%s]", region)
|
||||
}
|
||||
|
||||
logs.Warn("region[%s] use random hop", region)
|
||||
hash := 0
|
||||
for _, c := range dip {
|
||||
hash += int(c)
|
||||
}
|
||||
|
||||
hop := regionRoutes[hash%len(regionRoutes)]
|
||||
if hop == nil || hop.IsClosed() {
|
||||
return nil
|
||||
}
|
||||
return hop
|
||||
}
|
||||
|
||||
func (routeManager *Manager) addRoute(region string, item *routeItem) {
|
||||
routeManager.routeTableMu.Lock()
|
||||
defer routeManager.routeTableMu.Unlock()
|
||||
|
||||
regionItems := routeManager.routeTable[region]
|
||||
if regionItems == nil {
|
||||
regionItems = make([]*routeItem, 0)
|
||||
}
|
||||
|
||||
regionItems = append(regionItems, item)
|
||||
routeManager.routeTable[region] = regionItems
|
||||
}
|
||||
|
||||
func (routeManager *Manager) deleteRoute(region string, item *routeItem) {
|
||||
routeManager.routeTableMu.Lock()
|
||||
defer routeManager.routeTableMu.Unlock()
|
||||
regionItems := routeManager.routeTable[region]
|
||||
if regionItems == nil {
|
||||
return
|
||||
}
|
||||
|
||||
conns := make([]*routeItem, 0, len(regionItems))
|
||||
for _, it := range regionItems {
|
||||
if it == item {
|
||||
continue
|
||||
}
|
||||
|
||||
conns = append(conns, it)
|
||||
}
|
||||
|
||||
routeManager.routeTable[region] = conns
|
||||
}
|
||||
|
||||
func Setup(region string, routes []*config.RouteConfig) error {
|
||||
for _, cfg := range routes {
|
||||
conn, err := newConn(region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
if err != nil {
|
||||
fmt.Printf("region[%s] connect to %s://%s fail: %v\n",
|
||||
region, cfg.Scheme, cfg.Server, cfg.AuthKey)
|
||||
return err
|
||||
}
|
||||
|
||||
cm.regionConn[region] = append(cm.regionConn[region], conn)
|
||||
|
||||
t, ok := tm.regionTrace[region]
|
||||
if !ok {
|
||||
logs.Debug("add region[%s] trace", region)
|
||||
t = newTrace(region)
|
||||
tm.regionTrace[region] = t
|
||||
} else {
|
||||
logs.Debug("region[%s] trace exist", region)
|
||||
}
|
||||
|
||||
t.addTarget(traceTarget{
|
||||
traceAddr: cfg.Trace,
|
||||
serverAddr: cfg.Server,
|
||||
scheme: cfg.Scheme,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Run() {
|
||||
go tm.startTrace()
|
||||
go cm.startConn()
|
||||
}
|
107
src/gtun/route/route_test.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
gomonkey "github.com/agiledragon/gomonkey/v2"
|
||||
"github.com/smartystreets/goconvey/convey"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRoute(t *testing.T) {
|
||||
convey.Convey("test route", t, func() {
|
||||
convey.Convey("not exist region", func() {
|
||||
conn := GetRouteManager().Route("unknown region", "127.0.0.1")
|
||||
convey.So(conn, convey.ShouldBeNil)
|
||||
})
|
||||
|
||||
convey.Convey("not route to host", func() {
|
||||
GetRouteManager().routeTable["region1"] = make([]*routeItem, 0)
|
||||
conn := GetRouteManager().Route("unknown region", "127.0.0.1")
|
||||
convey.So(conn, convey.ShouldBeNil)
|
||||
delete(GetRouteManager().routeTable, "region1")
|
||||
})
|
||||
|
||||
convey.Convey("best node", func() {
|
||||
p := gomonkey.ApplyPrivateMethod(tm, "getRegionBestTarget", func(tm *traceManager, region string) (traceTarget, bool) {
|
||||
return traceTarget{
|
||||
traceAddr: "",
|
||||
serverAddr: "127.0.0.1:5201",
|
||||
scheme: "kcp",
|
||||
}, true
|
||||
})
|
||||
defer p.Reset()
|
||||
|
||||
convey.Convey("best node match", func() {
|
||||
newRoute := &routeItem{
|
||||
region: "",
|
||||
scheme: "kcp",
|
||||
serverAddr: "127.0.0.1:5201",
|
||||
Conn: &mockConn{},
|
||||
}
|
||||
GetRouteManager().addRoute("region1", newRoute)
|
||||
defer GetRouteManager().deleteRoute("region1", newRoute)
|
||||
|
||||
conn := GetRouteManager().Route("region1", "127.0.0.1:8954")
|
||||
convey.So(conn, convey.ShouldNotBeNil)
|
||||
})
|
||||
|
||||
convey.Convey("best node not match", func() {
|
||||
gomonkey.ApplyFunc(logs.Warn, func(f interface{}, v ...interface{}) {
|
||||
convey.So(strings.Contains(f.(string), "use random hop"), convey.ShouldBeTrue)
|
||||
})
|
||||
newRoute := &routeItem{
|
||||
region: "",
|
||||
scheme: "kcp",
|
||||
serverAddr: "127.0.0.1:5202",
|
||||
Conn: &mockConn{},
|
||||
}
|
||||
GetRouteManager().addRoute("region1", newRoute)
|
||||
defer GetRouteManager().deleteRoute("region1", newRoute)
|
||||
|
||||
conn := GetRouteManager().Route("region1", "127.0.0.1:8954")
|
||||
convey.So(conn, convey.ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type mockConn struct {
|
||||
}
|
||||
|
||||
func (m *mockConn) LocalAddr() net.Addr {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) SetDeadline(t time.Time) error {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) OpenStream() (transport.Stream, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) AcceptStream() (transport.Stream, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) Close() {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockConn) IsClosed() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mockConn) RemoteAddr() net.Addr {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
@@ -2,82 +2,81 @@ package route
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"math"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
)
|
||||
|
||||
var traceManager = &TraceManager{
|
||||
regionTrace: make(map[string]*Trace),
|
||||
var tm = &traceManager{
|
||||
regionTrace: make(map[string]*trace),
|
||||
}
|
||||
|
||||
func GetTraceManager() *TraceManager {
|
||||
return traceManager
|
||||
type traceManager struct {
|
||||
regionTrace map[string]*trace
|
||||
}
|
||||
|
||||
// TraceManager manage region trace
|
||||
type TraceManager struct {
|
||||
regionTraceMu sync.Mutex
|
||||
regionTrace map[string]*Trace
|
||||
}
|
||||
|
||||
func (m *TraceManager) RunRace() {
|
||||
for _, race := range m.regionTrace {
|
||||
go race.Run()
|
||||
func (m *traceManager) addTraces(traces map[string]*trace) {
|
||||
for k, _ := range traces {
|
||||
m.regionTrace[k] = traces[k]
|
||||
}
|
||||
}
|
||||
|
||||
// AddRegionTrace adds a trace instance for region
|
||||
func (m *TraceManager) AddRegionTrace(region string, race *Trace) {
|
||||
m.regionTraceMu.Lock()
|
||||
defer m.regionTraceMu.Unlock()
|
||||
m.regionTrace[region] = race
|
||||
func (m *traceManager) startTrace() {
|
||||
for _, trace := range m.regionTrace {
|
||||
logs.Debug("region[%s] running trace", trace.region)
|
||||
go trace.runTraceJob()
|
||||
}
|
||||
}
|
||||
|
||||
// GetBestNode returns the highest score of region target region
|
||||
func (m *TraceManager) GetBestNode(region string) string {
|
||||
regionRace := m.regionTrace[region]
|
||||
if regionRace == nil {
|
||||
return ""
|
||||
func (m *traceManager) getRegionBestTarget(region string) (traceTarget, bool) {
|
||||
regionTrace := m.regionTrace[region]
|
||||
if regionTrace == nil {
|
||||
logs.Warn("trace for region[%s] not exist", region)
|
||||
return traceTarget{}, false
|
||||
}
|
||||
|
||||
return regionRace.GetBestNode()
|
||||
return regionTrace.getBestNode()
|
||||
}
|
||||
|
||||
// Trace is a region trace instance
|
||||
type Trace struct {
|
||||
type traceTarget struct {
|
||||
traceAddr string
|
||||
serverAddr string
|
||||
scheme string
|
||||
}
|
||||
|
||||
type trace struct {
|
||||
region string
|
||||
targets []string
|
||||
targets []traceTarget
|
||||
targetScoreMu sync.Mutex
|
||||
targetScore map[string]float64
|
||||
targetScore map[traceTarget]float64
|
||||
totalRtt int32
|
||||
}
|
||||
|
||||
// NewTrace return trace instance
|
||||
func NewTrace(region string, targets []string) *Trace {
|
||||
return &Trace{
|
||||
func newTrace(region string) *trace {
|
||||
return &trace{
|
||||
region: region,
|
||||
targets: targets,
|
||||
targetScoreMu: sync.Mutex{},
|
||||
targetScore: make(map[string]float64),
|
||||
targetScore: make(map[traceTarget]float64),
|
||||
}
|
||||
}
|
||||
|
||||
// Run trace job
|
||||
func (r *Trace) Run() {
|
||||
r.trace()
|
||||
func (t *trace) addTarget(target traceTarget) {
|
||||
t.targets = append(t.targets, target)
|
||||
}
|
||||
|
||||
func (t *trace) runTraceJob() {
|
||||
t.trace()
|
||||
tick := time.NewTicker(time.Second * 120)
|
||||
for range tick.C {
|
||||
r.trace()
|
||||
t.trace()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Trace) trace() {
|
||||
for _, target := range r.targets {
|
||||
raddr, err := net.ResolveUDPAddr("udp", target)
|
||||
func (t *trace) trace() {
|
||||
for i, target := range t.targets {
|
||||
raddr, err := net.ResolveUDPAddr("udp", target.traceAddr)
|
||||
if err != nil {
|
||||
logs.Error("resolve udp addr: %v", err)
|
||||
continue
|
||||
@@ -117,21 +116,20 @@ func (r *Trace) trace() {
|
||||
diff := time.Now().Sub(beg).Milliseconds()
|
||||
rtt += int(diff)
|
||||
}
|
||||
remoteAddr := rconn.RemoteAddr().String()
|
||||
rconn.Close()
|
||||
|
||||
if rtt < 0 {
|
||||
rtt = math.MaxInt
|
||||
}
|
||||
|
||||
lossRank := r.calcLossScore(loss)
|
||||
delayRank := r.calcRttScore(rtt)
|
||||
lossRank := t.calcLossScore(loss)
|
||||
delayRank := t.calcRttScore(rtt)
|
||||
score := lossRank + delayRank
|
||||
logs.Debug("region[%s] %s loss %d rtt %d lossRank %.4f delayRank %.4f score %.4f",
|
||||
r.region, target, loss, rtt, lossRank, delayRank, score)
|
||||
r.targetScoreMu.Lock()
|
||||
r.targetScore[remoteAddr] = score
|
||||
r.targetScoreMu.Unlock()
|
||||
t.region, target, loss, rtt, lossRank, delayRank, score)
|
||||
t.targetScoreMu.Lock()
|
||||
t.targetScore[t.targets[i]] = score
|
||||
t.targetScoreMu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +138,7 @@ func (r *Trace) trace() {
|
||||
// f(p) = 35+(1.25-p)x10 0.75% < p <= 1.25%,
|
||||
// f(p) = 30+(2.25-p)x5 1.25% < p <= 2.25%,
|
||||
// f(p) = 30+(p-2.25)x5x-1 p > 2.25%
|
||||
func (r *Trace) calcLossScore(loss int) float64 {
|
||||
func (t *trace) calcLossScore(loss int) float64 {
|
||||
lossRate := float64(loss) / 60
|
||||
if 0 < lossRate && lossRate <= 0.75 {
|
||||
return 40 + (0.75-lossRate)*13
|
||||
@@ -154,7 +152,7 @@ func (r *Trace) calcLossScore(loss int) float64 {
|
||||
return 50
|
||||
}
|
||||
|
||||
func (r *Trace) calcRttScore(rtt int) float64 {
|
||||
func (t *trace) calcRttScore(rtt int) float64 {
|
||||
avgRtt := float64(rtt) / 60
|
||||
if 0 < avgRtt && avgRtt < 45.0 {
|
||||
return 50
|
||||
@@ -171,17 +169,18 @@ func (r *Trace) calcRttScore(rtt int) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetBestNode of all the targets of trace
|
||||
func (r *Trace) GetBestNode() string {
|
||||
r.targetScoreMu.Lock()
|
||||
defer r.targetScoreMu.Unlock()
|
||||
func (t *trace) getBestNode() (traceTarget, bool) {
|
||||
t.targetScoreMu.Lock()
|
||||
defer t.targetScoreMu.Unlock()
|
||||
bestScore := float64(-1)
|
||||
node := ""
|
||||
for target, score := range r.targetScore {
|
||||
if bestScore < score {
|
||||
var node traceTarget
|
||||
var ok bool = false
|
||||
for target, score := range t.targetScore {
|
||||
if bestScore*1000 < score*1000 {
|
||||
bestScore = score
|
||||
node = target
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return node
|
||||
return node, ok
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package gtund
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -7,7 +7,11 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var gConfig *Config
|
||||
|
||||
type Config struct {
|
||||
EnableAuth bool `yaml:"enable_auth"`
|
||||
Auths []AuthConfig `yaml:"auths"`
|
||||
Trace string `yaml:"trace"`
|
||||
ServerConfig []ServerConfig `yaml:"server"`
|
||||
Log Log `yaml:"log"`
|
||||
@@ -19,6 +23,12 @@ type Log struct {
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
AccessToken string `yaml:"access_token"`
|
||||
ExpiredAt int64 `yaml:"expired_at"`
|
||||
RateLimit int64 `yaml:"rate_limit"` // mbps
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (*Config, error) {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -31,6 +41,10 @@ func ParseConfig(path string) (*Config, error) {
|
||||
func parseConfig(content []byte) (*Config, error) {
|
||||
var c Config
|
||||
err := yaml.Unmarshal(content, &c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gConfig = &c
|
||||
return &c, err
|
||||
}
|
||||
|
||||
@@ -38,3 +52,7 @@ func (c *Config) String() string {
|
||||
cnt, _ := json.MarshalIndent(c, "", "\t")
|
||||
return string(cnt)
|
||||
}
|
||||
|
||||
func GetConfig() *Config {
|
||||
return gConfig
|
||||
}
|
119
src/gtund/main.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/optw/transport/transport_api"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var version = ""
|
||||
|
||||
var logo = `
|
||||
====================================
|
||||
██████ ████████ ██ ██ ███ ██
|
||||
██ ██ ██ ██ ████ ██
|
||||
██ ███ ██ ██ ██ ██ ██ ██
|
||||
██ ██ ██ ██ ██ ██ ██ ██
|
||||
██████ ██ ██████ ██ ████
|
||||
====================================
|
||||
https://github.com/ICKelin/gtun
|
||||
`
|
||||
|
||||
func init() {
|
||||
go http.ListenAndServe(":6060", nil)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flgVersion := flag.Bool("v", false, "print version")
|
||||
flgTest := flag.Bool("t", false, "test config file")
|
||||
flgConf := flag.String("c", "", "config file")
|
||||
flag.Parse()
|
||||
|
||||
fmt.Println(logo)
|
||||
|
||||
if *flgVersion {
|
||||
fmt.Println(version)
|
||||
return
|
||||
}
|
||||
|
||||
if *flgTest {
|
||||
_, err := ParseConfig(*flgConf)
|
||||
if err != nil {
|
||||
fmt.Printf("FAILED: %v\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
conf, err := ParseConfig(*flgConf)
|
||||
if err != nil {
|
||||
fmt.Printf("parse config file fail: %s %v\n", *flgConf, err)
|
||||
return
|
||||
}
|
||||
logs.Init(conf.Log.Path, conf.Log.Level, conf.Log.Days)
|
||||
logs.Info("%s", logo)
|
||||
logs.Debug("config: %s", conf.String())
|
||||
|
||||
if conf.Trace != "" {
|
||||
go NewTraceServer(conf.Trace).ListenAndServe()
|
||||
}
|
||||
|
||||
for _, cfg := range conf.ServerConfig {
|
||||
listener, err := transport_api.NewListen(cfg.Scheme, cfg.Listen, cfg.ListenerConfig)
|
||||
if err != nil {
|
||||
logs.Error("new listener fail: %v", err)
|
||||
return
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
if conf.EnableAuth {
|
||||
listener.SetAuthFunc(func(token string) bool {
|
||||
ok := false
|
||||
auths := GetConfig().Auths
|
||||
logs.Info("verify auth token %s", token)
|
||||
for _, auth := range auths {
|
||||
if auth.AccessToken == token {
|
||||
if auth.ExpiredAt == 0 {
|
||||
ok = true
|
||||
} else if time.Now().Unix() < auth.ExpiredAt {
|
||||
ok = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return ok
|
||||
})
|
||||
}
|
||||
|
||||
s := NewServer(listener)
|
||||
go s.Run()
|
||||
}
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGHUP)
|
||||
|
||||
for sig := range c {
|
||||
switch sig {
|
||||
case syscall.SIGHUP:
|
||||
logs.Info("receive hup signal")
|
||||
cfg, err := ParseConfig(*flgConf)
|
||||
if err != nil {
|
||||
logs.Warn("reload config fail: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// rewrite conf pointer
|
||||
conf = cfg
|
||||
logs.Info("reload config success")
|
||||
|
||||
default:
|
||||
logs.Info("un handle signal %v", sig.String())
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +1,17 @@
|
||||
package gtund
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ICKelin/gtun/internal/utils"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"github.com/ICKelin/gtun/src/internal/proto"
|
||||
"github.com/ICKelin/gtun/src/internal/utils"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/internal/proto"
|
||||
"github.com/ICKelin/optw/transport"
|
||||
)
|
||||
|
||||
@@ -66,7 +66,7 @@ func (s *Server) Run() error {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return err
|
||||
continue
|
||||
}
|
||||
|
||||
logs.Info("accept connect from remote: %s", conn.RemoteAddr().String())
|
||||
@@ -116,15 +116,6 @@ func (s *Server) handleStream(stream transport.Stream) {
|
||||
s.tcpProxy(stream, &proxyProtocol)
|
||||
case "udp":
|
||||
s.udpProxy(stream, &proxyProtocol)
|
||||
case "tun":
|
||||
if s.devStream != nil {
|
||||
s.devStream.Close()
|
||||
s.devStream = stream
|
||||
} else {
|
||||
s.devStream = stream
|
||||
go s.readDev()
|
||||
}
|
||||
s.tunProxy(stream, &proxyProtocol)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,44 +211,3 @@ func (s *Server) udpProxy(stream transport.Stream, p *proto.ProxyProtocol) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) tunProxy(stream transport.Stream, p *proto.ProxyProtocol) {
|
||||
defer stream.Close()
|
||||
hdr := make([]byte, 2)
|
||||
for {
|
||||
_, err := io.ReadFull(stream, hdr)
|
||||
if err != nil {
|
||||
logs.Error("read stream fail: %v", err)
|
||||
break
|
||||
}
|
||||
nlen := binary.BigEndian.Uint16(hdr)
|
||||
buf := make([]byte, nlen)
|
||||
_, err = io.ReadFull(stream, buf)
|
||||
if err != nil {
|
||||
logs.Error("read stream body fail: %v", err)
|
||||
break
|
||||
}
|
||||
|
||||
_, err = s.dev.Write(buf)
|
||||
if err != nil {
|
||||
logs.Error("write to dev fail: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) readDev() {
|
||||
for {
|
||||
buf, err := s.dev.Read()
|
||||
if err != nil {
|
||||
logs.Error("read interface fail: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
bytes := proto.EncodeData(buf)
|
||||
_, err = s.devStream.Write(bytes)
|
||||
if err != nil {
|
||||
logs.Error("stream write fail: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
package gtund
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ICKelin/gtun/internal/logs"
|
||||
"github.com/ICKelin/gtun/src/internal/logs"
|
||||
"net"
|
||||
)
|
||||
|
@@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package logs
|