Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd4741a0a0 | ||
|
|
9a9dc2594d | ||
|
|
02547e9475 | ||
|
|
9749db9235 | ||
|
|
e35ddc4d53 | ||
|
|
99b06e813e | ||
|
|
7164349944 | ||
|
|
bf43b3adee | ||
|
|
6aa4b3c8a9 | ||
|
|
7a9f7ef95e | ||
|
|
ee1a9d3ec7 | ||
|
|
6a69e58be5 | ||
|
|
6e1d788677 | ||
|
|
24f8f789c5 | ||
|
|
2fb779f990 | ||
|
|
0a9d3cd309 | ||
|
|
977b1aba1c | ||
|
|
a02aeeb906 | ||
|
|
7e2e63137e | ||
|
|
4b35219c27 | ||
|
|
0247c4701d | ||
|
|
e2cd0b8e4f | ||
|
|
ee93171c63 | ||
|
|
ddd2302cb2 | ||
|
|
c96d2288b3 | ||
|
|
6f5a088091 | ||
|
|
9a07797e29 | ||
|
|
055a020d33 |
17
CHANGELOG
17
CHANGELOG
@ -1,4 +1,21 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v4.1
|
||||||
|
1.优化了http(s),socks5代理中的域名智能判断,如果是内网IP,直接走本地网络,提升浏览体验.
|
||||||
|
|
||||||
|
v4.0
|
||||||
|
1.内网穿透三端重构了一个multiplexing版本,使用github.com/xtaci/smux实现了tcp链接的多路复用,
|
||||||
|
鼎鼎大名的kcp-go底层就是使用的这个库,基于kcp-go的双边加速工具kcptun的广泛使用已经很好
|
||||||
|
的验证来该库的强大与稳定。multiplexing版的内网穿透对应的子命令分别是server,client,bridge
|
||||||
|
使用方式和参数与之前的子命令tserver,tclient,tserver完全一样,另外server,client增加了
|
||||||
|
压缩传输参数--c,使用压缩传输速度更快。
|
||||||
|
|
||||||
|
v3.9
|
||||||
|
1.增加了守护运行参数--forever,比如: proxy http --forever ,
|
||||||
|
proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后重启子进程.
|
||||||
|
该参数配合后台运行参数--daemon和日志参数--log,可以保障proxy一直在后台执行不会因为意外退出,
|
||||||
|
而且可以通过日志文件看到proxy的输出日志内容.
|
||||||
|
比如: proxy http -p ":9090" --forever --log proxy.log --daemon
|
||||||
|
|
||||||
v3.8
|
v3.8
|
||||||
1.增加了日志输出到文件--log参数,比如: --log proxy.log,日志就会输出到proxy.log方便排除问题.
|
1.增加了日志输出到文件--log参数,比如: --log proxy.log,日志就会输出到proxy.log方便排除问题.
|
||||||
|
|
||||||
|
|||||||
135
README.md
135
README.md
@ -1,5 +1,5 @@
|
|||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
||||||
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务器,支持正向代理、内网穿透、SSH中转。
|
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务器,支持正向代理、内网穿透、TCP/UDP端口转发、SSH中转。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- 域名黑白名单,更加自由的控制网站的访问方式。
|
- 域名黑白名单,更加自由的控制网站的访问方式。
|
||||||
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
||||||
- 多协议支持,支持HTTP(S),TCP,UDP,Websocket,SOCKS5代理.
|
- 多协议支持,支持HTTP(S),TCP,UDP,Websocket,SOCKS5代理.
|
||||||
|
- TCP/UDP端口转发.
|
||||||
- 支持内网穿透,协议支持TCP和UDP.
|
- 支持内网穿透,协议支持TCP和UDP.
|
||||||
- SSH中转,HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
- SSH中转,HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
- [KCP](https://github.com/xtaci/kcp-go)协议支持,HTTP(S),SOCKS5代理支持KCP协议传输数据,降低延迟,提升浏览体验.
|
- [KCP](https://github.com/xtaci/kcp-go)协议支持,HTTP(S),SOCKS5代理支持KCP协议传输数据,降低延迟,提升浏览体验.
|
||||||
@ -27,7 +28,10 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
|
||||||
本页是v3.6-v3.7手册,其他版本手册请点击下面链接查看.
|
本页是v4.0手册,其他版本手册请点击下面链接查看.
|
||||||
|
- [v3.9手册](https://github.com/snail007/goproxy/tree/v3.9)
|
||||||
|
- [v3.8手册](https://github.com/snail007/goproxy/tree/v3.8)
|
||||||
|
- [v3.6-v3.7手册](https://github.com/snail007/goproxy/tree/v3.6)
|
||||||
- [v3.5手册](https://github.com/snail007/goproxy/tree/v3.5)
|
- [v3.5手册](https://github.com/snail007/goproxy/tree/v3.5)
|
||||||
- [v3.4手册](https://github.com/snail007/goproxy/tree/v3.4)
|
- [v3.4手册](https://github.com/snail007/goproxy/tree/v3.4)
|
||||||
- [v3.3手册](https://github.com/snail007/goproxy/tree/v3.3)
|
- [v3.3手册](https://github.com/snail007/goproxy/tree/v3.3)
|
||||||
@ -46,7 +50,10 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
### 首次使用必看
|
### 首次使用必看
|
||||||
- [环境](#首次使用必看-1)
|
- [环境](#首次使用必看-1)
|
||||||
- [使用配置文件](#使用配置文件)
|
- [使用配置文件](#使用配置文件)
|
||||||
|
- [调试输出](#调试输出)
|
||||||
|
- [使用日志文件](#使用日志文件)
|
||||||
- [后台运行](#后台运行)
|
- [后台运行](#后台运行)
|
||||||
|
- [守护运行](#守护运行)
|
||||||
- [生成通讯证书文件](#生成加密通讯需要的证书文件)
|
- [生成通讯证书文件](#生成加密通讯需要的证书文件)
|
||||||
- [安全建议](#安全建议)
|
- [安全建议](#安全建议)
|
||||||
|
|
||||||
@ -71,11 +78,11 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [2.5 加密三级TCP代理](#25加密三级tcp代理)
|
- [2.5 加密三级TCP代理](#25加密三级tcp代理)
|
||||||
- [2.6 查看帮助](#26查看帮助)
|
- [2.6 查看帮助](#26查看帮助)
|
||||||
- [3. UDP代理](#3udp代理)
|
- [3. UDP代理](#3udp代理)
|
||||||
- [3.1 普通一级TCP代理](#31普通一级udp代理)
|
- [3.1 普通一级UDP代理](#31普通一级udp代理)
|
||||||
- [3.2 普通二级TCP代理](#32普通二级udp代理)
|
- [3.2 普通二级UDP代理](#32普通二级udp代理)
|
||||||
- [3.3 普通三级TCP代理](#33普通三级udp代理)
|
- [3.3 普通三级UDP代理](#33普通三级udp代理)
|
||||||
- [3.4 加密二级TCP代理](#34加密二级udp代理)
|
- [3.4 加密二级UDP代理](#34加密二级udp代理)
|
||||||
- [3.5 加密三级TCP代理](#35加密三级udp代理)
|
- [3.5 加密三级UDP代理](#35加密三级udp代理)
|
||||||
- [3.6 查看帮助](#36查看帮助)
|
- [3.6 查看帮助](#36查看帮助)
|
||||||
- [4. 内网穿透](#4内网穿透)
|
- [4. 内网穿透](#4内网穿透)
|
||||||
- [4.1 原理说明](#41原理说明)
|
- [4.1 原理说明](#41原理说明)
|
||||||
@ -84,7 +91,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [4.4 UDP普通用法](#44udp普通用法)
|
- [4.4 UDP普通用法](#44udp普通用法)
|
||||||
- [4.5 高级用法一](#45高级用法一)
|
- [4.5 高级用法一](#45高级用法一)
|
||||||
- [4.6 高级用法一](#46高级用法二)
|
- [4.6 高级用法一](#46高级用法二)
|
||||||
- [4.7 tserver的-r参数](#47tserver的-r参数)
|
- [4.7 server的-r参数](#47server的-r参数)
|
||||||
- [4.8 查看帮助](#48查看帮助)
|
- [4.8 查看帮助](#48查看帮助)
|
||||||
- [5. SOCKS5代理](#5socks5代理)
|
- [5. SOCKS5代理](#5socks5代理)
|
||||||
- [5.1 普通SOCKS5代理](#51普通socks5代理)
|
- [5.1 普通SOCKS5代理](#51普通socks5代理)
|
||||||
@ -110,22 +117,14 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
|
|||||||
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
|
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
|
||||||
|
|
||||||
#### 手动安装
|
#### 手动安装
|
||||||
#### **1.登录你的VPS,下载守护进程monexec,选择合适你的版本,vps一般选择"linux_amd64.tar.gz"的即可.**
|
|
||||||
下载地址:https://github.com/reddec/monexec/releases
|
#### **1.下载proxy**
|
||||||
比如下载到/root/proxy/
|
|
||||||
执行:
|
|
||||||
```shell
|
|
||||||
mkdir /root/proxy/
|
|
||||||
cd /root/proxy/
|
|
||||||
wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
|
|
||||||
```
|
|
||||||
#### **2.下载proxy**
|
|
||||||
下载地址:https://github.com/snail007/goproxy/releases
|
下载地址:https://github.com/snail007/goproxy/releases
|
||||||
```shell
|
```shell
|
||||||
cd /root/proxy/
|
cd /root/proxy/
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v3.8/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v4.0/proxy-linux-amd64.tar.gz
|
||||||
```
|
```
|
||||||
#### **3.下载自动安装脚本**
|
#### **2.下载自动安装脚本**
|
||||||
```shell
|
```shell
|
||||||
cd /root/proxy/
|
cd /root/proxy/
|
||||||
wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
|
wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
|
||||||
@ -133,7 +132,7 @@ chmod +x install.sh
|
|||||||
./install.sh
|
./install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## 首次使用必看
|
## **首次使用必看**
|
||||||
|
|
||||||
#### **环境**
|
#### **环境**
|
||||||
接下来的教程,默认系统是linux,程序是proxy;所有操作需要root权限;
|
接下来的教程,默认系统是linux,程序是proxy;所有操作需要root权限;
|
||||||
@ -150,26 +149,40 @@ http
|
|||||||
--local-type=tcp
|
--local-type=tcp
|
||||||
--local=:33080
|
--local=:33080
|
||||||
```
|
```
|
||||||
### 生成加密通讯需要的证书文件
|
### **调试输出**
|
||||||
|
默认情况下,日志输出的信息不包含文件行数,某些情况下为了排除程序问题,快速定位问题,
|
||||||
|
可以使用--debug参数,输出代码行数和毫秒时间.
|
||||||
|
|
||||||
|
### **使用日志文件**
|
||||||
|
默认情况下,日志是直接在控制台显示出来的,如果要保存到文件,可以使用--log参数,
|
||||||
|
比如: --log proxy.log,日志就会输出到proxy.log方便排除问题.
|
||||||
|
|
||||||
|
|
||||||
|
### **生成加密通讯需要的证书文件**
|
||||||
http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,当然可以选择不加密通信通讯,本教程所有和上级通讯都采用加密,需要证书文件.
|
http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,当然可以选择不加密通信通讯,本教程所有和上级通讯都采用加密,需要证书文件.
|
||||||
在linux上并安装了openssl命令,可以直接通过下面的命令生成证书和key文件.
|
在linux上并安装了openssl命令,可以直接通过下面的命令生成证书和key文件.
|
||||||
`./proxy keygen`
|
`./proxy keygen`
|
||||||
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
||||||
|
|
||||||
### 后台运行
|
### **后台运行**
|
||||||
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
|
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
|
||||||
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
|
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
|
||||||
比如:
|
比如:
|
||||||
`./proxy http -t tcp -p "0.0.0.0:38080" --daemon`
|
`./proxy http -t tcp -p "0.0.0.0:38080" --daemon`
|
||||||
更推荐用monexec守护运行proxy比较好.
|
|
||||||
|
|
||||||
### 安全建议
|
### **守护运行**
|
||||||
|
守护运行参数--forever,比如: `proxy http --forever` ,
|
||||||
|
proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后重启子进程.
|
||||||
|
该参数配合后台运行参数--daemon和日志参数--log,可以保障proxy一直在后台执行不会因为意外退出,
|
||||||
|
而且可以通过日志文件看到proxy的输出日志内容.
|
||||||
|
比如: `proxy http -p ":9090" --forever --log proxy.log --daemon`
|
||||||
|
|
||||||
|
### **安全建议**
|
||||||
当VPS在nat设备后面,vps上网卡IP都是内网IP,这个时候可以通过-g参数添加vps的外网ip防止死循环.
|
当VPS在nat设备后面,vps上网卡IP都是内网IP,这个时候可以通过-g参数添加vps的外网ip防止死循环.
|
||||||
假设你的vps外网ip是23.23.23.23,下面命令通过-g参数设置23.23.23.23
|
假设你的vps外网ip是23.23.23.23,下面命令通过-g参数设置23.23.23.23
|
||||||
`./proxy http -g "23.23.23.23"`
|
`./proxy http -g "23.23.23.23"`
|
||||||
|
|
||||||
### 1.HTTP代理
|
### **1.HTTP代理**
|
||||||
#### **1.1.普通HTTP代理**
|
#### **1.1.普通HTTP代理**
|
||||||
`./proxy http -t tcp -p "0.0.0.0:38080"`
|
`./proxy http -t tcp -p "0.0.0.0:38080"`
|
||||||
|
|
||||||
@ -255,7 +268,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
|||||||
#### **1.9.查看帮助**
|
#### **1.9.查看帮助**
|
||||||
`./proxy help http`
|
`./proxy help http`
|
||||||
|
|
||||||
### 2.TCP代理
|
### **2.TCP代理**
|
||||||
|
|
||||||
#### **2.1.普通一级TCP代理**
|
#### **2.1.普通一级TCP代理**
|
||||||
本地执行:
|
本地执行:
|
||||||
@ -280,16 +293,16 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
#### **2.4.加密二级TCP代理**
|
#### **2.4.加密二级TCP代理**
|
||||||
VPS(IP:22.22.22.33)执行:
|
VPS(IP:22.22.22.33)执行:
|
||||||
`./proxy tcp --tls -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0 -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0 -C proxy.crt -K proxy.key`
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy tcp -p ":23080" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
`./proxy tcp -p ":23080" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||||
那么访问本地23080端口就是通过加密TCP隧道访问22.22.22.33的8080端口.
|
那么访问本地23080端口就是通过加密TCP隧道访问22.22.22.33的8080端口.
|
||||||
|
|
||||||
#### **2.5.加密三级TCP代理**
|
#### **2.5.加密三级TCP代理**
|
||||||
一级TCP代理VPS_01,IP:22.22.22.22
|
一级TCP代理VPS_01,IP:22.22.22.22
|
||||||
`./proxy tcp --tls -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
||||||
二级TCP代理VPS_02,IP:33.33.33.33
|
二级TCP代理VPS_02,IP:33.33.33.33
|
||||||
`./proxy tcp --tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
三级TCP代理(本地)
|
三级TCP代理(本地)
|
||||||
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||||
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
||||||
@ -297,7 +310,7 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
#### **2.6.查看帮助**
|
#### **2.6.查看帮助**
|
||||||
`./proxy help tcp`
|
`./proxy help tcp`
|
||||||
|
|
||||||
### 3.UDP代理
|
### **3.UDP代理**
|
||||||
|
|
||||||
#### **3.1.普通一级UDP代理**
|
#### **3.1.普通一级UDP代理**
|
||||||
本地执行:
|
本地执行:
|
||||||
@ -322,16 +335,16 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
#### **3.4.加密二级UDP代理**
|
#### **3.4.加密二级UDP代理**
|
||||||
VPS(IP:22.22.22.33)执行:
|
VPS(IP:22.22.22.33)执行:
|
||||||
`./proxy tcp --tls -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy udp -p ":5353" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
`./proxy udp -p ":5353" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||||
那么访问本地UDP:5353端口就是通过加密TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
那么访问本地UDP:5353端口就是通过加密TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
||||||
|
|
||||||
#### **3.5.加密三级UDP代理**
|
#### **3.5.加密三级UDP代理**
|
||||||
一级TCP代理VPS_01,IP:22.22.22.22
|
一级TCP代理VPS_01,IP:22.22.22.22
|
||||||
`./proxy tcp --tls -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||||
二级TCP代理VPS_02,IP:33.33.33.33
|
二级TCP代理VPS_02,IP:33.33.33.33
|
||||||
`./proxy tcp --tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
三级TCP代理(本地)
|
三级TCP代理(本地)
|
||||||
`./proxy udp -p ":5353" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
`./proxy udp -p ":5353" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||||
那么访问本地5353端口就是通过加密TCP隧道,通过VPS_01访问8.8.8.8的53端口.
|
那么访问本地5353端口就是通过加密TCP隧道,通过VPS_01访问8.8.8.8的53端口.
|
||||||
@ -339,9 +352,17 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
#### **3.6.查看帮助**
|
#### **3.6.查看帮助**
|
||||||
`./proxy help udp`
|
`./proxy help udp`
|
||||||
|
|
||||||
### 4.内网穿透
|
### **4.内网穿透**
|
||||||
#### **4.1、原理说明**
|
#### **4.1、原理说明**
|
||||||
内网穿透,由三部分组成:client端,server端,bridge端;client和server主动连接bridge端进行桥接.
|
内网穿透,分为两个版本,“多链接版本”和“多路复用版本”,一般像web服务这种不是长时间连接的服务建议用“多链接版本”,如果是要保持长时间连接建议使用“多路复用版本”。
|
||||||
|
1. 多链接版本,对应的子命令是tserver,tclient,tbridge。
|
||||||
|
1. 多路复用版本,对应的子命令是server,client,bridge。
|
||||||
|
1. 多链接版本和多路复用版本的参数和使用方式完全一样。
|
||||||
|
1. **多路复用版本的server,client可以开启压缩传输,参数是--c。**
|
||||||
|
1. **server,client要么都开启压缩,要么都不开启,不能只开一个。**
|
||||||
|
|
||||||
|
下面的教程以“多路复用版本”为例子,说明使用方法。
|
||||||
|
内网穿透由三部分组成:client端,server端,bridge端;client和server主动连接bridge端进行桥接.
|
||||||
当用户访问server端,流程是:
|
当用户访问server端,流程是:
|
||||||
1. server主动和bridge端建立连接;
|
1. server主动和bridge端建立连接;
|
||||||
1. 然后bridge端通知client端连接bridge端,并连接内网目标端口;
|
1. 然后bridge端通知client端连接bridge端,并连接内网目标端口;
|
||||||
@ -359,11 +380,11 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
步骤:
|
步骤:
|
||||||
1. 在vps上执行
|
1. 在vps上执行
|
||||||
`./proxy tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
`./proxy bridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
`./proxy tserver -r ":28080@:80" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
`./proxy server -r ":28080@:80" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在公司机器A上面执行
|
1. 在公司机器A上面执行
|
||||||
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
@ -381,11 +402,11 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
步骤:
|
步骤:
|
||||||
1. 在vps上执行,确保vps的80端口没被其它程序占用.
|
1. 在vps上执行,确保vps的80端口没被其它程序占用.
|
||||||
`./proxy tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
`./proxy bridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
`./proxy tserver -r ":80@:80" -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy server -r ":80@:80" -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在自己笔记本上面执行
|
1. 在自己笔记本上面执行
|
||||||
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
@ -399,11 +420,11 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
步骤:
|
步骤:
|
||||||
1. 在vps上执行
|
1. 在vps上执行
|
||||||
`./proxy tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
`./proxy bridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
`./proxy tserver --udp -r ":53@:53" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
`./proxy server --udp -r ":53@:53" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在公司机器A上面执行
|
1. 在公司机器A上面执行
|
||||||
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
@ -418,13 +439,13 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
步骤:
|
步骤:
|
||||||
1. 在vps上执行
|
1. 在vps上执行
|
||||||
`./proxy tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
`./proxy bridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在公司机器A上面执行
|
1. 在公司机器A上面执行
|
||||||
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy client -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在家里电脑上执行
|
1. 在家里电脑上执行
|
||||||
`./proxy tserver -r ":28080@:80" -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy server -r ":28080@:80" -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
@ -445,15 +466,15 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
|
|
||||||
步骤:
|
步骤:
|
||||||
1. 在vps上执行
|
1. 在vps上执行
|
||||||
`./proxy tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
`./proxy bridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
`./proxy tserver -r ":28080@:80" -r ":29090@:21" --k test -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
`./proxy server -r ":28080@:80" -r ":29090@:21" --k test -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在公司机器A上面执行
|
1. 在公司机器A上面执行
|
||||||
`./proxy tclient --k test -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
`./proxy client --k test -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
#### **4.7.tserver的-r参数**
|
#### **4.7.server的-r参数**
|
||||||
-r完整格式是:`PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT`
|
-r完整格式是:`PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT`
|
||||||
|
|
||||||
4.7.1.协议PROTOCOL:tcp或者udp.
|
4.7.1.协议PROTOCOL:tcp或者udp.
|
||||||
@ -469,11 +490,11 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`;
|
4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`;
|
||||||
|
|
||||||
#### **4.8.查看帮助**
|
#### **4.8.查看帮助**
|
||||||
`./proxy help tbridge`
|
`./proxy help bridge`
|
||||||
`./proxy help tserver`
|
`./proxy help server`
|
||||||
`./proxy help tserver`
|
`./proxy help server`
|
||||||
|
|
||||||
### 5.SOCKS5代理
|
### **5.SOCKS5代理**
|
||||||
提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
提示:SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
||||||
#### **5.1.普通SOCKS5代理**
|
#### **5.1.普通SOCKS5代理**
|
||||||
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
||||||
@ -560,7 +581,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
|||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- http,socks代理多个上级负载均衡?
|
- http,socks代理多个上级负载均衡?
|
||||||
- 内网穿透增加multiplexing模式?
|
- http(s)代理增加pac支持?
|
||||||
- 欢迎加群反馈...
|
- 欢迎加群反馈...
|
||||||
|
|
||||||
### 如何使用源码?
|
### 如何使用源码?
|
||||||
|
|||||||
124
config.go
124
config.go
@ -1,12 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"proxy/services"
|
"proxy/services"
|
||||||
"proxy/utils"
|
"proxy/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
@ -14,6 +16,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
app *kingpin.Application
|
app *kingpin.Application
|
||||||
service *services.ServiceItem
|
service *services.ServiceItem
|
||||||
|
cmd *exec.Cmd
|
||||||
)
|
)
|
||||||
|
|
||||||
func initConfig() (err error) {
|
func initConfig() (err error) {
|
||||||
@ -31,6 +34,9 @@ func initConfig() (err error) {
|
|||||||
tunnelServerArgs := services.TunnelServerArgs{}
|
tunnelServerArgs := services.TunnelServerArgs{}
|
||||||
tunnelClientArgs := services.TunnelClientArgs{}
|
tunnelClientArgs := services.TunnelClientArgs{}
|
||||||
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
||||||
|
muxServerArgs := services.MuxServerArgs{}
|
||||||
|
muxClientArgs := services.MuxClientArgs{}
|
||||||
|
muxBridgeArgs := services.MuxBridgeArgs{}
|
||||||
udpArgs := services.UDPArgs{}
|
udpArgs := services.UDPArgs{}
|
||||||
socksArgs := services.SocksArgs{}
|
socksArgs := services.SocksArgs{}
|
||||||
//build srvice args
|
//build srvice args
|
||||||
@ -38,6 +44,7 @@ func initConfig() (err error) {
|
|||||||
app.Author("snail").Version(APP_VERSION)
|
app.Author("snail").Version(APP_VERSION)
|
||||||
debug := app.Flag("debug", "debug log output").Default("false").Bool()
|
debug := app.Flag("debug", "debug log output").Default("false").Bool()
|
||||||
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
|
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
|
||||||
|
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
|
||||||
logfile := app.Flag("log", "log file path").Default("").String()
|
logfile := app.Flag("log", "log file path").Default("").String()
|
||||||
|
|
||||||
//########http#########
|
//########http#########
|
||||||
@ -95,6 +102,33 @@ func initConfig() (err error) {
|
|||||||
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||||
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
|
||||||
|
//########mux-server#########
|
||||||
|
muxServer := app.Command("server", "proxy on mux server mode")
|
||||||
|
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
|
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
|
muxServerArgs.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool()
|
||||||
|
muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String()
|
||||||
|
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||||
|
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||||
|
|
||||||
|
//########mux-client#########
|
||||||
|
muxClient := app.Command("client", "proxy on mux client mode")
|
||||||
|
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
|
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
|
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
|
||||||
|
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||||
|
|
||||||
|
//########mux-bridge#########
|
||||||
|
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
|
||||||
|
muxBridgeArgs.CertFile = muxBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
|
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
|
||||||
//########tunnel-server#########
|
//########tunnel-server#########
|
||||||
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
||||||
tunnelServerArgs.Parent = tunnelServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
tunnelServerArgs.Parent = tunnelServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
@ -103,8 +137,7 @@ func initConfig() (err error) {
|
|||||||
tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
|
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
|
||||||
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
|
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
|
||||||
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as :PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||||
tunnelServerArgs.Mux = tunnelServer.Flag("mux", "use multiplexing mode").Default("false").Bool()
|
|
||||||
|
|
||||||
//########tunnel-client#########
|
//########tunnel-client#########
|
||||||
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
|
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
|
||||||
@ -113,7 +146,6 @@ func initConfig() (err error) {
|
|||||||
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
||||||
tunnelClientArgs.Mux = tunnelClient.Flag("mux", "use multiplexing mode").Default("false").Bool()
|
|
||||||
|
|
||||||
//########tunnel-bridge#########
|
//########tunnel-bridge#########
|
||||||
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
||||||
@ -121,7 +153,6 @@ func initConfig() (err error) {
|
|||||||
tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
tunnelBridgeArgs.Mux = tunnelBridge.Flag("mux", "use multiplexing mode").Default("false").Bool()
|
|
||||||
|
|
||||||
//########ssh#########
|
//########ssh#########
|
||||||
socks := app.Command("socks", "proxy on ssh mode")
|
socks := app.Command("socks", "proxy on ssh mode")
|
||||||
@ -155,18 +186,6 @@ func initConfig() (err error) {
|
|||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
flags := log.Ldate
|
flags := log.Ldate
|
||||||
if *daemon {
|
|
||||||
args := []string{}
|
|
||||||
for _, arg := range os.Args[1:] {
|
|
||||||
if arg != "--daemon" {
|
|
||||||
args = append(args, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmd := exec.Command(os.Args[0], args...)
|
|
||||||
cmd.Start()
|
|
||||||
fmt.Printf("%s [PID] %d running...\n", os.Args[0], cmd.Process.Pid)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
if *debug {
|
if *debug {
|
||||||
flags |= log.Lshortfile | log.Lmicroseconds
|
flags |= log.Lshortfile | log.Lmicroseconds
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +199,75 @@ func initConfig() (err error) {
|
|||||||
log.Fatal(e)
|
log.Fatal(e)
|
||||||
}
|
}
|
||||||
log.SetOutput(f)
|
log.SetOutput(f)
|
||||||
} else {
|
}
|
||||||
|
if *daemon {
|
||||||
|
args := []string{}
|
||||||
|
for _, arg := range os.Args[1:] {
|
||||||
|
if arg != "--daemon" {
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd = exec.Command(os.Args[0], args...)
|
||||||
|
cmd.Start()
|
||||||
|
f := ""
|
||||||
|
if *forever {
|
||||||
|
f = "forever "
|
||||||
|
}
|
||||||
|
log.Printf("%s%s [PID] %d running...\n", f, os.Args[0], cmd.Process.Pid)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if *forever {
|
||||||
|
args := []string{}
|
||||||
|
for _, arg := range os.Args[1:] {
|
||||||
|
if arg != "--forever" {
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if cmd != nil {
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
cmd = exec.Command(os.Args[0], args...)
|
||||||
|
cmdReaderStderr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERR:%s,restarting...\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmdReader, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERR:%s,restarting...\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scanner := bufio.NewScanner(cmdReader)
|
||||||
|
scannerStdErr := bufio.NewScanner(cmdReaderStderr)
|
||||||
|
go func() {
|
||||||
|
for scanner.Scan() {
|
||||||
|
fmt.Println(scanner.Text())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
for scannerStdErr.Scan() {
|
||||||
|
fmt.Println(scannerStdErr.Text())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Printf("ERR:%s,restarting...\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pid := cmd.Process.Pid
|
||||||
|
log.Printf("worker %s [PID] %d running...\n", os.Args[0], pid)
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Printf("ERR:%s,restarting...", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("worker %s [PID] %d unexpected exited, restarting...\n", os.Args[0], pid)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *logfile == "" {
|
||||||
poster()
|
poster()
|
||||||
}
|
}
|
||||||
//regist services and run service
|
//regist services and run service
|
||||||
@ -190,6 +277,9 @@ func initConfig() (err error) {
|
|||||||
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs)
|
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs)
|
||||||
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs)
|
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs)
|
||||||
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs)
|
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs)
|
||||||
|
services.Regist("server", services.NewMuxServerManager(), muxServerArgs)
|
||||||
|
services.Regist("client", services.NewMuxClient(), muxClientArgs)
|
||||||
|
services.Regist("bridge", services.NewMuxBridge(), muxBridgeArgs)
|
||||||
services.Regist("socks", services.NewSocks(), socksArgs)
|
services.Regist("socks", services.NewSocks(), socksArgs)
|
||||||
service, err = services.Run(serviceName)
|
service, err = services.Run(serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# install monexec
|
|
||||||
tar zxvf monexec_0.1.1_linux_amd64.tar.gz
|
|
||||||
cd monexec_0.1.1_linux_amd64
|
|
||||||
cp monexec /usr/bin/
|
|
||||||
chmod +x /usr/bin/monexec
|
|
||||||
cd ..
|
|
||||||
# #install proxy
|
# #install proxy
|
||||||
tar zxvf proxy-linux-amd64.tar.gz
|
tar zxvf proxy-linux-amd64.tar.gz
|
||||||
cp proxy /usr/bin/
|
cp proxy /usr/bin/
|
||||||
|
|||||||
@ -5,15 +5,8 @@ if [ -e /tmp/proxy ]; then
|
|||||||
fi
|
fi
|
||||||
mkdir /tmp/proxy
|
mkdir /tmp/proxy
|
||||||
cd /tmp/proxy
|
cd /tmp/proxy
|
||||||
wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v4.0/proxy-linux-amd64.tar.gz
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v3.8/proxy-linux-amd64.tar.gz
|
|
||||||
|
|
||||||
# install monexec
|
|
||||||
tar zxvf monexec_0.1.1_linux_amd64.tar.gz
|
|
||||||
cd monexec_0.1.1_linux_amd64
|
|
||||||
cp monexec /usr/bin/
|
|
||||||
chmod +x /usr/bin/monexec
|
|
||||||
cd ..
|
|
||||||
# #install proxy
|
# #install proxy
|
||||||
tar zxvf proxy-linux-amd64.tar.gz
|
tar zxvf proxy-linux-amd64.tar.gz
|
||||||
cp proxy /usr/bin/
|
cp proxy /usr/bin/
|
||||||
|
|||||||
19
main.go
19
main.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -9,14 +8,18 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VERSION = "3.8"
|
const APP_VERSION = "4.0"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := initConfig()
|
err := initConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("err : %s", err)
|
log.Fatalf("err : %s", err)
|
||||||
}
|
}
|
||||||
Clean(&service.S)
|
if service != nil && service.S != nil {
|
||||||
|
Clean(&service.S)
|
||||||
|
} else {
|
||||||
|
Clean(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func Clean(s *services.Service) {
|
func Clean(s *services.Service) {
|
||||||
signalChan := make(chan os.Signal, 1)
|
signalChan := make(chan os.Signal, 1)
|
||||||
@ -29,8 +32,14 @@ func Clean(s *services.Service) {
|
|||||||
syscall.SIGQUIT)
|
syscall.SIGQUIT)
|
||||||
go func() {
|
go func() {
|
||||||
for _ = range signalChan {
|
for _ = range signalChan {
|
||||||
fmt.Println("\nReceived an interrupt, stopping services...")
|
log.Println("Received an interrupt, stopping services...")
|
||||||
(*s).Clean()
|
if s != nil && *s != nil {
|
||||||
|
(*s).Clean()
|
||||||
|
}
|
||||||
|
if cmd != nil {
|
||||||
|
log.Printf("clean process %d", cmd.Process.Pid)
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}
|
||||||
cleanupDone <- true
|
cleanupDone <- true
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
83
release.sh
83
release.sh
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="3.8"
|
VER="4.0"
|
||||||
RELEASE="release-${VER}"
|
RELEASE="release-${VER}"
|
||||||
rm -rf .cert
|
rm -rf .cert
|
||||||
mkdir .cert
|
mkdir .cert
|
||||||
@ -9,56 +9,59 @@ cd .cert
|
|||||||
cd ..
|
cd ..
|
||||||
rm -rf ${RELEASE}
|
rm -rf ${RELEASE}
|
||||||
mkdir ${RELEASE}
|
mkdir ${RELEASE}
|
||||||
export CGO_ENABLED=0
|
|
||||||
#linux
|
#linux
|
||||||
GOOS=linux GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-linux-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-linux-386.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-linux-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-linux-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=arm GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v6.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=arm64 GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=6 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v6.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=mips go build && tar zcfv "${RELEASE}/proxy-linux-mips.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v7.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=mips64 go build && tar zcfv "${RELEASE}/proxy-linux-mips64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v7.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=mips64le go build && tar zcfv "${RELEASE}/proxy-linux-mips64le.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=8 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v8.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=mipsle go build && tar zcfv "${RELEASE}/proxy-linux-mipsle.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=8 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v8.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=ppc64 go build && tar zcfv "${RELEASE}/proxy-linux-ppc64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build && tar zcfv "${RELEASE}/proxy-linux-mips.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=ppc64le go build && tar zcfv "${RELEASE}/proxy-linux-ppc64le.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build && tar zcfv "${RELEASE}/proxy-linux-mips64.tar.gz" proxy direct blocked
|
||||||
GOOS=linux GOARCH=s390x go build && tar zcfv "${RELEASE}/proxy-linux-s390x.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build && tar zcfv "${RELEASE}/proxy-linux-mips64le.tar.gz" proxy direct blocked
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build && tar zcfv "${RELEASE}/proxy-linux-mipsle.tar.gz" proxy direct blocked
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64 go build && tar zcfv "${RELEASE}/proxy-linux-ppc64.tar.gz" proxy direct blocked
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le go build && tar zcfv "${RELEASE}/proxy-linux-ppc64le.tar.gz" proxy direct blocked
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=s390x go build && tar zcfv "${RELEASE}/proxy-linux-s390x.tar.gz" proxy direct blocked
|
||||||
#android
|
#android
|
||||||
GOOS=android GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-android-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=android GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-android-386.tar.gz" proxy direct blocked
|
||||||
GOOS=android GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-android-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=android GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-android-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=android GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-android-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=android GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-android-arm.tar.gz" proxy direct blocked
|
||||||
GOOS=android GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-android-arm64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=android GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-android-arm64.tar.gz" proxy direct blocked
|
||||||
#darwin
|
#darwin
|
||||||
GOOS=darwin GOARCH=386 go build go build && tar zcfv "${RELEASE}/proxy-darwin-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build go build && tar zcfv "${RELEASE}/proxy-darwin-386.tar.gz" proxy direct blocked
|
||||||
GOOS=darwin GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-darwin-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-darwin-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=darwin GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-darwin-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=darwin GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-darwin-arm.tar.gz" proxy direct blocked
|
||||||
GOOS=darwin GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-darwin-arm64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-darwin-arm64.tar.gz" proxy direct blocked
|
||||||
#dragonfly
|
#dragonfly
|
||||||
GOOS=dragonfly GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-dragonfly-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-dragonfly-amd64.tar.gz" proxy direct blocked
|
||||||
#freebsd
|
#freebsd
|
||||||
GOOS=freebsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-freebsd-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-freebsd-386.tar.gz" proxy direct blocked
|
||||||
GOOS=freebsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-freebsd-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-freebsd-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=freebsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-freebsd-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-freebsd-arm.tar.gz" proxy direct blocked
|
||||||
#nacl
|
#nacl
|
||||||
GOOS=nacl GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-nacl-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=nacl GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-nacl-386.tar.gz" proxy direct blocked
|
||||||
GOOS=nacl GOARCH=amd64p32 go build && tar zcfv "${RELEASE}/proxy-nacl-amd64p32.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=nacl GOARCH=amd64p32 go build && tar zcfv "${RELEASE}/proxy-nacl-amd64p32.tar.gz" proxy direct blocked
|
||||||
GOOS=nacl GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-nacl-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=nacl GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-nacl-arm.tar.gz" proxy direct blocked
|
||||||
#netbsd
|
#netbsd
|
||||||
GOOS=netbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-netbsd-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-netbsd-386.tar.gz" proxy direct blocked
|
||||||
GOOS=netbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-netbsd-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-netbsd-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=netbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-netbsd-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-netbsd-arm.tar.gz" proxy direct blocked
|
||||||
#openbsd
|
#openbsd
|
||||||
GOOS=openbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-openbsd-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=openbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-openbsd-386.tar.gz" proxy direct blocked
|
||||||
GOOS=openbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-openbsd-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-openbsd-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=openbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-openbsd-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-openbsd-arm.tar.gz" proxy direct blocked
|
||||||
#plan9
|
#plan9
|
||||||
GOOS=plan9 GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-plan9-386.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=plan9 GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-plan9-386.tar.gz" proxy direct blocked
|
||||||
GOOS=plan9 GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-plan9-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=plan9 GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-plan9-amd64.tar.gz" proxy direct blocked
|
||||||
GOOS=plan9 GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-plan9-arm.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=plan9 GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-plan9-arm.tar.gz" proxy direct blocked
|
||||||
#solaris
|
#solaris
|
||||||
GOOS=solaris GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
|
CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
|
||||||
#windows
|
#windows
|
||||||
GOOS=windows GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
|
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
|
||||||
GOOS=windows GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
|
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
|
||||||
|
|
||||||
rm -rf proxy proxy.exe .cert
|
rm -rf proxy proxy.exe .cert
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,41 @@ const (
|
|||||||
CONN_CLIENT_MUX = uint8(7)
|
CONN_CLIENT_MUX = uint8(7)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MuxServerArgs struct {
|
||||||
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
Local *string
|
||||||
|
IsUDP *bool
|
||||||
|
Key *string
|
||||||
|
Remote *string
|
||||||
|
Timeout *int
|
||||||
|
Route *[]string
|
||||||
|
Mgr *MuxServerManager
|
||||||
|
IsCompress *bool
|
||||||
|
}
|
||||||
|
type MuxClientArgs struct {
|
||||||
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
Key *string
|
||||||
|
Timeout *int
|
||||||
|
IsCompress *bool
|
||||||
|
}
|
||||||
|
type MuxBridgeArgs struct {
|
||||||
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
Local *string
|
||||||
|
Timeout *int
|
||||||
|
IsCompress *bool
|
||||||
|
}
|
||||||
type TunnelServerArgs struct {
|
type TunnelServerArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
|
|||||||
@ -152,22 +152,26 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
address := req.Host
|
address := req.Host
|
||||||
|
host, _, _ := net.SplitHostPort(address)
|
||||||
useProxy := true
|
useProxy := false
|
||||||
if *s.cfg.Parent == "" {
|
if !utils.IsIternalIP(host) {
|
||||||
useProxy = false
|
|
||||||
} else if *s.cfg.Always {
|
|
||||||
useProxy = true
|
useProxy = true
|
||||||
} else {
|
if *s.cfg.Parent == "" {
|
||||||
if req.IsHTTPS() {
|
useProxy = false
|
||||||
s.checker.Add(address, true, req.Method, "", nil)
|
} else if *s.cfg.Always {
|
||||||
|
useProxy = true
|
||||||
} else {
|
} else {
|
||||||
s.checker.Add(address, false, req.Method, req.URL, req.HeadBuf)
|
if req.IsHTTPS() {
|
||||||
|
s.checker.Add(address, true, req.Method, "", nil)
|
||||||
|
} else {
|
||||||
|
s.checker.Add(address, false, req.Method, req.URL, req.HeadBuf)
|
||||||
|
}
|
||||||
|
//var n, m uint
|
||||||
|
useProxy, _, _ = s.checker.IsBlocked(req.Host)
|
||||||
|
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
||||||
}
|
}
|
||||||
//var n, m uint
|
|
||||||
useProxy, _, _ = s.checker.IsBlocked(req.Host)
|
|
||||||
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("use proxy : %v, %s", useProxy, address)
|
log.Printf("use proxy : %v, %s", useProxy, address)
|
||||||
|
|
||||||
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
||||||
|
|||||||
146
services/mux_bridge.go
Normal file
146
services/mux_bridge.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"proxy/utils"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtaci/smux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MuxBridge struct {
|
||||||
|
cfg MuxBridgeArgs
|
||||||
|
clientControlConns utils.ConcurrentMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMuxBridge() Service {
|
||||||
|
return &MuxBridge{
|
||||||
|
cfg: MuxBridgeArgs{},
|
||||||
|
clientControlConns: utils.NewConcurrentMap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxBridge) InitService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *MuxBridge) CheckArgs() {
|
||||||
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
|
log.Fatalf("cert and key file required")
|
||||||
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
func (s *MuxBridge) StopService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *MuxBridge) Start(args interface{}) (err error) {
|
||||||
|
s.cfg = args.(MuxBridgeArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
s.InitService()
|
||||||
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
sc := utils.NewServerChannel(host, p)
|
||||||
|
|
||||||
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
|
||||||
|
reader := bufio.NewReader(inConn)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var connType uint8
|
||||||
|
var key string
|
||||||
|
err = utils.ReadPacket(reader, &connType, &key)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch connType {
|
||||||
|
case CONN_SERVER:
|
||||||
|
var serverID string
|
||||||
|
err = utils.ReadPacketData(reader, &serverID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("server connection %s %s connected", serverID, key)
|
||||||
|
session, err := smux.Server(inConn, nil)
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("server session error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
stream, err := session.AcceptStream()
|
||||||
|
if err != nil {
|
||||||
|
session.Close()
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go s.callback(stream, serverID, key)
|
||||||
|
}
|
||||||
|
case CONN_CLIENT:
|
||||||
|
|
||||||
|
log.Printf("client connection %s connected", key)
|
||||||
|
session, err := smux.Client(inConn, nil)
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("client session error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.clientControlConns.Set(key, session)
|
||||||
|
//log.Printf("set client session,key: %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("proxy on mux bridge mode %s", (*sc.Listener).Addr())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MuxBridge) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||||
|
try := 20
|
||||||
|
for {
|
||||||
|
try--
|
||||||
|
if try == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
session, ok := s.clientControlConns.Get(key)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("client %s session not exists for server stream %s", key, serverID)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stream, err := session.(*smux.Session).OpenStream()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
log.Printf("%s server %s stream created", key, serverID)
|
||||||
|
die1 := make(chan bool, 1)
|
||||||
|
die2 := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
io.Copy(stream, inConn)
|
||||||
|
die1 <- true
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
io.Copy(inConn, stream)
|
||||||
|
die2 <- true
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-die1:
|
||||||
|
case <-die2:
|
||||||
|
}
|
||||||
|
stream.Close()
|
||||||
|
inConn.Close()
|
||||||
|
log.Printf("%s server %s stream released", key, serverID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
206
services/mux_client.go
Normal file
206
services/mux_client.go
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"proxy/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/snappy"
|
||||||
|
"github.com/xtaci/smux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MuxClient struct {
|
||||||
|
cfg MuxClientArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMuxClient() Service {
|
||||||
|
return &MuxClient{
|
||||||
|
cfg: MuxClientArgs{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxClient) InitService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxClient) CheckArgs() {
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||||
|
} else {
|
||||||
|
log.Fatalf("parent required")
|
||||||
|
}
|
||||||
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
|
log.Fatalf("cert and key file required")
|
||||||
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
func (s *MuxClient) StopService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *MuxClient) Start(args interface{}) (err error) {
|
||||||
|
s.cfg = args.(MuxClientArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
s.InitService()
|
||||||
|
log.Printf("proxy on mux client mode, compress %v", *s.cfg.IsCompress)
|
||||||
|
for {
|
||||||
|
var _conn tls.Conn
|
||||||
|
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connection err: %s, retrying...", err)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn := net.Conn(&_conn)
|
||||||
|
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, *s.cfg.Key))
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
log.Printf("connection err: %s, retrying...", err)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
session, err := smux.Server(conn, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("session err: %s, retrying...", err)
|
||||||
|
conn.Close()
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
stream, err := session.AcceptStream()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("accept stream err: %s, retrying...", err)
|
||||||
|
session.Close()
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
var ID, clientLocalAddr, serverID string
|
||||||
|
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read stream signal err: %s", err)
|
||||||
|
stream.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("signal revecived,server %s stream %s %s", serverID, ID, clientLocalAddr)
|
||||||
|
protocol := clientLocalAddr[:3]
|
||||||
|
localAddr := clientLocalAddr[4:]
|
||||||
|
if protocol == "udp" {
|
||||||
|
s.ServeUDP(stream, localAddr, ID)
|
||||||
|
} else {
|
||||||
|
s.ServeConn(stream, localAddr, ID)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *MuxClient) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||||
|
|
||||||
|
for {
|
||||||
|
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("udp packet revecived fail, err: %s", err)
|
||||||
|
log.Printf("connection %s released", ID)
|
||||||
|
inConn.Close()
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
||||||
|
go s.processUDPPacket(inConn, srcAddr, localAddr, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr string, body []byte) {
|
||||||
|
dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't resolve address: %s", err)
|
||||||
|
inConn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||||
|
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
_, err = conn.Write(body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respBody := buf[0:length]
|
||||||
|
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||||
|
bs := utils.UDPPacket(srcAddr, respBody)
|
||||||
|
_, err = (*inConn).Write(bs)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("send udp response fail ,ERR:%s", err)
|
||||||
|
inConn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
|
||||||
|
}
|
||||||
|
func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
|
||||||
|
var err error
|
||||||
|
var outConn net.Conn
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
i++
|
||||||
|
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
|
||||||
|
if err == nil || i == 3 {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if i == 3 {
|
||||||
|
log.Printf("connect to %s err: %s, retrying...", localAddr, err)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
inConn.Close()
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
log.Printf("build connection error, err: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("stream %s created", ID)
|
||||||
|
if *s.cfg.IsCompress {
|
||||||
|
die1 := make(chan bool, 1)
|
||||||
|
die2 := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
io.Copy(outConn, snappy.NewReader(inConn))
|
||||||
|
die1 <- true
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
io.Copy(snappy.NewWriter(inConn), outConn)
|
||||||
|
die2 <- true
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-die1:
|
||||||
|
case <-die2:
|
||||||
|
}
|
||||||
|
outConn.Close()
|
||||||
|
inConn.Close()
|
||||||
|
log.Printf("%s stream %s released", *s.cfg.Key, ID)
|
||||||
|
} else {
|
||||||
|
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||||
|
log.Printf("stream %s released", ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
333
services/mux_server.go
Normal file
333
services/mux_server.go
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"proxy/utils"
|
||||||
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/snappy"
|
||||||
|
"github.com/xtaci/smux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MuxServer struct {
|
||||||
|
cfg MuxServerArgs
|
||||||
|
udpChn chan MuxUDPItem
|
||||||
|
sc utils.ServerChannel
|
||||||
|
session *smux.Session
|
||||||
|
lockChn chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type MuxServerManager struct {
|
||||||
|
cfg MuxServerArgs
|
||||||
|
udpChn chan MuxUDPItem
|
||||||
|
sc utils.ServerChannel
|
||||||
|
serverID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMuxServerManager() Service {
|
||||||
|
return &MuxServerManager{
|
||||||
|
cfg: MuxServerArgs{},
|
||||||
|
udpChn: make(chan MuxUDPItem, 50000),
|
||||||
|
serverID: utils.Uniqueid(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||||
|
s.cfg = args.(MuxServerArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||||
|
} else {
|
||||||
|
log.Fatalf("parent required")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.InitService()
|
||||||
|
|
||||||
|
log.Printf("server id: %s", s.serverID)
|
||||||
|
//log.Printf("route:%v", *s.cfg.Route)
|
||||||
|
for _, _info := range *s.cfg.Route {
|
||||||
|
if _info == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
IsUDP := *s.cfg.IsUDP
|
||||||
|
if strings.HasPrefix(_info, "udp://") {
|
||||||
|
IsUDP = true
|
||||||
|
}
|
||||||
|
info := strings.TrimPrefix(_info, "udp://")
|
||||||
|
info = strings.TrimPrefix(info, "tcp://")
|
||||||
|
_routeInfo := strings.Split(info, "@")
|
||||||
|
server := NewMuxServer()
|
||||||
|
local := _routeInfo[0]
|
||||||
|
remote := _routeInfo[1]
|
||||||
|
KEY := *s.cfg.Key
|
||||||
|
if strings.HasPrefix(remote, "[") {
|
||||||
|
KEY = remote[1:strings.LastIndex(remote, "]")]
|
||||||
|
remote = remote[strings.LastIndex(remote, "]")+1:]
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(remote, ":") {
|
||||||
|
remote = fmt.Sprintf("127.0.0.1%s", remote)
|
||||||
|
}
|
||||||
|
err = server.Start(MuxServerArgs{
|
||||||
|
CertBytes: s.cfg.CertBytes,
|
||||||
|
KeyBytes: s.cfg.KeyBytes,
|
||||||
|
Parent: s.cfg.Parent,
|
||||||
|
CertFile: s.cfg.CertFile,
|
||||||
|
KeyFile: s.cfg.KeyFile,
|
||||||
|
Local: &local,
|
||||||
|
IsUDP: &IsUDP,
|
||||||
|
Remote: &remote,
|
||||||
|
Key: &KEY,
|
||||||
|
Timeout: s.cfg.Timeout,
|
||||||
|
Mgr: s,
|
||||||
|
IsCompress: s.cfg.IsCompress,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MuxServerManager) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
func (s *MuxServerManager) StopService() {
|
||||||
|
}
|
||||||
|
func (s *MuxServerManager) CheckArgs() {
|
||||||
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
|
log.Fatalf("cert and key file required")
|
||||||
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
func (s *MuxServerManager) InitService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMuxServer() Service {
|
||||||
|
return &MuxServer{
|
||||||
|
cfg: MuxServerArgs{},
|
||||||
|
udpChn: make(chan MuxUDPItem, 50000),
|
||||||
|
lockChn: make(chan bool, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MuxUDPItem struct {
|
||||||
|
packet *[]byte
|
||||||
|
localAddr *net.UDPAddr
|
||||||
|
srcAddr *net.UDPAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxServer) InitService() {
|
||||||
|
s.UDPConnDeamon()
|
||||||
|
}
|
||||||
|
func (s *MuxServer) CheckArgs() {
|
||||||
|
if *s.cfg.Remote == "" {
|
||||||
|
log.Fatalf("remote required")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MuxServer) Start(args interface{}) (err error) {
|
||||||
|
s.cfg = args.(MuxServerArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
s.InitService()
|
||||||
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
s.sc = utils.NewServerChannel(host, p)
|
||||||
|
if *s.cfg.IsUDP {
|
||||||
|
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||||
|
s.udpChn <- MuxUDPItem{
|
||||||
|
packet: &packet,
|
||||||
|
localAddr: localAddr,
|
||||||
|
srcAddr: srcAddr,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("proxy on udp mux server mode %s", (*s.sc.UDPListener).LocalAddr())
|
||||||
|
} else {
|
||||||
|
err = s.sc.ListenTCP(func(inConn net.Conn) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("connection handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var outConn net.Conn
|
||||||
|
var ID string
|
||||||
|
for {
|
||||||
|
outConn, ID, err = s.GetOutConn()
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("%s stream %s created", *s.cfg.Key, ID)
|
||||||
|
if *s.cfg.IsCompress {
|
||||||
|
die1 := make(chan bool, 1)
|
||||||
|
die2 := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
io.Copy(inConn, snappy.NewReader(outConn))
|
||||||
|
die1 <- true
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
io.Copy(snappy.NewWriter(outConn), inConn)
|
||||||
|
die2 <- true
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-die1:
|
||||||
|
case <-die2:
|
||||||
|
}
|
||||||
|
outConn.Close()
|
||||||
|
inConn.Close()
|
||||||
|
log.Printf("%s stream %s released", *s.cfg.Key, ID)
|
||||||
|
} else {
|
||||||
|
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||||
|
log.Printf("%s stream %s released", *s.cfg.Key, ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("proxy on mux server mode %s, compress %v", (*s.sc.Listener).Addr(), *s.cfg.IsCompress)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MuxServer) Clean() {
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||||
|
outConn, err = s.GetConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connection err: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remoteAddr := "tcp:" + *s.cfg.Remote
|
||||||
|
if *s.cfg.IsUDP {
|
||||||
|
remoteAddr = "udp:" + *s.cfg.Remote
|
||||||
|
}
|
||||||
|
ID = utils.Uniqueid()
|
||||||
|
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write stream data err: %s ,retrying...", err)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MuxServer) GetConn() (conn net.Conn, err error) {
|
||||||
|
select {
|
||||||
|
case s.lockChn <- true:
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("can not connect at same time")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
<-s.lockChn
|
||||||
|
}()
|
||||||
|
if s.session == nil {
|
||||||
|
var _conn tls.Conn
|
||||||
|
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
s.session = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c := net.Conn(&_conn)
|
||||||
|
_, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
s.session = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
s.session, err = smux.Client(c, nil)
|
||||||
|
if err != nil {
|
||||||
|
s.session = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn, err = s.session.OpenStream()
|
||||||
|
if err != nil {
|
||||||
|
s.session.Close()
|
||||||
|
s.session = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MuxServer) UDPConnDeamon() {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var outConn net.Conn
|
||||||
|
var ID string
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
item := <-s.udpChn
|
||||||
|
RETRY:
|
||||||
|
if outConn == nil {
|
||||||
|
for {
|
||||||
|
outConn, ID, err = s.GetOutConn()
|
||||||
|
if err != nil {
|
||||||
|
outConn = nil
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
go func(outConn net.Conn, ID string) {
|
||||||
|
go func() {
|
||||||
|
// outConn.Close()
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||||
|
log.Printf("UDP deamon connection %s exited", ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
|
||||||
|
_srcAddr := strings.Split(srcAddrFromConn, ":")
|
||||||
|
if len(_srcAddr) != 2 {
|
||||||
|
log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
port, _ := strconv.Atoi(_srcAddr[1])
|
||||||
|
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||||
|
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//log.Printf("udp response to local %s success , %v", srcAddrFromConn, body)
|
||||||
|
}
|
||||||
|
}(outConn, ID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outConn.SetWriteDeadline(time.Now().Add(time.Second))
|
||||||
|
_, err = outConn.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
|
||||||
|
outConn.SetWriteDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
outConn = nil
|
||||||
|
log.Printf("write udp packet to %s fail ,flush err:%s ,retrying...", *s.cfg.Parent, err)
|
||||||
|
goto RETRY
|
||||||
|
}
|
||||||
|
//log.Printf("write packet %v", *item.packet)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
@ -416,8 +416,14 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||||
} else {
|
} else {
|
||||||
if *s.cfg.Parent != "" {
|
if *s.cfg.Parent != "" {
|
||||||
s.checker.Add(request.Addr(), true, "", "", nil)
|
host, _, _ := net.SplitHostPort(request.Addr())
|
||||||
useProxy, _, _ = s.checker.IsBlocked(request.Addr())
|
useProxy := false
|
||||||
|
if utils.IsIternalIP(host) {
|
||||||
|
useProxy = false
|
||||||
|
} else {
|
||||||
|
s.checker.Add(request.Addr(), true, "", "", nil)
|
||||||
|
useProxy, _, _ = s.checker.IsBlocked(request.Addr())
|
||||||
|
}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
rm -rf /usr/bin/proxy
|
rm -rf /usr/bin/proxy
|
||||||
rm -rf /usr/bin/proxyd
|
|
||||||
echo "uninstall done"
|
echo "uninstall done"
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -20,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
|
"proxy/utils/id"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -301,9 +301,10 @@ func ReadUDPPacket(_reader io.Reader) (srcAddr string, packet []byte, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func Uniqueid() string {
|
func Uniqueid() string {
|
||||||
var src = rand.NewSource(time.Now().UnixNano())
|
return xid.New().String()
|
||||||
s := fmt.Sprintf("%d", src.Int63())
|
// var src = rand.NewSource(time.Now().UnixNano())
|
||||||
return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
// s := fmt.Sprintf("%d", src.Int63())
|
||||||
|
// return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
||||||
}
|
}
|
||||||
func ReadData(r io.Reader) (data string, err error) {
|
func ReadData(r io.Reader) (data string, err error) {
|
||||||
var len uint16
|
var len uint16
|
||||||
@ -453,6 +454,29 @@ func HttpGet(URL string, timeout int) (body []byte, code int, err error) {
|
|||||||
body, err = ioutil.ReadAll(resp.Body)
|
body, err = ioutil.ReadAll(resp.Body)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func IsIternalIP(domainOrIP string) bool {
|
||||||
|
var outIPs []net.IP
|
||||||
|
outIPs, err := net.LookupIP(domainOrIP)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, ip := range outIPs {
|
||||||
|
if ip.IsLoopback() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "10.0.0.0" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "192.168.0.0" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "172.0.0.0" {
|
||||||
|
i, _ := strconv.Atoi(strings.Split(ip.To4().String(), ".")[1])
|
||||||
|
return i >= 16 && i <= 31
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// type sockaddr struct {
|
// type sockaddr struct {
|
||||||
// family uint16
|
// family uint16
|
||||||
|
|||||||
264
utils/id/xid.go
Normal file
264
utils/id/xid.go
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
// Package xid is a globally unique id generator suited for web scale
|
||||||
|
//
|
||||||
|
// Xid is using Mongo Object ID algorithm to generate globally unique ids:
|
||||||
|
// https://docs.mongodb.org/manual/reference/object-id/
|
||||||
|
//
|
||||||
|
// - 4-byte value representing the seconds since the Unix epoch,
|
||||||
|
// - 3-byte machine identifier,
|
||||||
|
// - 2-byte process id, and
|
||||||
|
// - 3-byte counter, starting with a random value.
|
||||||
|
//
|
||||||
|
// The binary representation of the id is compatible with Mongo 12 bytes Object IDs.
|
||||||
|
// The string representation is using base32 hex (w/o padding) for better space efficiency
|
||||||
|
// when stored in that form (20 bytes). The hex variant of base32 is used to retain the
|
||||||
|
// sortable property of the id.
|
||||||
|
//
|
||||||
|
// Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an
|
||||||
|
// issue when transported as a string between various systems. Base36 wasn't retained either
|
||||||
|
// because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned)
|
||||||
|
// and 3/ it would not remain sortable. To validate a base32 `xid`, expect a 20 chars long,
|
||||||
|
// all lowercase sequence of `a` to `v` letters and `0` to `9` numbers (`[0-9a-v]{20}`).
|
||||||
|
//
|
||||||
|
// UUID is 16 bytes (128 bits), snowflake is 8 bytes (64 bits), xid stands in between
|
||||||
|
// with 12 bytes with a more compact string representation ready for the web and no
|
||||||
|
// required configuration or central generation server.
|
||||||
|
//
|
||||||
|
// Features:
|
||||||
|
//
|
||||||
|
// - Size: 12 bytes (96 bits), smaller than UUID, larger than snowflake
|
||||||
|
// - Base32 hex encoded by default (16 bytes storage when transported as printable string)
|
||||||
|
// - Non configured, you don't need set a unique machine and/or data center id
|
||||||
|
// - K-ordered
|
||||||
|
// - Embedded time with 1 second precision
|
||||||
|
// - Unicity guaranted for 16,777,216 (24 bits) unique ids per second and per host/process
|
||||||
|
//
|
||||||
|
// Best used with xlog's RequestIDHandler (https://godoc.org/github.com/rs/xlog#RequestIDHandler).
|
||||||
|
//
|
||||||
|
// References:
|
||||||
|
//
|
||||||
|
// - http://www.slideshare.net/davegardnerisme/unique-id-generation-in-distributed-systems
|
||||||
|
// - https://en.wikipedia.org/wiki/Universally_unique_identifier
|
||||||
|
// - https://blog.twitter.com/2010/announcing-snowflake
|
||||||
|
package xid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Code inspired from mgo/bson ObjectId
|
||||||
|
|
||||||
|
// ID represents a unique request id
|
||||||
|
type ID [rawLen]byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
encodedLen = 20 // string encoded len
|
||||||
|
decodedLen = 15 // len after base32 decoding with the padded data
|
||||||
|
rawLen = 12 // binary raw len
|
||||||
|
|
||||||
|
// encoding stores a custom version of the base32 encoding with lower case
|
||||||
|
// letters.
|
||||||
|
encoding = "0123456789abcdefghijklmnopqrstuv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrInvalidID is returned when trying to unmarshal an invalid ID
|
||||||
|
var ErrInvalidID = errors.New("xid: invalid ID")
|
||||||
|
|
||||||
|
// objectIDCounter is atomically incremented when generating a new ObjectId
|
||||||
|
// using NewObjectId() function. It's used as a counter part of an id.
|
||||||
|
// This id is initialized with a random value.
|
||||||
|
var objectIDCounter = randInt()
|
||||||
|
|
||||||
|
// machineId stores machine id generated once and used in subsequent calls
|
||||||
|
// to NewObjectId function.
|
||||||
|
var machineID = readMachineID()
|
||||||
|
|
||||||
|
// pid stores the current process id
|
||||||
|
var pid = os.Getpid()
|
||||||
|
|
||||||
|
// dec is the decoding map for base32 encoding
|
||||||
|
var dec [256]byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < len(dec); i++ {
|
||||||
|
dec[i] = 0xFF
|
||||||
|
}
|
||||||
|
for i := 0; i < len(encoding); i++ {
|
||||||
|
dec[encoding[i]] = byte(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// readMachineId generates machine id and puts it into the machineId global
|
||||||
|
// variable. If this function fails to get the hostname, it will cause
|
||||||
|
// a runtime error.
|
||||||
|
func readMachineID() []byte {
|
||||||
|
id := make([]byte, 3)
|
||||||
|
if hostname, err := os.Hostname(); err == nil {
|
||||||
|
hw := md5.New()
|
||||||
|
hw.Write([]byte(hostname))
|
||||||
|
copy(id, hw.Sum(nil))
|
||||||
|
} else {
|
||||||
|
// Fallback to rand number if machine id can't be gathered
|
||||||
|
if _, randErr := rand.Reader.Read(id); randErr != nil {
|
||||||
|
panic(fmt.Errorf("xid: cannot get hostname nor generate a random number: %v; %v", err, randErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// randInt generates a random uint32
|
||||||
|
func randInt() uint32 {
|
||||||
|
b := make([]byte, 3)
|
||||||
|
if _, err := rand.Reader.Read(b); err != nil {
|
||||||
|
panic(fmt.Errorf("xid: cannot generate random number: %v;", err))
|
||||||
|
}
|
||||||
|
return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
// New generates a globaly unique ID
|
||||||
|
func New() ID {
|
||||||
|
var id ID
|
||||||
|
// Timestamp, 4 bytes, big endian
|
||||||
|
binary.BigEndian.PutUint32(id[:], uint32(time.Now().Unix()))
|
||||||
|
// Machine, first 3 bytes of md5(hostname)
|
||||||
|
id[4] = machineID[0]
|
||||||
|
id[5] = machineID[1]
|
||||||
|
id[6] = machineID[2]
|
||||||
|
// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
|
||||||
|
id[7] = byte(pid >> 8)
|
||||||
|
id[8] = byte(pid)
|
||||||
|
// Increment, 3 bytes, big endian
|
||||||
|
i := atomic.AddUint32(&objectIDCounter, 1)
|
||||||
|
id[9] = byte(i >> 16)
|
||||||
|
id[10] = byte(i >> 8)
|
||||||
|
id[11] = byte(i)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString reads an ID from its string representation
|
||||||
|
func FromString(id string) (ID, error) {
|
||||||
|
i := &ID{}
|
||||||
|
err := i.UnmarshalText([]byte(id))
|
||||||
|
return *i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a base32 hex lowercased with no padding representation of the id (char set is 0-9, a-v).
|
||||||
|
func (id ID) String() string {
|
||||||
|
text := make([]byte, encodedLen)
|
||||||
|
encode(text, id[:])
|
||||||
|
return string(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding/text TextMarshaler interface
|
||||||
|
func (id ID) MarshalText() ([]byte, error) {
|
||||||
|
text := make([]byte, encodedLen)
|
||||||
|
encode(text, id[:])
|
||||||
|
return text, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode by unrolling the stdlib base32 algorithm + removing all safe checks
|
||||||
|
func encode(dst, id []byte) {
|
||||||
|
dst[0] = encoding[id[0]>>3]
|
||||||
|
dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F]
|
||||||
|
dst[2] = encoding[(id[1]>>1)&0x1F]
|
||||||
|
dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F]
|
||||||
|
dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F]
|
||||||
|
dst[5] = encoding[(id[3]>>2)&0x1F]
|
||||||
|
dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F]
|
||||||
|
dst[7] = encoding[id[4]&0x1F]
|
||||||
|
dst[8] = encoding[id[5]>>3]
|
||||||
|
dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F]
|
||||||
|
dst[10] = encoding[(id[6]>>1)&0x1F]
|
||||||
|
dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F]
|
||||||
|
dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F]
|
||||||
|
dst[13] = encoding[(id[8]>>2)&0x1F]
|
||||||
|
dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F]
|
||||||
|
dst[15] = encoding[id[9]&0x1F]
|
||||||
|
dst[16] = encoding[id[10]>>3]
|
||||||
|
dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F]
|
||||||
|
dst[18] = encoding[(id[11]>>1)&0x1F]
|
||||||
|
dst[19] = encoding[(id[11]<<4)&0x1F]
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding/text TextUnmarshaler interface
|
||||||
|
func (id *ID) UnmarshalText(text []byte) error {
|
||||||
|
if len(text) != encodedLen {
|
||||||
|
return ErrInvalidID
|
||||||
|
}
|
||||||
|
for _, c := range text {
|
||||||
|
if dec[c] == 0xFF {
|
||||||
|
return ErrInvalidID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decode(id, text)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode by unrolling the stdlib base32 algorithm + removing all safe checks
|
||||||
|
func decode(id *ID, src []byte) {
|
||||||
|
id[0] = dec[src[0]]<<3 | dec[src[1]]>>2
|
||||||
|
id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4
|
||||||
|
id[2] = dec[src[3]]<<4 | dec[src[4]]>>1
|
||||||
|
id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3
|
||||||
|
id[4] = dec[src[6]]<<5 | dec[src[7]]
|
||||||
|
id[5] = dec[src[8]]<<3 | dec[src[9]]>>2
|
||||||
|
id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4
|
||||||
|
id[7] = dec[src[11]]<<4 | dec[src[12]]>>1
|
||||||
|
id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3
|
||||||
|
id[9] = dec[src[14]]<<5 | dec[src[15]]
|
||||||
|
id[10] = dec[src[16]]<<3 | dec[src[17]]>>2
|
||||||
|
id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the timestamp part of the id.
|
||||||
|
// It's a runtime error to call this method with an invalid id.
|
||||||
|
func (id ID) Time() time.Time {
|
||||||
|
// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
|
||||||
|
secs := int64(binary.BigEndian.Uint32(id[0:4]))
|
||||||
|
return time.Unix(secs, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine returns the 3-byte machine id part of the id.
|
||||||
|
// It's a runtime error to call this method with an invalid id.
|
||||||
|
func (id ID) Machine() []byte {
|
||||||
|
return id[4:7]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pid returns the process id part of the id.
|
||||||
|
// It's a runtime error to call this method with an invalid id.
|
||||||
|
func (id ID) Pid() uint16 {
|
||||||
|
return binary.BigEndian.Uint16(id[7:9])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter returns the incrementing value part of the id.
|
||||||
|
// It's a runtime error to call this method with an invalid id.
|
||||||
|
func (id ID) Counter() int32 {
|
||||||
|
b := id[9:12]
|
||||||
|
// Counter is stored as big-endian 3-byte value
|
||||||
|
return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver.Valuer interface.
|
||||||
|
func (id ID) Value() (driver.Value, error) {
|
||||||
|
b, err := id.MarshalText()
|
||||||
|
return string(b), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the sql.Scanner interface.
|
||||||
|
func (id *ID) Scan(value interface{}) (err error) {
|
||||||
|
switch val := value.(type) {
|
||||||
|
case string:
|
||||||
|
return id.UnmarshalText([]byte(val))
|
||||||
|
case []byte:
|
||||||
|
return id.UnmarshalText(val)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("xid: scanning unsupported type: %T", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user