28 Commits
v3.8 ... v4.1

Author SHA1 Message Date
snail007
bd4741a0a0 Update README.md 2018-01-23 21:32:37 +08:00
snail007
9a9dc2594d Merge pull request #20 from wujunze/patch-1
修正文档参数
2018-01-15 18:05:45 +08:00
Panda
02547e9475 修正文档参数
修正文档参数
2018-01-15 16:31:08 +08:00
arraykeys@gmail.com
9749db9235 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-05 11:48:32 +08:00
arraykeys@gmail.com
e35ddc4d53 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-05 11:18:40 +08:00
arraykeys@gmail.com
99b06e813e Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-05 10:27:51 +08:00
arraykeys@gmail.com
7164349944 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-04 11:07:23 +08:00
arraykeys@gmail.com
bf43b3adee Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-04 10:35:44 +08:00
arraykeys
6aa4b3c8a9 no message 2017-12-02 21:14:11 +08:00
arraykeys
7a9f7ef95e no message 2017-12-02 14:25:18 +08:00
arraykeys
ee1a9d3ec7 no message 2017-12-02 14:24:30 +08:00
arraykeys
6a69e58be5 no message 2017-12-02 14:22:14 +08:00
arraykeys
6e1d788677 no message 2017-12-02 14:21:21 +08:00
arraykeys
24f8f789c5 no message 2017-12-02 14:20:15 +08:00
arraykeys
2fb779f990 no message 2017-12-02 14:18:53 +08:00
arraykeys
0a9d3cd309 no message 2017-12-02 14:16:16 +08:00
arraykeys
977b1aba1c no message 2017-12-02 14:02:17 +08:00
arraykeys
a02aeeb906 no message 2017-12-01 23:52:21 +08:00
arraykeys
7e2e63137e no message 2017-12-01 22:14:07 +08:00
arraykeys@gmail.com
4b35219c27 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-12-01 18:01:59 +08:00
arraykeys@gmail.com
0247c4701d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 18:43:31 +08:00
arraykeys@gmail.com
e2cd0b8e4f Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 16:50:47 +08:00
arraykeys@gmail.com
ee93171c63 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 15:37:27 +08:00
arraykeys@gmail.com
ddd2302cb2 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 15:37:01 +08:00
arraykeys@gmail.com
c96d2288b3 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 15:33:32 +08:00
arraykeys@gmail.com
6f5a088091 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-30 14:25:44 +08:00
arraykeys@gmail.com
9a07797e29 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-27 12:44:43 +08:00
arraykeys@gmail.com
055a020d33 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-27 12:41:12 +08:00
16 changed files with 1300 additions and 156 deletions

View File

@ -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版的内网穿透对应的子命令分别是serverclientbridge
使用方式和参数与之前的子命令tservertclienttserver完全一样另外serverclient增加了
压缩传输参数--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
View File

@ -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. 多链接版本对应的子命令是tservertclienttbridge。
1. 多路复用版本对应的子命令是serverclientbridge。
1. 多链接版本和多路复用版本的参数和使用方式完全一样。
1. **多路复用版本的serverclient可以开启压缩传输参数是--c。**
1. **serverclient要么都开启压缩要么都不开启不能只开一个。**
下面的教程以“多路复用版本”为例子,说明使用方法。
内网穿透由三部分组成: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
View File

@ -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 {

View File

@ -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/

View File

@ -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
View File

@ -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
} }
}() }()

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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
View 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)
}
}()
}

View File

@ -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 {

View File

@ -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"

View File

@ -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
View 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)
}
}