Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d225a6cdb | ||
|
|
ccca75ecbd | ||
|
|
2360808604 | ||
|
|
b7c2b0e8fa | ||
|
|
581ff2b840 | ||
|
|
8a75e202d6 | ||
|
|
c23d733cfd | ||
|
|
aab8b41da9 | ||
|
|
e9139ee56f | ||
|
|
24d3d88980 | ||
|
|
078acaa0e8 | ||
|
|
96cd7a2b63 | ||
|
|
bf095b2c76 | ||
|
|
a80e4df6f0 | ||
|
|
3cd0d91c22 | ||
|
|
716aaa272d | ||
|
|
87c13e4aec | ||
|
|
7005d66ed6 | ||
|
|
ba62ce24b8 | ||
|
|
2ec7131659 | ||
|
|
65f441f5b5 | ||
|
|
ee0e85a30f | ||
|
|
8cdb5d1857 | ||
|
|
5cb8620e82 | ||
|
|
f0733655f8 | ||
|
|
59a5a4a68a | ||
|
|
b9cd57d873 | ||
|
|
9504061e4e | ||
|
|
f41f3a3b63 | ||
|
|
8f0c80980c | ||
|
|
e9b46d38e3 | ||
|
|
3440af51b0 | ||
|
|
95db78bc0b | ||
|
|
bde10ad8ef | ||
|
|
b8c2766639 | ||
|
|
5bb8bf20fe | ||
|
|
db71b77da4 | ||
|
|
af19092a7d | ||
|
|
3020dc5c94 | ||
|
|
e28d5449b5 | ||
|
|
efb075c7ba | ||
|
|
31073d398e | ||
|
|
8bafb88bc4 | ||
|
|
dc82b94c6b | ||
|
|
cf6043b0de | ||
|
|
ce1095d6de | ||
|
|
9f08170cd3 | ||
|
|
5c66f5f5d2 | ||
|
|
1a9c3244a3 | ||
|
|
00688bbf33 | ||
|
|
787cc56ed4 | ||
|
|
3984083e23 | ||
|
|
a91790b16d | ||
|
|
b2549e8d48 | ||
|
|
768e5dd6c0 | ||
|
|
7899f1ec00 | ||
|
|
ef93946fb1 | ||
|
|
675061fd63 | ||
|
|
4b212eee0d |
18
CHANGELOG
@ -1,4 +1,22 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v3.4
|
||||||
|
1.socks5代理新增了用户名密码验证支持.
|
||||||
|
2.socks5,http(s)代理增加了kcp传输协议支持.
|
||||||
|
3.优化了内网穿透的心跳机制.
|
||||||
|
|
||||||
|
v3.3
|
||||||
|
1.修复了socks代理模式对证书文件的判断逻辑.
|
||||||
|
2.增强了http代理,socks代理的ssh中转模式的稳定性.
|
||||||
|
3.socks代理tls,tcp模式新增了CMD_ASSOCIATE(udp)支持.socks代理ssh模式不支持udp.
|
||||||
|
4.修复了http代理某些情况下会崩溃的bug.
|
||||||
|
|
||||||
|
v3.2
|
||||||
|
1.内网穿透功能server端-r参数增加了协议和key设置.
|
||||||
|
2.手册增加了对-r参数的详细说明.
|
||||||
|
3.修复了普通模式也检查证书文件的bug.
|
||||||
|
4.增加了Socks5支持,目前只支持TCP协议,不支持UDP协议.
|
||||||
|
5.Socks5上级代理支持ssh中转,linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
6.http(s)代理增加了ssh中转支持,linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
|
||||||
v3.1
|
v3.1
|
||||||
1.优化了内网穿透功能,bridge,client和server只需要启动一个即可。
|
1.优化了内网穿透功能,bridge,client和server只需要启动一个即可。
|
||||||
|
|||||||
281
README.md
@ -1,5 +1,5 @@
|
|||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
||||||
Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支持正向代理和内网穿透.
|
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务器,支持正向代理、内网穿透、SSH中转。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -8,11 +8,12 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支
|
|||||||
### Features
|
### Features
|
||||||
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
|
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
|
||||||
- 通讯加密,如果程序不是一级代理,而且上级代理也是本程序,那么可以加密和上级代理之间的通讯,采用底层tls高强度加密,安全无特征.
|
- 通讯加密,如果程序不是一级代理,而且上级代理也是本程序,那么可以加密和上级代理之间的通讯,采用底层tls高强度加密,安全无特征.
|
||||||
- 智能HTTP代理,会自动判断访问的网站是否屏蔽,如果被屏蔽那么就会使用上级代理(前提是配置了上级代理)访问网站;如果访问的网站没有被屏蔽,为了加速访问,代理会直接访问网站,不使用上级代理.
|
- 智能HTTP,SOCKS5代理,会自动判断访问的网站是否屏蔽,如果被屏蔽那么就会使用上级代理(前提是配置了上级代理)访问网站;如果访问的网站没有被屏蔽,为了加速访问,代理会直接访问网站,不使用上级代理.
|
||||||
- 域名黑白名单,更加自由的控制网站的访问方式。
|
- 域名黑白名单,更加自由的控制网站的访问方式。
|
||||||
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
- 跨平台性,无论你是widows,linux,还是mac,甚至是树莓派,都可以很好的运行proxy.
|
||||||
- 多协议支持,支持HTTP,TCP,UDP,Websocket代理.
|
- 多协议支持,支持HTTP(S),TCP,UDP,Websocket,SOCKS5代理.
|
||||||
- 支持内网穿透,协议支持TCP和UDP.
|
- 支持内网穿透,协议支持TCP和UDP.
|
||||||
|
- HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- 当由于安全因素或者限制,我们不能顺畅的访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道,顺畅的访问我们的服务.
|
- 当由于安全因素或者限制,我们不能顺畅的访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道,顺畅的访问我们的服务.
|
||||||
@ -23,21 +24,84 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp代理服务器,支
|
|||||||
- 替代圣剑内网通,显IP内网通,花生壳之类的工具.
|
- 替代圣剑内网通,显IP内网通,花生壳之类的工具.
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
### 手册目录
|
|
||||||
本页是最新v3.1手册,其他版本手册请点击下面链接查看.
|
本页是v3.4手册,其他版本手册请点击下面链接查看.
|
||||||
|
- [v3.3手册](https://github.com/snail007/goproxy/tree/v3.3)
|
||||||
|
- [v3.2手册](https://github.com/snail007/goproxy/tree/v3.2)
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
1. [快速安装](#自动安装)
|
||||||
|
1. [手动安装](#手动安装)
|
||||||
|
|
||||||
|
### 首次使用必看
|
||||||
|
- [环境](#使用教程)
|
||||||
|
- [使用配置文件](#使用配置文件)
|
||||||
|
- [生成通讯证书文件](#生成加密通讯需要的证书文件)
|
||||||
|
|
||||||
|
### 手册目录
|
||||||
|
- [1. HTTP代理](#1http代理)
|
||||||
|
- [1.1 普通HTTP代理](#11普通http代理)
|
||||||
|
- [1.2 普通二级HTTP代理](#12普通二级http代理)
|
||||||
|
- [1.3 HTTP二级代理(加密)](#13http二级代理加密)
|
||||||
|
- [1.4 HTTP三级代理(加密)](#14http三级代理加密)
|
||||||
|
- [1.5 Basic认证](#15basic认证)
|
||||||
|
- [1.6 强制走上级HTTP代理](#16http代理流量强制走上级http代理)
|
||||||
|
- [1.7 通过SSH中转](#17https通过ssh中转)
|
||||||
|
- [1.7.1 用户名和密码的方式](#171-ssh用户名和密码的方式)
|
||||||
|
- [1.7.2 用户名和密钥的方式](#172-ssh用户名和密钥的方式)
|
||||||
|
- [1.8 KCP协议传输](#18KCP协议传输)
|
||||||
|
- [1.9 查看帮助](#19查看帮助)
|
||||||
|
- [2. TCP代理](#2tcp代理)
|
||||||
|
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
|
||||||
|
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
|
||||||
|
- [2.3 普通三级TCP代理](#23普通三级tcp代理)
|
||||||
|
- [2.4 加密二级TCP代理](#24加密二级tcp代理)
|
||||||
|
- [2.5 加密三级TCP代理](#25加密三级tcp代理)
|
||||||
|
- [2.6 查看帮助](#26查看帮助)
|
||||||
|
- [3. UDP代理](#3udp代理)
|
||||||
|
- [3.1 普通一级TCP代理](#31普通一级udp代理)
|
||||||
|
- [3.2 普通二级TCP代理](#32普通二级udp代理)
|
||||||
|
- [3.3 普通三级TCP代理](#33普通三级udp代理)
|
||||||
|
- [3.4 加密二级TCP代理](#34加密二级udp代理)
|
||||||
|
- [3.5 加密三级TCP代理](#35加密三级udp代理)
|
||||||
|
- [3.6 查看帮助](#36查看帮助)
|
||||||
|
- [4. 内网穿透](#4内网穿透)
|
||||||
|
- [4.1 原理说明](#41原理说明)
|
||||||
|
- [4.2 TCP普通用法](#42tcp普通用法)
|
||||||
|
- [4.3 微信接口本地开发](#43微信接口本地开发)
|
||||||
|
- [4.4 UDP普通用法](#44udp普通用法)
|
||||||
|
- [4.5 高级用法一](#45高级用法一)
|
||||||
|
- [4.6 高级用法一](#46高级用法二)
|
||||||
|
- [4.7 tserver的-r参数](#47tserver的-r参数)
|
||||||
|
- [4.8 查看帮助](#48查看帮助)
|
||||||
|
- [5. SOCKS5代理](#5socks5代理)
|
||||||
|
- [5.1 普通SOCKS5代理](#51普通socks5代理)
|
||||||
|
- [5.2 普通二级SOCKS5代理](#52普通二级socks5代理)
|
||||||
|
- [5.3 SOCKS二级代理(加密)](#53socks二级代理加密)
|
||||||
|
- [5.4 SOCKS三级代理(加密)](#54socks三级代理加密)
|
||||||
|
- [5.5 流量强制走上级SOCKS代理](#55socks代理流量强制走上级socks代理)
|
||||||
|
- [5.6 通过SSH中转](#56socks通过ssh中转)
|
||||||
|
- [5.6.1 用户名和密码的方式](#561-ssh用户名和密码的方式)
|
||||||
|
- [5.6.2 用户名和密钥的方式](#562-ssh用户名和密钥的方式)
|
||||||
|
- [5.7 认证](#57认证)
|
||||||
|
- [5.8 KCP协议传输](#58KCP协议传输)
|
||||||
|
- [5.9 查看帮助](#59查看帮助)
|
||||||
|
|
||||||
### Fast Start
|
### Fast Start
|
||||||
提示:所有操作需要root权限.
|
提示:所有操作需要root权限.
|
||||||
**0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
|
#### 自动安装
|
||||||
|
#### **0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
|
||||||
```shell
|
```shell
|
||||||
curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
|
curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
|
||||||
```
|
```
|
||||||
安装完成,配置目录是/etc/proxy,更详细的使用方法参考下面的进一步了解.
|
安装完成,配置目录是/etc/proxy,更详细的使用方法参考下面的进一步了解.
|
||||||
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
|
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
|
||||||
|
|
||||||
**1.登录你的VPS,下载守护进程monexec,选择合适你的版本,vps一般选择"linux_amd64.tar.gz"的即可.**
|
#### 手动安装
|
||||||
|
#### **1.登录你的VPS,下载守护进程monexec,选择合适你的版本,vps一般选择"linux_amd64.tar.gz"的即可.**
|
||||||
下载地址:https://github.com/reddec/monexec/releases
|
下载地址:https://github.com/reddec/monexec/releases
|
||||||
比如下载到/root/proxy/
|
比如下载到/root/proxy/
|
||||||
执行:
|
执行:
|
||||||
@ -46,13 +110,13 @@ mkdir /root/proxy/
|
|||||||
cd /root/proxy/
|
cd /root/proxy/
|
||||||
wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
|
wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
|
||||||
```
|
```
|
||||||
**2.下载proxy**
|
#### **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.1/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v3.1fix/proxy-linux-amd64.tar.gz
|
||||||
```
|
```
|
||||||
**3.下载自动安装脚本**
|
#### **3.下载自动安装脚本**
|
||||||
```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
|
||||||
@ -62,11 +126,11 @@ chmod +x install.sh
|
|||||||
|
|
||||||
## 使用教程
|
## 使用教程
|
||||||
|
|
||||||
**提示**
|
#### **提示**
|
||||||
接下来的教程,默认系统是linux,程序是proxy;所有操作需要root权限;
|
接下来的教程,默认系统是linux,程序是proxy;所有操作需要root权限;
|
||||||
如果你的是windows,请使用windows版本的proxy.exe即可.
|
如果你的是windows,请使用windows版本的proxy.exe即可.
|
||||||
|
|
||||||
**使用配置文件**
|
### **使用配置文件**
|
||||||
接下来的教程都是通过命令行参数介绍使用方法,也可以通过读取配置文件获取参数.
|
接下来的教程都是通过命令行参数介绍使用方法,也可以通过读取配置文件获取参数.
|
||||||
具体格式是通过@符号指定配置文件,例如:./proxy @configfile.txt
|
具体格式是通过@符号指定配置文件,例如:./proxy @configfile.txt
|
||||||
configfile.txt里面的格式是,第一行是子命令名称,第二行开始一行一个:参数的长格式=参数值,前后不能有空格和双引号.
|
configfile.txt里面的格式是,第一行是子命令名称,第二行开始一行一个:参数的长格式=参数值,前后不能有空格和双引号.
|
||||||
@ -85,18 +149,19 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
||||||
|
|
||||||
### 1.HTTP代理
|
### 1.HTTP代理
|
||||||
**1.1.普通HTTP代理**
|
#### **1.1.普通HTTP代理**
|
||||||
`./proxy http -t tcp -p "0.0.0.0:38080"`
|
`./proxy http -t tcp -p "0.0.0.0:38080"`
|
||||||
|
|
||||||
**1.2.普通二级HTTP代理**
|
#### **1.2.普通二级HTTP代理**
|
||||||
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080`
|
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080`
|
||||||
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||||
默认开启了连接池,如果为了网络情况很好,-L可以关闭连接池,0就是连接池大小,0为关闭.
|
默认关闭了连接池,如果要加快访问速度,-L可以开启连接池,10就是连接池大小,0为关闭,
|
||||||
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -L 0`
|
开启连接池在网络不好的情况下,稳定不是很好.
|
||||||
|
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -L 10`
|
||||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,怕匹配规则是最右批评匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
我们还可以指定网站域名的黑白名单文件,一行一个域名,怕匹配规则是最右批评匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||||
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||||
|
|
||||||
**1.3.HTTP二级代理(加密)**
|
#### **1.3.HTTP二级代理(加密)**
|
||||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||||
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
@ -108,7 +173,7 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
`./proxy.exe http -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
`./proxy.exe http -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
然后设置你的windos系统中,需要通过代理上网的程序的代理为http模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
然后设置你的windos系统中,需要通过代理上网的程序的代理为http模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
||||||
|
|
||||||
**1.4.HTTP三级代理(加密)**
|
#### **1.4.HTTP三级代理(加密)**
|
||||||
一级HTTP代理VPS_01,IP:22.22.22.22
|
一级HTTP代理VPS_01,IP:22.22.22.22
|
||||||
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
二级HTTP代理VPS_02,IP:33.33.33.33
|
二级HTTP代理VPS_02,IP:33.33.33.33
|
||||||
@ -117,7 +182,7 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
`./proxy http -t tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
`./proxy http -t tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||||
那么访问本地的8080端口就是访问一级HTTP代理上面的代理端口38080.
|
那么访问本地的8080端口就是访问一级HTTP代理上面的代理端口38080.
|
||||||
|
|
||||||
**1.5.Basic认证**
|
#### **1.5.Basic认证**
|
||||||
对于代理HTTP协议我们可以basic进行Basic认证,认证的用户名和密码可以在命令行指定
|
对于代理HTTP协议我们可以basic进行Basic认证,认证的用户名和密码可以在命令行指定
|
||||||
`./proxy http -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
`./proxy http -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
多个用户,重复-a参数即可.
|
多个用户,重复-a参数即可.
|
||||||
@ -125,29 +190,51 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
|||||||
`./proxy http -t tcp -p ":33080" -F auth-file.txt`
|
`./proxy http -t tcp -p ":33080" -F auth-file.txt`
|
||||||
如果没有-a或-F参数,就是关闭Basic认证.
|
如果没有-a或-F参数,就是关闭Basic认证.
|
||||||
|
|
||||||
**1.6.HTTP代理流量强制走上级HTTP代理**
|
#### **1.6.HTTP代理流量强制走上级HTTP代理**
|
||||||
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理.
|
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级HTTP代理.通过--always可以使全部HTTP代理流量强制走上级HTTP代理.
|
||||||
`./proxy http --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
`./proxy http --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
**1.7.查看帮助**
|
#### **1.7.HTTP(S)通过SSH中转**
|
||||||
`./proxy help http`
|
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||||
|
假设有:vps
|
||||||
|
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||||
|
- 用户user的ssh私钥名称是user.key
|
||||||
|
|
||||||
|
##### ***1.7.1 ssh用户名和密码的方式***
|
||||||
|
本地HTTP(S)代理28080端口,执行:
|
||||||
|
`./proxy http -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"`
|
||||||
|
##### ***1.7.2 ssh用户名和密钥的方式***
|
||||||
|
本地HTTP(S)代理28080端口,执行:
|
||||||
|
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||||
|
|
||||||
|
#### **1.8.KCP协议传输**
|
||||||
|
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||||
|
|
||||||
|
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||||
|
`./proxy http -t kcp -p ":38080" -B mypassword
|
||||||
|
|
||||||
|
二级HTTP代理(本地Linux)
|
||||||
|
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||||
|
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||||
|
|
||||||
|
#### **1.9.查看帮助**
|
||||||
|
`./proxy help http`
|
||||||
|
|
||||||
### 2.TCP代理
|
### 2.TCP代理
|
||||||
|
|
||||||
**2.1.普通一级TCP代理**
|
#### **2.1.普通一级TCP代理**
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22" -L 0`
|
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22" -L 0`
|
||||||
那么访问本地33080端口就是访问192.168.22.33的22端口.
|
那么访问本地33080端口就是访问192.168.22.33的22端口.
|
||||||
|
|
||||||
**2.2.普通二级TCP代理**
|
#### **2.2.普通二级TCP代理**
|
||||||
VPS(IP:22.22.22.33)执行:
|
VPS(IP:22.22.22.33)执行:
|
||||||
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0`
|
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0`
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy tcp -p ":23080" -T tcp -P "22.22.22.33:33080"`
|
`./proxy tcp -p ":23080" -T tcp -P "22.22.22.33:33080"`
|
||||||
那么访问本地23080端口就是访问22.22.22.33的8080端口.
|
那么访问本地23080端口就是访问22.22.22.33的8080端口.
|
||||||
|
|
||||||
**2.3.普通三级TCP代理**
|
#### **2.3.普通三级TCP代理**
|
||||||
一级TCP代理VPS_01,IP:22.22.22.22
|
一级TCP代理VPS_01,IP:22.22.22.22
|
||||||
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080" -L 0`
|
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080" -L 0`
|
||||||
二级TCP代理VPS_02,IP:33.33.33.33
|
二级TCP代理VPS_02,IP:33.33.33.33
|
||||||
@ -156,14 +243,14 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
`./proxy tcp -p ":8080" -T tcp -P "33.33.33.33:28080"`
|
`./proxy tcp -p ":8080" -T tcp -P "33.33.33.33:28080"`
|
||||||
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
||||||
|
|
||||||
**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 --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 --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
|
||||||
@ -172,24 +259,24 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
`./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端口.
|
||||||
|
|
||||||
**2.6.查看帮助**
|
#### **2.6.查看帮助**
|
||||||
`./proxy help tcp`
|
`./proxy help tcp`
|
||||||
|
|
||||||
### 3.UDP代理
|
### 3.UDP代理
|
||||||
|
|
||||||
**3.1.普通一级UDP代理**
|
#### **3.1.普通一级UDP代理**
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
|
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
|
||||||
那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口.
|
那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口.
|
||||||
|
|
||||||
**3.2.普通二级UDP代理**
|
#### **3.2.普通二级UDP代理**
|
||||||
VPS(IP:22.22.22.33)执行:
|
VPS(IP:22.22.22.33)执行:
|
||||||
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"`
|
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"`
|
||||||
本地执行:
|
本地执行:
|
||||||
`./proxy udp -p ":5353" -T tcp -P "22.22.22.33:33080"`
|
`./proxy udp -p ":5353" -T tcp -P "22.22.22.33:33080"`
|
||||||
那么访问本地UDP:5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
那么访问本地UDP:5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
||||||
|
|
||||||
**3.3.普通三级UDP代理**
|
#### **3.3.普通三级UDP代理**
|
||||||
一级TCP代理VPS_01,IP:22.22.22.22
|
一级TCP代理VPS_01,IP:22.22.22.22
|
||||||
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
|
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
|
||||||
二级TCP代理VPS_02,IP:33.33.33.33
|
二级TCP代理VPS_02,IP:33.33.33.33
|
||||||
@ -198,14 +285,14 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
`./proxy udp -p ":5353" -T tcp -P "33.33.33.33:28080"`
|
`./proxy udp -p ":5353" -T tcp -P "33.33.33.33:28080"`
|
||||||
那么访问本地5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的53端口.
|
那么访问本地5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的53端口.
|
||||||
|
|
||||||
**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 --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 --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
|
||||||
@ -214,11 +301,11 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
`./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端口.
|
||||||
|
|
||||||
**3.6.查看帮助**
|
#### **3.6.查看帮助**
|
||||||
`./proxy help udp`
|
`./proxy help udp`
|
||||||
|
|
||||||
### 4.内网穿透
|
### 4.内网穿透
|
||||||
**4.1、原理说明**
|
#### **4.1、原理说明**
|
||||||
内网穿透,由三部分组成:client端,server端,bridge端;client和server主动连接bridge端进行桥接.
|
内网穿透,由三部分组成:client端,server端,bridge端;client和server主动连接bridge端进行桥接.
|
||||||
当用户访问server端,流程是:
|
当用户访问server端,流程是:
|
||||||
1. server主动和bridge端建立连接;
|
1. server主动和bridge端建立连接;
|
||||||
@ -227,11 +314,10 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
1. 然后bridge端把client过来的连接与server端过来的连接绑定;
|
1. 然后bridge端把client过来的连接与server端过来的连接绑定;
|
||||||
1. 整个通道建立完成;
|
1. 整个通道建立完成;
|
||||||
|
|
||||||
**4.2、TCP普通用法**
|
#### **4.2、TCP普通用法**
|
||||||
背景:
|
背景:
|
||||||
- 公司机器A提供了web服务80端口
|
- 公司机器A提供了web服务80端口
|
||||||
- 有VPS一个,公网IP:22.22.22.22
|
- 有VPS一个,公网IP:22.22.22.22
|
||||||
- 本用法典型案例就是微信接口本地开发
|
|
||||||
|
|
||||||
需求:
|
需求:
|
||||||
在家里能够通过访问VPS的28080端口访问到公司机器A的80端口
|
在家里能够通过访问VPS的28080端口访问到公司机器A的80端口
|
||||||
@ -242,11 +328,11 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
`./proxy tserver -r ":28080@:80" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
`./proxy tserver -r ":28080@:80" -P "127.0.0.1:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 在公司机器A上面执行
|
1. 在公司机器A上面执行
|
||||||
`./proxy tclient -C proxy.crt -K proxy.key`
|
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
**4.3、微信接口本地开发**
|
#### **4.3、微信接口本地开发**
|
||||||
背景:
|
背景:
|
||||||
- 自己的笔记本提供了nginx服务80端口
|
- 自己的笔记本提供了nginx服务80端口
|
||||||
- 有VPS一个,公网IP:22.22.22.22
|
- 有VPS一个,公网IP:22.22.22.22
|
||||||
@ -261,14 +347,14 @@ 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 tbridge -p ":33080" -C proxy.crt -K proxy.key`
|
||||||
`./proxy tserver -r ":80@:80" -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`
|
||||||
|
|
||||||
1. 在自己笔记本上面执行
|
1. 在自己笔记本上面执行
|
||||||
`./proxy tclient -C proxy.crt -K proxy.key`
|
`./proxy tclient -P "22.22.22.22:33080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
**4.4、UDP普通用法**
|
#### **4.4、UDP普通用法**
|
||||||
背景:
|
背景:
|
||||||
- 公司机器A提供了DNS解析服务,UDP:53端口
|
- 公司机器A提供了DNS解析服务,UDP:53端口
|
||||||
- 有VPS一个,公网IP:22.22.22.22
|
- 有VPS一个,公网IP:22.22.22.22
|
||||||
@ -286,7 +372,7 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
**4.5、高级用法一**
|
#### **4.5、高级用法一**
|
||||||
背景:
|
背景:
|
||||||
- 公司机器A提供了web服务80端口
|
- 公司机器A提供了web服务80端口
|
||||||
- 有VPS一个,公网IP:22.22.22.22
|
- 有VPS一个,公网IP:22.22.22.22
|
||||||
@ -307,12 +393,12 @@ VPS(IP:22.22.22.33)执行:
|
|||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
**4.6、高级用法二**
|
#### **4.6、高级用法二**
|
||||||
提示:
|
提示:
|
||||||
如果同时有多个client连接到同一个bridge,需要指定不同的key,可以通过--k参数设定,--k可以是任意唯一字符串,
|
如果同时有多个client连接到同一个bridge,需要指定不同的key,可以通过--k参数设定,--k可以是任意唯一字符串,
|
||||||
只要在同一个bridge上唯一即可.
|
只要在同一个bridge上唯一即可.
|
||||||
server连接到bridge的时候,如果同时有多个client连接到同一个bridge,需要使用--k参数选择client.
|
server连接到bridge的时候,如果同时有多个client连接到同一个bridge,需要使用--k参数选择client.
|
||||||
暴露多个端口重复-r参数即可.-r格式是:"本地IP:本地端口@clientHOST:client端口"
|
暴露多个端口重复-r参数即可.-r格式是:"本地IP:本地端口@clientHOST:client端口".
|
||||||
|
|
||||||
背景:
|
背景:
|
||||||
- 公司机器A提供了web服务80端口,ftp服务21端口
|
- 公司机器A提供了web服务80端口,ftp服务21端口
|
||||||
@ -332,14 +418,109 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
|||||||
|
|
||||||
1. 完成
|
1. 完成
|
||||||
|
|
||||||
**4.7.查看帮助**
|
#### **4.7.tserver的-r参数**
|
||||||
|
-r完整格式是:`PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT`
|
||||||
|
|
||||||
|
4.7.1.协议PROTOCOL:tcp或者udp.
|
||||||
|
比如: `-r "udp://:10053@:53" -r "tcp://:10800@:1080" -r ":8080@:80"`
|
||||||
|
如果指定了--udp参数,PROTOCOL默认为udp,那么:`-r ":8080@:80"`默认为udp;
|
||||||
|
如果没有指定--udp参数,PROTOCOL默认为tcp,那么:`-r ":8080@:80"`默认为tcp;
|
||||||
|
|
||||||
|
4.7.2.CLIENT_KEY:默认是default.
|
||||||
|
比如: -r "udp://:10053@[test1]:53" -r "tcp://:10800@[test2]:1080" -r ":8080@:80"
|
||||||
|
如果指定了--k参数,比如--k test,那么:`-r ":8080@:80"`CLIENT_KEY默认为test;
|
||||||
|
如果没有指定--k参数,那么:`-r ":8080@:80"`CLIENT_KEY默认为default;
|
||||||
|
|
||||||
|
4.7.3.LOCAL_IP为空默认是:`0.0.0.0`,CLIENT_LOCAL_HOST为空默认是:`127.0.0.1`;
|
||||||
|
|
||||||
|
#### **4.8.查看帮助**
|
||||||
`./proxy help tbridge`
|
`./proxy help tbridge`
|
||||||
`./proxy help tserver`
|
`./proxy help tserver`
|
||||||
`./proxy help tserver`
|
`./proxy help tserver`
|
||||||
|
|
||||||
|
### 5.SOCKS5代理
|
||||||
|
提示:SOCKS5代理,只支持TCP协议,不支持UDP协议,不支持用户名密码认证.
|
||||||
|
#### **5.1.普通SOCKS5代理**
|
||||||
|
`./proxy socks -t tcp -p "0.0.0.0:38080"`
|
||||||
|
|
||||||
|
#### **5.2.普通二级SOCKS5代理**
|
||||||
|
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
||||||
|
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||||
|
我们还可以指定网站域名的黑白名单文件,一行一个域名,怕匹配规则是最右批评匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||||
|
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||||
|
|
||||||
|
#### **5.3.SOCKS二级代理(加密)**
|
||||||
|
一级SOCKS代理(VPS,IP:22.22.22.22)
|
||||||
|
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
二级SOCKS代理(本地Linux)
|
||||||
|
`./proxy socks -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
那么访问本地的8080端口就是访问VPS上面的代理端口38080.
|
||||||
|
|
||||||
|
二级SOCKS代理(本地windows)
|
||||||
|
`./proxy.exe socks -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
然后设置你的windos系统中,需要通过代理上网的程序的代理为socks5模式,地址为:127.0.0.1,端口为:8080,程序即可通过加密通道通过vps上网。
|
||||||
|
|
||||||
|
#### **5.4.SOCKS三级代理(加密)**
|
||||||
|
一级SOCKS代理VPS_01,IP:22.22.22.22
|
||||||
|
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||||
|
二级SOCKS代理VPS_02,IP:33.33.33.33
|
||||||
|
`./proxy socks -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
三级SOCKS代理(本地)
|
||||||
|
`./proxy socks -t tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||||
|
那么访问本地的8080端口就是访问一级SOCKS代理上面的代理端口38080.
|
||||||
|
|
||||||
|
#### **5.5.SOCKS代理流量强制走上级SOCKS代理**
|
||||||
|
默认情况下,proxy会智能判断一个网站域名是否无法访问,如果无法访问才走上级SOCKS代理.通过--always可以使全部SOCKS代理流量强制走上级SOCKS代理.
|
||||||
|
`./proxy socks --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||||
|
|
||||||
|
#### **5.6.SOCKS通过SSH中转**
|
||||||
|
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
|
||||||
|
假设有:vps
|
||||||
|
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
|
||||||
|
- 用户user的ssh私钥名称是user.key
|
||||||
|
|
||||||
|
##### ***5.6.1 ssh用户名和密码的方式***
|
||||||
|
本地SOCKS5代理28080端口,执行:
|
||||||
|
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"`
|
||||||
|
##### ***5.6.2 ssh用户名和密钥的方式***
|
||||||
|
本地SOCKS5代理28080端口,执行:
|
||||||
|
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||||
|
|
||||||
|
那么访问本地的28080端口就是通过VPS访问目标地址.
|
||||||
|
|
||||||
|
#### **5.7.认证**
|
||||||
|
对于socks5代理协议我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||||
|
`./proxy socks -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
多个用户,重复-a参数即可.
|
||||||
|
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||||
|
`./proxy socks -t tcp -p ":33080" -F auth-file.txt`
|
||||||
|
如果没有-a或-F参数,就是关闭认证.
|
||||||
|
|
||||||
|
#### **5.8.KCP协议传输**
|
||||||
|
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||||
|
|
||||||
|
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||||
|
`./proxy socks -t kcp -p ":38080" -B mypassword
|
||||||
|
|
||||||
|
二级HTTP代理(本地Linux)
|
||||||
|
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||||
|
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||||
|
|
||||||
|
#### **5.9.查看帮助**
|
||||||
|
`./proxy help socks`
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- socks5代理支持.
|
- http,socks代理多个上级负载均衡?
|
||||||
|
- 内网穿透server<->bridge心跳机制?
|
||||||
|
- 欢迎加群反馈...
|
||||||
|
|
||||||
|
### 如何使用源码?
|
||||||
|
cd进入你的go src目录,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
|
||||||
|
编译直接:go build
|
||||||
|
运行: go run *.go
|
||||||
|
utils是工具包,service是具体的每个服务类.
|
||||||
|
|
||||||
### License
|
### License
|
||||||
Proxy is licensed under GPLv3 license.
|
Proxy is licensed under GPLv3 license.
|
||||||
### Contact
|
### Contact
|
||||||
|
|||||||
99
config.go
@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"proxy/services"
|
"proxy/services"
|
||||||
@ -24,7 +23,7 @@ func initConfig() (err error) {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args := services.Args{}
|
|
||||||
//define args
|
//define args
|
||||||
tcpArgs := services.TCPArgs{}
|
tcpArgs := services.TCPArgs{}
|
||||||
httpArgs := services.HTTPArgs{}
|
httpArgs := services.HTTPArgs{}
|
||||||
@ -32,18 +31,18 @@ func initConfig() (err error) {
|
|||||||
tunnelClientArgs := services.TunnelClientArgs{}
|
tunnelClientArgs := services.TunnelClientArgs{}
|
||||||
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
tunnelBridgeArgs := services.TunnelBridgeArgs{}
|
||||||
udpArgs := services.UDPArgs{}
|
udpArgs := services.UDPArgs{}
|
||||||
|
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)
|
||||||
args.Parent = app.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
debug := app.Flag("debug", "debug log output").Default("false").Bool()
|
||||||
certTLS := app.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
|
||||||
keyTLS := app.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
|
||||||
|
|
||||||
//########http#########
|
//########http#########
|
||||||
http := app.Command("http", "proxy on http mode")
|
http := app.Command("http", "proxy on http mode")
|
||||||
httpArgs.LocalType = http.Flag("local-type", "parent protocol type <tls|tcp>").Default("tcp").Short('t').Enum("tls", "tcp")
|
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp>").Short('T').Enum("tls", "tcp")
|
httpArgs.CertFile = http.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
httpArgs.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
|
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh|kcp>").Short('T').Enum("tls", "tcp", "ssh", "kcp")
|
||||||
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
|
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
|
||||||
httpArgs.Timeout = http.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
httpArgs.Timeout = http.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
||||||
httpArgs.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
|
httpArgs.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
|
||||||
@ -55,9 +54,18 @@ func initConfig() (err error) {
|
|||||||
httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||||
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||||
httpArgs.Local = http.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
httpArgs.Local = http.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||||
|
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||||
|
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').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.KCPMethod = http.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||||
|
|
||||||
//########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.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.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('t').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|udp>").Short('T').Enum("tls", "tcp", "udp")
|
||||||
tcpArgs.IsTLS = tcp.Flag("tls", "proxy on tls mode").Default("false").Bool()
|
tcpArgs.IsTLS = tcp.Flag("tls", "proxy on tls mode").Default("false").Bool()
|
||||||
@ -67,6 +75,9 @@ func initConfig() (err error) {
|
|||||||
|
|
||||||
//########udp#########
|
//########udp#########
|
||||||
udp := app.Command("udp", "proxy on udp mode")
|
udp := app.Command("udp", "proxy on udp mode")
|
||||||
|
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
|
udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
||||||
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
|
||||||
udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
|
||||||
@ -75,36 +86,62 @@ func initConfig() (err error) {
|
|||||||
|
|
||||||
//########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.CertFile = tunnelServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
tunnelServerArgs.KeyFile = tunnelServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
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.Remote = tunnelServer.Flag("remote", "client's network host:port").Short('R').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.Local = tunnelServer.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
|
||||||
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as :localip:localport@clienthost:clientport").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")
|
||||||
|
tunnelClientArgs.Parent = tunnelClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
|
tunnelClientArgs.CertFile = tunnelClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
|
||||||
|
|
||||||
//########tunnel-bridge#########
|
//########tunnel-bridge#########
|
||||||
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
|
||||||
|
tunnelBridgeArgs.CertFile = tunnelBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||||
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
|
||||||
|
//########ssh#########
|
||||||
|
socks := app.Command("socks", "proxy on ssh mode")
|
||||||
|
socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').String()
|
||||||
|
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
||||||
|
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
|
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
|
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
||||||
|
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
||||||
|
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
|
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
|
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||||
|
socksArgs.SSHKeyFile = socks.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||||
|
socksArgs.SSHKeyFileSalt = socks.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
|
||||||
|
socksArgs.SSHPassword = socks.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
|
||||||
|
socksArgs.Always = socks.Flag("always", "always use parent proxy").Default("false").Bool()
|
||||||
|
socksArgs.Timeout = socks.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("5000").Int()
|
||||||
|
socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
||||||
|
socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
|
||||||
|
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
|
||||||
|
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||||
|
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.KCPMethod = socks.Flag("kcp-method", "kcp encrypt/decrypt method").Short('M').Default("3des").String()
|
||||||
|
|
||||||
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
flags := log.Ldate
|
||||||
if *certTLS != "" && *keyTLS != "" {
|
if *debug {
|
||||||
args.CertBytes, args.KeyBytes = tlsBytes(*certTLS, *keyTLS)
|
flags |= log.Lshortfile | log.Lmicroseconds
|
||||||
|
} else {
|
||||||
|
flags |= log.Ltime
|
||||||
}
|
}
|
||||||
|
log.SetFlags(flags)
|
||||||
//common args
|
|
||||||
httpArgs.Args = args
|
|
||||||
tcpArgs.Args = args
|
|
||||||
udpArgs.Args = args
|
|
||||||
tunnelBridgeArgs.Args = args
|
|
||||||
tunnelClientArgs.Args = args
|
|
||||||
tunnelServerArgs.Args = args
|
|
||||||
poster()
|
poster()
|
||||||
//regist services and run service
|
//regist services and run service
|
||||||
services.Regist("http", services.NewHTTP(), httpArgs)
|
services.Regist("http", services.NewHTTP(), httpArgs)
|
||||||
@ -113,9 +150,10 @@ 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("socks", services.NewSocks(), socksArgs)
|
||||||
service, err = services.Run(serviceName)
|
service, err = services.Run(serviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("run service [%s] fail, ERR:%s", service, err)
|
log.Fatalf("run service [%s] fail, ERR:%s", serviceName, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -132,16 +170,3 @@ func poster() {
|
|||||||
|
|
||||||
v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION)
|
v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION)
|
||||||
}
|
}
|
||||||
func tlsBytes(cert, key string) (certBytes, keyBytes []byte) {
|
|
||||||
certBytes, err := ioutil.ReadFile(cert)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("err : %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keyBytes, err = ioutil.ReadFile(key)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("err : %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
这里以vps centos 64位为例子
|
|
||||||
Linux 部分
|
|
||||||
1.Putty工具(或其他工具)
|
|
||||||
root登入
|
|
||||||
2.下载批量命令文件install_auto.sh(64位的话直接执行这个命令即可)
|
|
||||||
#curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
|
|
||||||
注意
|
|
||||||
这里的install_auto.sh 源码可以下载修改proxy版本,保存后执行.
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image001.png?raw=true"/>
|
|
||||||
3.修改/etc/proxy/proxy.toml配置文件
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image002.png?raw=true"/>
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image003.png?raw=true"/>
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image004.png?raw=true"/>
|
|
||||||
#/usr/bin/proxyd status
|
|
||||||
如果未运行那么执行调试命令:/usr/bin/proxy
|
|
||||||
如果一切正常,可以使用proxyd命令管理proxy,执行 proxyd 可以查看用法.
|
|
||||||
后台启动proxy: proxyd start
|
|
||||||
4.下载证书加密文件/etc/proxy/proxy.crt和/etc/proxy/proxy.key到windows
|
|
||||||
Windows部分
|
|
||||||
5.https://github.com/snail007/goproxy/releases 下载对应windows版本
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image005.jpg?raw=true"/>
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image006.png?raw=true"/>
|
|
||||||
我的是d:盘
|
|
||||||
6.修改windows下的proxy.toml vps服务ip和上面设置的端口哦
|
|
||||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/image007.png?raw=true"/>
|
|
||||||
然后运行proxy.exe即可.
|
|
||||||
这时候浏览器代理服务器就是127.0.0.1:9501啦,完毕!
|
|
||||||
|
|
||||||
要隐藏windows命令用工具下载RunHiddenConsole.exe 写个bat文件都放proxy目录下就行
|
|
||||||
Start.bat
|
|
||||||
|
|
||||||
@echo off
|
|
||||||
echo Starting
|
|
||||||
RunHiddenConsole D:/proxy/proxy.exe
|
|
||||||
|
|
||||||
Stop.bat
|
|
||||||
@echo off
|
|
||||||
echo Stopping
|
|
||||||
taskkill /F /IM proxy.exe > nul
|
|
||||||
exit
|
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@ -6,7 +6,7 @@ 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/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
|
||||||
wget https://github.com/snail007/goproxy/releases/download/v3.1/proxy-linux-amd64.tar.gz
|
wget https://github.com/snail007/goproxy/releases/download/v3.4/proxy-linux-amd64.tar.gz
|
||||||
|
|
||||||
# install monexec
|
# install monexec
|
||||||
tar zxvf monexec_0.1.1_linux_amd64.tar.gz
|
tar zxvf monexec_0.1.1_linux_amd64.tar.gz
|
||||||
|
|||||||
2
main.go
@ -9,7 +9,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VERSION = "3.0"
|
const APP_VERSION = "3.4"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := initConfig()
|
err := initConfig()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="3.1"
|
VER="3.4"
|
||||||
RELEASE="release-${VER}"
|
RELEASE="release-${VER}"
|
||||||
rm -rf .cert
|
rm -rf .cert
|
||||||
mkdir .cert
|
mkdir .cert
|
||||||
|
|||||||
112
services/args.go
@ -1,44 +1,61 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
|
import "golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
// tcp := app.Command("tcp", "proxy on tcp mode")
|
// tcp := app.Command("tcp", "proxy on tcp mode")
|
||||||
// t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
// t := tcp.Flag("tcp-timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TYPE_TCP = "tcp"
|
TYPE_TCP = "tcp"
|
||||||
TYPE_UDP = "udp"
|
TYPE_UDP = "udp"
|
||||||
TYPE_HTTP = "http"
|
TYPE_HTTP = "http"
|
||||||
TYPE_TLS = "tls"
|
TYPE_TLS = "tls"
|
||||||
CONN_CONTROL = uint8(1)
|
TYPE_KCP = "kcp"
|
||||||
CONN_SERVER = uint8(2)
|
CONN_CLIENT_CONTROL = uint8(1)
|
||||||
CONN_CLIENT = uint8(3)
|
CONN_CLIENT_HEARBEAT = uint8(2)
|
||||||
|
CONN_SERVER_HEARBEAT = uint8(3)
|
||||||
|
CONN_SERVER = uint8(4)
|
||||||
|
CONN_CLIENT = uint8(5)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Args struct {
|
type TunnelServerArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
}
|
Local *string
|
||||||
type TunnelServerArgs struct {
|
IsUDP *bool
|
||||||
Args
|
Key *string
|
||||||
Local *string
|
Remote *string
|
||||||
IsUDP *bool
|
Timeout *int
|
||||||
Key *string
|
Route *[]string
|
||||||
Remote *string
|
Mgr *TunnelServerManager
|
||||||
Timeout *int
|
|
||||||
Route *[]string
|
|
||||||
}
|
}
|
||||||
type TunnelClientArgs struct {
|
type TunnelClientArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
Key *string
|
CertFile *string
|
||||||
Timeout *int
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
Key *string
|
||||||
|
Timeout *int
|
||||||
}
|
}
|
||||||
type TunnelBridgeArgs struct {
|
type TunnelBridgeArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
Local *string
|
CertFile *string
|
||||||
Timeout *int
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
Local *string
|
||||||
|
Timeout *int
|
||||||
}
|
}
|
||||||
type TCPArgs struct {
|
type TCPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
IsTLS *bool
|
IsTLS *bool
|
||||||
@ -48,7 +65,11 @@ type TCPArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPArgs struct {
|
type HTTPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
Always *bool
|
Always *bool
|
||||||
HTTPTimeout *int
|
HTTPTimeout *int
|
||||||
@ -62,15 +83,54 @@ type HTTPArgs struct {
|
|||||||
Timeout *int
|
Timeout *int
|
||||||
PoolSize *int
|
PoolSize *int
|
||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
|
SSHKeyFile *string
|
||||||
|
SSHKeyFileSalt *string
|
||||||
|
SSHPassword *string
|
||||||
|
SSHUser *string
|
||||||
|
SSHKeyBytes []byte
|
||||||
|
SSHAuthMethod ssh.AuthMethod
|
||||||
|
KCPMethod *string
|
||||||
|
KCPKey *string
|
||||||
}
|
}
|
||||||
type UDPArgs struct {
|
type UDPArgs struct {
|
||||||
Args
|
Parent *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
PoolSize *int
|
PoolSize *int
|
||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
}
|
}
|
||||||
|
type SocksArgs struct {
|
||||||
|
Parent *string
|
||||||
|
ParentType *string
|
||||||
|
Local *string
|
||||||
|
LocalType *string
|
||||||
|
CertFile *string
|
||||||
|
KeyFile *string
|
||||||
|
CertBytes []byte
|
||||||
|
KeyBytes []byte
|
||||||
|
SSHKeyFile *string
|
||||||
|
SSHKeyFileSalt *string
|
||||||
|
SSHPassword *string
|
||||||
|
SSHUser *string
|
||||||
|
SSHKeyBytes []byte
|
||||||
|
SSHAuthMethod ssh.AuthMethod
|
||||||
|
Timeout *int
|
||||||
|
Always *bool
|
||||||
|
Interval *int
|
||||||
|
Blocked *string
|
||||||
|
Direct *string
|
||||||
|
AuthFile *string
|
||||||
|
Auth *[]string
|
||||||
|
KCPMethod *string
|
||||||
|
KCPKey *string
|
||||||
|
UDPParent *string
|
||||||
|
UDPLocal *string
|
||||||
|
}
|
||||||
|
|
||||||
func (a *TCPArgs) Protocol() string {
|
func (a *TCPArgs) Protocol() string {
|
||||||
if *a.IsTLS {
|
if *a.IsTLS {
|
||||||
|
|||||||
197
services/http.go
@ -3,11 +3,15 @@ package services
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"proxy/utils"
|
"proxy/utils"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
@ -15,6 +19,8 @@ type HTTP struct {
|
|||||||
cfg HTTPArgs
|
cfg HTTPArgs
|
||||||
checker utils.Checker
|
checker utils.Checker
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
|
sshClient *ssh.Client
|
||||||
|
lockChn chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP() Service {
|
func NewHTTP() Service {
|
||||||
@ -23,6 +29,43 @@ func NewHTTP() Service {
|
|||||||
cfg: HTTPArgs{},
|
cfg: HTTPArgs{},
|
||||||
checker: utils.Checker{},
|
checker: utils.Checker{},
|
||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
|
lockChn: make(chan bool, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *HTTP) CheckArgs() {
|
||||||
|
var err error
|
||||||
|
if *s.cfg.Parent != "" && *s.cfg.ParentType == "" {
|
||||||
|
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh>")
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
if *s.cfg.SSHUser == "" {
|
||||||
|
log.Fatalf("ssh user required")
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||||
|
log.Fatalf("ssh password or key required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *s.cfg.SSHPassword != "" {
|
||||||
|
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
|
||||||
|
} else {
|
||||||
|
var SSHSigner ssh.Signer
|
||||||
|
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("read key file ERR: %s", err)
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFileSalt != "" {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||||
|
} else {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||||
|
}
|
||||||
|
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitService() {
|
func (s *HTTP) InitService() {
|
||||||
@ -30,6 +73,34 @@ func (s *HTTP) InitService() {
|
|||||||
if *s.cfg.Parent != "" {
|
if *s.cfg.Parent != "" {
|
||||||
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
err := s.ConnectSSH()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init service fail, ERR: %s", err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
//循环检查ssh网络连通性
|
||||||
|
for {
|
||||||
|
conn, err := utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout*2)
|
||||||
|
if err == nil {
|
||||||
|
_, err = conn.Write([]byte{0})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
if s.sshClient.Conn != nil {
|
||||||
|
s.sshClient.Conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("ssh offline, retrying...")
|
||||||
|
s.ConnectSSH()
|
||||||
|
} else {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) StopService() {
|
func (s *HTTP) StopService() {
|
||||||
if s.outPool.Pool != nil {
|
if s.outPool.Pool != nil {
|
||||||
@ -38,20 +109,21 @@ func (s *HTTP) StopService() {
|
|||||||
}
|
}
|
||||||
func (s *HTTP) Start(args interface{}) (err error) {
|
func (s *HTTP) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(HTTPArgs)
|
s.cfg = args.(HTTPArgs)
|
||||||
|
s.CheckArgs()
|
||||||
if *s.cfg.Parent != "" {
|
if *s.cfg.Parent != "" {
|
||||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.InitService()
|
s.InitService()
|
||||||
|
|
||||||
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.LocalType == TYPE_TCP {
|
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
|
||||||
@ -69,7 +141,9 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
req, err := utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
|
var err interface{}
|
||||||
|
var req utils.HTTPRequest
|
||||||
|
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 , form %s, ERR:%s", err, inConn.RemoteAddr())
|
||||||
@ -95,8 +169,9 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
|
//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)
|
||||||
//os.Exit(0)
|
|
||||||
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if *s.cfg.Parent == "" {
|
if *s.cfg.Parent == "" {
|
||||||
log.Printf("connect to %s fail, ERR:%s", address, err)
|
log.Printf("connect to %s fail, ERR:%s", address, err)
|
||||||
@ -106,7 +181,7 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (err error) {
|
func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (err interface{}) {
|
||||||
inAddr := (*inConn).RemoteAddr().String()
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
inLocalAddr := (*inConn).LocalAddr().String()
|
inLocalAddr := (*inConn).LocalAddr().String()
|
||||||
//防止死循环
|
//防止死循环
|
||||||
@ -117,13 +192,29 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
}
|
}
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
var _outConn interface{}
|
var _outConn interface{}
|
||||||
if useProxy {
|
tryCount := 0
|
||||||
_outConn, err = s.outPool.Pool.Get()
|
maxTryCount := 5
|
||||||
if err == nil {
|
for {
|
||||||
outConn = _outConn.(net.Conn)
|
if useProxy {
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
outConn, err = s.getSSHConn(address)
|
||||||
|
} else {
|
||||||
|
//log.Printf("%v", s.outPool)
|
||||||
|
_outConn, err = s.outPool.Pool.Get()
|
||||||
|
if err == nil {
|
||||||
|
outConn = _outConn.(net.Conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
tryCount++
|
||||||
|
if err == nil || tryCount > maxTryCount {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
log.Printf("connect to %s , err:%s,retrying...", *s.cfg.Parent, err)
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
outConn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
||||||
@ -134,29 +225,95 @@ 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 {
|
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||||
req.HTTPSReply()
|
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
||||||
|
err = req.HTTPSReply()
|
||||||
} else {
|
} else {
|
||||||
outConn.Write(req.HeadBuf)
|
//https或者http,上级是代理,proxy需要转发
|
||||||
|
_, err = outConn.Write(req.HeadBuf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.IoBind((*inConn), outConn, func(err error) {
|
utils.IoBind((*inConn), outConn, func(err error) {
|
||||||
log.Printf("conn %s - %s - %s -%s released [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
log.Printf("conn %s - %s - %s - %s released [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
}, func(n int, d bool) {}, 0)
|
})
|
||||||
log.Printf("conn %s - %s - %s - %s connected [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
log.Printf("conn %s - %s - %s - %s connected [%s]", inAddr, inLocalAddr, outLocalAddr, outAddr, req.Host)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) OutToUDP(inConn *net.Conn) (err error) {
|
|
||||||
|
func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
|
||||||
|
maxTryCount := 1
|
||||||
|
tryCount := 0
|
||||||
|
RETRY:
|
||||||
|
if tryCount >= maxTryCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wait := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = recover()
|
||||||
|
}
|
||||||
|
wait <- true
|
||||||
|
}()
|
||||||
|
outConn, err = s.sshClient.Dial("tcp", host)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-wait:
|
||||||
|
case <-time.After(time.Second * 5):
|
||||||
|
err = fmt.Errorf("ssh dial %s timeout", host)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
|
e := s.ConnectSSH()
|
||||||
|
if e == nil {
|
||||||
|
tryCount++
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
goto RETRY
|
||||||
|
} else {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *HTTP) ConnectSSH() (err error) {
|
||||||
|
select {
|
||||||
|
case s.lockChn <- true:
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("can not connect at same time")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
config := ssh.ClientConfig{
|
||||||
|
Timeout: time.Duration(*s.cfg.Timeout) * time.Millisecond,
|
||||||
|
User: *s.cfg.SSHUser,
|
||||||
|
Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod},
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config)
|
||||||
|
<-s.lockChn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitOutConnPool() {
|
func (s *HTTP) 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 == TYPE_TLS,
|
*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,
|
||||||
|
|||||||
570
services/socks.go
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"proxy/utils"
|
||||||
|
"proxy/utils/aes"
|
||||||
|
"proxy/utils/socks"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Socks struct {
|
||||||
|
cfg SocksArgs
|
||||||
|
checker utils.Checker
|
||||||
|
basicAuth utils.BasicAuth
|
||||||
|
sshClient *ssh.Client
|
||||||
|
lockChn chan bool
|
||||||
|
udpSC utils.ServerChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSocks() Service {
|
||||||
|
return &Socks{
|
||||||
|
cfg: SocksArgs{},
|
||||||
|
checker: utils.Checker{},
|
||||||
|
basicAuth: utils.BasicAuth{},
|
||||||
|
lockChn: make(chan bool, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks) CheckArgs() {
|
||||||
|
var err error
|
||||||
|
if *s.cfg.LocalType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
if *s.cfg.ParentType == "" {
|
||||||
|
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh>")
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
if *s.cfg.SSHUser == "" {
|
||||||
|
log.Fatalf("ssh user required")
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
|
||||||
|
log.Fatalf("ssh password or key required")
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHPassword != "" {
|
||||||
|
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
|
||||||
|
} else {
|
||||||
|
var SSHSigner ssh.Signer
|
||||||
|
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("read key file ERR: %s", err)
|
||||||
|
}
|
||||||
|
if *s.cfg.SSHKeyFileSalt != "" {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
|
||||||
|
} else {
|
||||||
|
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("parse ssh private key fail,ERR: %s", err)
|
||||||
|
}
|
||||||
|
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *Socks) InitService() {
|
||||||
|
s.InitBasicAuth()
|
||||||
|
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
err := s.ConnectSSH()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init service fail, ERR: %s", err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
//循环检查ssh网络连通性
|
||||||
|
for {
|
||||||
|
conn, err := utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout*2)
|
||||||
|
if err == nil {
|
||||||
|
_, err = conn.Write([]byte{0})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
log.Printf("ssh offline, retrying...")
|
||||||
|
s.ConnectSSH()
|
||||||
|
} else {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
log.Println("warn: socks udp not suppored for ssh")
|
||||||
|
} else {
|
||||||
|
|
||||||
|
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
|
||||||
|
err := s.udpSC.ListenUDP(s.udpCallback)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("init udp service fail, ERR: %s", err)
|
||||||
|
}
|
||||||
|
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *Socks) StopService() {
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
if s.udpSC.UDPListener != nil {
|
||||||
|
s.udpSC.UDPListener.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (s *Socks) Start(args interface{}) (err error) {
|
||||||
|
//start()
|
||||||
|
s.cfg = args.(SocksArgs)
|
||||||
|
s.CheckArgs()
|
||||||
|
s.InitService()
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
|
}
|
||||||
|
sc := utils.NewServerChannelHost(*s.cfg.Local)
|
||||||
|
if *s.cfg.LocalType == TYPE_TCP {
|
||||||
|
err = sc.ListenTCP(s.socksConnCallback)
|
||||||
|
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||||
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
|
||||||
|
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||||
|
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.socksConnCallback)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
func (s *Socks) UDPKey() []byte {
|
||||||
|
return s.cfg.KeyBytes[:32]
|
||||||
|
}
|
||||||
|
func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||||
|
rawB := b
|
||||||
|
var err error
|
||||||
|
if *s.cfg.LocalType == "tls" {
|
||||||
|
//decode b
|
||||||
|
rawB, err = goaes.Decrypt(s.UDPKey(), b)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("decrypt udp packet fail from %s", srcAddr.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p, err := socks.ParseUDPPacket(rawB)
|
||||||
|
log.Printf("udp revecived:%v", len(p.Data()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("parse udp packet fail, ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port())
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
//有上级代理,转发给上级
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
//encode b
|
||||||
|
rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent := *s.cfg.UDPParent
|
||||||
|
if parent == "" {
|
||||||
|
parent = *s.cfg.Parent
|
||||||
|
}
|
||||||
|
dstAddr, err := net.ResolveUDPAddr("udp", parent)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't resolve address: %s", err)
|
||||||
|
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*5)))
|
||||||
|
_, err = conn.Write(rawB)
|
||||||
|
log.Printf("udp request:%v", len(rawB))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
|
buf := make([]byte, 10*1024)
|
||||||
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respBody := buf[0:length]
|
||||||
|
log.Printf("udp response:%v", len(respBody))
|
||||||
|
//log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
//decode b
|
||||||
|
respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *s.cfg.LocalType == "tls" {
|
||||||
|
d, err := goaes.Encrypt(s.UDPKey(), respBody)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||||
|
log.Printf("udp reply:%v", len(d))
|
||||||
|
} else {
|
||||||
|
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
||||||
|
log.Printf("udp reply:%v", len(respBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//本地代理
|
||||||
|
dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(p.Host(), p.Port()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("can't resolve address: %s", err)
|
||||||
|
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*3)))
|
||||||
|
_, err = conn.Write(p.Data())
|
||||||
|
log.Printf("udp send:%v", len(p.Data()))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||||
|
buf := make([]byte, 10*1024)
|
||||||
|
length, _, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
respBody := buf[0:length]
|
||||||
|
//封装来自真实服务器的数据,返回给访问者
|
||||||
|
respPacket := p.NewReply(respBody)
|
||||||
|
//log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||||
|
if *s.cfg.LocalType == "tls" {
|
||||||
|
d, err := goaes.Encrypt(s.UDPKey(), respPacket)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||||
|
} else {
|
||||||
|
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
||||||
|
}
|
||||||
|
log.Printf("udp reply:%v", len(respPacket))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
}()
|
||||||
|
//协商开始
|
||||||
|
|
||||||
|
//method select request
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
methodReq, err := socks.NewMethodsRequest(inConn)
|
||||||
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("new methods request fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.IsBasicAuth() {
|
||||||
|
if !methodReq.Select(socks.Method_NO_AUTH) {
|
||||||
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("none method found : Method_NO_AUTH")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//method select reply
|
||||||
|
err = methodReq.Reply(socks.Method_NO_AUTH)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("reply answer data fail,ERR: %s", err)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// log.Printf("% x", methodReq.Bytes())
|
||||||
|
} else {
|
||||||
|
//auth
|
||||||
|
if !methodReq.Select(socks.Method_USER_PASS) {
|
||||||
|
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
log.Printf("none method found : Method_USER_PASS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//method reply need auth
|
||||||
|
err = methodReq.Reply(socks.Method_USER_PASS)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("reply answer data fail,ERR: %s", err)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//read auth
|
||||||
|
buf := make([]byte, 500)
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
n, err := inConn.Read(buf)
|
||||||
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r := buf[:n]
|
||||||
|
user := string(r[2 : r[1]+2])
|
||||||
|
pass := string(r[2+r[1]+1:])
|
||||||
|
//log.Printf("user:%s,pass:%s", user, pass)
|
||||||
|
//auth
|
||||||
|
if s.basicAuth.CheckUserPass(user, pass) {
|
||||||
|
inConn.Write([]byte{0x01, 0x00})
|
||||||
|
} else {
|
||||||
|
inConn.Write([]byte{0x01, 0x01})
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//request detail
|
||||||
|
request, err := socks.NewRequest(inConn)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read request data fail,ERR: %s", err)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//协商结束
|
||||||
|
|
||||||
|
switch request.CMD() {
|
||||||
|
case socks.CMD_BIND:
|
||||||
|
//bind 不支持
|
||||||
|
request.TCPReply(socks.REP_UNKNOWN)
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
return
|
||||||
|
case socks.CMD_CONNECT:
|
||||||
|
//tcp
|
||||||
|
s.proxyTCP(&inConn, methodReq, request)
|
||||||
|
case socks.CMD_ASSOCIATE:
|
||||||
|
//udp
|
||||||
|
s.proxyUDP(&inConn, methodReq, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
||||||
|
if *s.cfg.ParentType == "ssh" {
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
||||||
|
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
|
||||||
|
log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
|
||||||
|
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
|
||||||
|
}
|
||||||
|
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
||||||
|
var outConn net.Conn
|
||||||
|
defer utils.CloseConn(&outConn)
|
||||||
|
var err interface{}
|
||||||
|
useProxy := true
|
||||||
|
tryCount := 0
|
||||||
|
maxTryCount := 5
|
||||||
|
for {
|
||||||
|
if *s.cfg.Always {
|
||||||
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||||
|
} else {
|
||||||
|
if *s.cfg.Parent != "" {
|
||||||
|
s.checker.Add(request.Addr(), true, "", "", nil)
|
||||||
|
useProxy, _, _ = s.checker.IsBlocked(request.Addr())
|
||||||
|
if useProxy {
|
||||||
|
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(request.Addr(), *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(request.Addr(), *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tryCount++
|
||||||
|
if err == nil || tryCount > maxTryCount {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
log.Printf("get out conn fail,%s,retrying...", err)
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("get out conn fail,%s", err)
|
||||||
|
request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("use proxy %v : %s", useProxy, request.Addr())
|
||||||
|
|
||||||
|
request.TCPReply(socks.REP_SUCCESS)
|
||||||
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
|
inLocalAddr := (*inConn).LocalAddr().String()
|
||||||
|
|
||||||
|
log.Printf("conn %s - %s connected [%s]", inAddr, inLocalAddr, request.Addr())
|
||||||
|
utils.IoBind(*inConn, outConn, func(err error) {
|
||||||
|
log.Printf("conn %s - %s released [%s]", inAddr, inLocalAddr, request.Addr())
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
|
||||||
|
switch *s.cfg.ParentType {
|
||||||
|
case "kcp":
|
||||||
|
fallthrough
|
||||||
|
case "tls":
|
||||||
|
fallthrough
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
var _outConn tls.Conn
|
||||||
|
_outConn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||||
|
outConn = net.Conn(&_outConn)
|
||||||
|
} else if *s.cfg.ParentType == "kcp" {
|
||||||
|
outConn, err = utils.ConnectKCPHost(*s.cfg.Parent, *s.cfg.KCPMethod, *s.cfg.KCPKey)
|
||||||
|
} else {
|
||||||
|
outConn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("connect fail,%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buf = make([]byte, 1024)
|
||||||
|
//var n int
|
||||||
|
_, err = outConn.Write(methodBytes)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("write method fail,%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = outConn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("read method reply fail,%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//resp := buf[:n]
|
||||||
|
//log.Printf("resp:%v", resp)
|
||||||
|
|
||||||
|
_, err = outConn.Write(reqBytes)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("write req detail fail,%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// _, err = outConn.Read(buf)
|
||||||
|
// if err != nil {
|
||||||
|
// err = fmt.Errorf("read req reply fail,%s", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//result := buf[:n]
|
||||||
|
//log.Printf("result:%v", result)
|
||||||
|
|
||||||
|
case "ssh":
|
||||||
|
maxTryCount := 1
|
||||||
|
tryCount := 0
|
||||||
|
RETRY:
|
||||||
|
if tryCount >= maxTryCount {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wait := make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = recover()
|
||||||
|
}
|
||||||
|
wait <- true
|
||||||
|
}()
|
||||||
|
outConn, err = s.sshClient.Dial("tcp", host)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-wait:
|
||||||
|
case <-time.After(time.Millisecond * time.Duration(*s.cfg.Timeout) * 2):
|
||||||
|
err = fmt.Errorf("ssh dial %s timeout", host)
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
|
e := s.ConnectSSH()
|
||||||
|
if e == nil {
|
||||||
|
tryCount++
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
goto RETRY
|
||||||
|
} else {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) ConnectSSH() (err error) {
|
||||||
|
select {
|
||||||
|
case s.lockChn <- true:
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("can not connect at same time")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
config := ssh.ClientConfig{
|
||||||
|
Timeout: time.Duration(*s.cfg.Timeout) * time.Millisecond,
|
||||||
|
User: *s.cfg.SSHUser,
|
||||||
|
Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod},
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if s.sshClient != nil {
|
||||||
|
s.sshClient.Close()
|
||||||
|
}
|
||||||
|
s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config)
|
||||||
|
<-s.lockChn
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) InitBasicAuth() (err error) {
|
||||||
|
s.basicAuth = utils.NewBasicAuth()
|
||||||
|
if *s.cfg.AuthFile != "" {
|
||||||
|
var n = 0
|
||||||
|
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
if len(*s.cfg.Auth) > 0 {
|
||||||
|
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||||
|
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) IsBasicAuth() bool {
|
||||||
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0
|
||||||
|
}
|
||||||
@ -24,6 +24,17 @@ func NewTCP() Service {
|
|||||||
cfg: TCPArgs{},
|
cfg: TCPArgs{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (s *TCP) CheckArgs() {
|
||||||
|
if *s.cfg.Parent == "" {
|
||||||
|
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "" {
|
||||||
|
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" || *s.cfg.IsTLS {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
func (s *TCP) InitService() {
|
func (s *TCP) InitService() {
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
}
|
}
|
||||||
@ -34,12 +45,8 @@ func (s *TCP) StopService() {
|
|||||||
}
|
}
|
||||||
func (s *TCP) Start(args interface{}) (err error) {
|
func (s *TCP) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(TCPArgs)
|
s.cfg = args.(TCPArgs)
|
||||||
if *s.cfg.Parent != "" {
|
s.CheckArgs()
|
||||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
} else {
|
|
||||||
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.InitService()
|
s.InitService()
|
||||||
|
|
||||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
@ -99,11 +106,11 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
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 error) {
|
||||||
log.Printf("conn %s - %s - %s -%s released", inAddr, inLocalAddr, outLocalAddr, outAddr)
|
log.Printf("conn %s - %s - %s - %s released", inAddr, inLocalAddr, outLocalAddr, outAddr)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
}, func(n int, d bool) {}, 0)
|
})
|
||||||
log.Printf("conn %s - %s - %s -%s connected", inAddr, inLocalAddr, outLocalAddr, outAddr)
|
log.Printf("conn %s - %s - %s - %s connected", inAddr, inLocalAddr, outLocalAddr, outAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
|
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
|
||||||
@ -160,7 +167,8 @@ func (s *TCP) InitOutConnPool() {
|
|||||||
//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 == TYPE_TLS,
|
*s.cfg.ParentType,
|
||||||
|
"", "",
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||||
*s.cfg.Parent,
|
*s.cfg.Parent,
|
||||||
*s.cfg.Timeout,
|
*s.cfg.Timeout,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/binary"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"proxy/utils"
|
"proxy/utils"
|
||||||
@ -11,14 +10,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ServerConn struct {
|
type ServerConn struct {
|
||||||
ClientLocalAddr string //tcp:2.2.22:333@ID
|
//ClientLocalAddr string //tcp:2.2.22:333@ID
|
||||||
Conn *net.Conn
|
Conn *net.Conn
|
||||||
//Conn *utils.HeartbeatReadWriter
|
|
||||||
}
|
}
|
||||||
type TunnelBridge struct {
|
type TunnelBridge struct {
|
||||||
cfg TunnelBridgeArgs
|
cfg TunnelBridgeArgs
|
||||||
serverConns utils.ConcurrentMap
|
serverConns utils.ConcurrentMap
|
||||||
clientControlConns utils.ConcurrentMap
|
clientControlConns utils.ConcurrentMap
|
||||||
|
cmServer utils.ConnManager
|
||||||
|
cmClient utils.ConnManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunnelBridge() Service {
|
func NewTunnelBridge() Service {
|
||||||
@ -26,24 +26,26 @@ func NewTunnelBridge() Service {
|
|||||||
cfg: TunnelBridgeArgs{},
|
cfg: TunnelBridgeArgs{},
|
||||||
serverConns: utils.NewConcurrentMap(),
|
serverConns: utils.NewConcurrentMap(),
|
||||||
clientControlConns: utils.NewConcurrentMap(),
|
clientControlConns: utils.NewConcurrentMap(),
|
||||||
|
cmServer: utils.NewConnManager(),
|
||||||
|
cmClient: utils.NewConnManager(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TunnelBridge) InitService() {
|
func (s *TunnelBridge) InitService() {
|
||||||
|
|
||||||
}
|
}
|
||||||
func (s *TunnelBridge) Check() {
|
func (s *TunnelBridge) CheckArgs() {
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
log.Fatalf("cert and key file required")
|
log.Fatalf("cert and key file required")
|
||||||
}
|
}
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
}
|
}
|
||||||
func (s *TunnelBridge) StopService() {
|
func (s *TunnelBridge) StopService() {
|
||||||
|
|
||||||
}
|
}
|
||||||
func (s *TunnelBridge) Start(args interface{}) (err error) {
|
func (s *TunnelBridge) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(TunnelBridgeArgs)
|
s.cfg = args.(TunnelBridgeArgs)
|
||||||
s.Check()
|
s.CheckArgs()
|
||||||
s.InitService()
|
s.InitService()
|
||||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
@ -53,79 +55,27 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
|||||||
//log.Printf("connection from %s ", inConn.RemoteAddr())
|
//log.Printf("connection from %s ", inConn.RemoteAddr())
|
||||||
|
|
||||||
reader := bufio.NewReader(inConn)
|
reader := bufio.NewReader(inConn)
|
||||||
|
var err error
|
||||||
var connType uint8
|
var connType uint8
|
||||||
err = binary.Read(reader, binary.LittleEndian, &connType)
|
err = utils.ReadPacket(reader, &connType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&inConn)
|
log.Printf("read error,ERR:%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Printf("conn type %d", connType)
|
|
||||||
|
|
||||||
var key, clientLocalAddr, ID string
|
|
||||||
var connTypeStrMap = map[uint8]string{CONN_SERVER: "server", CONN_CLIENT: "client", CONN_CONTROL: "client"}
|
|
||||||
var keyLength uint16
|
|
||||||
err = binary.Read(reader, binary.LittleEndian, &keyLength)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_key := make([]byte, keyLength)
|
|
||||||
n, err := reader.Read(_key)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if n != int(keyLength) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
key = string(_key)
|
|
||||||
//log.Printf("conn key %s", key)
|
|
||||||
|
|
||||||
if connType != CONN_CONTROL {
|
|
||||||
var IDLength uint16
|
|
||||||
err = binary.Read(reader, binary.LittleEndian, &IDLength)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_id := make([]byte, IDLength)
|
|
||||||
n, err := reader.Read(_id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if n != int(IDLength) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ID = string(_id)
|
|
||||||
|
|
||||||
if connType == CONN_SERVER {
|
|
||||||
var addrLength uint16
|
|
||||||
err = binary.Read(reader, binary.LittleEndian, &addrLength)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_addr := make([]byte, addrLength)
|
|
||||||
n, err = reader.Read(_addr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if n != int(addrLength) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientLocalAddr = string(_addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Printf("connection from %s , key: %s , id: %s", connTypeStrMap[connType], key, ID)
|
|
||||||
|
|
||||||
switch connType {
|
switch connType {
|
||||||
case CONN_SERVER:
|
case CONN_SERVER:
|
||||||
// hb := utils.NewHeartbeatReadWriter(&inConn, 3, func(err error, hb *utils.HeartbeatReadWriter) {
|
var key, ID, clientLocalAddr, serverID string
|
||||||
// log.Printf("%s conn %s from server released", key, ID)
|
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
|
||||||
// s.serverConns.Remove(ID)
|
if err != nil {
|
||||||
// })
|
log.Printf("read error,ERR:%s", err)
|
||||||
addr := clientLocalAddr + "@" + ID
|
return
|
||||||
|
}
|
||||||
|
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
|
||||||
|
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
|
||||||
|
|
||||||
|
//addr := clientLocalAddr + "@" + ID
|
||||||
s.serverConns.Set(ID, ServerConn{
|
s.serverConns.Set(ID, ServerConn{
|
||||||
//Conn: &hb,
|
Conn: &inConn,
|
||||||
Conn: &inConn,
|
|
||||||
ClientLocalAddr: addr,
|
|
||||||
})
|
})
|
||||||
for {
|
for {
|
||||||
item, ok := s.clientControlConns.Get(key)
|
item, ok := s.clientControlConns.Get(key)
|
||||||
@ -134,16 +84,27 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
|||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err := (*item.(*net.Conn)).Write([]byte(addr))
|
(*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
_, err := (*item.(*net.Conn)).Write(packet)
|
||||||
|
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
|
s.cmServer.Add(serverID, ID, &inConn)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case CONN_CLIENT:
|
case CONN_CLIENT:
|
||||||
|
var key, ID, serverID string
|
||||||
|
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
|
||||||
|
|
||||||
serverConnItem, ok := s.serverConns.Get(ID)
|
serverConnItem, ok := s.serverConns.Get(ID)
|
||||||
if !ok {
|
if !ok {
|
||||||
inConn.Close()
|
inConn.Close()
|
||||||
@ -151,33 +112,127 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
serverConn := serverConnItem.(ServerConn).Conn
|
serverConn := serverConnItem.(ServerConn).Conn
|
||||||
// hw := utils.NewHeartbeatReadWriter(&inConn, 3, func(err error, hw *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("%s conn %s from client released", key, ID)
|
|
||||||
// hw.Close()
|
|
||||||
// })
|
|
||||||
utils.IoBind(*serverConn, inConn, func(err error) {
|
utils.IoBind(*serverConn, inConn, func(err error) {
|
||||||
// utils.IoBind(serverConn, inConn, func(isSrcErr bool, err error) {
|
|
||||||
//serverConn.Close()
|
|
||||||
(*serverConn).Close()
|
(*serverConn).Close()
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
// hw.Close()
|
|
||||||
s.serverConns.Remove(ID)
|
s.serverConns.Remove(ID)
|
||||||
|
s.cmClient.RemoveOne(key, ID)
|
||||||
|
s.cmServer.RemoveOne(serverID, ID)
|
||||||
log.Printf("conn %s released", ID)
|
log.Printf("conn %s released", ID)
|
||||||
}, func(i int, b bool) {}, 0)
|
})
|
||||||
|
s.cmClient.Add(key, ID, &inConn)
|
||||||
log.Printf("conn %s created", ID)
|
log.Printf("conn %s created", ID)
|
||||||
case CONN_CONTROL:
|
|
||||||
|
case CONN_CLIENT_CONTROL:
|
||||||
|
var key string
|
||||||
|
err = utils.ReadPacketData(reader, &key)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("client control connection, key: %s", key)
|
||||||
if s.clientControlConns.Has(key) {
|
if s.clientControlConns.Has(key) {
|
||||||
item, _ := s.clientControlConns.Get(key)
|
item, _ := s.clientControlConns.Get(key)
|
||||||
//(*item.(*utils.HeartbeatReadWriter)).Close()
|
|
||||||
(*item.(*net.Conn)).Close()
|
(*item.(*net.Conn)).Close()
|
||||||
}
|
}
|
||||||
// hb := utils.NewHeartbeatReadWriter(&inConn, 3, func(err error, hb *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("client %s disconnected", key)
|
|
||||||
// s.clientControlConns.Remove(key)
|
|
||||||
// })
|
|
||||||
// s.clientControlConns.Set(key, &hb)
|
|
||||||
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:
|
||||||
|
var serverID string
|
||||||
|
err = utils.ReadPacketData(reader, &serverID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("server heartbeat connection, id: %s", serverID)
|
||||||
|
writeDie := make(chan bool)
|
||||||
|
readDie := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
_, err = inConn.Write([]byte{0x00})
|
||||||
|
inConn.SetWriteDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("server heartbeat connection write err %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
|
close(writeDie)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
signal := make([]byte, 1)
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||||
|
_, err := inConn.Read(signal)
|
||||||
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("server heartbeat connection read err: %s", err)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
// log.Printf("heartbeat from server ,id:%s", serverID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(readDie)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-readDie:
|
||||||
|
case <-writeDie:
|
||||||
|
}
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
s.cmServer.Remove(serverID)
|
||||||
|
log.Printf("server heartbeat conn %s released", serverID)
|
||||||
|
case CONN_CLIENT_HEARBEAT:
|
||||||
|
var clientID string
|
||||||
|
err = utils.ReadPacketData(reader, &clientID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("read error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("client heartbeat connection, id: %s", clientID)
|
||||||
|
writeDie := make(chan bool)
|
||||||
|
readDie := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
_, err = inConn.Write([]byte{0x00})
|
||||||
|
inConn.SetWriteDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("client heartbeat connection write err %s", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
}
|
||||||
|
close(writeDie)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
signal := make([]byte, 1)
|
||||||
|
inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
|
||||||
|
_, err := inConn.Read(signal)
|
||||||
|
inConn.SetReadDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("client control connection read err: %s", err)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
// log.Printf("heartbeat from client ,id:%s", clientID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(readDie)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-readDie:
|
||||||
|
case <-writeDie:
|
||||||
|
}
|
||||||
|
utils.CloseConn(&inConn)
|
||||||
|
s.cmClient.Remove(clientID)
|
||||||
|
if s.clientControlConns.Has(clientID) {
|
||||||
|
item, _ := s.clientControlConns.Get(clientID)
|
||||||
|
(*item.(*net.Conn)).Close()
|
||||||
|
}
|
||||||
|
s.clientControlConns.Remove(clientID)
|
||||||
|
log.Printf("client heartbeat conn %s released", clientID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,80 +1,142 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"proxy/utils"
|
"proxy/utils"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunnelClient struct {
|
type TunnelClient struct {
|
||||||
cfg TunnelClientArgs
|
cfg TunnelClientArgs
|
||||||
|
cm utils.ConnManager
|
||||||
|
ctrlConn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunnelClient() Service {
|
func NewTunnelClient() Service {
|
||||||
return &TunnelClient{
|
return &TunnelClient{
|
||||||
cfg: TunnelClientArgs{},
|
cfg: TunnelClientArgs{},
|
||||||
|
cm: utils.NewConnManager(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TunnelClient) InitService() {
|
func (s *TunnelClient) InitService() {
|
||||||
|
s.InitHeartbeatDeamon()
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) Check() {
|
func (s *TunnelClient) InitHeartbeatDeamon() {
|
||||||
|
log.Printf("heartbeat started")
|
||||||
|
go func() {
|
||||||
|
var heartbeatConn net.Conn
|
||||||
|
var ID = *s.cfg.Key
|
||||||
|
for {
|
||||||
|
|
||||||
|
//close all connection
|
||||||
|
s.cm.RemoveAll()
|
||||||
|
if s.ctrlConn != nil {
|
||||||
|
s.ctrlConn.Close()
|
||||||
|
}
|
||||||
|
utils.CloseConn(&heartbeatConn)
|
||||||
|
heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID)
|
||||||
|
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 *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)
|
||||||
} else {
|
} else {
|
||||||
log.Fatalf("parent required")
|
log.Fatalf("parent required")
|
||||||
}
|
}
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||||
log.Fatalf("cert and key file required")
|
log.Fatalf("cert and key file required")
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) Start(args interface{}) (err error) {
|
func (s *TunnelClient) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(TunnelClientArgs)
|
s.cfg = args.(TunnelClientArgs)
|
||||||
s.Check()
|
s.CheckArgs()
|
||||||
s.InitService()
|
s.InitService()
|
||||||
log.Printf("proxy on tunnel client mode")
|
log.Printf("proxy on tunnel client mode")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ctrlConn, err := s.GetInConn(CONN_CONTROL, "")
|
//close all conn
|
||||||
|
s.cm.Remove(*s.cfg.Key)
|
||||||
|
if s.ctrlConn != nil {
|
||||||
|
s.ctrlConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ctrlConn, err = s.GetInConn(CONN_CLIENT_CONTROL, *s.cfg.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("control connection err: %s", err)
|
log.Printf("control connection err: %s, retrying...", err)
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
utils.CloseConn(&ctrlConn)
|
if s.ctrlConn != nil {
|
||||||
|
s.ctrlConn.Close()
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// rw := utils.NewHeartbeatReadWriter(&ctrlConn, 3, func(err error, hb *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("ctrlConn err %s", err)
|
|
||||||
// utils.CloseConn(&ctrlConn)
|
|
||||||
// })
|
|
||||||
for {
|
for {
|
||||||
signal := make([]byte, 50)
|
var ID, clientLocalAddr, serverID string
|
||||||
// n, err := rw.Read(signal)
|
err = utils.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID)
|
||||||
n, err := ctrlConn.Read(signal)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&ctrlConn)
|
if s.ctrlConn != nil {
|
||||||
log.Printf("read connection signal err: %s", err)
|
s.ctrlConn.Close()
|
||||||
|
}
|
||||||
|
log.Printf("read connection signal err: %s, retrying...", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
addr := string(signal[:n])
|
log.Printf("signal revecived:%s %s %s", serverID, ID, clientLocalAddr)
|
||||||
// log.Printf("n:%d addr:%s err:%s", n, addr, err)
|
protocol := clientLocalAddr[:3]
|
||||||
// os.Exit(0)
|
localAddr := clientLocalAddr[4:]
|
||||||
log.Printf("signal revecived:%s", addr)
|
|
||||||
protocol := addr[:3]
|
|
||||||
atIndex := strings.Index(addr, "@")
|
|
||||||
ID := addr[atIndex+1:]
|
|
||||||
localAddr := addr[4:atIndex]
|
|
||||||
if protocol == "udp" {
|
if protocol == "udp" {
|
||||||
go s.ServeUDP(localAddr, ID)
|
go s.ServeUDP(localAddr, ID, serverID)
|
||||||
} else {
|
} else {
|
||||||
go s.ServeConn(localAddr, ID)
|
go s.ServeConn(localAddr, ID, serverID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,25 +144,13 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
|
|||||||
func (s *TunnelClient) Clean() {
|
func (s *TunnelClient) Clean() {
|
||||||
s.StopService()
|
s.StopService()
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) GetInConn(typ uint8, ID string) (outConn net.Conn, err error) {
|
func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, err error) {
|
||||||
outConn, err = s.GetConn()
|
outConn, err = s.GetConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("connection err: %s", err)
|
err = fmt.Errorf("connection err: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyBytes := []byte(*s.cfg.Key)
|
_, err = outConn.Write(utils.BuildPacket(typ, data...))
|
||||||
keyLength := uint16(len(keyBytes))
|
|
||||||
pkg := new(bytes.Buffer)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, typ)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, keyLength)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, keyBytes)
|
|
||||||
if ID != "" {
|
|
||||||
IDBytes := []byte(ID)
|
|
||||||
IDLength := uint16(len(IDBytes))
|
|
||||||
binary.Write(pkg, binary.LittleEndian, IDLength)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, IDBytes)
|
|
||||||
}
|
|
||||||
_, err = outConn.Write(pkg.Bytes())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("write connection data err: %s ,retrying...", err)
|
err = fmt.Errorf("write connection data err: %s ,retrying...", err)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
@ -116,12 +166,13 @@ func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) ServeUDP(localAddr, ID string) {
|
func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||||
var inConn net.Conn
|
var inConn net.Conn
|
||||||
var err error
|
var err error
|
||||||
// for {
|
// for {
|
||||||
for {
|
for {
|
||||||
inConn, err = s.GetInConn(CONN_CLIENT, ID)
|
s.cm.RemoveOne(*s.cfg.Key, ID)
|
||||||
|
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
log.Printf("connection err: %s, retrying...", err)
|
log.Printf("connection err: %s, retrying...", err)
|
||||||
@ -131,13 +182,10 @@ func (s *TunnelClient) ServeUDP(localAddr, ID string) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.cm.Add(*s.cfg.Key, ID, &inConn)
|
||||||
log.Printf("conn %s created", ID)
|
log.Printf("conn %s created", ID)
|
||||||
// hw := utils.NewHeartbeatReadWriter(&inConn, 3, func(err error, hw *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("hw err %s", err)
|
|
||||||
// hw.Close()
|
|
||||||
// })
|
|
||||||
for {
|
for {
|
||||||
// srcAddr, body, err := utils.ReadUDPPacket(&hw)
|
|
||||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
log.Printf("connection %s released", ID)
|
log.Printf("connection %s released", ID)
|
||||||
@ -146,7 +194,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID string) {
|
|||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Printf("udp packet revecived fail, err: %s", err)
|
log.Printf("udp packet revecived fail, err: %s", err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
||||||
go s.processUDPPacket(&inConn, srcAddr, localAddr, body)
|
go s.processUDPPacket(&inConn, srcAddr, localAddr, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +228,7 @@ func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr str
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
respBody := buf[0:length]
|
respBody := buf[0:length]
|
||||||
log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||||
bs := utils.UDPPacket(srcAddr, respBody)
|
bs := utils.UDPPacket(srcAddr, respBody)
|
||||||
_, err = (*inConn).Write(bs)
|
_, err = (*inConn).Write(bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -188,13 +236,13 @@ func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr str
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
|
//log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
|
||||||
}
|
}
|
||||||
func (s *TunnelClient) ServeConn(localAddr, ID string) {
|
func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||||
var inConn, outConn net.Conn
|
var inConn, outConn net.Conn
|
||||||
var err error
|
var err error
|
||||||
for {
|
for {
|
||||||
inConn, err = s.GetInConn(CONN_CLIENT, ID)
|
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
log.Printf("connection err: %s, retrying...", err)
|
log.Printf("connection err: %s, retrying...", err)
|
||||||
@ -229,6 +277,8 @@ func (s *TunnelClient) ServeConn(localAddr, ID string) {
|
|||||||
log.Printf("conn %s released", ID)
|
log.Printf("conn %s released", ID)
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
}, func(i int, b bool) {}, 0)
|
s.cm.RemoveOne(*s.cfg.Key, ID)
|
||||||
|
})
|
||||||
|
s.cm.Add(*s.cfg.Key, ID, &inConn)
|
||||||
log.Printf("conn %s created", ID)
|
log.Printf("conn %s created", ID)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -21,38 +20,67 @@ type TunnelServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TunnelServerManager struct {
|
type TunnelServerManager struct {
|
||||||
cfg TunnelServerArgs
|
cfg TunnelServerArgs
|
||||||
udpChn chan UDPItem
|
udpChn chan UDPItem
|
||||||
sc utils.ServerChannel
|
sc utils.ServerChannel
|
||||||
|
serverID string
|
||||||
|
cm utils.ConnManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTunnelServerManager() Service {
|
func NewTunnelServerManager() Service {
|
||||||
return &TunnelServerManager{
|
return &TunnelServerManager{
|
||||||
cfg: TunnelServerArgs{},
|
cfg: TunnelServerArgs{},
|
||||||
udpChn: make(chan UDPItem, 50000),
|
udpChn: make(chan UDPItem, 50000),
|
||||||
|
serverID: utils.Uniqueid(),
|
||||||
|
cm: utils.NewConnManager(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(TunnelServerArgs)
|
s.cfg = args.(TunnelServerArgs)
|
||||||
|
s.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)
|
||||||
} else {
|
} else {
|
||||||
log.Fatalf("parent required")
|
log.Fatalf("parent required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.InitService()
|
||||||
|
|
||||||
|
log.Printf("server id: %s", s.serverID)
|
||||||
//log.Printf("route:%v", *s.cfg.Route)
|
//log.Printf("route:%v", *s.cfg.Route)
|
||||||
for _, info := range *s.cfg.Route {
|
for _, _info := range *s.cfg.Route {
|
||||||
|
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, "@")
|
_routeInfo := strings.Split(info, "@")
|
||||||
server := NewTunnelServer()
|
server := NewTunnelServer()
|
||||||
local := _routeInfo[0]
|
local := _routeInfo[0]
|
||||||
remote := _routeInfo[1]
|
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(TunnelServerArgs{
|
err = server.Start(TunnelServerArgs{
|
||||||
Args: s.cfg.Args,
|
CertBytes: s.cfg.CertBytes,
|
||||||
Local: &local,
|
KeyBytes: s.cfg.KeyBytes,
|
||||||
IsUDP: s.cfg.IsUDP,
|
Parent: s.cfg.Parent,
|
||||||
Remote: &remote,
|
CertFile: s.cfg.CertFile,
|
||||||
Key: s.cfg.Key,
|
KeyFile: s.cfg.KeyFile,
|
||||||
Timeout: s.cfg.Timeout,
|
Local: &local,
|
||||||
|
IsUDP: &IsUDP,
|
||||||
|
Remote: &remote,
|
||||||
|
Key: &KEY,
|
||||||
|
Timeout: s.cfg.Timeout,
|
||||||
|
Mgr: s,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -60,7 +88,96 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *TunnelServerManager) Clean() {
|
func (s *TunnelServerManager) Clean() {
|
||||||
|
s.StopService()
|
||||||
|
}
|
||||||
|
func (s *TunnelServerManager) StopService() {
|
||||||
|
s.cm.RemoveAll()
|
||||||
|
}
|
||||||
|
func (s *TunnelServerManager) 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 *TunnelServerManager) InitService() {
|
||||||
|
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) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
|
||||||
|
outConn, err = s.GetConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("connection err: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ID = s.serverID
|
||||||
|
_, err = outConn.Write(utils.BuildPacket(typ, s.serverID))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write connection data err: %s ,retrying...", err)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
|
||||||
|
var _conn tls.Conn
|
||||||
|
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||||
|
if err == nil {
|
||||||
|
conn = net.Conn(&_conn)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
func NewTunnelServer() Service {
|
func NewTunnelServer() Service {
|
||||||
return &TunnelServer{
|
return &TunnelServer{
|
||||||
@ -78,19 +195,15 @@ type UDPItem struct {
|
|||||||
func (s *TunnelServer) InitService() {
|
func (s *TunnelServer) InitService() {
|
||||||
s.UDPConnDeamon()
|
s.UDPConnDeamon()
|
||||||
}
|
}
|
||||||
func (s *TunnelServer) Check() {
|
func (s *TunnelServer) CheckArgs() {
|
||||||
if *s.cfg.Remote == "" {
|
if *s.cfg.Remote == "" {
|
||||||
log.Fatalf("remote required")
|
log.Fatalf("remote required")
|
||||||
}
|
}
|
||||||
if s.cfg.CertBytes == nil || s.cfg.KeyBytes == nil {
|
|
||||||
log.Fatalf("cert and key file required")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (s *TunnelServer) StopService() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TunnelServer) Start(args interface{}) (err error) {
|
func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(TunnelServerArgs)
|
s.cfg = args.(TunnelServerArgs)
|
||||||
s.Check()
|
s.CheckArgs()
|
||||||
s.InitService()
|
s.InitService()
|
||||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
@ -117,7 +230,7 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
|||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
var ID string
|
var ID string
|
||||||
for {
|
for {
|
||||||
outConn, ID, err = s.GetOutConn("")
|
outConn, ID, err = s.GetOutConn(CONN_SERVER)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
||||||
@ -127,17 +240,14 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// hb := utils.NewHeartbeatReadWriter(&outConn, 3, func(err error, hb *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("%s conn %s to bridge released", *s.cfg.Key, ID)
|
|
||||||
// hb.Close()
|
|
||||||
// })
|
|
||||||
// utils.IoBind(inConn, &hb, func(err error) {
|
|
||||||
utils.IoBind(inConn, outConn, func(err error) {
|
utils.IoBind(inConn, outConn, func(err error) {
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
utils.CloseConn(&inConn)
|
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)
|
||||||
}, func(i int, b bool) {}, 0)
|
})
|
||||||
|
//add conn
|
||||||
|
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 {
|
||||||
@ -148,37 +258,20 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *TunnelServer) Clean() {
|
func (s *TunnelServer) Clean() {
|
||||||
s.StopService()
|
|
||||||
}
|
}
|
||||||
func (s *TunnelServer) GetOutConn(id string) (outConn net.Conn, ID string, err error) {
|
func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
|
||||||
outConn, err = s.GetConn()
|
outConn, err = s.GetConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("connection err: %s", err)
|
log.Printf("connection err: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyBytes := []byte(*s.cfg.Key)
|
remoteAddr := "tcp:" + *s.cfg.Remote
|
||||||
keyLength := uint16(len(keyBytes))
|
|
||||||
ID = utils.Uniqueid()
|
|
||||||
IDBytes := []byte(ID)
|
|
||||||
if id != "" {
|
|
||||||
ID = id
|
|
||||||
IDBytes = []byte(id)
|
|
||||||
}
|
|
||||||
IDLength := uint16(len(IDBytes))
|
|
||||||
remoteAddr := []byte("tcp:" + *s.cfg.Remote)
|
|
||||||
if *s.cfg.IsUDP {
|
if *s.cfg.IsUDP {
|
||||||
remoteAddr = []byte("udp:" + *s.cfg.Remote)
|
remoteAddr = "udp:" + *s.cfg.Remote
|
||||||
}
|
}
|
||||||
remoteAddrLength := uint16(len(remoteAddr))
|
ID = utils.Uniqueid()
|
||||||
pkg := new(bytes.Buffer)
|
_, err = outConn.Write(utils.BuildPacket(typ, *s.cfg.Key, ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||||
binary.Write(pkg, binary.LittleEndian, CONN_SERVER)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, keyLength)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, keyBytes)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, IDLength)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, IDBytes)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, remoteAddrLength)
|
|
||||||
binary.Write(pkg, binary.LittleEndian, remoteAddr)
|
|
||||||
_, err = outConn.Write(pkg.Bytes())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("write connection data err: %s ,retrying...", err)
|
log.Printf("write connection data err: %s ,retrying...", err)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
@ -204,35 +297,28 @@ func (s *TunnelServer) UDPConnDeamon() {
|
|||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
// var hb utils.HeartbeatReadWriter
|
// var hb utils.HeartbeatReadWriter
|
||||||
var ID string
|
var ID string
|
||||||
var cmdChn = make(chan bool, 1)
|
// var cmdChn = make(chan bool, 1000)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
for {
|
for {
|
||||||
item := <-s.udpChn
|
item := <-s.udpChn
|
||||||
RETRY:
|
RETRY:
|
||||||
if outConn == nil {
|
if outConn == nil {
|
||||||
for {
|
for {
|
||||||
outConn, ID, err = s.GetOutConn("")
|
outConn, ID, err = s.GetOutConn(CONN_SERVER)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdChn <- true
|
// cmdChn <- true
|
||||||
outConn = nil
|
outConn = nil
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
// hb = utils.NewHeartbeatReadWriter(&outConn, 3, func(err error, hb *utils.HeartbeatReadWriter) {
|
|
||||||
// log.Printf("%s conn %s to bridge released", *s.cfg.Key, ID)
|
|
||||||
// hb.Close()
|
|
||||||
// })
|
|
||||||
// go func(outConn net.Conn, hb utils.HeartbeatReadWriter, ID string) {
|
|
||||||
go func(outConn net.Conn, ID string) {
|
go func(outConn net.Conn, ID string) {
|
||||||
go func() {
|
go func() {
|
||||||
<-cmdChn
|
// <-cmdChn
|
||||||
outConn.Close()
|
// outConn.Close()
|
||||||
}()
|
}()
|
||||||
for {
|
for {
|
||||||
//srcAddrFromConn, body, err := utils.ReadUDPPacket(&hb)
|
|
||||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
log.Printf("UDP deamon connection %s exited", ID)
|
log.Printf("UDP deamon connection %s exited", ID)
|
||||||
@ -257,18 +343,13 @@ func (s *TunnelServer) UDPConnDeamon() {
|
|||||||
}
|
}
|
||||||
//log.Printf("udp response to local %s success , %v", srcAddrFromConn, body)
|
//log.Printf("udp response to local %s success , %v", srcAddrFromConn, body)
|
||||||
}
|
}
|
||||||
// }(outConn, hb, ID)
|
|
||||||
}(outConn, ID)
|
}(outConn, ID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outConn.SetWriteDeadline(time.Now().Add(time.Second))
|
outConn.SetWriteDeadline(time.Now().Add(time.Second))
|
||||||
// _, err = hb.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
|
|
||||||
_, err = outConn.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
|
_, err = outConn.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
|
||||||
// writer := bufio.NewWriter(outConn)
|
|
||||||
// writer.Write(utils.UDPPacket(item.srcAddr.String(), *item.packet))
|
|
||||||
// err := writer.Flush()
|
|
||||||
outConn.SetWriteDeadline(time.Time{})
|
outConn.SetWriteDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
|
|||||||
@ -27,6 +27,17 @@ func NewUDP() Service {
|
|||||||
p: utils.NewConcurrentMap(),
|
p: utils.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (s *UDP) CheckArgs() {
|
||||||
|
if *s.cfg.Parent == "" {
|
||||||
|
log.Fatalf("parent required for udp %s", *s.cfg.Local)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "" {
|
||||||
|
log.Fatalf("parent type unkown,use -T <tls|tcp>")
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
func (s *UDP) InitService() {
|
func (s *UDP) InitService() {
|
||||||
if *s.cfg.ParentType != TYPE_UDP {
|
if *s.cfg.ParentType != TYPE_UDP {
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
@ -39,12 +50,8 @@ func (s *UDP) StopService() {
|
|||||||
}
|
}
|
||||||
func (s *UDP) Start(args interface{}) (err error) {
|
func (s *UDP) Start(args interface{}) (err error) {
|
||||||
s.cfg = args.(UDPArgs)
|
s.cfg = args.(UDPArgs)
|
||||||
if *s.cfg.Parent != "" {
|
s.CheckArgs()
|
||||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
} else {
|
|
||||||
log.Fatalf("parent required for udp %s", *s.cfg.Local)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.InitService()
|
s.InitService()
|
||||||
|
|
||||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||||
@ -200,7 +207,8 @@ func (s *UDP) InitOutConnPool() {
|
|||||||
//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 == TYPE_TLS,
|
*s.cfg.ParentType,
|
||||||
|
"", "",
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||||
*s.cfg.Parent,
|
*s.cfg.Parent,
|
||||||
*s.cfg.Timeout,
|
*s.cfg.Timeout,
|
||||||
|
|||||||
84
utils/aes/aes.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Playbook - http://play.golang.org/p/3wFl4lacjX
|
||||||
|
|
||||||
|
package goaes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addBase64Padding(value string) string {
|
||||||
|
m := len(value) % 4
|
||||||
|
if m != 0 {
|
||||||
|
value += strings.Repeat("=", 4-m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeBase64Padding(value string) string {
|
||||||
|
return strings.Replace(value, "=", "", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Pad(src []byte) []byte {
|
||||||
|
padding := aes.BlockSize - len(src)%aes.BlockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(src, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unpad(src []byte) ([]byte, error) {
|
||||||
|
length := len(src)
|
||||||
|
unpadding := int(src[length-1])
|
||||||
|
|
||||||
|
if unpadding > length {
|
||||||
|
return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
|
||||||
|
}
|
||||||
|
|
||||||
|
return src[:(length - unpadding)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encrypt(key []byte, text []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := Pad(text)
|
||||||
|
ciphertext := make([]byte, aes.BlockSize+len(msg))
|
||||||
|
iv := ciphertext[:aes.BlockSize]
|
||||||
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||||
|
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg))
|
||||||
|
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decrypt(key []byte, text []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if (len(text) % aes.BlockSize) != 0 {
|
||||||
|
return nil, errors.New("blocksize must be multipe of decoded message length")
|
||||||
|
}
|
||||||
|
iv := text[:aes.BlockSize]
|
||||||
|
msg := text[aes.BlockSize:]
|
||||||
|
|
||||||
|
cfb := cipher.NewCFBDecrypter(block, iv)
|
||||||
|
cfb.XORKeyStream(msg, msg)
|
||||||
|
|
||||||
|
unpadMsg, err := Unpad(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return unpadMsg, nil
|
||||||
|
}
|
||||||
@ -3,106 +3,64 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
|
||||||
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error), cfn func(count int, isPositive bool), bytesPreSec float64) {
|
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error)) {
|
||||||
var one = &sync.Once{}
|
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
e1 := make(chan error, 1)
|
||||||
if e := recover(); e != nil {
|
e2 := make(chan error, 1)
|
||||||
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
go func() {
|
||||||
}
|
defer func() {
|
||||||
}()
|
if e := recover(); e != nil {
|
||||||
var err error
|
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
if bytesPreSec > 0 {
|
|
||||||
newreader := NewReader(src)
|
|
||||||
newreader.SetRateLimit(bytesPreSec)
|
|
||||||
_, err = ioCopy(dst, newreader, func(c int) {
|
|
||||||
cfn(c, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
_, err = ioCopy(dst, src, func(c int) {
|
|
||||||
cfn(c, false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
one.Do(func() {
|
|
||||||
fn(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
if e := recover(); e != nil {
|
|
||||||
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
var err error
|
|
||||||
if bytesPreSec > 0 {
|
|
||||||
newReader := NewReader(dst)
|
|
||||||
newReader.SetRateLimit(bytesPreSec)
|
|
||||||
_, err = ioCopy(src, newReader, func(c int) {
|
|
||||||
cfn(c, true)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
_, err = ioCopy(src, dst, func(c int) {
|
|
||||||
cfn(c, true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
one.Do(func() {
|
|
||||||
fn(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
func ioCopy(dst io.Writer, src io.Reader, fn ...func(count int)) (written int64, err error) {
|
|
||||||
buf := make([]byte, 32*1024)
|
|
||||||
for {
|
|
||||||
nr, er := src.Read(buf)
|
|
||||||
if nr > 0 {
|
|
||||||
nw, ew := dst.Write(buf[0:nr])
|
|
||||||
if nw > 0 {
|
|
||||||
written += int64(nw)
|
|
||||||
if len(fn) == 1 {
|
|
||||||
fn[0](nw)
|
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
if ew != nil {
|
|
||||||
err = ew
|
_, e := io.Copy(dst, src)
|
||||||
break
|
e1 <- e
|
||||||
}
|
}()
|
||||||
if nr != nw {
|
go func() {
|
||||||
err = io.ErrShortWrite
|
defer func() {
|
||||||
break
|
if e := recover(); e != nil {
|
||||||
}
|
log.Printf("IoBind crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, e := io.Copy(src, dst)
|
||||||
|
e2 <- e
|
||||||
|
}()
|
||||||
|
var err error
|
||||||
|
select {
|
||||||
|
case err = <-e1:
|
||||||
|
case err = <-e2:
|
||||||
}
|
}
|
||||||
if er != nil {
|
fn(err)
|
||||||
err = er
|
}()
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return written, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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])
|
||||||
@ -144,6 +102,10 @@ func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
|
|||||||
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
|
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func ConnectKCPHost(hostAndPort, method, key string) (conn net.Conn, err error) {
|
||||||
|
conn, err = kcp.DialWithOptions(hostAndPort, GetKCPBlock(method, key), 10, 3)
|
||||||
|
return
|
||||||
|
}
|
||||||
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
|
||||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||||
@ -193,6 +155,9 @@ func HTTPGet(URL string, timeout int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CloseConn(conn *net.Conn) {
|
func CloseConn(conn *net.Conn) {
|
||||||
|
defer func() {
|
||||||
|
_ = recover()
|
||||||
|
}()
|
||||||
if conn != nil && *conn != nil {
|
if conn != nil && *conn != nil {
|
||||||
(*conn).SetDeadline(time.Now().Add(time.Millisecond))
|
(*conn).SetDeadline(time.Now().Add(time.Millisecond))
|
||||||
(*conn).Close()
|
(*conn).Close()
|
||||||
@ -311,6 +276,131 @@ func Uniqueid() string {
|
|||||||
s := fmt.Sprintf("%d", src.Int63())
|
s := fmt.Sprintf("%d", src.Int63())
|
||||||
return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
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) {
|
||||||
|
var len uint16
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &len)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var n int
|
||||||
|
_data := make([]byte, len)
|
||||||
|
n, err = r.Read(_data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != int(len) {
|
||||||
|
err = fmt.Errorf("error data len")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data = string(_data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func ReadPacketData(r io.Reader, data ...*string) (err error) {
|
||||||
|
for _, d := range data {
|
||||||
|
*d, err = ReadData(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func ReadPacket(r io.Reader, typ *uint8, data ...*string) (err error) {
|
||||||
|
var connType uint8
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &connType)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*typ = connType
|
||||||
|
for _, d := range data {
|
||||||
|
*d, err = ReadData(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func BuildPacket(typ uint8, data ...string) []byte {
|
||||||
|
pkg := new(bytes.Buffer)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, typ)
|
||||||
|
for _, d := range data {
|
||||||
|
bytes := []byte(d)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, uint16(len(bytes)))
|
||||||
|
binary.Write(pkg, binary.LittleEndian, bytes)
|
||||||
|
}
|
||||||
|
return pkg.Bytes()
|
||||||
|
}
|
||||||
|
func BuildPacketData(data ...string) []byte {
|
||||||
|
pkg := new(bytes.Buffer)
|
||||||
|
for _, d := range data {
|
||||||
|
bytes := []byte(d)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, uint16(len(bytes)))
|
||||||
|
binary.Write(pkg, binary.LittleEndian, bytes)
|
||||||
|
}
|
||||||
|
return pkg.Bytes()
|
||||||
|
}
|
||||||
|
func SubStr(str string, start, end int) string {
|
||||||
|
if len(str) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if end >= len(str) {
|
||||||
|
end = len(str) - 1
|
||||||
|
}
|
||||||
|
return str[start:end]
|
||||||
|
}
|
||||||
|
func SubBytes(bytes []byte, start, end int) []byte {
|
||||||
|
if len(bytes) == 0 {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
if end >= len(bytes) {
|
||||||
|
end = len(bytes) - 1
|
||||||
|
}
|
||||||
|
return bytes[start:end]
|
||||||
|
}
|
||||||
|
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
|
||||||
|
certBytes, err := ioutil.ReadFile(cert)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
keyBytes, err = ioutil.ReadFile(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("err : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func GetKCPBlock(method, key string) (block kcp.BlockCrypt) {
|
||||||
|
pass := pbkdf2.Key([]byte(key), []byte(key), 4096, 32, sha1.New)
|
||||||
|
switch method {
|
||||||
|
case "sm4":
|
||||||
|
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||||
|
case "tea":
|
||||||
|
block, _ = kcp.NewTEABlockCrypt(pass[:16])
|
||||||
|
case "xor":
|
||||||
|
block, _ = kcp.NewSimpleXORBlockCrypt(pass)
|
||||||
|
case "none":
|
||||||
|
block, _ = kcp.NewNoneBlockCrypt(pass)
|
||||||
|
case "aes-128":
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass[:16])
|
||||||
|
case "aes-192":
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass[:24])
|
||||||
|
case "blowfish":
|
||||||
|
block, _ = kcp.NewBlowfishBlockCrypt(pass)
|
||||||
|
case "twofish":
|
||||||
|
block, _ = kcp.NewTwofishBlockCrypt(pass)
|
||||||
|
case "cast5":
|
||||||
|
block, _ = kcp.NewCast5BlockCrypt(pass[:16])
|
||||||
|
case "3des":
|
||||||
|
block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
|
||||||
|
case "xtea":
|
||||||
|
block, _ = kcp.NewXTEABlockCrypt(pass[:16])
|
||||||
|
case "salsa20":
|
||||||
|
block, _ = kcp.NewSalsa20BlockCrypt(pass)
|
||||||
|
default:
|
||||||
|
block, _ = kcp.NewAESBlockCrypt(pass)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// type sockaddr struct {
|
// type sockaddr struct {
|
||||||
// family uint16
|
// family uint16
|
||||||
|
|||||||
@ -5,6 +5,9 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerChannel struct {
|
type ServerChannel struct {
|
||||||
@ -24,6 +27,17 @@ func NewServerChannel(ip string, port int) ServerChannel {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func NewServerChannelHost(host string) ServerChannel {
|
||||||
|
h, port, _ := net.SplitHostPort(host)
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
return ServerChannel{
|
||||||
|
ip: h,
|
||||||
|
port: p,
|
||||||
|
errAcceptHandler: func(err error) {
|
||||||
|
log.Printf("accept error , ERR:%s", err)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||||
sc.errAcceptHandler = fn
|
sc.errAcceptHandler = fn
|
||||||
}
|
}
|
||||||
@ -43,7 +57,7 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes []byte, fn func(conn net.
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
log.Printf("connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
log.Printf("tls connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fn(conn)
|
fn(conn)
|
||||||
@ -77,7 +91,7 @@ func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
log.Printf("connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
log.Printf("tcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fn(conn)
|
fn(conn)
|
||||||
@ -124,3 +138,35 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (sc *ServerChannel) ListenKCP(method, key string, fn func(conn net.Conn)) (err error) {
|
||||||
|
var l net.Listener
|
||||||
|
l, err = kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), GetKCPBlock(method, key), 10, 3)
|
||||||
|
if err == nil {
|
||||||
|
sc.Listener = &l
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
log.Printf("ListenKCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
var conn net.Conn
|
||||||
|
conn, err = (*sc.Listener).Accept()
|
||||||
|
if err == nil {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fn(conn)
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
sc.errAcceptHandler(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
260
utils/socks/structs.go
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Method_NO_AUTH = uint8(0x00)
|
||||||
|
Method_GSSAPI = uint8(0x01)
|
||||||
|
Method_USER_PASS = uint8(0x02)
|
||||||
|
Method_IANA = uint8(0x7F)
|
||||||
|
Method_RESVERVE = uint8(0x80)
|
||||||
|
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||||
|
VERSION_V5 = uint8(0x05)
|
||||||
|
CMD_CONNECT = uint8(0x01)
|
||||||
|
CMD_BIND = uint8(0x02)
|
||||||
|
CMD_ASSOCIATE = uint8(0x03)
|
||||||
|
ATYP_IPV4 = uint8(0x01)
|
||||||
|
ATYP_DOMAIN = uint8(0x03)
|
||||||
|
ATYP_IPV6 = uint8(0x04)
|
||||||
|
REP_SUCCESS = uint8(0x00)
|
||||||
|
REP_REQ_FAIL = uint8(0x01)
|
||||||
|
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||||
|
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||||
|
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||||
|
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||||
|
REP_TTL_TIMEOUT = uint8(0x06)
|
||||||
|
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||||
|
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||||
|
REP_UNKNOWN = uint8(0x09)
|
||||||
|
RSV = uint8(0x00)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
ZERO_PORT = []byte{0x00, 0x00}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
ver uint8
|
||||||
|
cmd uint8
|
||||||
|
reserve uint8
|
||||||
|
addressType uint8
|
||||||
|
dstAddr string
|
||||||
|
dstPort string
|
||||||
|
dstHost string
|
||||||
|
bytes []byte
|
||||||
|
rw io.ReadWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequest(rw io.ReadWriter) (req Request, err interface{}) {
|
||||||
|
var b [1024]byte
|
||||||
|
var n int
|
||||||
|
req = Request{rw: rw}
|
||||||
|
n, err = rw.Read(b[:])
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("read req data fail,ERR: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.ver = uint8(b[0])
|
||||||
|
req.cmd = uint8(b[1])
|
||||||
|
req.reserve = uint8(b[2])
|
||||||
|
req.addressType = uint8(b[3])
|
||||||
|
|
||||||
|
if b[0] != 0x5 {
|
||||||
|
err = fmt.Errorf("sosck version supported")
|
||||||
|
req.TCPReply(REP_REQ_FAIL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch b[3] {
|
||||||
|
case 0x01: //IP V4
|
||||||
|
req.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||||
|
case 0x03: //域名
|
||||||
|
req.dstHost = string(b[5 : n-2]) //b[4]表示域名的长度
|
||||||
|
case 0x04: //IP V6
|
||||||
|
req.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
|
||||||
|
}
|
||||||
|
req.dstPort = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1]))
|
||||||
|
req.dstAddr = net.JoinHostPort(req.dstHost, req.dstPort)
|
||||||
|
req.bytes = b[:n]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Request) Bytes() []byte {
|
||||||
|
return s.bytes
|
||||||
|
}
|
||||||
|
func (s *Request) Addr() string {
|
||||||
|
return s.dstAddr
|
||||||
|
}
|
||||||
|
func (s *Request) Host() string {
|
||||||
|
return s.dstHost
|
||||||
|
}
|
||||||
|
func (s *Request) Port() string {
|
||||||
|
return s.dstPort
|
||||||
|
}
|
||||||
|
func (s *Request) AType() uint8 {
|
||||||
|
return s.addressType
|
||||||
|
}
|
||||||
|
func (s *Request) CMD() uint8 {
|
||||||
|
return s.cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Request) TCPReply(rep uint8) (err error) {
|
||||||
|
_, err = s.rw.Write(s.NewReply(rep, "0.0.0.0:0"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Request) UDPReply(rep uint8, addr string) (err error) {
|
||||||
|
_, err = s.rw.Write(s.NewReply(rep, addr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Request) NewReply(rep uint8, addr string) []byte {
|
||||||
|
var response bytes.Buffer
|
||||||
|
host, port, _ := net.SplitHostPort(addr)
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
ipb := ip.To4()
|
||||||
|
atyp := ATYP_IPV4
|
||||||
|
ipv6 := ip.To16()
|
||||||
|
zeroiIPv6 := fmt.Sprintf("%d%d%d%d%d%d%d%d%d%d%d%d",
|
||||||
|
ipv6[0], ipv6[1], ipv6[2], ipv6[3],
|
||||||
|
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
|
||||||
|
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
|
||||||
|
)
|
||||||
|
if ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||||
|
atyp = ATYP_IPV6
|
||||||
|
ipb = ip.To16()
|
||||||
|
}
|
||||||
|
porti, _ := strconv.Atoi(port)
|
||||||
|
portb := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(portb, uint16(porti))
|
||||||
|
// log.Printf("atyp : %v", atyp)
|
||||||
|
// log.Printf("ip : %v", []byte(ip))
|
||||||
|
response.WriteByte(VERSION_V5)
|
||||||
|
response.WriteByte(rep)
|
||||||
|
response.WriteByte(RSV)
|
||||||
|
response.WriteByte(atyp)
|
||||||
|
response.Write(ipb)
|
||||||
|
response.Write(portb)
|
||||||
|
return response.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
type MethodsRequest struct {
|
||||||
|
ver uint8
|
||||||
|
methodsCount uint8
|
||||||
|
methods []uint8
|
||||||
|
bytes []byte
|
||||||
|
rw *io.ReadWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMethodsRequest(r io.ReadWriter) (s MethodsRequest, err interface{}) {
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = recover()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
s = MethodsRequest{}
|
||||||
|
s.rw = &r
|
||||||
|
var buf = make([]byte, 300)
|
||||||
|
var n int
|
||||||
|
n, err = r.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if buf[0] != 0x05 {
|
||||||
|
err = fmt.Errorf("socks version not supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != int(buf[1])+int(2) {
|
||||||
|
err = fmt.Errorf("socks methods data length error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ver = buf[0]
|
||||||
|
s.methodsCount = buf[1]
|
||||||
|
s.methods = buf[2:n]
|
||||||
|
s.bytes = buf[:n]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MethodsRequest) Version() uint8 {
|
||||||
|
return s.ver
|
||||||
|
}
|
||||||
|
func (s *MethodsRequest) MethodsCount() uint8 {
|
||||||
|
return s.methodsCount
|
||||||
|
}
|
||||||
|
func (s *MethodsRequest) Select(method uint8) bool {
|
||||||
|
for _, m := range s.methods {
|
||||||
|
if m == method {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (s *MethodsRequest) Reply(method uint8) (err error) {
|
||||||
|
_, err = (*s.rw).Write([]byte{byte(VERSION_V5), byte(method)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *MethodsRequest) Bytes() []byte {
|
||||||
|
return s.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPPacket struct {
|
||||||
|
rsv uint16
|
||||||
|
frag uint8
|
||||||
|
atype uint8
|
||||||
|
dstHost string
|
||||||
|
dstPort string
|
||||||
|
data []byte
|
||||||
|
header []byte
|
||||||
|
bytes []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||||
|
p = UDPPacket{}
|
||||||
|
p.frag = uint8(b[2])
|
||||||
|
p.bytes = b
|
||||||
|
if p.frag != 0 {
|
||||||
|
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
portIndex := 0
|
||||||
|
p.atype = b[3]
|
||||||
|
switch p.atype {
|
||||||
|
case ATYP_IPV4: //IP V4
|
||||||
|
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||||
|
portIndex = 8
|
||||||
|
case ATYP_DOMAIN: //域名
|
||||||
|
domainLen := uint8(b[4])
|
||||||
|
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
||||||
|
portIndex = int(5 + domainLen)
|
||||||
|
case ATYP_IPV6: //IP V6
|
||||||
|
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
|
||||||
|
portIndex = 20
|
||||||
|
}
|
||||||
|
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
|
||||||
|
p.data = b[portIndex+2:]
|
||||||
|
p.header = b[:portIndex+2]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *UDPPacket) Header() []byte {
|
||||||
|
return s.header
|
||||||
|
}
|
||||||
|
func (s *UDPPacket) NewReply(data []byte) []byte {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.Write(s.header)
|
||||||
|
buf.Write(data)
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
func (s *UDPPacket) Host() string {
|
||||||
|
return s.dstHost
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UDPPacket) Port() string {
|
||||||
|
return s.dstPort
|
||||||
|
}
|
||||||
|
func (s *UDPPacket) Data() []byte {
|
||||||
|
return s.data
|
||||||
|
}
|
||||||
@ -213,7 +213,12 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (ba *BasicAuth) CheckUserPass(user, pass string) (ok bool) {
|
||||||
|
if p, _ok := ba.data.Get(user); _ok {
|
||||||
|
return p.(string) == pass
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
func (ba *BasicAuth) Check(userpass string) (ok bool) {
|
func (ba *BasicAuth) Check(userpass string) (ok bool) {
|
||||||
u := strings.Split(strings.Trim(userpass, " "), ":")
|
u := strings.Split(strings.Trim(userpass, " "), ":")
|
||||||
if len(u) == 2 {
|
if len(u) == 2 {
|
||||||
@ -256,13 +261,13 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
|||||||
req.HeadBuf = buf[:len]
|
req.HeadBuf = buf[:len]
|
||||||
index := bytes.IndexByte(req.HeadBuf, '\n')
|
index := bytes.IndexByte(req.HeadBuf, '\n')
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
err = fmt.Errorf("http decoder data line err:%s", string(req.HeadBuf)[:50])
|
err = fmt.Errorf("http decoder data line err:%s", SubStr(string(req.HeadBuf), 0, 50))
|
||||||
CloseConn(inConn)
|
CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
|
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
|
||||||
if req.Method == "" || req.hostOrURL == "" {
|
if req.Method == "" || req.hostOrURL == "" {
|
||||||
err = fmt.Errorf("http decoder data err:%s", string(req.HeadBuf)[:50])
|
err = fmt.Errorf("http decoder data err:%s", SubStr(string(req.HeadBuf), 0, 50))
|
||||||
CloseConn(inConn)
|
CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -385,19 +390,23 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
|
|||||||
type OutPool struct {
|
type OutPool struct {
|
||||||
Pool ConnPool
|
Pool ConnPool
|
||||||
dur int
|
dur int
|
||||||
isTLS bool
|
typ string
|
||||||
certBytes []byte
|
certBytes []byte
|
||||||
keyBytes []byte
|
keyBytes []byte
|
||||||
|
kcpMethod string
|
||||||
|
kcpKey string
|
||||||
address string
|
address string
|
||||||
timeout int
|
timeout int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutPool(dur int, isTLS bool, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
|
func NewOutPool(dur int, typ, kcpMethod, kcpKey string, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
|
||||||
op = OutPool{
|
op = OutPool{
|
||||||
dur: dur,
|
dur: dur,
|
||||||
isTLS: isTLS,
|
typ: typ,
|
||||||
certBytes: certBytes,
|
certBytes: certBytes,
|
||||||
keyBytes: keyBytes,
|
keyBytes: keyBytes,
|
||||||
|
kcpMethod: kcpMethod,
|
||||||
|
kcpKey: kcpKey,
|
||||||
address: address,
|
address: address,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
}
|
}
|
||||||
@ -431,12 +440,14 @@ func NewOutPool(dur int, isTLS bool, certBytes, keyBytes []byte, address string,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (op *OutPool) getConn() (conn interface{}, err error) {
|
func (op *OutPool) getConn() (conn interface{}, err error) {
|
||||||
if op.isTLS {
|
if op.typ == "tls" {
|
||||||
var _conn tls.Conn
|
var _conn tls.Conn
|
||||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes)
|
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
conn = net.Conn(&_conn)
|
conn = net.Conn(&_conn)
|
||||||
}
|
}
|
||||||
|
} else if op.typ == "kcp" {
|
||||||
|
conn, err = ConnectKCPHost(op.address, op.kcpMethod, op.kcpKey)
|
||||||
} else {
|
} else {
|
||||||
conn, err = ConnectHost(op.address, op.timeout)
|
conn, err = ConnectHost(op.address, op.timeout)
|
||||||
}
|
}
|
||||||
@ -612,3 +623,64 @@ func (rw *HeartbeatReadWriter) Write(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConnManager struct {
|
||||||
|
pool ConcurrentMap
|
||||||
|
l *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnManager() ConnManager {
|
||||||
|
cm := ConnManager{
|
||||||
|
pool: NewConcurrentMap(),
|
||||||
|
l: &sync.Mutex{},
|
||||||
|
}
|
||||||
|
return cm
|
||||||
|
}
|
||||||
|
func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
|
||||||
|
cm.pool.Upsert(key, nil, func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
|
||||||
|
var conns ConcurrentMap
|
||||||
|
if !exist {
|
||||||
|
conns = NewConcurrentMap()
|
||||||
|
} else {
|
||||||
|
conns = valueInMap.(ConcurrentMap)
|
||||||
|
}
|
||||||
|
if conns.Has(ID) {
|
||||||
|
v, _ := conns.Get(ID)
|
||||||
|
(*v.(*net.Conn)).Close()
|
||||||
|
}
|
||||||
|
conns.Set(ID, conn)
|
||||||
|
log.Printf("%s conn added", key)
|
||||||
|
return conns
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (cm *ConnManager) Remove(key string) {
|
||||||
|
var conns ConcurrentMap
|
||||||
|
if v, ok := cm.pool.Get(key); ok {
|
||||||
|
conns = v.(ConcurrentMap)
|
||||||
|
conns.IterCb(func(key string, v interface{}) {
|
||||||
|
CloseConn(v.(*net.Conn))
|
||||||
|
})
|
||||||
|
log.Printf("%s conns closed", key)
|
||||||
|
}
|
||||||
|
cm.pool.Remove(key)
|
||||||
|
}
|
||||||
|
func (cm *ConnManager) RemoveOne(key string, ID string) {
|
||||||
|
defer cm.l.Unlock()
|
||||||
|
cm.l.Lock()
|
||||||
|
var conns ConcurrentMap
|
||||||
|
if v, ok := cm.pool.Get(key); ok {
|
||||||
|
conns = v.(ConcurrentMap)
|
||||||
|
if conns.Has(ID) {
|
||||||
|
v, _ := conns.Get(ID)
|
||||||
|
(*v.(*net.Conn)).Close()
|
||||||
|
conns.Remove(ID)
|
||||||
|
cm.pool.Set(key, conns)
|
||||||
|
log.Printf("%s %s conn closed", key, ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (cm *ConnManager) RemoveAll() {
|
||||||
|
for _, k := range cm.pool.Keys() {
|
||||||
|
cm.Remove(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||