72 Commits
v3.4 ... 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
arraykeys@gmail.com
4681ff3827 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-27 12:21:59 +08:00
arraykeys@gmail.com
cff92faf06 Merge branch 'master' of https://github.com/snail007/goproxy.git into dev 2017-11-27 11:28:24 +08:00
arraykeys@gmail.com
890daf5489 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2017-11-27 11:28:17 +08:00
snail007
182bdeb766 Merge pull request #14 from snail007/dev
Update README.md
2017-11-23 19:27:53 -06:00
snail007
a4a953b167 Update README.md 2017-11-24 09:27:07 +08:00
arraykeys@gmail.com
ff37b7e18c Merge branch 'dev' 2017-11-21 14:03:24 +08:00
arraykeys@gmail.com
7aa0e78c15 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-21 14:02:28 +08:00
arraykeys@gmail.com
d798807693 Merge branch 'dev' 2017-11-14 11:58:06 +08:00
arraykeys@gmail.com
35b78c2da6 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-14 11:57:56 +08:00
arraykeys@gmail.com
66a4291c97 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-14 11:56:24 +08:00
arraykeys@gmail.com
e89a965aff Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-14 10:02:51 +08:00
arraykeys@gmail.com
85a9f10be4 Merge branch 'dev' 2017-11-09 13:11:57 +08:00
arraykeys@gmail.com
8bc6e0ffec Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-09 13:11:47 +08:00
arraykeys@gmail.com
98fc0ade4a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-07 11:31:12 +08:00
arraykeys@gmail.com
f5626c21f7 Merge branch 'dev' 2017-11-07 10:52:31 +08:00
arraykeys@gmail.com
b5a76c7ff2 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-07 10:52:23 +08:00
arraykeys@gmail.com
612bae4c93 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-07 10:46:09 +08:00
arraykeys@gmail.com
e45bf338cb Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 19:16:52 +08:00
arraykeys@gmail.com
577261806c Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 19:05:32 +08:00
arraykeys@gmail.com
8842097bd4 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 15:23:25 +08:00
arraykeys@gmail.com
a4b14dd0bd Merge branch 'dev' 2017-11-03 13:51:39 +08:00
arraykeys@gmail.com
94f0142c7d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 13:51:27 +08:00
arraykeys@gmail.com
319affa43f Merge branch 'master' of https://github.com/snail007/goproxy.git 2017-11-03 13:30:06 +08:00
arraykeys@gmail.com
14f43a5976 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 13:27:36 +08:00
arraykeys@gmail.com
9e9a9ac6de Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 12:50:50 +08:00
arraykeys@gmail.com
cc24cfc26f Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-03 11:11:53 +08:00
arraykeys@gmail.com
712f7dae4a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-02 17:52:41 +08:00
arraykeys@gmail.com
6d20908465 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-11-01 11:20:25 +08:00
arraykeys@gmail.com
e2f0fe71f4 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-30 14:20:13 +08:00
arraykeys@gmail.com
1241b74562 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:35:39 +08:00
arraykeys@gmail.com
2d610003d5 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:34:36 +08:00
arraykeys@gmail.com
7b2952f4d6 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:33:00 +08:00
arraykeys@gmail.com
b18c5e08bb Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:31:39 +08:00
arraykeys@gmail.com
63cb67f009 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:30:32 +08:00
arraykeys@gmail.com
cd212cb978 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 18:29:37 +08:00
arraykeys@gmail.com
d934c1fb4a Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2017-10-27 16:53:59 +08:00
arraykeys@gmail.com
c8327b4075 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 16:52:54 +08:00
snail007
8410930d2d Update README.md 2017-10-27 16:29:52 +08:00
arraykeys@gmail.com
f5218a93f6 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2017-10-27 16:06:41 +08:00
arraykeys@gmail.com
ca2f367950 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-27 15:59:49 +08:00
snail007
c8559b757f Merge pull request #9 from snail007/dev
Update README.md
2017-10-26 20:01:14 +08:00
snail007
db620ebe83 Update README.md 2017-10-26 19:59:45 +08:00
arraykeys@gmail.com
abc7a4fa42 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-26 17:13:02 +08:00
arraykeys@gmail.com
b02d75eb3a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2017-10-26 15:45:24 +08:00
21 changed files with 1926 additions and 461 deletions

View File

@ -1,4 +1,41 @@
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
1.增加了日志输出到文件--log参数,比如: --log proxy.log,日志就会输出到proxy.log方便排除问题.
v3.7
1.修复了socks代理不能正常和上级代理通讯的问题.
v3.6
1.http(s),socks代理,集成了外部HTTP API认证,可以通过外部API对用户名和密码进行认证.
2.手册http(s),socks代理认证部分增加了集成外部HTTP API认证的使用说明.
v3.5
1.优化了kcp参数,速度有所提升.
2.修复了socks无法正常工作的问题.
3.修正了文档中的一些描述.
4.tcp代理增加了kcp协议传输数据.
5.优化了死循环检查,增加了添加本地IP参数,当VPS在nat设备后面,
vps上网卡IP都是内网IP,这个时候可以通过-g参数添加vps的外网ip防止死循环.
6.增加了--daemon参数,可以后台运行程序哟.
v3.4 v3.4
1.socks5代理新增了用户名密码验证支持. 1.socks5代理新增了用户名密码验证支持.
2.socks5,http(s)代理增加了kcp传输协议支持. 2.socks5,http(s)代理增加了kcp传输协议支持.

199
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,11 +12,14 @@ 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.
- HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网. - SSH中转,HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
- [KCP](https://github.com/xtaci/kcp-go)协议支持,HTTP(S),SOCKS5代理支持KCP协议传输数据,降低延迟,提升浏览体验.
- 集成外部APIHTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成可以方便的通过外部系统控制代理用户
### Why need these? ### Why need these?
- 当由于安全因素或者限制,我们不能顺畅的访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道,顺畅的访问我们的服务. - 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.  
- 微信接口本地开发,方便调试. - 微信接口本地开发,方便调试.
- 远程访问内网机器. - 远程访问内网机器.
- 和小伙伴一起玩局域网游戏. - 和小伙伴一起玩局域网游戏.
@ -25,21 +28,34 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- ...   - ...  
本页是v3.4手册,其他版本手册请点击下面链接查看. 本页是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.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)
- [v3.2手册](https://github.com/snail007/goproxy/tree/v3.2) - [v3.2手册](https://github.com/snail007/goproxy/tree/v3.2)
- [v3.1手册](https://github.com/snail007/goproxy/tree/v3.1) - [v3.1手册](https://github.com/snail007/goproxy/tree/v3.1)
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0) - [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2) - [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)
### 怎么找到组织?
[点击加入交流组织](https://gitter.im/go-proxy/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
### 安装 ### 安装
1. [快速安装](#自动安装) 1. [快速安装](#自动安装)
1. [手动安装](#手动安装) 1. [手动安装](#手动安装)
### 首次使用必看 ### 首次使用必看
- [环境](#使用教程) - [环境](#首次使用必看-1)
- [使用配置文件](#使用配置文件) - [使用配置文件](#使用配置文件)
- [调试输出](#调试输出)
- [使用日志文件](#使用日志文件)
- [后台运行](#后台运行)
- [守护运行](#守护运行)
- [生成通讯证书文件](#生成加密通讯需要的证书文件) - [生成通讯证书文件](#生成加密通讯需要的证书文件)
- [安全建议](#安全建议)
### 手册目录 ### 手册目录
- [1. HTTP代理](#1http代理) - [1. HTTP代理](#1http代理)
@ -52,7 +68,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [1.7 通过SSH中转](#17https通过ssh中转) - [1.7 通过SSH中转](#17https通过ssh中转)
- [1.7.1 用户名和密码的方式](#171-ssh用户名和密码的方式) - [1.7.1 用户名和密码的方式](#171-ssh用户名和密码的方式)
- [1.7.2 用户名和密钥的方式](#172-ssh用户名和密钥的方式) - [1.7.2 用户名和密钥的方式](#172-ssh用户名和密钥的方式)
- [1.8 KCP协议传输](#18KCP协议传输) - [1.8 KCP协议传输](#18kcp协议传输)
- [1.9 查看帮助](#19查看帮助) - [1.9 查看帮助](#19查看帮助)
- [2. TCP代理](#2tcp代理) - [2. TCP代理](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理) - [2.1 普通一级TCP代理](#21普通一级tcp代理)
@ -62,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原理说明)
@ -75,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代理)
@ -87,7 +103,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [5.6.1 用户名和密码的方式](#561-ssh用户名和密码的方式) - [5.6.1 用户名和密码的方式](#561-ssh用户名和密码的方式)
- [5.6.2 用户名和密钥的方式](#562-ssh用户名和密钥的方式) - [5.6.2 用户名和密钥的方式](#562-ssh用户名和密钥的方式)
- [5.7 认证](#57认证) - [5.7 认证](#57认证)
- [5.8 KCP协议传输](#58KCP协议传输) - [5.8 KCP协议传输](#58kcp协议传输)
- [5.9 查看帮助](#59查看帮助) - [5.9 查看帮助](#59查看帮助)
### Fast Start ### Fast Start
@ -101,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.1fix/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
@ -124,9 +132,9 @@ chmod +x install.sh
./install.sh ./install.sh
``` ```
## 使用教程 ## **首次使用必看**
#### **提示** #### **环境**
接下来的教程,默认系统是linux,程序是proxy所有操作需要root权限 接下来的教程,默认系统是linux,程序是proxy所有操作需要root权限
如果你的是windows,请使用windows版本的proxy.exe即可. 如果你的是windows,请使用windows版本的proxy.exe即可.
@ -141,14 +149,40 @@ http
--local-type=tcp --local-type=tcp
--local=:33080 --local=:33080
``` ```
### 0.生成加密通讯需要的证书文件 ### **调试输出**
默认情况下,日志输出的信息不包含文件行数,某些情况下为了排除程序问题,快速定位问题,
可以使用--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。
### 1.HTTP代理 ### **后台运行**
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
比如:
`./proxy http -t tcp -p "0.0.0.0:38080" --daemon`
### **守护运行**
守护运行参数--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外网ip是23.23.23.23,下面命令通过-g参数设置23.23.23.23
`./proxy http -g "23.23.23.23"`
### **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"`
@ -188,7 +222,21 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
多个用户,重复-a参数即可. 多个用户,重复-a参数即可.
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定. 也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
`./proxy http -t tcp -p ":33080" -F auth-file.txt` `./proxy http -t tcp -p ":33080" -F auth-file.txt`
如果没有-a或-F参数,就是关闭Basic认证.
另外,http(s)代理还集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
其它情况认为认证失败.
比如:
`./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,target四个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
user:用户名
pass:密码
ip:用户的IP,比如:192.168.1.200
target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80
如果没有-a或-F或--auth-url参数,就是关闭Basic认证.
#### **1.6.HTTP代理流量强制走上级HTTP代理** #### **1.6.HTTP代理流量强制走上级HTTP代理**
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理. 默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理.
@ -211,7 +259,7 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
KCP协议需要-B参数设置一个密码用于加密解密数据 KCP协议需要-B参数设置一个密码用于加密解密数据
一级HTTP代理(VPS,IP:22.22.22.22) 一级HTTP代理(VPS,IP:22.22.22.22)
`./proxy http -t kcp -p ":38080" -B mypassword `./proxy http -t kcp -p ":38080" -B mypassword`
二级HTTP代理(本地Linux) 二级HTTP代理(本地Linux)
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword` `./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
@ -220,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代理**
本地执行: 本地执行:
@ -245,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端口.
@ -262,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代理**
本地执行: 本地执行:
@ -287,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端口.
@ -304,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端,并连接内网目标端口;
@ -324,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. 完成
@ -346,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. 完成
@ -364,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 --udp -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. 完成
@ -383,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. 完成
@ -410,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.
@ -434,12 +490,12 @@ 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代理,只支持TCP协议,不支持UDP协议,不支持用户名密码认证. 提示: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"`
@ -495,13 +551,26 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
多个用户,重复-a参数即可. 多个用户,重复-a参数即可.
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定. 也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
`./proxy socks -t tcp -p ":33080" -F auth-file.txt` `./proxy socks -t tcp -p ":33080" -F auth-file.txt`
如果没有-a或-F参数,就是关闭认证.
另外,socks5代理还集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
其它情况认为认证失败.
比如:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,三个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}
user:用户名
pass:密码
ip:用户的IP,比如:192.168.1.200
如果没有-a或-F或--auth-url参数,就是关闭认证.
#### **5.8.KCP协议传输** #### **5.8.KCP协议传输**
KCP协议需要-B参数设置一个密码用于加密解密数据 KCP协议需要-B参数设置一个密码用于加密解密数据
一级HTTP代理(VPS,IP:22.22.22.22) 一级HTTP代理(VPS,IP:22.22.22.22)
`./proxy socks -t kcp -p ":38080" -B mypassword `./proxy socks -t kcp -p ":38080" -B mypassword`
二级HTTP代理(本地Linux) 二级HTTP代理(本地Linux)
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword` `./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
@ -512,7 +581,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
### TODO ### TODO
- http,socks代理多个上级负载均衡? - http,socks代理多个上级负载均衡?
- 内网穿透server<->bridge心跳机制? - http(s)代理增加pac支持?
- 欢迎加群反馈... - 欢迎加群反馈...
### 如何使用源码? ### 如何使用源码?

140
config.go
View File

@ -1,11 +1,14 @@
package main package main
import ( import (
"bufio"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"proxy/services" "proxy/services"
"proxy/utils" "proxy/utils"
"time"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
@ -13,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) {
@ -30,12 +34,19 @@ 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
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
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()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String()
//########http######### //########http#########
http := app.Command("http", "proxy on http mode") http := app.Command("http", "proxy on http mode")
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
@ -60,18 +71,25 @@ func initConfig() (err error) {
httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String() httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
httpArgs.KCPKey = http.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() httpArgs.KCPKey = http.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
httpArgs.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() httpArgs.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
httpArgs.AuthURLOkCode = http.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
//########tcp######### //########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode") tcp := app.Command("tcp", "proxy on tcp mode")
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String() tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('t').Default("2000").Int() tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp") tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.IsTLS = tcp.Flag("tls", "proxy on tls mode").Default("false").Bool() tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
tcpArgs.KCPKey = tcp.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
tcpArgs.KCPMethod = tcp.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
//########udp######### //########udp#########
udp := app.Command("udp", "proxy on udp mode") udp := app.Command("udp", "proxy on udp mode")
@ -84,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()
@ -92,7 +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()
//########tunnel-client######### //########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode") tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
@ -132,6 +177,11 @@ func initConfig() (err error) {
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
socksArgs.KCPKey = socks.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String() socksArgs.KCPKey = socks.Flag("kcp-key", "key for kcp encrypt/decrypt data").Short('B').Default("encrypt").String()
socksArgs.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String() socksArgs.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
//parse args //parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
@ -142,7 +192,84 @@ func initConfig() (err error) {
flags |= log.Ltime flags |= log.Ltime
} }
log.SetFlags(flags) log.SetFlags(flags)
poster()
if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil {
log.Fatal(e)
}
log.SetOutput(f)
}
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()
}
//regist services and run service //regist services and run service
services.Regist("http", services.NewHTTP(), httpArgs) services.Regist("http", services.NewHTTP(), httpArgs)
services.Regist("tcp", services.NewTCP(), tcpArgs) services.Regist("tcp", services.NewTCP(), tcpArgs)
@ -150,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.4/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.4" 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.4" VER="4.0"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert
@ -9,55 +9,64 @@ cd .cert
cd .. cd ..
rm -rf ${RELEASE} rm -rf ${RELEASE}
mkdir ${RELEASE} mkdir ${RELEASE}
set 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
#todo
#1.release.sh VER="xxx"
#2.main.go APP_VERSION="xxx"
#3.install_auto.sh goproxy/releases/download/vxxx
#4.README goproxy/releases/download/vxxx

View File

@ -16,8 +16,45 @@ const (
CONN_SERVER_HEARBEAT = uint8(3) CONN_SERVER_HEARBEAT = uint8(3)
CONN_SERVER = uint8(4) CONN_SERVER = uint8(4)
CONN_CLIENT = uint8(5) CONN_CLIENT = uint8(5)
CONN_SERVER_MUX = uint8(6)
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
@ -31,6 +68,7 @@ type TunnelServerArgs struct {
Timeout *int Timeout *int
Route *[]string Route *[]string
Mgr *TunnelServerManager Mgr *TunnelServerManager
Mux *bool
} }
type TunnelClientArgs struct { type TunnelClientArgs struct {
Parent *string Parent *string
@ -40,6 +78,7 @@ type TunnelClientArgs struct {
KeyBytes []byte KeyBytes []byte
Key *string Key *string
Timeout *int Timeout *int
Mux *bool
} }
type TunnelBridgeArgs struct { type TunnelBridgeArgs struct {
Parent *string Parent *string
@ -49,6 +88,7 @@ type TunnelBridgeArgs struct {
KeyBytes []byte KeyBytes []byte
Local *string Local *string
Timeout *int Timeout *int
Mux *bool
} }
type TCPArgs struct { type TCPArgs struct {
Parent *string Parent *string
@ -58,10 +98,12 @@ type TCPArgs struct {
KeyBytes []byte KeyBytes []byte
Local *string Local *string
ParentType *string ParentType *string
IsTLS *bool LocalType *string
Timeout *int Timeout *int
PoolSize *int PoolSize *int
CheckParentInterval *int CheckParentInterval *int
KCPMethod *string
KCPKey *string
} }
type HTTPArgs struct { type HTTPArgs struct {
@ -78,6 +120,10 @@ type HTTPArgs struct {
Direct *string Direct *string
AuthFile *string AuthFile *string
Auth *[]string Auth *[]string
AuthURL *string
AuthURLOkCode *int
AuthURLTimeout *int
AuthURLRetry *int
ParentType *string ParentType *string
LocalType *string LocalType *string
Timeout *int Timeout *int
@ -91,6 +137,7 @@ type HTTPArgs struct {
SSHAuthMethod ssh.AuthMethod SSHAuthMethod ssh.AuthMethod
KCPMethod *string KCPMethod *string
KCPKey *string KCPKey *string
LocalIPS *[]string
} }
type UDPArgs struct { type UDPArgs struct {
Parent *string Parent *string
@ -126,15 +173,25 @@ type SocksArgs struct {
Direct *string Direct *string
AuthFile *string AuthFile *string
Auth *[]string Auth *[]string
AuthURL *string
AuthURLOkCode *int
AuthURLTimeout *int
AuthURLRetry *int
KCPMethod *string KCPMethod *string
KCPKey *string KCPKey *string
UDPParent *string UDPParent *string
UDPLocal *string UDPLocal *string
LocalIPS *[]string
} }
func (a *TCPArgs) Protocol() string { func (a *TCPArgs) Protocol() string {
if *a.IsTLS { switch *a.LocalType {
return "tls" case TYPE_TLS:
return TYPE_TLS
case TYPE_TCP:
return TYPE_TCP
case TYPE_KCP:
return TYPE_KCP
} }
return "tcp" return "unknown"
} }

View File

@ -146,28 +146,32 @@ func (s *HTTP) callback(inConn net.Conn) {
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth) req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
log.Printf("decoder error , form %s, ERR:%s", err, inConn.RemoteAddr()) log.Printf("decoder error , from %s, ERR:%s", inConn.RemoteAddr(), err)
} }
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
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)
@ -223,7 +227,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} }
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") { if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标 //https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
@ -238,12 +242,10 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} }
} }
utils.IoBind((*inConn), outConn, func(err error) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s - %s - %s released [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host) log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
utils.CloseConn(inConn)
utils.CloseConn(&outConn)
}) })
log.Printf("conn %s - %s - %s - %s connected [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host) log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
return return
} }
@ -324,6 +326,10 @@ func (s *HTTP) InitOutConnPool() {
} }
func (s *HTTP) InitBasicAuth() (err error) { func (s *HTTP) InitBasicAuth() (err error) {
s.basicAuth = utils.NewBasicAuth() s.basicAuth = utils.NewBasicAuth()
if *s.cfg.AuthURL != "" {
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
log.Printf("auth from %s", *s.cfg.AuthURL)
}
if *s.cfg.AuthFile != "" { if *s.cfg.AuthFile != "" {
var n = 0 var n = 0
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile) n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
@ -340,7 +346,7 @@ func (s *HTTP) InitBasicAuth() (err error) {
return return
} }
func (s *HTTP) IsBasicAuth() bool { func (s *HTTP) IsBasicAuth() bool {
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
} }
func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool { func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
inIP, inPort, err := net.SplitHostPort(inLocalAddr) inIP, inPort, err := net.SplitHostPort(inLocalAddr)
@ -362,6 +368,9 @@ func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
} }
} }
interfaceIPs, err := utils.GetAllInterfaceAddr() interfaceIPs, err := utils.GetAllInterfaceAddr()
for _, ip := range *s.cfg.LocalIPS {
interfaceIPs = append(interfaceIPs, net.ParseIP(ip).To4())
}
if err == nil { if err == nil {
for _, localIP := range interfaceIPs { for _, localIP := range interfaceIPs {
for _, outIP := range outIPs { for _, outIP := range outIPs {

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

@ -10,6 +10,7 @@ import (
"proxy/utils/aes" "proxy/utils/aes"
"proxy/utils/socks" "proxy/utils/socks"
"runtime/debug" "runtime/debug"
"strings"
"time" "time"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -167,6 +168,11 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
log.Printf("parse udp packet fail, ERR:%s", err) log.Printf("parse udp packet fail, ERR:%s", err)
return return
} }
//防止死循环
if s.IsDeadLoop((*localAddr).String(), p.Host()) {
log.Printf("dead loop detected , %s", p.Host())
return
}
//log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port()) //log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port())
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
//有上级代理,转发给上级 //有上级代理,转发给上级
@ -288,8 +294,8 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
inConn.Close()
} }
utils.CloseConn(&inConn)
}() }()
//协商开始 //协商开始
@ -348,7 +354,8 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
pass := string(r[2+r[1]+1:]) pass := string(r[2+r[1]+1:])
//log.Printf("user:%s,pass:%s", user, pass) //log.Printf("user:%s,pass:%s", user, pass)
//auth //auth
if s.basicAuth.CheckUserPass(user, pass) { _addr := strings.Split(inConn.RemoteAddr().String(), ":")
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
inConn.Write([]byte{0x01, 0x00}) inConn.Write([]byte{0x01, 0x00})
} else { } else {
inConn.Write([]byte{0x01, 0x01}) inConn.Write([]byte{0x01, 0x01})
@ -393,18 +400,30 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
} }
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
var outConn net.Conn var outConn net.Conn
defer utils.CloseConn(&outConn)
var err interface{} var err interface{}
useProxy := true useProxy := true
tryCount := 0 tryCount := 0
maxTryCount := 5 maxTryCount := 5
//防止死循环
if s.IsDeadLoop((*inConn).LocalAddr().String(), request.Host()) {
utils.CloseConn(inConn)
log.Printf("dead loop detected , %s", request.Host())
utils.CloseConn(inConn)
return
}
for { for {
if *s.cfg.Always { if *s.cfg.Always {
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 {
@ -412,10 +431,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
} }
} else { } else {
outConn, err = utils.ConnectHost(request.Addr(), *s.cfg.Timeout) outConn, err = utils.ConnectHost(request.Addr(), *s.cfg.Timeout)
useProxy = false
} }
} }
tryCount++ tryCount++
if err == nil || tryCount > maxTryCount { if err == nil || tryCount > maxTryCount || *s.cfg.Parent == "" {
break break
} else { } else {
log.Printf("get out conn fail,%s,retrying...", err) log.Printf("get out conn fail,%s,retrying...", err)
@ -431,13 +451,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
request.TCPReply(socks.REP_SUCCESS) request.TCPReply(socks.REP_SUCCESS)
inAddr := (*inConn).RemoteAddr().String() inAddr := (*inConn).RemoteAddr().String()
inLocalAddr := (*inConn).LocalAddr().String() //inLocalAddr := (*inConn).LocalAddr().String()
log.Printf("conn %s - %s connected [%s]", inAddr, inLocalAddr, request.Addr()) log.Printf("conn %s - %s connected", inAddr, request.Addr())
utils.IoBind(*inConn, outConn, func(err error) { utils.IoBind(*inConn, outConn, func(err interface{}) {
log.Printf("conn %s - %s released [%s]", inAddr, inLocalAddr, request.Addr()) log.Printf("conn %s - %s released", inAddr, request.Addr())
utils.CloseConn(inConn)
utils.CloseConn(&outConn)
}) })
} }
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) { func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
@ -480,11 +498,11 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
err = fmt.Errorf("write req detail fail,%s", err) err = fmt.Errorf("write req detail fail,%s", err)
return return
} }
// _, err = outConn.Read(buf) _, err = outConn.Read(buf)
// if err != nil { if err != nil {
// err = fmt.Errorf("read req reply fail,%s", err) err = fmt.Errorf("read req reply fail,%s", err)
// return return
// } }
//result := buf[:n] //result := buf[:n]
//log.Printf("result:%v", result) //log.Printf("result:%v", result)
@ -550,6 +568,10 @@ func (s *Socks) ConnectSSH() (err error) {
} }
func (s *Socks) InitBasicAuth() (err error) { func (s *Socks) InitBasicAuth() (err error) {
s.basicAuth = utils.NewBasicAuth() s.basicAuth = utils.NewBasicAuth()
if *s.cfg.AuthURL != "" {
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
log.Printf("auth from %s", *s.cfg.AuthURL)
}
if *s.cfg.AuthFile != "" { if *s.cfg.AuthFile != "" {
var n = 0 var n = 0
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile) n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
@ -566,5 +588,40 @@ func (s *Socks) InitBasicAuth() (err error) {
return return
} }
func (s *Socks) IsBasicAuth() bool { func (s *Socks) IsBasicAuth() bool {
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
}
func (s *Socks) IsDeadLoop(inLocalAddr string, host string) bool {
inIP, inPort, err := net.SplitHostPort(inLocalAddr)
if err != nil {
return false
}
outDomain, outPort, err := net.SplitHostPort(host)
if err != nil {
return false
}
if inPort == outPort {
var outIPs []net.IP
outIPs, err = net.LookupIP(outDomain)
if err == nil {
for _, ip := range outIPs {
if ip.String() == inIP {
return true
}
}
}
interfaceIPs, err := utils.GetAllInterfaceAddr()
for _, ip := range *s.cfg.LocalIPS {
interfaceIPs = append(interfaceIPs, net.ParseIP(ip).To4())
}
if err == nil {
for _, localIP := range interfaceIPs {
for _, outIP := range outIPs {
if localIP.Equal(outIP) {
return true
}
}
}
}
}
return false
} }

View File

@ -29,9 +29,9 @@ func (s *TCP) CheckArgs() {
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local) log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
} }
if *s.cfg.ParentType == "" { if *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp>") log.Fatalf("parent type unkown,use -T <tls|tcp|kcp|udp>")
} }
if *s.cfg.ParentType == "tls" || *s.cfg.IsTLS { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
} }
@ -52,10 +52,13 @@ func (s *TCP) Start(args interface{}) (err error) {
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p)
if !*s.cfg.IsTLS {
if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
} }
if err != nil { if err != nil {
return return
@ -75,6 +78,8 @@ func (s *TCP) callback(inConn net.Conn) {
}() }()
var err error var err error
switch *s.cfg.ParentType { switch *s.cfg.ParentType {
case TYPE_KCP:
fallthrough
case TYPE_TCP: case TYPE_TCP:
fallthrough fallthrough
case TYPE_TLS: case TYPE_TLS:
@ -102,15 +107,13 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
return return
} }
inAddr := (*inConn).RemoteAddr().String() inAddr := (*inConn).RemoteAddr().String()
inLocalAddr := (*inConn).LocalAddr().String() //inLocalAddr := (*inConn).LocalAddr().String()
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
utils.IoBind((*inConn), outConn, func(err error) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s - %s - %s released", inAddr, inLocalAddr, outLocalAddr, outAddr) log.Printf("conn %s - %s released", inAddr, outAddr)
utils.CloseConn(inConn)
utils.CloseConn(&outConn)
}) })
log.Printf("conn %s - %s - %s - %s connected", inAddr, inLocalAddr, outLocalAddr, outAddr) log.Printf("conn %s - %s connected", inAddr, outAddr)
return return
} }
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) { func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
@ -162,13 +165,14 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
} }
func (s *TCP) InitOutConnPool() { func (s *TCP) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP { if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte, //dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int //parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool( s.outPool = utils.NewOutPool(
*s.cfg.CheckParentInterval, *s.cfg.CheckParentInterval,
*s.cfg.ParentType, *s.cfg.ParentType,
"", "", *s.cfg.KCPMethod,
*s.cfg.KCPKey,
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CertBytes, s.cfg.KeyBytes,
*s.cfg.Parent, *s.cfg.Parent,
*s.cfg.Timeout, *s.cfg.Timeout,

View File

@ -17,8 +17,8 @@ type TunnelBridge struct {
cfg TunnelBridgeArgs cfg TunnelBridgeArgs
serverConns utils.ConcurrentMap serverConns utils.ConcurrentMap
clientControlConns utils.ConcurrentMap clientControlConns utils.ConcurrentMap
cmServer utils.ConnManager // cmServer utils.ConnManager
cmClient utils.ConnManager // cmClient utils.ConnManager
} }
func NewTunnelBridge() Service { func NewTunnelBridge() Service {
@ -26,8 +26,8 @@ func NewTunnelBridge() Service {
cfg: TunnelBridgeArgs{}, cfg: TunnelBridgeArgs{},
serverConns: utils.NewConcurrentMap(), serverConns: utils.NewConcurrentMap(),
clientControlConns: utils.NewConcurrentMap(), clientControlConns: utils.NewConcurrentMap(),
cmServer: utils.NewConnManager(), // cmServer: utils.NewConnManager(),
cmClient: utils.NewConnManager(), // cmClient: utils.NewConnManager(),
} }
} }
@ -92,7 +92,7 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
s.cmServer.Add(serverID, ID, &inConn) // s.cmServer.Add(serverID, ID, &inConn)
break break
} }
} }
@ -112,15 +112,13 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
return return
} }
serverConn := serverConnItem.(ServerConn).Conn serverConn := serverConnItem.(ServerConn).Conn
utils.IoBind(*serverConn, inConn, func(err error) { utils.IoBind(*serverConn, inConn, func(err interface{}) {
(*serverConn).Close()
utils.CloseConn(&inConn)
s.serverConns.Remove(ID) s.serverConns.Remove(ID)
s.cmClient.RemoveOne(key, ID) // s.cmClient.RemoveOne(key, ID)
s.cmServer.RemoveOne(serverID, ID) // s.cmServer.RemoveOne(serverID, ID)
log.Printf("conn %s released", ID) log.Printf("conn %s released", ID)
}) })
s.cmClient.Add(key, ID, &inConn) // s.cmClient.Add(key, ID, &inConn)
log.Printf("conn %s created", ID) log.Printf("conn %s created", ID)
case CONN_CLIENT_CONTROL: case CONN_CLIENT_CONTROL:
@ -138,101 +136,101 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
s.clientControlConns.Set(key, &inConn) s.clientControlConns.Set(key, &inConn)
log.Printf("set client %s control conn", key) log.Printf("set client %s control conn", key)
case CONN_SERVER_HEARBEAT: // case CONN_SERVER_HEARBEAT:
var serverID string // var serverID string
err = utils.ReadPacketData(reader, &serverID) // err = utils.ReadPacketData(reader, &serverID)
if err != nil { // if err != nil {
log.Printf("read error,ERR:%s", err) // log.Printf("read error,ERR:%s", err)
return // return
} // }
log.Printf("server heartbeat connection, id: %s", serverID) // log.Printf("server heartbeat connection, id: %s", serverID)
writeDie := make(chan bool) // writeDie := make(chan bool)
readDie := make(chan bool) // readDie := make(chan bool)
go func() { // go func() {
for { // for {
inConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) // inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
_, err = inConn.Write([]byte{0x00}) // _, err = inConn.Write([]byte{0x00})
inConn.SetWriteDeadline(time.Time{}) // inConn.SetWriteDeadline(time.Time{})
if err != nil { // if err != nil {
log.Printf("server heartbeat connection write err %s", err) // log.Printf("server heartbeat connection write err %s", err)
break // break
} // }
time.Sleep(time.Second * 3) // time.Sleep(time.Second * 3)
} // }
close(writeDie) // close(writeDie)
}() // }()
go func() { // go func() {
for { // for {
signal := make([]byte, 1) // signal := make([]byte, 1)
inConn.SetReadDeadline(time.Now().Add(time.Second * 6)) // inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
_, err := inConn.Read(signal) // _, err := inConn.Read(signal)
inConn.SetReadDeadline(time.Time{}) // inConn.SetReadDeadline(time.Time{})
if err != nil { // if err != nil {
log.Printf("server heartbeat connection read err: %s", err) // log.Printf("server heartbeat connection read err: %s", err)
break // break
} else { // } else {
// log.Printf("heartbeat from server ,id:%s", serverID) // // log.Printf("heartbeat from server ,id:%s", serverID)
} // }
} // }
close(readDie) // close(readDie)
}() // }()
select { // select {
case <-readDie: // case <-readDie:
case <-writeDie: // case <-writeDie:
} // }
utils.CloseConn(&inConn) // utils.CloseConn(&inConn)
s.cmServer.Remove(serverID) // s.cmServer.Remove(serverID)
log.Printf("server heartbeat conn %s released", serverID) // log.Printf("server heartbeat conn %s released", serverID)
case CONN_CLIENT_HEARBEAT: // case CONN_CLIENT_HEARBEAT:
var clientID string // var clientID string
err = utils.ReadPacketData(reader, &clientID) // err = utils.ReadPacketData(reader, &clientID)
if err != nil { // if err != nil {
log.Printf("read error,ERR:%s", err) // log.Printf("read error,ERR:%s", err)
return // return
} // }
log.Printf("client heartbeat connection, id: %s", clientID) // log.Printf("client heartbeat connection, id: %s", clientID)
writeDie := make(chan bool) // writeDie := make(chan bool)
readDie := make(chan bool) // readDie := make(chan bool)
go func() { // go func() {
for { // for {
inConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) // inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
_, err = inConn.Write([]byte{0x00}) // _, err = inConn.Write([]byte{0x00})
inConn.SetWriteDeadline(time.Time{}) // inConn.SetWriteDeadline(time.Time{})
if err != nil { // if err != nil {
log.Printf("client heartbeat connection write err %s", err) // log.Printf("client heartbeat connection write err %s", err)
break // break
} // }
time.Sleep(time.Second * 3) // time.Sleep(time.Second * 3)
} // }
close(writeDie) // close(writeDie)
}() // }()
go func() { // go func() {
for { // for {
signal := make([]byte, 1) // signal := make([]byte, 1)
inConn.SetReadDeadline(time.Now().Add(time.Second * 6)) // inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
_, err := inConn.Read(signal) // _, err := inConn.Read(signal)
inConn.SetReadDeadline(time.Time{}) // inConn.SetReadDeadline(time.Time{})
if err != nil { // if err != nil {
log.Printf("client control connection read err: %s", err) // log.Printf("client control connection read err: %s", err)
break // break
} else { // } else {
// log.Printf("heartbeat from client ,id:%s", clientID) // // log.Printf("heartbeat from client ,id:%s", clientID)
} // }
} // }
close(readDie) // close(readDie)
}() // }()
select { // select {
case <-readDie: // case <-readDie:
case <-writeDie: // case <-writeDie:
} // }
utils.CloseConn(&inConn) // utils.CloseConn(&inConn)
s.cmClient.Remove(clientID) // s.cmClient.Remove(clientID)
if s.clientControlConns.Has(clientID) { // if s.clientControlConns.Has(clientID) {
item, _ := s.clientControlConns.Get(clientID) // item, _ := s.clientControlConns.Get(clientID)
(*item.(*net.Conn)).Close() // (*item.(*net.Conn)).Close()
} // }
s.clientControlConns.Remove(clientID) // s.clientControlConns.Remove(clientID)
log.Printf("client heartbeat conn %s released", clientID) // log.Printf("client heartbeat conn %s released", clientID)
} }
}) })
if err != nil { if err != nil {

View File

@ -11,79 +11,80 @@ import (
) )
type TunnelClient struct { type TunnelClient struct {
cfg TunnelClientArgs cfg TunnelClientArgs
cm utils.ConnManager // cm utils.ConnManager
ctrlConn net.Conn ctrlConn net.Conn
} }
func NewTunnelClient() Service { func NewTunnelClient() Service {
return &TunnelClient{ return &TunnelClient{
cfg: TunnelClientArgs{}, cfg: TunnelClientArgs{},
cm: utils.NewConnManager(), // cm: utils.NewConnManager(),
} }
} }
func (s *TunnelClient) InitService() { func (s *TunnelClient) InitService() {
s.InitHeartbeatDeamon() // s.InitHeartbeatDeamon()
} }
func (s *TunnelClient) InitHeartbeatDeamon() {
log.Printf("heartbeat started")
go func() {
var heartbeatConn net.Conn
var ID = *s.cfg.Key
for {
//close all connection // func (s *TunnelClient) InitHeartbeatDeamon() {
s.cm.RemoveAll() // log.Printf("heartbeat started")
if s.ctrlConn != nil { // go func() {
s.ctrlConn.Close() // var heartbeatConn net.Conn
} // var ID = *s.cfg.Key
utils.CloseConn(&heartbeatConn) // for {
heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID)
if err != nil { // //close all connection
log.Printf("heartbeat connection err: %s, retrying...", err) // s.cm.RemoveAll()
time.Sleep(time.Second * 3) // if s.ctrlConn != nil {
utils.CloseConn(&heartbeatConn) // s.ctrlConn.Close()
continue // }
} // utils.CloseConn(&heartbeatConn)
log.Printf("heartbeat connection created,id:%s", ID) // heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID)
writeDie := make(chan bool) // if err != nil {
readDie := make(chan bool) // log.Printf("heartbeat connection err: %s, retrying...", err)
go func() { // time.Sleep(time.Second * 3)
for { // utils.CloseConn(&heartbeatConn)
heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3)) // continue
_, err = heartbeatConn.Write([]byte{0x00}) // }
heartbeatConn.SetWriteDeadline(time.Time{}) // log.Printf("heartbeat connection created,id:%s", ID)
if err != nil { // writeDie := make(chan bool)
log.Printf("heartbeat connection write err %s", err) // readDie := make(chan bool)
break // go func() {
} // for {
time.Sleep(time.Second * 3) // heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
} // _, err = heartbeatConn.Write([]byte{0x00})
close(writeDie) // heartbeatConn.SetWriteDeadline(time.Time{})
}() // if err != nil {
go func() { // log.Printf("heartbeat connection write err %s", err)
for { // break
signal := make([]byte, 1) // }
heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6)) // time.Sleep(time.Second * 3)
_, err := heartbeatConn.Read(signal) // }
heartbeatConn.SetReadDeadline(time.Time{}) // close(writeDie)
if err != nil { // }()
log.Printf("heartbeat connection read err: %s", err) // go func() {
break // for {
} else { // signal := make([]byte, 1)
log.Printf("heartbeat from bridge") // heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
} // _, err := heartbeatConn.Read(signal)
} // heartbeatConn.SetReadDeadline(time.Time{})
close(readDie) // if err != nil {
}() // log.Printf("heartbeat connection read err: %s", err)
select { // break
case <-readDie: // } else {
case <-writeDie: // //log.Printf("heartbeat from bridge")
} // }
} // }
}() // close(readDie)
} // }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// }
// }()
// }
func (s *TunnelClient) CheckArgs() { func (s *TunnelClient) CheckArgs() {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) log.Printf("use tls parent %s", *s.cfg.Parent)
@ -96,7 +97,7 @@ func (s *TunnelClient) CheckArgs() {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
func (s *TunnelClient) StopService() { func (s *TunnelClient) StopService() {
s.cm.RemoveAll() // s.cm.RemoveAll()
} }
func (s *TunnelClient) Start(args interface{}) (err error) { func (s *TunnelClient) Start(args interface{}) (err error) {
s.cfg = args.(TunnelClientArgs) s.cfg = args.(TunnelClientArgs)
@ -106,7 +107,7 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
for { for {
//close all conn //close all conn
s.cm.Remove(*s.cfg.Key) // s.cm.Remove(*s.cfg.Key)
if s.ctrlConn != nil { if s.ctrlConn != nil {
s.ctrlConn.Close() s.ctrlConn.Close()
} }
@ -171,7 +172,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
var err error var err error
// for { // for {
for { for {
s.cm.RemoveOne(*s.cfg.Key, ID) // s.cm.RemoveOne(*s.cfg.Key, ID)
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID) inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
@ -182,7 +183,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
break break
} }
} }
s.cm.Add(*s.cfg.Key, ID, &inConn) // s.cm.Add(*s.cfg.Key, ID, &inConn)
log.Printf("conn %s created", ID) log.Printf("conn %s created", ID)
for { for {
@ -273,12 +274,10 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
log.Printf("build connection error, err: %s", err) log.Printf("build connection error, err: %s", err)
return return
} }
utils.IoBind(inConn, outConn, func(err error) { utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("conn %s released", ID) log.Printf("conn %s released", ID)
utils.CloseConn(&inConn) // s.cm.RemoveOne(*s.cfg.Key, ID)
utils.CloseConn(&outConn)
s.cm.RemoveOne(*s.cfg.Key, ID)
}) })
s.cm.Add(*s.cfg.Key, ID, &inConn) // s.cm.Add(*s.cfg.Key, ID, &inConn)
log.Printf("conn %s created", ID) log.Printf("conn %s created", ID)
} }

View File

@ -24,7 +24,7 @@ type TunnelServerManager struct {
udpChn chan UDPItem udpChn chan UDPItem
sc utils.ServerChannel sc utils.ServerChannel
serverID string serverID string
cm utils.ConnManager // cm utils.ConnManager
} }
func NewTunnelServerManager() Service { func NewTunnelServerManager() Service {
@ -32,7 +32,7 @@ func NewTunnelServerManager() Service {
cfg: TunnelServerArgs{}, cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000), udpChn: make(chan UDPItem, 50000),
serverID: utils.Uniqueid(), serverID: utils.Uniqueid(),
cm: utils.NewConnManager(), // cm: utils.NewConnManager(),
} }
} }
func (s *TunnelServerManager) Start(args interface{}) (err error) { func (s *TunnelServerManager) Start(args interface{}) (err error) {
@ -91,7 +91,7 @@ func (s *TunnelServerManager) Clean() {
s.StopService() s.StopService()
} }
func (s *TunnelServerManager) StopService() { func (s *TunnelServerManager) StopService() {
s.cm.RemoveAll() // s.cm.RemoveAll()
} }
func (s *TunnelServerManager) CheckArgs() { func (s *TunnelServerManager) CheckArgs() {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" { if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
@ -100,62 +100,63 @@ func (s *TunnelServerManager) CheckArgs() {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
func (s *TunnelServerManager) InitService() { func (s *TunnelServerManager) InitService() {
s.InitHeartbeatDeamon() // s.InitHeartbeatDeamon()
}
func (s *TunnelServerManager) InitHeartbeatDeamon() {
log.Printf("heartbeat started")
go func() {
var heartbeatConn net.Conn
var ID string
for {
//close all connection
s.cm.Remove(ID)
utils.CloseConn(&heartbeatConn)
heartbeatConn, ID, err := s.GetOutConn(CONN_SERVER_HEARBEAT)
if err != nil {
log.Printf("heartbeat connection err: %s, retrying...", err)
time.Sleep(time.Second * 3)
utils.CloseConn(&heartbeatConn)
continue
}
log.Printf("heartbeat connection created,id:%s", ID)
writeDie := make(chan bool)
readDie := make(chan bool)
go func() {
for {
heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
_, err = heartbeatConn.Write([]byte{0x00})
heartbeatConn.SetWriteDeadline(time.Time{})
if err != nil {
log.Printf("heartbeat connection write err %s", err)
break
}
time.Sleep(time.Second * 3)
}
close(writeDie)
}()
go func() {
for {
signal := make([]byte, 1)
heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
_, err := heartbeatConn.Read(signal)
heartbeatConn.SetReadDeadline(time.Time{})
if err != nil {
log.Printf("heartbeat connection read err: %s", err)
break
} else {
// log.Printf("heartbeat from bridge")
}
}
close(readDie)
}()
select {
case <-readDie:
case <-writeDie:
}
}
}()
} }
// func (s *TunnelServerManager) InitHeartbeatDeamon() {
// log.Printf("heartbeat started")
// go func() {
// var heartbeatConn net.Conn
// var ID string
// for {
// //close all connection
// s.cm.Remove(ID)
// utils.CloseConn(&heartbeatConn)
// heartbeatConn, ID, err := s.GetOutConn(CONN_SERVER_HEARBEAT)
// if err != nil {
// log.Printf("heartbeat connection err: %s, retrying...", err)
// time.Sleep(time.Second * 3)
// utils.CloseConn(&heartbeatConn)
// continue
// }
// log.Printf("heartbeat connection created,id:%s", ID)
// writeDie := make(chan bool)
// readDie := make(chan bool)
// go func() {
// for {
// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
// _, err = heartbeatConn.Write([]byte{0x00})
// heartbeatConn.SetWriteDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection write err %s", err)
// break
// }
// time.Sleep(time.Second * 3)
// }
// close(writeDie)
// }()
// go func() {
// for {
// signal := make([]byte, 1)
// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
// _, err := heartbeatConn.Read(signal)
// heartbeatConn.SetReadDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection read err: %s", err)
// break
// } else {
// // log.Printf("heartbeat from bridge")
// }
// }
// close(readDie)
// }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// }
// }()
// }
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) { func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn() outConn, err = s.GetConn()
if err != nil { if err != nil {
@ -240,14 +241,12 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
break break
} }
} }
utils.IoBind(inConn, outConn, func(err error) { utils.IoBind(inConn, outConn, func(err interface{}) {
utils.CloseConn(&outConn) // s.cfg.Mgr.cm.RemoveOne(s.cfg.Mgr.serverID, ID)
utils.CloseConn(&inConn)
s.cfg.Mgr.cm.RemoveOne(s.cfg.Mgr.serverID, ID)
log.Printf("%s conn %s released", *s.cfg.Key, ID) log.Printf("%s conn %s released", *s.cfg.Key, ID)
}) })
//add conn //add conn
s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn) // s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn)
log.Printf("%s conn %s created", *s.cfg.Key, ID) log.Printf("%s conn %s created", *s.cfg.Key, ID)
}) })
if err != nil { if err != nil {

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,7 +19,7 @@ import (
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
"runtime/debug" "proxy/utils/id"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -28,39 +27,62 @@ import (
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
) )
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error)) { func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{})) {
go func() { go func() {
e1 := make(chan error, 1) defer func() {
e2 := make(chan error, 1) if err := recover(); err != nil {
log.Printf("bind crashed %s", err)
}
}()
e1 := make(chan interface{}, 1)
e2 := make(chan interface{}, 1)
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if err := recover(); err != nil {
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) log.Printf("bind crashed %s", err)
} }
}() }()
//_, err := io.Copy(dst, src)
_, e := io.Copy(dst, src) err := ioCopy(dst, src)
e1 <- e e1 <- err
}() }()
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if err := recover(); err != nil {
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) log.Printf("bind crashed %s", err)
} }
}() }()
//_, err := io.Copy(src, dst)
_, e := io.Copy(src, dst) err := ioCopy(src, dst)
e2 <- e e2 <- err
}() }()
var err error var err interface{}
select { select {
case err = <-e1: case err = <-e1:
//log.Printf("e1")
case err = <-e2: case err = <-e2:
//log.Printf("e2")
} }
src.Close()
dst.Close()
fn(err) fn(err)
}() }()
} }
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
buf := make([]byte, 32*1024)
n := 0
for {
n, err = src.Read(buf)
if n > 0 {
if _, e := dst.Write(buf[0:n]); e != nil {
return e
}
}
if err != nil {
return
}
}
}
func TlsConnectHost(host string, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) { func TlsConnectHost(host string, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":") h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1]) port, _ := strconv.Atoi(h[1])
@ -103,8 +125,15 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
return return
} }
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) { func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) {
conn, err = kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3) kcpconn, err := kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3)
return if err != nil {
return
}
kcpconn.SetNoDelay(1, 10, 2, 1)
kcpconn.SetWindowSize(1024, 1024)
kcpconn.SetMtu(1400)
kcpconn.SetACKNoDelay(false)
return kcpconn, err
} }
func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) { func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) {
var cert tls.Certificate var cert tls.Certificate
@ -272,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
@ -401,6 +431,52 @@ func GetKCPBlock(method, key string) (block kcp.BlockCrypt) {
} }
return return
} }
func HttpGet(URL string, timeout int) (body []byte, code int, err error) {
var tr *http.Transport
var client *http.Client
conf := &tls.Config{
InsecureSkipVerify: true,
}
if strings.Contains(URL, "https://") {
tr = &http.Transport{TLSClientConfig: conf}
client = &http.Client{Timeout: time.Millisecond * time.Duration(timeout), Transport: tr}
} else {
tr = &http.Transport{}
client = &http.Client{Timeout: time.Millisecond * time.Duration(timeout), Transport: tr}
}
defer tr.CloseIdleConnections()
resp, err := client.Get(URL)
if err != nil {
return
}
defer resp.Body.Close()
code = resp.StatusCode
body, err = ioutil.ReadAll(resp.Body)
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)
}
}

View File

@ -176,7 +176,11 @@ func (c *Checker) Add(address string, isHTTPS bool, method, URL string, data []b
} }
type BasicAuth struct { type BasicAuth struct {
data ConcurrentMap data ConcurrentMap
authURL string
authOkCode int
authTimeout int
authRetry int
} }
func NewBasicAuth() BasicAuth { func NewBasicAuth() BasicAuth {
@ -184,6 +188,12 @@ func NewBasicAuth() BasicAuth {
data: NewConcurrentMap(), data: NewConcurrentMap(),
} }
} }
func (ba *BasicAuth) SetAuthURL(URL string, code, timeout, retry int) {
ba.authURL = URL
ba.authOkCode = code
ba.authTimeout = timeout
ba.authRetry = retry
}
func (ba *BasicAuth) AddFromFile(file string) (n int, err error) { func (ba *BasicAuth) AddFromFile(file string) (n int, err error) {
_content, err := ioutil.ReadFile(file) _content, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
@ -213,21 +223,69 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
} }
return return
} }
func (ba *BasicAuth) CheckUserPass(user, pass string) (ok bool) { func (ba *BasicAuth) CheckUserPass(user, pass, ip, target string) (ok bool) {
if p, _ok := ba.data.Get(user); _ok {
return p.(string) == pass return ba.Check(user+":"+pass, ip, target)
}
return
} }
func (ba *BasicAuth) Check(userpass string) (ok bool) { func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) == 2 { if len(u) == 2 {
if p, _ok := ba.data.Get(u[0]); _ok { if p, _ok := ba.data.Get(u[0]); _ok {
return p.(string) == u[1] return p.(string) == u[1]
} }
if ba.authURL != "" {
err := ba.checkFromURL(userpass, ip, target)
if err == nil {
return true
}
log.Printf("%s", err)
}
return false
} }
return return
} }
func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) != 2 {
return
}
URL := ba.authURL
if strings.Contains(URL, "?") {
URL += "&"
} else {
URL += "?"
}
URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&target=%s", u[0], u[1], ip, target)
var code int
var tryCount = 0
var body []byte
for tryCount <= ba.authRetry {
body, code, err = HttpGet(URL, ba.authTimeout)
if err == nil && code == ba.authOkCode {
break
} else if err != nil {
err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s", URL, err, ip)
} else {
if len(body) > 0 {
err = fmt.Errorf(string(body[0:100]))
} else {
err = fmt.Errorf("token error")
}
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, string(body))
}
if err != nil && tryCount < ba.authRetry {
log.Print(err)
time.Sleep(time.Second * 2)
}
tryCount++
}
if err != nil {
return
}
//log.Printf("auth success from auth url, %s", ip)
return
}
func (ba *BasicAuth) Total() (n int) { func (ba *BasicAuth) Total() (n int) {
n = ba.data.Count() n = ba.data.Count()
return return
@ -292,7 +350,11 @@ func (req *HTTPRequest) HTTP() (err error) {
} }
req.URL, err = req.getHTTPURL() req.URL, err = req.getHTTPURL()
if err == nil { if err == nil {
u, _ := url.Parse(req.URL) var u *url.URL
u, err = url.Parse(req.URL)
if err != nil {
return
}
req.Host = u.Host req.Host = u.Host
req.addPortIfNot() req.addPortIfNot()
} }
@ -321,6 +383,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
CloseConn(req.conn) CloseConn(req.conn)
return return
} }
if authorization == "" {
authorization, err = req.getHeader("Proxy-Authorization")
if err != nil {
fmt.Fprint((*req.conn), "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized")
CloseConn(req.conn)
return
}
}
//log.Printf("Authorization:%s", authorization) //log.Printf("Authorization:%s", authorization)
basic := strings.Fields(authorization) basic := strings.Fields(authorization)
if len(basic) != 2 { if len(basic) != 2 {
@ -334,7 +404,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
CloseConn(req.conn) CloseConn(req.conn)
return return
} }
authOk := (*req.basicAuth).Check(string(user)) addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
URL := ""
if req.IsHTTPS() {
URL = "https://" + req.Host
} else {
URL, _ = req.getHTTPURL()
}
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
//log.Printf("auth %s,%v", string(user), authOk) //log.Printf("auth %s,%v", string(user), authOk)
if !authOk { if !authOk {
fmt.Fprint((*req.conn), "HTTP/1.1 401 Unauthorized\r\n\r\nUnauthorized") fmt.Fprint((*req.conn), "HTTP/1.1 401 Unauthorized\r\n\r\nUnauthorized")
@ -358,6 +435,7 @@ func (req *HTTPRequest) getHTTPURL() (URL string, err error) {
func (req *HTTPRequest) getHeader(key string) (val string, err error) { func (req *HTTPRequest) getHeader(key string) (val string, err error) {
key = strings.ToUpper(key) key = strings.ToUpper(key)
lines := strings.Split(string(req.HeadBuf), "\r\n") lines := strings.Split(string(req.HeadBuf), "\r\n")
//log.Println(lines)
for _, line := range lines { for _, line := range lines {
line := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2) line := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2)
if len(line) == 2 { if len(line) == 2 {
@ -369,7 +447,6 @@ func (req *HTTPRequest) getHeader(key string) (val string, err error) {
} }
} }
} }
err = fmt.Errorf("can not find HOST header")
return return
} }