merge enterprise
This commit is contained in:
235
README_ZH.md
235
README_ZH.md
@ -37,6 +37,13 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- 自定义底层加密传输,http(s)\sps\socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可。
|
- 自定义底层加密传输,http(s)\sps\socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可。
|
||||||
- 底层压缩高效传输,http(s)\sps\socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在加密之后还可以对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的。
|
- 底层压缩高效传输,http(s)\sps\socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在加密之后还可以对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的。
|
||||||
- 安全的DNS代理,可以通过本地的proxy提供的DNS代理服务器与上级代理加密通讯实现安全防污染的DNS查询。
|
- 安全的DNS代理,可以通过本地的proxy提供的DNS代理服务器与上级代理加密通讯实现安全防污染的DNS查询。
|
||||||
|
- 负载均衡,高可用,HTTP(S)\SOCKS5\SPS代理支持上级负载均衡和高可用,多个上级重复-P参数即可.
|
||||||
|
- 指定出口IP,HTTP(S)\SOCKS5\SPS代理支持客户端用入口IP连接过来的,就用入口IP作为出口IP访问目标网站的功能。如果入口IP是内网IP,出口IP不会使用入口IP
|
||||||
|
- HTTP(S)\SOCKS5\SS协议相互转换,SPS提供此功能.
|
||||||
|
- 支持限速,HTTP(S)\SOCKS5\SPS代理支持限速.
|
||||||
|
- SOCKS5代理支持级联认证.
|
||||||
|
- 证书参数使用base64数据,默认情况下-C,-K参数是crt证书和key文件的路径,如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
|
||||||
|
|
||||||
|
|
||||||
### Why need these?
|
### Why need these?
|
||||||
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
||||||
@ -70,6 +77,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [安全建议](#安全建议)
|
- [安全建议](#安全建议)
|
||||||
|
|
||||||
### 手册目录
|
### 手册目录
|
||||||
|
- [负载均衡和高可用](#负载均衡和高可用)
|
||||||
- [1. HTTP代理](#1http代理)
|
- [1. HTTP代理](#1http代理)
|
||||||
- [1.1 普通HTTP代理](#11普通一级http代理)
|
- [1.1 普通HTTP代理](#11普通一级http代理)
|
||||||
- [1.2 普通二级HTTP代理](#12普通二级http代理)
|
- [1.2 普通二级HTTP代理](#12普通二级http代理)
|
||||||
@ -86,7 +94,11 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [1.11 自定义DNS](#111-自定义dns)
|
- [1.11 自定义DNS](#111-自定义dns)
|
||||||
- [1.12 自定义加密](#112-自定义加密)
|
- [1.12 自定义加密](#112-自定义加密)
|
||||||
- [1.13 压缩传输](#113-压缩传输)
|
- [1.13 压缩传输](#113-压缩传输)
|
||||||
- [1.14 查看帮助](#114-查看帮助)
|
- [1.14 负载均衡](#114-负载均衡)
|
||||||
|
- [1.15 限速](#115-限速)
|
||||||
|
- [1.16 指定出口IP](#116-指定出口ip)
|
||||||
|
- [1.17 证书参数使用base64数据](#117-证书参数使用base64数据)
|
||||||
|
- [1.18 查看帮助](#118-查看帮助)
|
||||||
- [2. TCP代理(端口映射)](#2tcp代理)
|
- [2. TCP代理(端口映射)](#2tcp代理)
|
||||||
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
|
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
|
||||||
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
|
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
|
||||||
@ -126,18 +138,27 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [5.9 自定义DNS](#59自定义dns)
|
- [5.9 自定义DNS](#59自定义dns)
|
||||||
- [5.10 自定义加密](#510-自定义加密)
|
- [5.10 自定义加密](#510-自定义加密)
|
||||||
- [5.11 压缩传输](#511-压缩传输)
|
- [5.11 压缩传输](#511-压缩传输)
|
||||||
- [5.12 查看帮助](#512查看帮助)
|
- [5.12 负载均衡](#512-负载均衡)
|
||||||
|
- [5.13 限速](#513-限速)
|
||||||
|
- [5.14 指定出口IP](#514-指定出口ip)
|
||||||
|
- [5.15 级联认证](#515-级联认证)
|
||||||
|
- [5.16 证书参数使用base64数据](#516-证书参数使用base64数据)
|
||||||
|
- [5.17 查看帮助](#517查看帮助)
|
||||||
- [6. 代理协议转换](#6代理协议转换)
|
- [6. 代理协议转换](#6代理协议转换)
|
||||||
- [6.1 功能介绍](#61-功能介绍)
|
- [6.1 功能介绍](#61-功能介绍)
|
||||||
- [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转httpssocks5)
|
- [6.2 HTTP(S)转HTTP(S)+SOCKS5+SS](#62-https转httpssocks5ss)
|
||||||
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
- [6.3 SOCKS5转HTTP(S)+SOCKS5+SS](#63-socks5转httpssocks5ss)
|
||||||
- [6.4 链式连接](#64-链式连接)
|
- [6.4 SS转HTTP(S)+SOCKS5+SS](#63-ss转httpssocks5ss)
|
||||||
- [6.5 监听多个端口](#65-监听多个端口)
|
- [6.5 链式连接](#64-链式连接)
|
||||||
- [6.6 认证功能](#66-认证功能)
|
- [6.6 监听多个端口](#65-监听多个端口)
|
||||||
- [6.7 自定义加密](#67-自定义加密)
|
- [6.7 认证功能](#66-认证功能)
|
||||||
- [6.8 压缩传输](#68-压缩传输)
|
- [6.8 自定义加密](#67-自定义加密)
|
||||||
- [6.9 禁用协议](#69-禁用协议)
|
- [6.9 压缩传输](#68-压缩传输)
|
||||||
- [6.10 查看帮助](#610-查看帮助)
|
- [6.10 禁用协议](#610-禁用协议)
|
||||||
|
- [6.11 限速](#611-限速)
|
||||||
|
- [6.12 指定出口IP](#612-指定出口ip)
|
||||||
|
- [6.13 证书参数使用base64数据](#613-证书参数使用base64数据)
|
||||||
|
- [6.14 查看帮助](#614-查看帮助)
|
||||||
- [7. KCP配置](#7kcp配置)
|
- [7. KCP配置](#7kcp配置)
|
||||||
- [7.1 配置介绍](#71-配置介绍)
|
- [7.1 配置介绍](#71-配置介绍)
|
||||||
- [7.2 详细配置](#72-详细配置)
|
- [7.2 详细配置](#72-详细配置)
|
||||||
@ -260,6 +281,32 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
|
|||||||
假设你的vps外网ip是23.23.23.23,下面命令通过-g参数设置23.23.23.23
|
假设你的vps外网ip是23.23.23.23,下面命令通过-g参数设置23.23.23.23
|
||||||
`./proxy http -g "23.23.23.23"`
|
`./proxy http -g "23.23.23.23"`
|
||||||
|
|
||||||
|
### **负载均衡和高可用**
|
||||||
|
|
||||||
|
HTTP(S)\SOCKS5\SPS代理支持上级负载均衡和高可用,多个上级重复-P参数即可.
|
||||||
|
|
||||||
|
负载均衡策略支持5种,可以通过`--lb-method`参数指定:
|
||||||
|
|
||||||
|
roundrobin 轮流使用
|
||||||
|
|
||||||
|
leastconn 使用最小连接数的
|
||||||
|
|
||||||
|
leasttime 使用连接时间最小的
|
||||||
|
|
||||||
|
hash 使用根据客户端地址计算出一个固定上级
|
||||||
|
|
||||||
|
weight 根据每个上级的权重和连接数情况,选择出一个上级
|
||||||
|
|
||||||
|
提示:
|
||||||
|
|
||||||
|
负载均衡检查时间间隔可以通过`--lb-retrytime`设置,单位毫秒
|
||||||
|
|
||||||
|
负载均衡连接超时时间可以通过`--lb-timeout`设置,单位毫秒
|
||||||
|
|
||||||
|
如果负载均衡策略是权重(weight),-P格式为:2.2.2.2:3880@1,1就是权重,大于0的整数.
|
||||||
|
|
||||||
|
如果负载均衡策略是hash,默认是根据客户端地址选择上级,可以通过开关`--lb-hashtarget`使用访问的目标地址选择上级.
|
||||||
|
|
||||||
### **1.HTTP代理**
|
### **1.HTTP代理**
|
||||||
#### **1.1.普通一级HTTP代理**
|
#### **1.1.普通一级HTTP代理**
|
||||||

|

|
||||||
@ -461,7 +508,43 @@ proxy的http(s)代理在tcp之上可以通过tls标准加密以及kcp协议加
|
|||||||
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||||
|
|
||||||
#### **1.14 查看帮助**
|
### **1.14 负载均衡**
|
||||||
|
|
||||||
|
HTTP(S)代理支持上级负载均衡,多个上级重复-P参数即可.
|
||||||
|
|
||||||
|
`proxy http --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080`
|
||||||
|
|
||||||
|
#### **1.14.1 设置重试间隔和超时时间**
|
||||||
|
|
||||||
|
`proxy http --lb-method=leastconn --lb-retrytime 300 --lb-timeout 300 -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
|
||||||
|
|
||||||
|
#### **1.14.2 设置权重**
|
||||||
|
|
||||||
|
`proxy http --lb-method=weight -T tcp -P 1.1.1.1:33080@1 -P 2.1.1.1:33080@2 -P 3.1.1.1:33080@1 -t tcp -p :33080`
|
||||||
|
|
||||||
|
#### **1.14.3 使用目标地址选择上级**
|
||||||
|
|
||||||
|
`proxy http --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
|
||||||
|
|
||||||
|
### **1.15 限速**
|
||||||
|
|
||||||
|
限速100K,通过`-l`参数即可指定,比如:100K 1.5M . 0意味着无限制.
|
||||||
|
|
||||||
|
`proxy http -t tcp -p 2.2.2.2:33080 -l 100K`
|
||||||
|
|
||||||
|
### **1.16 指定出口IP**
|
||||||
|
|
||||||
|
`--bind-listen`参数,就可以开启客户端用入口IP连接过来的,就用入口IP作为出口IP访问目标网站的功能。如果入口IP是内网IP,出口IP不会使用入口IP。
|
||||||
|
|
||||||
|
`proxy http -t tcp -p 2.2.2.2:33080 --bind-listen`
|
||||||
|
|
||||||
|
### **1.17 证书参数使用base64数据**
|
||||||
|
|
||||||
|
默认情况下-C,-K参数是crt证书和key文件的路径,
|
||||||
|
|
||||||
|
如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
|
||||||
|
|
||||||
|
#### **1.18 查看帮助**
|
||||||
`./proxy help http`
|
`./proxy help http`
|
||||||
|
|
||||||
### **2.TCP代理**
|
### **2.TCP代理**
|
||||||
@ -890,41 +973,98 @@ proxy的socks代理在tcp之上可以通过自定义加密和tls标准加密以
|
|||||||
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||||
|
|
||||||
#### **5.12.查看帮助**
|
|
||||||
|
#### **5.12 负载均衡**
|
||||||
|
|
||||||
|
SOCKS代理支持上级负载均衡,多个上级重复-P参数即可.
|
||||||
|
|
||||||
|
`proxy socks --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
|
||||||
|
|
||||||
|
#### **5.12.1 设置重试间隔和超时时间**
|
||||||
|
|
||||||
|
`proxy socks --lb-method=leastconn --lb-retrytime 300 --lb-timeout 300 -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
|
||||||
|
|
||||||
|
#### **5.12.2 设置权重**
|
||||||
|
|
||||||
|
`proxy socks --lb-method=weight -T tcp -P 1.1.1.1:33080@1 -P 2.1.1.1:33080@2 -P 3.1.1.1:33080@1 -p :33080 -t tcp`
|
||||||
|
|
||||||
|
#### **5.12.3 使用目标地址选择上级**
|
||||||
|
|
||||||
|
`proxy socks --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
|
||||||
|
|
||||||
|
#### **5.13 限速**
|
||||||
|
|
||||||
|
限速100K,通过`-l`参数即可指定,比如:100K 1.5M . 0意味着无限制.
|
||||||
|
|
||||||
|
`proxy socks -t tcp -p 2.2.2.2:33080 -l 100K`
|
||||||
|
|
||||||
|
#### **5.14 指定出口IP**
|
||||||
|
|
||||||
|
`--bind-listen`参数,就可以开启客户端用入口IP连接过来的,就用入口IP作为出口IP访问目标网站的功能。如果入口IP是内网IP,出口IP不会使用入口IP。
|
||||||
|
|
||||||
|
`proxy socks -t tcp -p 2.2.2.2:33080 --bind-listen`
|
||||||
|
|
||||||
|
#### **5.15 级联认证**
|
||||||
|
|
||||||
|
SOCKS5支持级联认证,-A可以设置上级认证信息.
|
||||||
|
|
||||||
|
上级:
|
||||||
|
|
||||||
|
`proxy socks -t tcp -p 2.2.2.2:33080 -a user:pass`
|
||||||
|
|
||||||
|
本地:
|
||||||
|
|
||||||
|
`proxy socks -T tcp -P 2.2.2.2:33080 -A user:pass -t tcp -p :33080`
|
||||||
|
|
||||||
|
#### **5.16 证书参数使用base64数据**
|
||||||
|
|
||||||
|
默认情况下-C,-K参数是crt证书和key文件的路径,
|
||||||
|
|
||||||
|
如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
|
||||||
|
|
||||||
|
|
||||||
|
#### **5.17.查看帮助**
|
||||||
`./proxy help socks`
|
`./proxy help socks`
|
||||||
|
|
||||||
### **6.代理协议转换**
|
### **6.代理协议转换**
|
||||||
|
|
||||||
#### **6.1 功能介绍**
|
#### **6.1 功能介绍**
|
||||||
代理协议转换使用的是sps子命令(socks+https的缩写),sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理;sps可以把已经存在的http(s)代理或者socks5代理转换为一个端口同时支持http(s)和socks5代理,而且http(s)代理支持正向代理和反向代理(SNI),转换后的SOCKS5代理,当上级是SOCKS5时仍然支持UDP功能;另外对于已经存在的http(s)代理或者socks5代理,支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建加密通道。
|
代理协议转换使用的是sps子命令,sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理或者socks5代理或者ss代理;sps可以把已经存在的http(s)代理或者socks5代理或ss代理转换为一个端口同时支持http(s)和socks5和ss的代理,而且http(s)代理支持正向代理和反向代理(SNI),转换后的SOCKS5代理,当上级是SOCKS5或者SS时仍然支持UDP功能;另外对于已经存在的http(s)代理或者socks5代理,支持tls、tcp、kcp三种模式,支持链式连接,也就是可以多个sps结点层级连接构建加密通道。
|
||||||
|
|
||||||
#### **6.2 HTTP(S)转HTTP(S)+SOCKS5**
|
#### **6.2 HTTP(S)转HTTP(S)+SOCKS5+SS**
|
||||||
假设已经存在一个普通的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
假设已经存在一个普通的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
假设已经存在一个tls的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080,tls需要证书文件。
|
假设已经存在一个tls的http(s)代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,tls需要证书文件,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S http -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
|
`./proxy sps -S http -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
假设已经存在一个kcp的http(s)代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
假设已经存在一个kcp的http(s)代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123 -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
#### **6.3 SOCKS5转HTTP(S)+SOCKS5**
|
#### **6.3 SOCKS5转HTTP(S)+SOCKS5+SS**
|
||||||
假设已经存在一个普通的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
假设已经存在一个普通的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S socks -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
|
`./proxy sps -S socks -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
假设已经存在一个tls的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080,tls需要证书文件。
|
假设已经存在一个tls的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,tls需要证书文件,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S socks -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
|
`./proxy sps -S socks -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
假设已经存在一个kcp的socks5代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
假设已经存在一个kcp的socks5代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
命令如下:
|
命令如下:
|
||||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123 -h aes-192-cfb -j pass`
|
||||||
|
|
||||||
#### **6.4 链式连接**
|
#### **6.4 SS转HTTP(S)+SOCKS5+SS**
|
||||||
|
SPS上级和本地支持ss协议,上级可以是SPS或者标准的ss服务.
|
||||||
|
SPS本地默认提供HTTP(S)\SOCKS5\SPS三种代理,当上级是SOCKS5时SOCKS5和SS支持UDP功能.
|
||||||
|
假设已经存在一个普通的SS或者SPS代理(开启了ss,加密方式:aes-256-cfb,密码:demo):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5和ss的普通代理,转换后的本地端口为18080,转换后的ss加密方式:aes-192-cfb,ss密码:pass。
|
||||||
|
命令如下:
|
||||||
|
`./proxy sps -S ss -H aes-256-cfb -J pass -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`.
|
||||||
|
|
||||||
|
#### **6.5 链式连接**
|
||||||

|

|
||||||
上面提过多个sps结点可以层级连接构建加密通道,假设有如下vps和家里的pc电脑。
|
上面提过多个sps结点可以层级连接构建加密通道,假设有如下vps和家里的pc电脑。
|
||||||
vps01:2.2.2.2
|
vps01:2.2.2.2
|
||||||
@ -944,11 +1084,11 @@ vps02:3.3.3.3
|
|||||||
|
|
||||||
完成。
|
完成。
|
||||||
|
|
||||||
#### **6.5 监听多个端口**
|
#### **6.6 监听多个端口**
|
||||||
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
||||||
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
||||||
|
|
||||||
#### **6.6 认证功能**
|
#### **6.7 认证功能**
|
||||||
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
||||||
1:用户发送认证信息`user-auth`。
|
1:用户发送认证信息`user-auth`。
|
||||||
2:设置的本地认证信息`local-auth`。
|
2:设置的本地认证信息`local-auth`。
|
||||||
@ -991,7 +1131,7 @@ target:如果客户端是http(s)代理请求,这里代表的是请求的完整ur
|
|||||||
如果没有-A参数,连接上级不使用认证.
|
如果没有-A参数,连接上级不使用认证.
|
||||||
|
|
||||||
|
|
||||||
#### **6.7 自定义加密**
|
#### **6.8 自定义加密**
|
||||||
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
|
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
|
||||||
自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义
|
自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义
|
||||||
一个密码即可,加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
|
一个密码即可,加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
|
||||||
@ -1019,7 +1159,7 @@ proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp
|
|||||||
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
|
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
|
||||||
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
|
||||||
|
|
||||||
#### **6.8 压缩传输**
|
#### **6.9 压缩传输**
|
||||||
proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
|
proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
|
||||||
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
|
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
|
||||||
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
|
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
|
||||||
@ -1045,8 +1185,7 @@ proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及
|
|||||||
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
|
||||||
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
|
||||||
|
|
||||||
|
#### **6.10 禁用协议**
|
||||||
#### **6.9 禁用协议**
|
|
||||||
SPS默认情况下一个端口支持http(s)和socks5两种代理协议,我们可以通过参数禁用某个协议
|
SPS默认情况下一个端口支持http(s)和socks5两种代理协议,我们可以通过参数禁用某个协议
|
||||||
比如:
|
比如:
|
||||||
1.禁用HTTP(S)代理功能只保留SOCKS5代理功能,参数:`--disable-http`.
|
1.禁用HTTP(S)代理功能只保留SOCKS5代理功能,参数:`--disable-http`.
|
||||||
@ -1055,7 +1194,31 @@ SPS默认情况下一个端口支持http(s)和socks5两种代理协议,我们可
|
|||||||
1.禁用SOCKS5代理功能只保留HTTP(S)代理功能,参数:`--disable-socks`.
|
1.禁用SOCKS5代理功能只保留HTTP(S)代理功能,参数:`--disable-socks`.
|
||||||
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
|
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
|
||||||
|
|
||||||
#### **6.10 查看帮助**
|
#### **6.11 限速**
|
||||||
|
|
||||||
|
假设存在SOCKS5上级:
|
||||||
|
|
||||||
|
`proxy socks -p 2.2.2.2:33080 -z password -t tcp`
|
||||||
|
|
||||||
|
sps下级,限速100K
|
||||||
|
|
||||||
|
`proxy sps -S socks -P 2.2.2.2:33080 -T tcp -Z password -l 100K -t tcp -p :33080`
|
||||||
|
|
||||||
|
通过`-l`参数即可指定,比如:100K 1.5M . 0意味着无限制.
|
||||||
|
|
||||||
|
#### **6.12 指定出口IP**
|
||||||
|
|
||||||
|
`--bind-listen`参数,就可以开启客户端用入口IP连接过来的,就用入口IP作为出口IP访问目标网站的功能。如果入口IP是内网IP,出口IP不会使用入口IP。
|
||||||
|
|
||||||
|
`proxy sps -S socks -P 2.2.2.2:33080 -T tcp -Z password -l 100K -t tcp --bind-listen -p :33080`
|
||||||
|
|
||||||
|
#### **6.13 证书参数使用base64数据**
|
||||||
|
|
||||||
|
默认情况下-C,-K参数是crt证书和key文件的路径,
|
||||||
|
|
||||||
|
如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
|
||||||
|
|
||||||
|
#### **6.14 查看帮助**
|
||||||
`./proxy help sps`
|
`./proxy help sps`
|
||||||
|
|
||||||
### **7.KCP配置**
|
### **7.KCP配置**
|
||||||
|
|||||||
@ -1,21 +1,3 @@
|
|||||||
SDK更新日志
|
|
||||||
v5.4
|
|
||||||
1.去掉了无用参数
|
|
||||||
|
|
||||||
|
|
||||||
v5.3
|
|
||||||
1.增加了支持日志输出回调的方法:
|
|
||||||
StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|
||||||
2.优化了socks_client握手端口判断,避免了sstap测试UDP失败的问题..
|
|
||||||
3.修复了HTTP(S)\SPS反向代理无法正常工作的问题.
|
|
||||||
4.优化了智能判断,减少不必要的DNS解析.
|
|
||||||
5.重构了SOCKS和SPS的UDP功能,基于UDP的游戏加速嗖嗖的.
|
|
||||||
|
|
||||||
v4.9
|
|
||||||
1.修复了HTTP Basic代理返回不合适的头部,导致浏览器不会弹框,个别代理插件无法认证的问题.
|
|
||||||
2.内网穿透切换smux到yamux.
|
|
||||||
3.优化了HTTP(S)\SOCKS5代理--always的处理逻辑.
|
|
||||||
|
|
||||||
v4.8
|
v4.8
|
||||||
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
|
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
|
||||||
2.增加了获取sdk版本的Version()方法.
|
2.增加了获取sdk版本的Version()方法.
|
||||||
|
|||||||
@ -25,7 +25,7 @@ proxy使用gombile实现了一份go代码编译为android和ios平台下面可
|
|||||||
#### 1.导入包
|
#### 1.导入包
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import snail007.proxy.Proxy
|
import snail007.proxy.Porxy
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2.启动一个服务
|
#### 2.启动一个服务
|
||||||
|
|||||||
@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
|
|
||||||
|
services "bitbucket.org/snail/proxy/services"
|
||||||
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
gocache "github.com/pmylund/go-cache"
|
gocache "github.com/pmylund/go-cache"
|
||||||
services "github.com/snail007/goproxy/services"
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DNSArgs struct {
|
type DNSArgs struct {
|
||||||
@ -76,7 +76,7 @@ func (s *DNS) InitService() (err error) {
|
|||||||
nil,
|
nil,
|
||||||
&net.Dialer{
|
&net.Dialer{
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
KeepAlive: 2 * time.Second,
|
KeepAlive: 5 * time.Second,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,7 +117,7 @@ func (s *DNS) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop dns service crashed,%s", e)
|
s.log.Printf("stop dns service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service dns stopped")
|
s.log.Printf("service dns stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
Stop(s.serviceKey)
|
Stop(s.serviceKey)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
VER="v5.5"
|
VER="v5.3"
|
||||||
rm -rf sdk-android-*.tar.gz
|
rm -rf sdk-android-*.tar.gz
|
||||||
rm -rf android
|
rm -rf android
|
||||||
mkdir android
|
mkdir android
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
VER="v5.5"
|
VER="v5.3"
|
||||||
rm -rf sdk-ios-*.tar.gz
|
rm -rf sdk-ios-*.tar.gz
|
||||||
rm -rf ios
|
rm -rf ios
|
||||||
mkdir ios
|
mkdir ios
|
||||||
|
|||||||
@ -10,21 +10,23 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
httpx "github.com/snail007/goproxy/services/http"
|
httpx "bitbucket.org/snail/proxy/services/http"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
mux "github.com/snail007/goproxy/services/mux"
|
keygenx "bitbucket.org/snail/proxy/services/keygen"
|
||||||
socksx "github.com/snail007/goproxy/services/socks"
|
mux "bitbucket.org/snail/proxy/services/mux"
|
||||||
spsx "github.com/snail007/goproxy/services/sps"
|
socksx "bitbucket.org/snail/proxy/services/socks"
|
||||||
tcpx "github.com/snail007/goproxy/services/tcp"
|
spsx "bitbucket.org/snail/proxy/services/sps"
|
||||||
tunnel "github.com/snail007/goproxy/services/tunnel"
|
tcpx "bitbucket.org/snail/proxy/services/tcp"
|
||||||
udpx "github.com/snail007/goproxy/services/udp"
|
tunnelx "bitbucket.org/snail/proxy/services/tunnel"
|
||||||
|
udpx "bitbucket.org/snail/proxy/services/udp"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SDK_VERSION = "5.5"
|
const SDK_VERSION = "5.3 enterprise"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
app *kingpin.Application
|
app *kingpin.Application
|
||||||
@ -62,9 +64,9 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
//define args
|
//define args
|
||||||
tcpArgs := tcpx.TCPArgs{}
|
tcpArgs := tcpx.TCPArgs{}
|
||||||
httpArgs := httpx.HTTPArgs{}
|
httpArgs := httpx.HTTPArgs{}
|
||||||
tunnelServerArgs := tunnel.TunnelServerArgs{}
|
tunnelServerArgs := tunnelx.TunnelServerArgs{}
|
||||||
tunnelClientArgs := tunnel.TunnelClientArgs{}
|
tunnelClientArgs := tunnelx.TunnelClientArgs{}
|
||||||
tunnelBridgeArgs := tunnel.TunnelBridgeArgs{}
|
tunnelBridgeArgs := tunnelx.TunnelBridgeArgs{}
|
||||||
muxServerArgs := mux.MuxServerArgs{}
|
muxServerArgs := mux.MuxServerArgs{}
|
||||||
muxClientArgs := mux.MuxClientArgs{}
|
muxClientArgs := mux.MuxClientArgs{}
|
||||||
muxBridgeArgs := mux.MuxBridgeArgs{}
|
muxBridgeArgs := mux.MuxBridgeArgs{}
|
||||||
@ -72,6 +74,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
socksArgs := socksx.SocksArgs{}
|
socksArgs := socksx.SocksArgs{}
|
||||||
spsArgs := spsx.SPSArgs{}
|
spsArgs := spsx.SPSArgs{}
|
||||||
dnsArgs := DNSArgs{}
|
dnsArgs := DNSArgs{}
|
||||||
|
keygenArgs := keygenx.KeygenArgs{}
|
||||||
kcpArgs := kcpcfg.KCPConfigArgs{}
|
kcpArgs := kcpcfg.KCPConfigArgs{}
|
||||||
//build srvice args
|
//build srvice args
|
||||||
app = kingpin.New("proxy", "happy with proxy")
|
app = kingpin.New("proxy", "happy with proxy")
|
||||||
@ -81,8 +84,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
|
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
|
||||||
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
|
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
|
||||||
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
|
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
|
||||||
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
|
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual")
|
||||||
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
|
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("450").Int()
|
||||||
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
|
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
|
||||||
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
|
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
|
||||||
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
|
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
|
||||||
@ -99,7 +102,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
|
|
||||||
//########http#########
|
//########http#########
|
||||||
http := app.Command("http", "proxy on http mode")
|
http := app.Command("http", "proxy on http mode")
|
||||||
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').Strings()
|
||||||
httpArgs.CaCertFile = http.Flag("ca", "ca cert file for tls").Default("").String()
|
httpArgs.CaCertFile = http.Flag("ca", "ca cert file for tls").Default("").String()
|
||||||
httpArgs.CertFile = http.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
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.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
@ -130,21 +133,29 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||||
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||||
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||||
|
httpArgs.LoadBalanceMethod = http.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
|
||||||
|
httpArgs.LoadBalanceTimeout = http.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
|
||||||
|
httpArgs.LoadBalanceRetryTime = http.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
|
||||||
|
httpArgs.LoadBalanceHashTarget = http.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
|
||||||
|
httpArgs.LoadBalanceOnlyHA = http.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
|
||||||
|
httpArgs.RateLimit = http.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
|
||||||
|
httpArgs.BindListen = http.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool()
|
||||||
|
httpArgs.Debug = debug
|
||||||
//########tcp#########
|
//########tcp#########
|
||||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("[]").Short('P').String()
|
||||||
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
||||||
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
|
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
|
||||||
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
|
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
|
||||||
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
tcpArgs.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
|
tcpArgs.Jumper = tcp.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
|
||||||
|
|
||||||
//########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.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.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.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()
|
||||||
@ -215,7 +226,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
|
|
||||||
//########ssh#########
|
//########ssh#########
|
||||||
socks := app.Command("socks", "proxy on ssh mode")
|
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.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').Strings()
|
||||||
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
|
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.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.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||||
@ -225,7 +236,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").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.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.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.SSHPassword = socks.Flag("ssh-password", "password for ssh").Short('D').Default("").String()
|
||||||
socksArgs.Always = socks.Flag("always", "always use parent proxy").Default("false").Bool()
|
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.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.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
|
||||||
@ -238,16 +249,25 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||||
socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||||
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||||
|
socksArgs.ParentAuth = socks.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||||
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||||
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
|
||||||
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||||
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||||
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||||
|
socksArgs.LoadBalanceMethod = socks.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
|
||||||
|
socksArgs.LoadBalanceTimeout = socks.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
|
||||||
|
socksArgs.LoadBalanceRetryTime = socks.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
|
||||||
|
socksArgs.LoadBalanceHashTarget = socks.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
|
||||||
|
socksArgs.LoadBalanceOnlyHA = socks.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
|
||||||
|
socksArgs.RateLimit = socks.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
|
||||||
|
socksArgs.BindListen = socks.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool()
|
||||||
|
socksArgs.Debug = debug
|
||||||
|
|
||||||
//########socks+http(s)#########
|
//########socks+http(s)#########
|
||||||
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
sps := app.Command("sps", "proxy on socks+http(s) mode")
|
||||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').Strings()
|
||||||
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||||
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
spsArgs.KeyFile = sps.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||||
spsArgs.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String()
|
spsArgs.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String()
|
||||||
@ -255,12 +275,12 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
||||||
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||||
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks|ss>").Short('S').Enum("http", "socks", "ss")
|
||||||
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||||
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||||
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||||
spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
spsArgs.LocalIPS = sps.Flag("local-bind-ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||||
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||||
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||||
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||||
@ -270,8 +290,21 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
|
||||||
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
|
||||||
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
|
||||||
|
spsArgs.SSMethod = sps.Flag("ss-method", "the following methods are supported: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4-md5-6, chacha20, salsa20, rc4, table, des-cfb, chacha20-ietf; if you use ss client , \"-t tcp\" is required").Short('h').Default("aes-256-cfb").String()
|
||||||
|
spsArgs.SSKey = sps.Flag("ss-key", "if you use ss client , \"-t tcp\" is required").Short('j').Default("sspassword").String()
|
||||||
|
spsArgs.ParentSSMethod = sps.Flag("parent-ss-method", "the following methods are supported: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4-md5-6, chacha20, salsa20, rc4, table, des-cfb, chacha20-ietf; if you use ss server as parent, \"-T tcp\" is required").Short('H').Default("aes-256-cfb").String()
|
||||||
|
spsArgs.ParentSSKey = sps.Flag("parent-ss-key", "if you use ss server as parent, \"-T tcp\" is required").Short('J').Default("sspassword").String()
|
||||||
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
|
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
|
||||||
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
|
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
|
||||||
|
spsArgs.DisableSS = sps.Flag("disable-ss", "disable ss proxy").Default("false").Bool()
|
||||||
|
spsArgs.LoadBalanceMethod = sps.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
|
||||||
|
spsArgs.LoadBalanceTimeout = sps.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
|
||||||
|
spsArgs.LoadBalanceRetryTime = sps.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
|
||||||
|
spsArgs.LoadBalanceHashTarget = sps.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
|
||||||
|
spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
|
||||||
|
spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
|
||||||
|
spsArgs.Debug = debug
|
||||||
|
|
||||||
//########dns#########
|
//########dns#########
|
||||||
dns := app.Command("dns", "proxy on dns server mode")
|
dns := app.Command("dns", "proxy on dns server mode")
|
||||||
dnsArgs.Parent = dns.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
dnsArgs.Parent = dns.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||||
@ -280,7 +313,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
dnsArgs.CaCertFile = dns.Flag("ca", "ca cert file for tls").Default("").String()
|
dnsArgs.CaCertFile = dns.Flag("ca", "ca cert file for tls").Default("").String()
|
||||||
dnsArgs.Timeout = dns.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
dnsArgs.Timeout = dns.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
||||||
dnsArgs.ParentType = dns.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
dnsArgs.ParentType = dns.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
|
||||||
dnsArgs.Local = dns.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
dnsArgs.Local = dns.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":53").String()
|
||||||
dnsArgs.ParentServiceType = dns.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
dnsArgs.ParentServiceType = dns.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||||
dnsArgs.RemoteDNSAddress = dns.Flag("dns-address", "remote dns for resolve doamin").Short('q').Default("8.8.8.8:53").String()
|
dnsArgs.RemoteDNSAddress = dns.Flag("dns-address", "remote dns for resolve doamin").Short('q').Default("8.8.8.8:53").String()
|
||||||
dnsArgs.DNSTTL = dns.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
dnsArgs.DNSTTL = dns.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
@ -290,6 +323,14 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
dnsArgs.CacheFile = dns.Flag("cache-file", "dns result cached file").Short('f').Default(filepath.Join(path.Dir(os.Args[0]), "cache.dat")).String()
|
dnsArgs.CacheFile = dns.Flag("cache-file", "dns result cached file").Short('f').Default(filepath.Join(path.Dir(os.Args[0]), "cache.dat")).String()
|
||||||
dnsArgs.LocalSocks5Port = dns.Flag("socks-port", "local socks5 port").Short('s').Default("65501").String()
|
dnsArgs.LocalSocks5Port = dns.Flag("socks-port", "local socks5 port").Short('s').Default("65501").String()
|
||||||
|
|
||||||
|
//########keygen#########
|
||||||
|
keygen := app.Command("keygen", "create certificate for proxy")
|
||||||
|
keygenArgs.CommonName = keygen.Flag("cn", "common name").Short('n').Default("").String()
|
||||||
|
keygenArgs.CaName = keygen.Flag("ca", "ca name").Short('C').Default("").String()
|
||||||
|
keygenArgs.CertName = keygen.Flag("cert", "cert name of sign to create").Short('c').Default("").String()
|
||||||
|
keygenArgs.SignDays = keygen.Flag("days", "days of sign").Short('d').Default("365").Int()
|
||||||
|
keygenArgs.Sign = keygen.Flag("sign", "cert is to signin").Short('s').Default("false").Bool()
|
||||||
|
|
||||||
//parse args
|
//parse args
|
||||||
_args := strings.Fields(strings.Trim(serviceArgsStr, " "))
|
_args := strings.Fields(strings.Trim(serviceArgsStr, " "))
|
||||||
args := []string{}
|
args := []string{}
|
||||||
@ -387,11 +428,11 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
case "udp":
|
case "udp":
|
||||||
services.Regist(serviceID, udpx.NewUDP(), udpArgs, log)
|
services.Regist(serviceID, udpx.NewUDP(), udpArgs, log)
|
||||||
case "tserver":
|
case "tserver":
|
||||||
services.Regist(serviceID, tunnel.NewTunnelServerManager(), tunnelServerArgs, log)
|
services.Regist(serviceID, tunnelx.NewTunnelServerManager(), tunnelServerArgs, log)
|
||||||
case "tclient":
|
case "tclient":
|
||||||
services.Regist(serviceID, tunnel.NewTunnelClient(), tunnelClientArgs, log)
|
services.Regist(serviceID, tunnelx.NewTunnelClient(), tunnelClientArgs, log)
|
||||||
case "tbridge":
|
case "tbridge":
|
||||||
services.Regist(serviceID, tunnel.NewTunnelBridge(), tunnelBridgeArgs, log)
|
services.Regist(serviceID, tunnelx.NewTunnelBridge(), tunnelBridgeArgs, log)
|
||||||
case "server":
|
case "server":
|
||||||
services.Regist(serviceID, mux.NewMuxServerManager(), muxServerArgs, log)
|
services.Regist(serviceID, mux.NewMuxServerManager(), muxServerArgs, log)
|
||||||
case "client":
|
case "client":
|
||||||
@ -403,7 +444,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
|||||||
case "sps":
|
case "sps":
|
||||||
services.Regist(serviceID, spsx.NewSPS(), spsArgs, log)
|
services.Regist(serviceID, spsx.NewSPS(), spsArgs, log)
|
||||||
case "dns":
|
case "dns":
|
||||||
services.Regist(serviceName, NewDNS(), dnsArgs, log)
|
services.Regist(serviceID, NewDNS(), dnsArgs, log)
|
||||||
}
|
}
|
||||||
_, err = services.Run(serviceID, nil)
|
_, err = services.Run(serviceID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
VER="v5.5"
|
VER="v5.3"
|
||||||
|
|
||||||
rm -rf sdk-linux-*.tar.gz
|
rm -rf sdk-linux-*.tar.gz
|
||||||
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
VER="v5.5"
|
VER="v5.3"
|
||||||
|
|
||||||
rm -rf *.tar.gz
|
rm -rf *.tar.gz
|
||||||
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
|
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#/bin/bash
|
#/bin/bash
|
||||||
VER="v5.5"
|
VER="v5.3"
|
||||||
|
|
||||||
#sudo rm /usr/local/go
|
#sudo rm /usr/local/go
|
||||||
#sudo ln -s /usr/local/go1.10.1 /usr/local/go
|
#sudo ln -s /usr/local/go1.10.1 /usr/local/go
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"C"
|
"C"
|
||||||
|
|
||||||
sdk "github.com/snail007/goproxy/sdk/android-ios"
|
sdk "bitbucket.org/snail/proxy/sdk/android-ios"
|
||||||
)
|
)
|
||||||
|
|
||||||
//export Start
|
//export Start
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -11,81 +12,100 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils/datasize"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"bitbucket.org/snail/proxy/utils/dnsx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/iolimiter"
|
||||||
|
"bitbucket.org/snail/proxy/utils/lb"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
|
"bitbucket.org/snail/proxy/utils"
|
||||||
|
"bitbucket.org/snail/proxy/utils/conncrypt"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTPArgs struct {
|
type HTTPArgs struct {
|
||||||
Parent *string
|
Parent *[]string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
KeyFile *string
|
KeyFile *string
|
||||||
CaCertFile *string
|
CaCertFile *string
|
||||||
CaCertBytes []byte
|
CaCertBytes []byte
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
Always *bool
|
Always *bool
|
||||||
HTTPTimeout *int
|
HTTPTimeout *int
|
||||||
Interval *int
|
Interval *int
|
||||||
Blocked *string
|
Blocked *string
|
||||||
Direct *string
|
Direct *string
|
||||||
AuthFile *string
|
AuthFile *string
|
||||||
Auth *[]string
|
Auth *[]string
|
||||||
AuthURL *string
|
AuthURL *string
|
||||||
AuthURLOkCode *int
|
AuthURLOkCode *int
|
||||||
AuthURLTimeout *int
|
AuthURLTimeout *int
|
||||||
AuthURLRetry *int
|
AuthURLRetry *int
|
||||||
ParentType *string
|
ParentType *string
|
||||||
LocalType *string
|
LocalType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
SSHKeyFile *string
|
SSHKeyFile *string
|
||||||
SSHKeyFileSalt *string
|
SSHKeyFileSalt *string
|
||||||
SSHPassword *string
|
SSHPassword *string
|
||||||
SSHUser *string
|
SSHUser *string
|
||||||
SSHKeyBytes []byte
|
SSHKeyBytes []byte
|
||||||
SSHAuthMethod ssh.AuthMethod
|
SSHAuthMethod ssh.AuthMethod
|
||||||
KCP kcpcfg.KCPConfigArgs
|
KCP kcpcfg.KCPConfigArgs
|
||||||
LocalIPS *[]string
|
LocalIPS *[]string
|
||||||
DNSAddress *string
|
DNSAddress *string
|
||||||
DNSTTL *int
|
DNSTTL *int
|
||||||
LocalKey *string
|
LocalKey *string
|
||||||
ParentKey *string
|
ParentKey *string
|
||||||
LocalCompress *bool
|
LocalCompress *bool
|
||||||
ParentCompress *bool
|
ParentCompress *bool
|
||||||
|
LoadBalanceMethod *string
|
||||||
|
LoadBalanceTimeout *int
|
||||||
|
LoadBalanceRetryTime *int
|
||||||
|
LoadBalanceHashTarget *bool
|
||||||
|
LoadBalanceOnlyHA *bool
|
||||||
|
|
||||||
|
RateLimit *string
|
||||||
|
RateLimitBytes float64
|
||||||
|
BindListen *bool
|
||||||
|
Debug *bool
|
||||||
}
|
}
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
outPool utils.OutConn
|
|
||||||
cfg HTTPArgs
|
cfg HTTPArgs
|
||||||
checker utils.Checker
|
checker utils.Checker
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
sshClient *ssh.Client
|
sshClient *ssh.Client
|
||||||
lockChn chan bool
|
lockChn chan bool
|
||||||
domainResolver utils.DomainResolver
|
domainResolver dnsx.DomainResolver
|
||||||
isStop bool
|
isStop bool
|
||||||
serverChannels []*utils.ServerChannel
|
serverChannels []*utils.ServerChannel
|
||||||
userConns utils.ConcurrentMap
|
userConns mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
|
lb *lb.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP() services.Service {
|
func NewHTTP() services.Service {
|
||||||
return &HTTP{
|
return &HTTP{
|
||||||
outPool: utils.OutConn{},
|
|
||||||
cfg: HTTPArgs{},
|
cfg: HTTPArgs{},
|
||||||
checker: utils.Checker{},
|
checker: utils.Checker{},
|
||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
lockChn: make(chan bool, 1),
|
lockChn: make(chan bool, 1),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
serverChannels: []*utils.ServerChannel{},
|
serverChannels: []*utils.ServerChannel{},
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) CheckArgs() (err error) {
|
func (s *HTTP) CheckArgs() (err error) {
|
||||||
if *s.cfg.Parent != "" && *s.cfg.ParentType == "" {
|
|
||||||
|
if len(*s.cfg.Parent) == 1 && (*s.cfg.Parent)[0] == "" {
|
||||||
|
(*s.cfg.Parent) = []string{}
|
||||||
|
}
|
||||||
|
if len(*s.cfg.Parent) > 0 && *s.cfg.ParentType == "" {
|
||||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -133,15 +153,26 @@ func (s *HTTP) CheckArgs() (err error) {
|
|||||||
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if *s.cfg.RateLimit != "0" && *s.cfg.RateLimit != "" {
|
||||||
|
var size uint64
|
||||||
|
size, err = datasize.Parse(*s.cfg.RateLimit)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("parse rate limit size error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.cfg.RateLimitBytes = float64(size)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitService() (err error) {
|
func (s *HTTP) InitService() (err error) {
|
||||||
s.InitBasicAuth()
|
s.InitBasicAuth()
|
||||||
if *s.cfg.Parent != "" {
|
//init lb
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
|
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
|
||||||
|
s.InitLB()
|
||||||
}
|
}
|
||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
(*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentType == "ssh" {
|
if *s.cfg.ParentType == "ssh" {
|
||||||
err = s.ConnectSSH()
|
err = s.ConnectSSH()
|
||||||
@ -155,7 +186,7 @@ func (s *HTTP) InitService() (err error) {
|
|||||||
if s.isStop {
|
if s.isStop {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write([]byte{0})
|
_, err = conn.Write([]byte{0})
|
||||||
@ -185,11 +216,11 @@ func (s *HTTP) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop http(s) service crashed,%s", e)
|
s.log.Printf("stop http(s) service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service http(s) stopped")
|
s.log.Printf("service http(s) stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.checker.Stop()
|
s.checker.Stop()
|
||||||
}
|
}
|
||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
@ -203,6 +234,9 @@ func (s *HTTP) StopService() {
|
|||||||
(*sc.UDPListener).Close()
|
(*sc.UDPListener).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if s.lb != nil {
|
||||||
|
s.lb.Stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
|
func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
|
||||||
s.log = log
|
s.log = log
|
||||||
@ -215,9 +249,8 @@ func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
s.log.Printf("use %s parent %v [ %s ]", *s.cfg.ParentType, *s.cfg.Parent, strings.ToUpper(*s.cfg.LoadBalanceMethod))
|
||||||
s.InitOutConnPool()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
||||||
@ -272,9 +305,9 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
address := req.Host
|
address := req.Host
|
||||||
host, _, _ := net.SplitHostPort(address)
|
host, _, _ := net.SplitHostPort(address)
|
||||||
useProxy := false
|
useProxy := false
|
||||||
if !utils.IsIternalIP(host, *s.cfg.Always) {
|
if !utils.IsInternalIP(host, *s.cfg.Always) {
|
||||||
useProxy = true
|
useProxy = true
|
||||||
if *s.cfg.Parent == "" {
|
if len(*s.cfg.Parent) == 0 {
|
||||||
useProxy = false
|
useProxy = false
|
||||||
} else if *s.cfg.Always {
|
} else if *s.cfg.Always {
|
||||||
useProxy = true
|
useProxy = true
|
||||||
@ -290,17 +323,17 @@ func (s *HTTP) callback(inConn net.Conn) {
|
|||||||
|
|
||||||
s.log.Printf("use proxy : %v, %s", useProxy, address)
|
s.log.Printf("use proxy : %v, %s", useProxy, address)
|
||||||
|
|
||||||
err = s.OutToTCP(useProxy, address, &inConn, &req)
|
lbAddr, err := s.OutToTCP(useProxy, address, &inConn, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if *s.cfg.Parent == "" {
|
if len(*s.cfg.Parent) == 0 {
|
||||||
s.log.Printf("connect to %s fail, ERR:%s", address, err)
|
s.log.Printf("connect to %s fail, ERR:%s", address, err)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("connect to %s parent %s fail", *s.cfg.ParentType, *s.cfg.Parent)
|
s.log.Printf("connect to %s parent %v fail", *s.cfg.ParentType, lbAddr)
|
||||||
}
|
}
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (err interface{}) {
|
func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (lbAddr string, err interface{}) {
|
||||||
inAddr := (*inConn).RemoteAddr().String()
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
inLocalAddr := (*inConn).LocalAddr().String()
|
inLocalAddr := (*inConn).LocalAddr().String()
|
||||||
//防止死循环
|
//防止死循环
|
||||||
@ -317,25 +350,26 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
if *s.cfg.ParentType == "ssh" {
|
// s.log.Printf("%v", s.outPool)
|
||||||
outConn, err = s.getSSHConn(address)
|
selectAddr := (*inConn).RemoteAddr().String()
|
||||||
} else {
|
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||||
// s.log.Printf("%v", s.outPool)
|
selectAddr = address
|
||||||
outConn, err = s.outPool.Get()
|
|
||||||
}
|
}
|
||||||
|
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
outConn, err = s.GetParentConn(lbAddr)
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(s.Resolve(address), *s.cfg.Timeout)
|
outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr)
|
||||||
}
|
}
|
||||||
tryCount++
|
tryCount++
|
||||||
if err == nil || tryCount > maxTryCount {
|
if err == nil || tryCount > maxTryCount {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("connect to %s , err:%s,retrying...", *s.cfg.Parent, err)
|
s.log.Printf("connect to %s , err:%s,retrying...", lbAddr, err)
|
||||||
time.Sleep(time.Second * 2)
|
time.Sleep(time.Second * 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
s.log.Printf("connect to %s , err:%s", lbAddr, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -347,6 +381,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
Password: *s.cfg.ParentKey,
|
Password: *s.cfg.ParentKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
outAddr := outConn.RemoteAddr().String()
|
outAddr := outConn.RemoteAddr().String()
|
||||||
//outLocalAddr := outConn.LocalAddr().String()
|
//outLocalAddr := outConn.LocalAddr().String()
|
||||||
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||||
@ -355,29 +390,39 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
|||||||
} else {
|
} else {
|
||||||
//https或者http,上级是代理,proxy需要转发
|
//https或者http,上级是代理,proxy需要转发
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
//直连目标或上级非代理或非SNI,清理HTTP头部的代理头信息.
|
//直连目标或上级非代理或非SNI,,清理HTTP头部的代理头信息
|
||||||
if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
|
if !useProxy || *s.cfg.ParentType == "ssh" && !req.IsSNI {
|
||||||
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
||||||
} else {
|
} else {
|
||||||
_, err = outConn.Write(req.HeadBuf)
|
_, err = outConn.Write(req.HeadBuf)
|
||||||
}
|
}
|
||||||
outConn.SetDeadline(time.Time{})
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
s.log.Printf("write to %s , err:%s", lbAddr, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.cfg.RateLimitBytes > 0 {
|
||||||
|
outConn = iolimiter.NewReaderConn(outConn, s.cfg.RateLimitBytes)
|
||||||
|
}
|
||||||
|
|
||||||
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||||
s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
|
s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
|
||||||
s.userConns.Remove(inAddr)
|
s.userConns.Remove(inAddr)
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
|
s.lb.DecreaseConns(lbAddr)
|
||||||
|
}
|
||||||
}, s.log)
|
}, s.log)
|
||||||
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
|
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
|
||||||
if c, ok := s.userConns.Get(inAddr); ok {
|
if c, ok := s.userConns.Get(inAddr); ok {
|
||||||
(*c.(*net.Conn)).Close()
|
(*c.(*net.Conn)).Close()
|
||||||
}
|
}
|
||||||
s.userConns.Set(inAddr, inConn)
|
s.userConns.Set(inAddr, inConn)
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
|
s.lb.IncreasConns(lbAddr)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,24 +479,11 @@ func (s *HTTP) ConnectSSH() (err error) {
|
|||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
s.sshClient.Close()
|
s.sshClient.Close()
|
||||||
}
|
}
|
||||||
s.sshClient, err = ssh.Dial("tcp", s.Resolve(*s.cfg.Parent), &config)
|
s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config)
|
||||||
<-s.lockChn
|
<-s.lockChn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *HTTP) InitOutConnPool() {
|
|
||||||
if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" || *s.cfg.ParentType == "kcp" {
|
|
||||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
|
||||||
//parent string, timeout int, InitialCap int, MaxCap int
|
|
||||||
s.outPool = utils.NewOutConn(
|
|
||||||
*s.cfg.CheckParentInterval,
|
|
||||||
*s.cfg.ParentType,
|
|
||||||
s.cfg.KCP,
|
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
|
|
||||||
s.Resolve(*s.cfg.Parent),
|
|
||||||
*s.cfg.Timeout,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (s *HTTP) InitBasicAuth() (err error) {
|
func (s *HTTP) InitBasicAuth() (err error) {
|
||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
|
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
|
||||||
@ -477,6 +509,27 @@ func (s *HTTP) InitBasicAuth() (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *HTTP) InitLB() {
|
||||||
|
configs := lb.BackendsConfig{}
|
||||||
|
for _, addr := range *s.cfg.Parent {
|
||||||
|
_addrInfo := strings.Split(addr, "@")
|
||||||
|
_addr := _addrInfo[0]
|
||||||
|
weight := 1
|
||||||
|
if len(_addrInfo) == 2 {
|
||||||
|
weight, _ = strconv.Atoi(_addrInfo[1])
|
||||||
|
}
|
||||||
|
configs = append(configs, &lb.BackendConfig{
|
||||||
|
Address: _addr,
|
||||||
|
Weight: weight,
|
||||||
|
ActiveAfter: 1,
|
||||||
|
InactiveAfter: 2,
|
||||||
|
Timeout: time.Duration(*s.cfg.LoadBalanceTimeout) * time.Millisecond,
|
||||||
|
RetryTime: time.Duration(*s.cfg.LoadBalanceRetryTime) * time.Millisecond,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
|
||||||
|
s.lb = &LB
|
||||||
|
}
|
||||||
func (s *HTTP) IsBasicAuth() bool {
|
func (s *HTTP) IsBasicAuth() bool {
|
||||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||||
}
|
}
|
||||||
@ -494,7 +547,7 @@ func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
|
|||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
|
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
|
||||||
} else {
|
} else {
|
||||||
outIPs, err = utils.MyLookupIP(outDomain)
|
outIPs, err = utils.LookupIP(outDomain)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, ip := range outIPs {
|
for _, ip := range outIPs {
|
||||||
@ -530,3 +583,39 @@ func (s *HTTP) Resolve(address string) string {
|
|||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
var _conn tls.Conn
|
||||||
|
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
|
||||||
|
if err == nil {
|
||||||
|
conn = net.Conn(&_conn)
|
||||||
|
}
|
||||||
|
} else if *s.cfg.ParentType == "kcp" {
|
||||||
|
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
|
||||||
|
} else if *s.cfg.ParentType == "ssh" {
|
||||||
|
var e interface{}
|
||||||
|
conn, e = s.getSSHConn(address)
|
||||||
|
if e != nil {
|
||||||
|
err = fmt.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *HTTP) GetDirectConn(address string, localAddr string) (conn net.Conn, err error) {
|
||||||
|
if !*s.cfg.BindListen {
|
||||||
|
return utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
ip, _, _ := net.SplitHostPort(localAddr)
|
||||||
|
if utils.IsInternalIP(ip, false) {
|
||||||
|
return utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
local, _ := net.ResolveTCPAddr("tcp", ip+":0")
|
||||||
|
d := net.Dialer{
|
||||||
|
Timeout: time.Millisecond * time.Duration(*s.cfg.Timeout),
|
||||||
|
LocalAddr: local,
|
||||||
|
}
|
||||||
|
conn, err = d.Dial("tcp", address)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/cert"
|
"bitbucket.org/snail/proxy/utils/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KeygenArgs struct {
|
type KeygenArgs struct {
|
||||||
|
|||||||
@ -12,18 +12,15 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
CONN_SERVER = uint8(4)
|
|
||||||
CONN_CLIENT = uint8(5)
|
|
||||||
)
|
|
||||||
|
|
||||||
type MuxBridgeArgs struct {
|
type MuxBridgeArgs struct {
|
||||||
CertFile *string
|
CertFile *string
|
||||||
KeyFile *string
|
KeyFile *string
|
||||||
@ -37,8 +34,8 @@ type MuxBridgeArgs struct {
|
|||||||
}
|
}
|
||||||
type MuxBridge struct {
|
type MuxBridge struct {
|
||||||
cfg MuxBridgeArgs
|
cfg MuxBridgeArgs
|
||||||
clientControlConns utils.ConcurrentMap
|
clientControlConns mapx.ConcurrentMap
|
||||||
serverConns utils.ConcurrentMap
|
serverConns mapx.ConcurrentMap
|
||||||
router utils.ClientKeyRouter
|
router utils.ClientKeyRouter
|
||||||
l *sync.Mutex
|
l *sync.Mutex
|
||||||
isStop bool
|
isStop bool
|
||||||
@ -49,8 +46,8 @@ type MuxBridge struct {
|
|||||||
func NewMuxBridge() services.Service {
|
func NewMuxBridge() services.Service {
|
||||||
b := &MuxBridge{
|
b := &MuxBridge{
|
||||||
cfg: MuxBridgeArgs{},
|
cfg: MuxBridgeArgs{},
|
||||||
clientControlConns: utils.NewConcurrentMap(),
|
clientControlConns: mapx.NewConcurrentMap(),
|
||||||
serverConns: utils.NewConcurrentMap(),
|
serverConns: mapx.NewConcurrentMap(),
|
||||||
l: &sync.Mutex{},
|
l: &sync.Mutex{},
|
||||||
isStop: false,
|
isStop: false,
|
||||||
}
|
}
|
||||||
@ -80,7 +77,7 @@ func (s *MuxBridge) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop bridge service crashed,%s", e)
|
s.log.Printf("stop bridge service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service bridge stopped")
|
s.log.Printf("service bridge stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -88,7 +85,7 @@ func (s *MuxBridge) StopService() {
|
|||||||
(*(*s.sc).Listener).Close()
|
(*(*s.sc).Listener).Close()
|
||||||
}
|
}
|
||||||
for _, g := range s.clientControlConns.Items() {
|
for _, g := range s.clientControlConns.Items() {
|
||||||
for _, session := range g.(*utils.ConcurrentMap).Items() {
|
for _, session := range g.(*mapx.ConcurrentMap).Items() {
|
||||||
(session.(*smux.Session)).Close()
|
(session.(*smux.Session)).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,11 +198,11 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
|||||||
s.l.Lock()
|
s.l.Lock()
|
||||||
defer s.l.Unlock()
|
defer s.l.Unlock()
|
||||||
if !s.clientControlConns.Has(groupKey) {
|
if !s.clientControlConns.Has(groupKey) {
|
||||||
item := utils.NewConcurrentMap()
|
item := mapx.NewConcurrentMap()
|
||||||
s.clientControlConns.Set(groupKey, &item)
|
s.clientControlConns.Set(groupKey, &item)
|
||||||
}
|
}
|
||||||
_group, _ := s.clientControlConns.Get(groupKey)
|
_group, _ := s.clientControlConns.Get(groupKey)
|
||||||
group := _group.(*utils.ConcurrentMap)
|
group := _group.(*mapx.ConcurrentMap)
|
||||||
if v, ok := group.Get(index); ok {
|
if v, ok := group.Get(index); ok {
|
||||||
v.(*smux.Session).Close()
|
v.(*smux.Session).Close()
|
||||||
}
|
}
|
||||||
@ -254,7 +251,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
|||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
group := _group.(*utils.ConcurrentMap)
|
group := _group.(*mapx.ConcurrentMap)
|
||||||
keys := group.Keys()
|
keys := group.Keys()
|
||||||
keysLen := len(keys)
|
keysLen := len(keys)
|
||||||
i := 0
|
i := 0
|
||||||
|
|||||||
@ -9,11 +9,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"bitbucket.org/snail/proxy/services"
|
||||||
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
|
"bitbucket.org/snail/proxy/utils"
|
||||||
|
"bitbucket.org/snail/proxy/utils/jumper"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
"github.com/snail007/goproxy/services"
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
|
||||||
"github.com/snail007/goproxy/utils"
|
|
||||||
"github.com/snail007/goproxy/utils/jumper"
|
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
@ -43,18 +45,18 @@ type ClientUDPConnItem struct {
|
|||||||
type MuxClient struct {
|
type MuxClient struct {
|
||||||
cfg MuxClientArgs
|
cfg MuxClientArgs
|
||||||
isStop bool
|
isStop bool
|
||||||
sessions utils.ConcurrentMap
|
sessions mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
jumper *jumper.Jumper
|
jumper *jumper.Jumper
|
||||||
udpConns utils.ConcurrentMap
|
udpConns mapx.ConcurrentMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMuxClient() services.Service {
|
func NewMuxClient() services.Service {
|
||||||
return &MuxClient{
|
return &MuxClient{
|
||||||
cfg: MuxClientArgs{},
|
cfg: MuxClientArgs{},
|
||||||
isStop: false,
|
isStop: false,
|
||||||
sessions: utils.NewConcurrentMap(),
|
sessions: mapx.NewConcurrentMap(),
|
||||||
udpConns: utils.NewConcurrentMap(),
|
udpConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ func (s *MuxClient) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop client service crashed,%s", e)
|
s.log.Printf("stop client service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service client stopped")
|
s.log.Printf("service client stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -341,7 +343,7 @@ func (s *MuxClient) UDPRevecive(key, ID string) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
func (s *MuxClient) UDPGCDeamon() {
|
func (s *MuxClient) UDPGCDeamon() {
|
||||||
gctime := int64(30)
|
gctime := int64(60)
|
||||||
go func() {
|
go func() {
|
||||||
if s.isStop {
|
if s.isStop {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -12,16 +12,23 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/jumper"
|
"bitbucket.org/snail/proxy/utils/jumper"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CONN_CLIENT_CONTROL = uint8(1)
|
||||||
|
CONN_SERVER = uint8(4)
|
||||||
|
CONN_CLIENT = uint8(5)
|
||||||
|
)
|
||||||
|
|
||||||
type MuxServerArgs struct {
|
type MuxServerArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
@ -41,19 +48,17 @@ type MuxServerArgs struct {
|
|||||||
KCP kcpcfg.KCPConfigArgs
|
KCP kcpcfg.KCPConfigArgs
|
||||||
Jumper *string
|
Jumper *string
|
||||||
}
|
}
|
||||||
|
type MuxServer struct {
|
||||||
|
cfg MuxServerArgs
|
||||||
|
sc utils.ServerChannel
|
||||||
|
sessions mapx.ConcurrentMap
|
||||||
|
lockChn chan bool
|
||||||
|
isStop bool
|
||||||
|
log *logger.Logger
|
||||||
|
jumper *jumper.Jumper
|
||||||
|
udpConns mapx.ConcurrentMap
|
||||||
|
}
|
||||||
|
|
||||||
type MuxUDPPacketItem struct {
|
|
||||||
packet *[]byte
|
|
||||||
localAddr *net.UDPAddr
|
|
||||||
srcAddr *net.UDPAddr
|
|
||||||
}
|
|
||||||
type UDPConnItem struct {
|
|
||||||
conn *net.Conn
|
|
||||||
touchtime int64
|
|
||||||
srcAddr *net.UDPAddr
|
|
||||||
localAddr *net.UDPAddr
|
|
||||||
connid string
|
|
||||||
}
|
|
||||||
type MuxServerManager struct {
|
type MuxServerManager struct {
|
||||||
cfg MuxServerArgs
|
cfg MuxServerArgs
|
||||||
serverID string
|
serverID string
|
||||||
@ -162,36 +167,35 @@ func (s *MuxServerManager) InitService() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type MuxServer struct {
|
|
||||||
cfg MuxServerArgs
|
|
||||||
sc utils.ServerChannel
|
|
||||||
sessions utils.ConcurrentMap
|
|
||||||
lockChn chan bool
|
|
||||||
isStop bool
|
|
||||||
log *logger.Logger
|
|
||||||
jumper *jumper.Jumper
|
|
||||||
udpConns utils.ConcurrentMap
|
|
||||||
// writelock *sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMuxServer() services.Service {
|
func NewMuxServer() services.Service {
|
||||||
return &MuxServer{
|
return &MuxServer{
|
||||||
cfg: MuxServerArgs{},
|
cfg: MuxServerArgs{},
|
||||||
lockChn: make(chan bool, 1),
|
lockChn: make(chan bool, 1),
|
||||||
sessions: utils.NewConcurrentMap(),
|
sessions: mapx.NewConcurrentMap(),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
udpConns: utils.NewConcurrentMap(),
|
|
||||||
// writelock: &sync.Mutex{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MuxUDPPacketItem struct {
|
||||||
|
packet *[]byte
|
||||||
|
localAddr *net.UDPAddr
|
||||||
|
srcAddr *net.UDPAddr
|
||||||
|
}
|
||||||
|
type UDPConnItem struct {
|
||||||
|
conn *net.Conn
|
||||||
|
touchtime int64
|
||||||
|
srcAddr *net.UDPAddr
|
||||||
|
localAddr *net.UDPAddr
|
||||||
|
connid string
|
||||||
|
}
|
||||||
|
|
||||||
func (s *MuxServer) StopService() {
|
func (s *MuxServer) StopService() {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop server service crashed,%s", e)
|
s.log.Printf("stop server service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service server stopped")
|
s.log.Printf("service server stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -243,7 +247,7 @@ func (s *MuxServer) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
s.sc = utils.NewServerChannel(host, p, s.log)
|
s.sc = utils.NewServerChannel(host, p, s.log)
|
||||||
if *s.cfg.IsUDP {
|
if *s.cfg.IsUDP {
|
||||||
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
err = s.sc.ListenUDP(func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||||
s.UDPSend(packet, localAddr, srcAddr)
|
s.UDPSend(packet, localAddr, srcAddr)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -425,7 +429,7 @@ func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *MuxServer) UDPGCDeamon() {
|
func (s *MuxServer) UDPGCDeamon() {
|
||||||
gctime := int64(30)
|
gctime := int64(60)
|
||||||
go func() {
|
go func() {
|
||||||
if s.isStop {
|
if s.isStop {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -8,53 +8,71 @@ import (
|
|||||||
logger "log"
|
logger "log"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"bitbucket.org/snail/proxy/utils/conncrypt"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"bitbucket.org/snail/proxy/utils/datasize"
|
||||||
|
"bitbucket.org/snail/proxy/utils/dnsx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/iolimiter"
|
||||||
|
"bitbucket.org/snail/proxy/utils/lb"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/socks"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SocksArgs struct {
|
type SocksArgs struct {
|
||||||
Parent *string
|
Parent *[]string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
Local *string
|
Local *string
|
||||||
LocalType *string
|
LocalType *string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
KeyFile *string
|
KeyFile *string
|
||||||
CaCertFile *string
|
CaCertFile *string
|
||||||
CaCertBytes []byte
|
CaCertBytes []byte
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
SSHKeyFile *string
|
SSHKeyFile *string
|
||||||
SSHKeyFileSalt *string
|
SSHKeyFileSalt *string
|
||||||
SSHPassword *string
|
SSHPassword *string
|
||||||
SSHUser *string
|
SSHUser *string
|
||||||
SSHKeyBytes []byte
|
SSHKeyBytes []byte
|
||||||
SSHAuthMethod ssh.AuthMethod
|
SSHAuthMethod ssh.AuthMethod
|
||||||
Timeout *int
|
Timeout *int
|
||||||
Always *bool
|
Always *bool
|
||||||
Interval *int
|
Interval *int
|
||||||
Blocked *string
|
Blocked *string
|
||||||
Direct *string
|
Direct *string
|
||||||
AuthFile *string
|
ParentAuth *string
|
||||||
Auth *[]string
|
AuthFile *string
|
||||||
AuthURL *string
|
Auth *[]string
|
||||||
AuthURLOkCode *int
|
AuthURL *string
|
||||||
AuthURLTimeout *int
|
AuthURLOkCode *int
|
||||||
AuthURLRetry *int
|
AuthURLTimeout *int
|
||||||
KCP kcpcfg.KCPConfigArgs
|
AuthURLRetry *int
|
||||||
LocalIPS *[]string
|
KCP kcpcfg.KCPConfigArgs
|
||||||
DNSAddress *string
|
LocalIPS *[]string
|
||||||
DNSTTL *int
|
DNSAddress *string
|
||||||
LocalKey *string
|
DNSTTL *int
|
||||||
ParentKey *string
|
LocalKey *string
|
||||||
LocalCompress *bool
|
ParentKey *string
|
||||||
ParentCompress *bool
|
LocalCompress *bool
|
||||||
|
ParentCompress *bool
|
||||||
|
LoadBalanceMethod *string
|
||||||
|
LoadBalanceTimeout *int
|
||||||
|
LoadBalanceRetryTime *int
|
||||||
|
LoadBalanceHashTarget *bool
|
||||||
|
LoadBalanceOnlyHA *bool
|
||||||
|
|
||||||
|
RateLimit *string
|
||||||
|
RateLimitBytes float64
|
||||||
|
BindListen *bool
|
||||||
|
Debug *bool
|
||||||
}
|
}
|
||||||
type Socks struct {
|
type Socks struct {
|
||||||
cfg SocksArgs
|
cfg SocksArgs
|
||||||
@ -64,11 +82,12 @@ type Socks struct {
|
|||||||
lockChn chan bool
|
lockChn chan bool
|
||||||
udpSC utils.ServerChannel
|
udpSC utils.ServerChannel
|
||||||
sc *utils.ServerChannel
|
sc *utils.ServerChannel
|
||||||
domainResolver utils.DomainResolver
|
domainResolver dnsx.DomainResolver
|
||||||
isStop bool
|
isStop bool
|
||||||
userConns utils.ConcurrentMap
|
userConns mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
udpRelatedPacketConns utils.ConcurrentMap
|
lb *lb.Group
|
||||||
|
udpRelatedPacketConns mapx.ConcurrentMap
|
||||||
udpLocalKey []byte
|
udpLocalKey []byte
|
||||||
udpParentKey []byte
|
udpParentKey []byte
|
||||||
}
|
}
|
||||||
@ -80,14 +99,14 @@ func NewSocks() services.Service {
|
|||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
lockChn: make(chan bool, 1),
|
lockChn: make(chan bool, 1),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
udpRelatedPacketConns: utils.NewConcurrentMap(),
|
udpRelatedPacketConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Socks) CheckArgs() (err error) {
|
func (s *Socks) CheckArgs() (err error) {
|
||||||
|
|
||||||
if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *s.cfg.ParentType == "tls") {
|
if *s.cfg.LocalType == "tls" || (len(*s.cfg.Parent) > 0 && *s.cfg.ParentType == "tls") {
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -100,7 +119,12 @@ func (s *Socks) CheckArgs() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if *s.cfg.Parent != "" {
|
|
||||||
|
if len(*s.cfg.Parent) == 1 && (*s.cfg.Parent)[0] == "" {
|
||||||
|
(*s.cfg.Parent) = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
if *s.cfg.ParentType == "" {
|
if *s.cfg.ParentType == "" {
|
||||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||||
return
|
return
|
||||||
@ -136,21 +160,30 @@ func (s *Socks) CheckArgs() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if *s.cfg.RateLimit != "0" && *s.cfg.RateLimit != "" {
|
||||||
|
var size uint64
|
||||||
|
size, err = datasize.Parse(*s.cfg.RateLimit)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("parse rate limit size error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.cfg.RateLimitBytes = float64(size)
|
||||||
|
}
|
||||||
s.udpLocalKey = s.LocalUDPKey()
|
s.udpLocalKey = s.LocalUDPKey()
|
||||||
s.udpParentKey = s.ParentUDPKey()
|
s.udpParentKey = s.ParentUDPKey()
|
||||||
//s.log.Printf("udpLocalKey : %v , udpParentKey : %v", s.udpLocalKey, s.udpParentKey)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *Socks) InitService() (err error) {
|
func (s *Socks) InitService() (err error) {
|
||||||
s.InitBasicAuth()
|
s.InitBasicAuth()
|
||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
(*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
||||||
}
|
}
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
|
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
|
||||||
|
s.InitLB()
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentType == "ssh" {
|
if *s.cfg.ParentType == "ssh" {
|
||||||
e := s.ConnectSSH()
|
e := s.ConnectSSH(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
err = fmt.Errorf("init service fail, ERR: %s", e)
|
err = fmt.Errorf("init service fail, ERR: %s", e)
|
||||||
return
|
return
|
||||||
@ -161,7 +194,7 @@ func (s *Socks) InitService() (err error) {
|
|||||||
if s.isStop {
|
if s.isStop {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
_, err = conn.Write([]byte{0})
|
_, err = conn.Write([]byte{0})
|
||||||
@ -172,7 +205,7 @@ func (s *Socks) InitService() (err error) {
|
|||||||
s.sshClient.Close()
|
s.sshClient.Close()
|
||||||
}
|
}
|
||||||
s.log.Printf("ssh offline, retrying...")
|
s.log.Printf("ssh offline, retrying...")
|
||||||
s.ConnectSSH()
|
s.ConnectSSH(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)))
|
||||||
} else {
|
} else {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
@ -191,11 +224,11 @@ func (s *Socks) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop socks service crashed,%s", e)
|
s.log.Printf("stop socks service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service socks stopped")
|
s.log.Printf("service socks stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.checker.Stop()
|
s.checker.Stop()
|
||||||
}
|
}
|
||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
@ -210,6 +243,9 @@ func (s *Socks) StopService() {
|
|||||||
for _, c := range s.userConns.Items() {
|
for _, c := range s.userConns.Items() {
|
||||||
(*c.(*net.Conn)).Close()
|
(*c.(*net.Conn)).Close()
|
||||||
}
|
}
|
||||||
|
if s.lb != nil {
|
||||||
|
s.lb.Stop()
|
||||||
|
}
|
||||||
for _, c := range s.udpRelatedPacketConns.Items() {
|
for _, c := range s.udpRelatedPacketConns.Items() {
|
||||||
(*c.(*net.UDPConn)).Close()
|
(*c.(*net.UDPConn)).Close()
|
||||||
}
|
}
|
||||||
@ -224,14 +260,14 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
if err = s.InitService(); err != nil {
|
if err = s.InitService(); err != nil {
|
||||||
s.InitService()
|
s.InitService()
|
||||||
}
|
}
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
s.log.Printf("use %s parent %v [ %s ]", *s.cfg.ParentType, *s.cfg.Parent, strings.ToUpper(*s.cfg.LoadBalanceMethod))
|
||||||
}
|
}
|
||||||
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
|
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
|
||||||
if *s.cfg.LocalType == "tcp" {
|
if *s.cfg.LocalType == "tcp" {
|
||||||
err = sc.ListenTCP(s.socksConnCallback)
|
err = sc.ListenTCP(s.socksConnCallback)
|
||||||
} else if *s.cfg.LocalType == "tls" {
|
} else if *s.cfg.LocalType == "tls" {
|
||||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback)
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.socksConnCallback)
|
||||||
} else if *s.cfg.LocalType == "kcp" {
|
} else if *s.cfg.LocalType == "kcp" {
|
||||||
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback, s.log)
|
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback, s.log)
|
||||||
}
|
}
|
||||||
@ -261,116 +297,40 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
|||||||
Password: *s.cfg.LocalKey,
|
Password: *s.cfg.LocalKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//协商开始
|
|
||||||
|
|
||||||
//method select request
|
//socks5 server
|
||||||
inConn.SetReadDeadline(time.Now().Add(time.Second * 3))
|
var serverConn *socks.ServerConn
|
||||||
methodReq, err := socks.NewMethodsRequest(inConn)
|
udpIP, _, _ := net.SplitHostPort(inConn.LocalAddr().String())
|
||||||
inConn.SetReadDeadline(time.Time{})
|
if s.IsBasicAuth() {
|
||||||
if err != nil {
|
serverConn = socks.NewServerConn(&inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, true, udpIP, nil)
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
|
||||||
utils.CloseConn(&inConn)
|
|
||||||
if err != io.EOF {
|
|
||||||
s.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)
|
|
||||||
s.log.Printf("none method found : Method_NO_AUTH")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//method select reply
|
|
||||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("reply answer data fail,ERR: %s", err)
|
|
||||||
utils.CloseConn(&inConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// s.log.Printf("% x", methodReq.Bytes())
|
|
||||||
} else {
|
} else {
|
||||||
//auth
|
serverConn = socks.NewServerConn(&inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, true, udpIP, nil)
|
||||||
if !methodReq.Select(socks.Method_USER_PASS) {
|
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
|
||||||
utils.CloseConn(&inConn)
|
|
||||||
s.log.Printf("none method found : Method_USER_PASS")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//method reply need auth
|
|
||||||
err = methodReq.Reply(socks.Method_USER_PASS)
|
|
||||||
if err != nil {
|
|
||||||
s.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:])
|
|
||||||
//s.log.Printf("user:%s,pass:%s", user, pass)
|
|
||||||
//auth
|
|
||||||
_addr := strings.Split(inConn.RemoteAddr().String(), ":")
|
|
||||||
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
|
|
||||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
inConn.Write([]byte{0x01, 0x00})
|
|
||||||
inConn.SetDeadline(time.Time{})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
inConn.Write([]byte{0x01, 0x01})
|
|
||||||
inConn.SetDeadline(time.Time{})
|
|
||||||
|
|
||||||
utils.CloseConn(&inConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if err := serverConn.Handshake(); err != nil {
|
||||||
//request detail
|
if !strings.HasSuffix(err.Error(), "EOF") {
|
||||||
request, err := socks.NewRequest(inConn)
|
s.log.Printf("handshake fail, ERR: %s", err)
|
||||||
if err != nil {
|
}
|
||||||
s.log.Printf("read request data fail,ERR: %s", err)
|
inConn.Close()
|
||||||
utils.CloseConn(&inConn)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//协商结束
|
if serverConn.IsUDP() {
|
||||||
|
s.proxyUDP(&inConn, serverConn)
|
||||||
switch request.CMD() {
|
} else if serverConn.IsTCP() {
|
||||||
case socks.CMD_BIND:
|
s.proxyTCP(&inConn, serverConn)
|
||||||
//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) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
func (s *Socks) proxyTCP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
var err interface{}
|
var err interface{}
|
||||||
|
lbAddr := ""
|
||||||
useProxy := true
|
useProxy := true
|
||||||
tryCount := 0
|
tryCount := 0
|
||||||
maxTryCount := 5
|
maxTryCount := 5
|
||||||
//防止死循环
|
//防止死循环
|
||||||
if s.IsDeadLoop((*inConn).LocalAddr().String(), request.Host()) {
|
if s.IsDeadLoop((*inConn).LocalAddr().String(), serverConn.Host()) {
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
s.log.Printf("dead loop detected , %s", request.Host())
|
s.log.Printf("dead loop detected , %s", serverConn.Host())
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -378,33 +338,70 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
if s.isStop {
|
if s.isStop {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if *s.cfg.Always {
|
if *s.cfg.Always {
|
||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
|
selectAddr := (*inConn).RemoteAddr().String()
|
||||||
|
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||||
|
selectAddr = serverConn.Target()
|
||||||
|
}
|
||||||
|
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
//lbAddr = s.lb.Select((*inConn).RemoteAddr().String())
|
||||||
|
outConn, err = s.GetParentConn(lbAddr, serverConn)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("connect to parent fail, %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//handshake
|
||||||
|
//socks client
|
||||||
|
_, err = s.HandshakeSocksParent(&outConn, "tcp", serverConn.Target(), serverConn.AuthData(), false)
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
s.log.Printf("handshake fail, %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
host, _, _ := net.SplitHostPort(request.Addr())
|
host, _, _ := net.SplitHostPort(serverConn.Target())
|
||||||
useProxy := false
|
useProxy := false
|
||||||
if utils.IsIternalIP(host, *s.cfg.Always) {
|
if utils.IsInternalIP(host, *s.cfg.Always) {
|
||||||
useProxy = false
|
useProxy = false
|
||||||
} else {
|
} else {
|
||||||
var isInMap bool
|
var isInMap bool
|
||||||
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
|
useProxy, isInMap, _, _ = s.checker.IsBlocked(serverConn.Target())
|
||||||
if !isInMap {
|
if !isInMap {
|
||||||
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
|
s.checker.Add(serverConn.Target(), s.Resolve(serverConn.Target()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr(), true)
|
selectAddr := (*inConn).RemoteAddr().String()
|
||||||
|
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||||
|
selectAddr = serverConn.Target()
|
||||||
|
}
|
||||||
|
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
//lbAddr = s.lb.Select((*inConn).RemoteAddr().String())
|
||||||
|
outConn, err = s.GetParentConn(lbAddr, serverConn)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("connect to parent fail, %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//handshake
|
||||||
|
//socks client
|
||||||
|
_, err = s.HandshakeSocksParent(&outConn, "tcp", serverConn.Target(), serverConn.AuthData(), false)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("handshake fail, %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout)
|
outConn, err = s.GetDirectConn(s.Resolve(serverConn.Target()), (*inConn).LocalAddr().String())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(s.Resolve(request.Addr()), *s.cfg.Timeout)
|
outConn, err = s.GetDirectConn(s.Resolve(serverConn.Target()), (*inConn).LocalAddr().String())
|
||||||
useProxy = false
|
useProxy = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tryCount++
|
tryCount++
|
||||||
if err == nil || tryCount > maxTryCount || *s.cfg.Parent == "" {
|
if err == nil || tryCount > maxTryCount || len(*s.cfg.Parent) == 0 {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("get out conn fail,%s,retrying...", err)
|
s.log.Printf("get out conn fail,%s,retrying...", err)
|
||||||
@ -413,28 +410,37 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("get out conn fail,%s", err)
|
s.log.Printf("get out conn fail,%s", err)
|
||||||
request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.log.Printf("use proxy %v : %s", useProxy, request.Addr())
|
s.log.Printf("use proxy %v : %s", useProxy, serverConn.Target())
|
||||||
|
|
||||||
request.TCPReply(socks.REP_SUCCESS)
|
|
||||||
inAddr := (*inConn).RemoteAddr().String()
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
|
//outRemoteAddr := outConn.RemoteAddr().String()
|
||||||
//inLocalAddr := (*inConn).LocalAddr().String()
|
//inLocalAddr := (*inConn).LocalAddr().String()
|
||||||
|
|
||||||
s.log.Printf("conn %s - %s connected", inAddr, request.Addr())
|
if s.cfg.RateLimitBytes > 0 {
|
||||||
|
outConn = iolimiter.NewReaderConn(outConn, s.cfg.RateLimitBytes)
|
||||||
|
}
|
||||||
|
|
||||||
utils.IoBind(*inConn, outConn, func(err interface{}) {
|
utils.IoBind(*inConn, outConn, func(err interface{}) {
|
||||||
s.log.Printf("conn %s - %s released", inAddr, request.Addr())
|
s.log.Printf("conn %s - %s released", inAddr, serverConn.Target())
|
||||||
s.userConns.Remove(inAddr)
|
s.userConns.Remove(inAddr)
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
|
s.lb.DecreaseConns(lbAddr)
|
||||||
|
}
|
||||||
}, s.log)
|
}, s.log)
|
||||||
if c, ok := s.userConns.Get(inAddr); ok {
|
if c, ok := s.userConns.Get(inAddr); ok {
|
||||||
(*c.(*net.Conn)).Close()
|
(*c.(*net.Conn)).Close()
|
||||||
s.userConns.Remove(inAddr)
|
s.userConns.Remove(inAddr)
|
||||||
}
|
}
|
||||||
s.userConns.Set(inAddr, inConn)
|
s.userConns.Set(inAddr, inConn)
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
|
s.lb.IncreasConns(lbAddr)
|
||||||
|
}
|
||||||
|
s.log.Printf("conn %s - %s connected", inAddr, serverConn.Target())
|
||||||
}
|
}
|
||||||
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake bool) (outConn net.Conn, err interface{}) {
|
func (s *Socks) GetParentConn(parentAddress string, serverConn *socks.ServerConn) (outConn net.Conn, err interface{}) {
|
||||||
switch *s.cfg.ParentType {
|
switch *s.cfg.ParentType {
|
||||||
case "kcp":
|
case "kcp":
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -442,13 +448,15 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake
|
|||||||
fallthrough
|
fallthrough
|
||||||
case "tcp":
|
case "tcp":
|
||||||
if *s.cfg.ParentType == "tls" {
|
if *s.cfg.ParentType == "tls" {
|
||||||
var _outConn tls.Conn
|
var _conn tls.Conn
|
||||||
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
_conn, err = utils.TlsConnectHost(parentAddress, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
|
||||||
outConn = net.Conn(&_outConn)
|
if err == nil {
|
||||||
|
outConn = net.Conn(&_conn)
|
||||||
|
}
|
||||||
} else if *s.cfg.ParentType == "kcp" {
|
} else if *s.cfg.ParentType == "kcp" {
|
||||||
outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), s.cfg.KCP)
|
outConn, err = utils.ConnectKCPHost(parentAddress, s.cfg.KCP)
|
||||||
} else {
|
} else {
|
||||||
outConn, err = utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout)
|
outConn, err = utils.ConnectHost(parentAddress, *s.cfg.Timeout)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("connect fail,%s", err)
|
err = fmt.Errorf("connect fail,%s", err)
|
||||||
@ -462,44 +470,6 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake
|
|||||||
Password: *s.cfg.ParentKey,
|
Password: *s.cfg.ParentKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if !handshake {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var buf = make([]byte, 1024)
|
|
||||||
//var n int
|
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
_, err = outConn.Write(methodBytes)
|
|
||||||
outConn.SetDeadline(time.Time{})
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("write method fail,%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
_, err = outConn.Read(buf)
|
|
||||||
outConn.SetDeadline(time.Time{})
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("read method reply fail,%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//resp := buf[:n]
|
|
||||||
//s.log.Printf("resp:%v", resp)
|
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
_, err = outConn.Write(reqBytes)
|
|
||||||
outConn.SetDeadline(time.Time{})
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("write req detail fail,%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
|
||||||
_, err = outConn.Read(buf)
|
|
||||||
outConn.SetDeadline(time.Time{})
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("read req reply fail,%s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//result := buf[:n]
|
|
||||||
//s.log.Printf("result:%v", result)
|
|
||||||
|
|
||||||
case "ssh":
|
case "ssh":
|
||||||
maxTryCount := 1
|
maxTryCount := 1
|
||||||
tryCount := 0
|
tryCount := 0
|
||||||
@ -515,17 +485,17 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake
|
|||||||
}
|
}
|
||||||
wait <- true
|
wait <- true
|
||||||
}()
|
}()
|
||||||
outConn, err = s.sshClient.Dial("tcp", host)
|
outConn, err = s.sshClient.Dial("tcp", serverConn.Target())
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case <-wait:
|
case <-wait:
|
||||||
case <-time.After(time.Millisecond * time.Duration(*s.cfg.Timeout) * 2):
|
case <-time.After(time.Millisecond * time.Duration(*s.cfg.Timeout) * 2):
|
||||||
err = fmt.Errorf("ssh dial %s timeout", host)
|
err = fmt.Errorf("ssh dial %s timeout", serverConn.Target())
|
||||||
s.sshClient.Close()
|
s.sshClient.Close()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
s.log.Printf("connect ssh fail, ERR: %s, retrying...", err)
|
||||||
e := s.ConnectSSH()
|
e := s.ConnectSSH(parentAddress)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
tryCount++
|
tryCount++
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
@ -538,7 +508,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string, handshake
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *Socks) ConnectSSH() (err error) {
|
func (s *Socks) ConnectSSH(lbAddr string) (err error) {
|
||||||
select {
|
select {
|
||||||
case s.lockChn <- true:
|
case s.lockChn <- true:
|
||||||
default:
|
default:
|
||||||
@ -556,7 +526,7 @@ func (s *Socks) ConnectSSH() (err error) {
|
|||||||
if s.sshClient != nil {
|
if s.sshClient != nil {
|
||||||
s.sshClient.Close()
|
s.sshClient.Close()
|
||||||
}
|
}
|
||||||
s.sshClient, err = ssh.Dial("tcp", s.Resolve(*s.cfg.Parent), &config)
|
s.sshClient, err = ssh.Dial("tcp", s.Resolve(lbAddr), &config)
|
||||||
<-s.lockChn
|
<-s.lockChn
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -585,6 +555,27 @@ func (s *Socks) InitBasicAuth() (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *Socks) InitLB() {
|
||||||
|
configs := lb.BackendsConfig{}
|
||||||
|
for _, addr := range *s.cfg.Parent {
|
||||||
|
_addrInfo := strings.Split(addr, "@")
|
||||||
|
_addr := _addrInfo[0]
|
||||||
|
weight := 1
|
||||||
|
if len(_addrInfo) == 2 {
|
||||||
|
weight, _ = strconv.Atoi(_addrInfo[1])
|
||||||
|
}
|
||||||
|
configs = append(configs, &lb.BackendConfig{
|
||||||
|
Address: _addr,
|
||||||
|
Weight: weight,
|
||||||
|
ActiveAfter: 1,
|
||||||
|
InactiveAfter: 2,
|
||||||
|
Timeout: time.Duration(*s.cfg.LoadBalanceTimeout) * time.Millisecond,
|
||||||
|
RetryTime: time.Duration(*s.cfg.LoadBalanceRetryTime) * time.Millisecond,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
|
||||||
|
s.lb = &LB
|
||||||
|
}
|
||||||
func (s *Socks) IsBasicAuth() bool {
|
func (s *Socks) IsBasicAuth() bool {
|
||||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||||
}
|
}
|
||||||
@ -602,7 +593,7 @@ func (s *Socks) IsDeadLoop(inLocalAddr string, host string) bool {
|
|||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
|
outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
|
||||||
} else {
|
} else {
|
||||||
outIPs, err = utils.MyLookupIP(outDomain)
|
outIPs, err = utils.LookupIP(outDomain)
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, ip := range outIPs {
|
for _, ip := range outIPs {
|
||||||
@ -638,3 +629,37 @@ func (s *Socks) Resolve(address string) string {
|
|||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
func (s *Socks) GetDirectConn(address string, localAddr string) (conn net.Conn, err error) {
|
||||||
|
if !*s.cfg.BindListen {
|
||||||
|
return utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
ip, _, _ := net.SplitHostPort(localAddr)
|
||||||
|
if utils.IsInternalIP(ip, false) {
|
||||||
|
return utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
local, _ := net.ResolveTCPAddr("tcp", ip+":0")
|
||||||
|
d := net.Dialer{
|
||||||
|
Timeout: time.Millisecond * time.Duration(*s.cfg.Timeout),
|
||||||
|
LocalAddr: local,
|
||||||
|
}
|
||||||
|
conn, err = d.Dial("tcp", address)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Socks) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
|
||||||
|
if *s.cfg.ParentAuth != "" {
|
||||||
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
|
if len(a) != 2 {
|
||||||
|
err = fmt.Errorf("parent auth data format error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
||||||
|
} else {
|
||||||
|
if !fromSS && !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
||||||
|
} else {
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = client.Handshake()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -9,9 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
goaes "github.com/snail007/goproxy/utils/aes"
|
goaes "bitbucket.org/snail/proxy/utils/aes"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"bitbucket.org/snail/proxy/utils/socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Socks) ParentUDPKey() (key []byte) {
|
func (s *Socks) ParentUDPKey() (key []byte) {
|
||||||
@ -44,7 +44,7 @@ func (s *Socks) LocalUDPKey() (key []byte) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
|
func (s *Socks) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
||||||
@ -54,23 +54,12 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
|
|
||||||
inconnRemoteAddr := (*inConn).RemoteAddr().String()
|
inconnRemoteAddr := (*inConn).RemoteAddr().String()
|
||||||
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
localAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||||
udpListener, err := net.ListenUDP("udp", localAddr)
|
udpListener := serverConn.UDPConnListener
|
||||||
if err != nil {
|
srcIP, _, _ := net.SplitHostPort((*inConn).RemoteAddr().String())
|
||||||
(*inConn).Close()
|
s.log.Printf("proxy udp on %s , for %s", udpListener.LocalAddr(), inconnRemoteAddr)
|
||||||
udpListener.Close()
|
|
||||||
s.log.Printf("udp bind fail , %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
|
||||||
_, port, _ := net.SplitHostPort(udpListener.LocalAddr().String())
|
|
||||||
if len(*s.cfg.LocalIPS) > 0 {
|
|
||||||
host = (*s.cfg.LocalIPS)[0]
|
|
||||||
}
|
|
||||||
s.log.Printf("proxy udp on %s , for %s", net.JoinHostPort(host, port), inconnRemoteAddr)
|
|
||||||
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
|
|
||||||
s.userConns.Set(inconnRemoteAddr, inConn)
|
s.userConns.Set(inconnRemoteAddr, inConn)
|
||||||
var (
|
var (
|
||||||
outUDPConn *net.UDPConn
|
outUDPConn *net.UDPConn
|
||||||
@ -134,15 +123,15 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
useProxy := true
|
useProxy := true
|
||||||
if *s.cfg.Parent != "" {
|
if len(*s.cfg.Parent) > 0 {
|
||||||
dstHost, _, _ := net.SplitHostPort(request.Addr())
|
dstHost, _, _ := net.SplitHostPort(serverConn.Target())
|
||||||
if utils.IsIternalIP(dstHost, *s.cfg.Always) {
|
if utils.IsInternalIP(dstHost, *s.cfg.Always) {
|
||||||
useProxy = false
|
useProxy = false
|
||||||
} else {
|
} else {
|
||||||
var isInMap bool
|
var isInMap bool
|
||||||
useProxy, isInMap, _, _ = s.checker.IsBlocked(request.Addr())
|
useProxy, isInMap, _, _ = s.checker.IsBlocked(serverConn.Target())
|
||||||
if !isInMap {
|
if !isInMap {
|
||||||
s.checker.Add(request.Addr(), s.Resolve(request.Addr()))
|
s.checker.Add(serverConn.Target(), s.Resolve(serverConn.Target()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -150,13 +139,17 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
}
|
}
|
||||||
if useProxy {
|
if useProxy {
|
||||||
//parent proxy
|
//parent proxy
|
||||||
outconn, err := s.getOutConn(nil, nil, "", false)
|
lbAddr := s.lb.Select((*inConn).RemoteAddr().String(), *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
outconn, err := s.GetParentConn(lbAddr, serverConn)
|
||||||
|
//outconn, err := s.GetParentConn(nil, nil, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
clean("connnect fail", fmt.Sprintf("%s", err))
|
clean("connnect fail", fmt.Sprintf("%s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client := socks.NewClientConn(&outconn, "udp", request.Addr(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
|
||||||
if err = client.Handshake(); err != nil {
|
client, err := s.HandshakeSocksParent(&outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
clean("handshake fail", fmt.Sprintf("%s", err))
|
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -179,7 +172,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
||||||
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
||||||
}
|
}
|
||||||
s.log.Printf("use proxy %v : udp %s", useProxy, request.Addr())
|
s.log.Printf("use proxy %v : udp %s", useProxy, serverConn.Target())
|
||||||
//relay
|
//relay
|
||||||
for {
|
for {
|
||||||
buf := utils.LeakyBuffer.Get()
|
buf := utils.LeakyBuffer.Get()
|
||||||
@ -245,6 +238,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
//var dlen = n
|
//var dlen = n
|
||||||
if useProxy {
|
if useProxy {
|
||||||
//forward to local
|
//forward to local
|
||||||
|
|||||||
@ -1,50 +1,17 @@
|
|||||||
package sps
|
package sps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
goaes "github.com/snail007/goproxy/utils/aes"
|
goaes "bitbucket.org/snail/proxy/utils/aes"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"bitbucket.org/snail/proxy/utils/socks"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *SPS) ParentUDPKey() (key []byte) {
|
|
||||||
switch *s.cfg.ParentType {
|
|
||||||
case "tcp":
|
|
||||||
if *s.cfg.ParentKey != "" {
|
|
||||||
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
|
|
||||||
return []byte(v)[:24]
|
|
||||||
}
|
|
||||||
case "tls":
|
|
||||||
return s.cfg.KeyBytes[:24]
|
|
||||||
case "kcp":
|
|
||||||
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
|
||||||
return []byte(v)[:24]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (s *SPS) LocalUDPKey() (key []byte) {
|
|
||||||
switch *s.cfg.LocalType {
|
|
||||||
case "tcp":
|
|
||||||
if *s.cfg.LocalKey != "" {
|
|
||||||
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
|
|
||||||
return []byte(v)[:24]
|
|
||||||
}
|
|
||||||
case "tls":
|
|
||||||
return s.cfg.KeyBytes[:24]
|
|
||||||
case "kcp":
|
|
||||||
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
|
||||||
return []byte(v)[:24]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
@ -123,41 +90,19 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
//parent proxy
|
//parent proxy
|
||||||
outconn, err := s.outPool.Get()
|
lbAddr := s.lb.Select((*inConn).RemoteAddr().String(), *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
|
||||||
|
outconn, err := s.GetParentConn(lbAddr)
|
||||||
//outconn, err := s.GetParentConn(nil, nil, "", false)
|
//outconn, err := s.GetParentConn(nil, nil, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
clean("connnect fail", fmt.Sprintf("%s", err))
|
clean("connnect fail", fmt.Sprintf("%s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentCompress {
|
|
||||||
outconn = utils.NewCompConn(outconn)
|
|
||||||
}
|
|
||||||
if *s.cfg.ParentKey != "" {
|
|
||||||
outconn = conncrypt.New(outconn, &conncrypt.Config{
|
|
||||||
Password: *s.cfg.ParentKey,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
s.log.Printf("connect %s for udp", serverConn.Target())
|
s.log.Printf("connect %s for udp", serverConn.Target())
|
||||||
//socks client
|
//socks client
|
||||||
var client *socks.ClientConn
|
|
||||||
auth := serverConn.AuthData()
|
|
||||||
if *s.cfg.ParentAuth != "" {
|
|
||||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
|
||||||
if len(a) != 2 {
|
|
||||||
err = fmt.Errorf("parent auth data format error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
|
||||||
} else {
|
|
||||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
|
||||||
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
|
||||||
} else {
|
|
||||||
client = socks.NewClientConn(&outconn, "udp", serverConn.Target(), time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = client.Handshake(); err != nil {
|
client, err := s.HandshakeSocksParent(&outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
|
||||||
|
if err != nil {
|
||||||
clean("handshake fail", fmt.Sprintf("%s", err))
|
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -181,9 +126,9 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
|||||||
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
//s.log.Printf("parent udp address %s", client.UDPAddr)
|
||||||
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
|
||||||
//relay
|
//relay
|
||||||
buf := utils.LeakyBuffer.Get()
|
|
||||||
defer utils.LeakyBuffer.Put(buf)
|
|
||||||
for {
|
for {
|
||||||
|
buf := utils.LeakyBuffer.Get()
|
||||||
|
defer utils.LeakyBuffer.Put(buf)
|
||||||
n, srcAddr, err := udpListener.ReadFromUDP(buf)
|
n, srcAddr, err := udpListener.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("udp listener read fail, %s", err.Error())
|
s.log.Printf("udp listener read fail, %s", err.Error())
|
||||||
@ -208,76 +153,42 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
|||||||
} else {
|
} else {
|
||||||
err = p.Parse(buf[:n])
|
err = p.Parse(buf[:n])
|
||||||
}
|
}
|
||||||
|
//err = p.Parse(buf[:n])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("udp listener parse packet fail, %s", err.Error())
|
s.log.Printf("udp listener parse packet fail, %s", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
port, _ := strconv.Atoi(p.Port())
|
|
||||||
|
|
||||||
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
|
if v, ok := s.udpRelatedPacketConns.Get(srcAddr.String()); !ok {
|
||||||
if destAddr == nil {
|
|
||||||
destAddr = &net.UDPAddr{IP: net.ParseIP(p.Host()), Port: port}
|
|
||||||
}
|
|
||||||
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
|
outUDPConn, err = net.DialUDP("udp", localAddr, destAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
|
s.log.Printf("create out udp conn fail , %s , from : %s", err, srcAddr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
|
s.udpRelatedPacketConns.Set(srcAddr.String(), outUDPConn)
|
||||||
go func() {
|
utils.UDPCopy(udpListener, outUDPConn, srcAddr, 0, func(data []byte) []byte {
|
||||||
defer func() {
|
//forward to local
|
||||||
if e := recover(); e != nil {
|
var v []byte
|
||||||
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", e, string(debug.Stack()))
|
//convert parent data to raw
|
||||||
}
|
if len(s.udpParentKey) > 0 {
|
||||||
}()
|
v, err = goaes.Decrypt(s.udpParentKey, data)
|
||||||
defer s.udpRelatedPacketConns.Remove(srcAddr.String())
|
|
||||||
//out->local io copy
|
|
||||||
buf := utils.LeakyBuffer.Get()
|
|
||||||
defer utils.LeakyBuffer.Put(buf)
|
|
||||||
for {
|
|
||||||
outUDPConn.SetReadDeadline(time.Now().Add(time.Second * 5))
|
|
||||||
n, err := outUDPConn.Read(buf)
|
|
||||||
outUDPConn.SetReadDeadline(time.Time{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("read out udp data fail , %s , from : %s", err, srcAddr)
|
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
|
||||||
if isClosedErr(err) {
|
return []byte{}
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
//var dlen = n
|
|
||||||
//forward to local
|
|
||||||
var v []byte
|
|
||||||
//convert parent data to raw
|
|
||||||
if len(s.udpParentKey) > 0 {
|
|
||||||
v, err = goaes.Decrypt(s.udpParentKey, buf[:n])
|
|
||||||
if err != nil {
|
|
||||||
s.log.Printf("udp outconn parse packet fail, %s", err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v = buf[:n]
|
|
||||||
}
|
|
||||||
//now v is raw, try convert v to local
|
|
||||||
if len(s.udpLocalKey) > 0 {
|
|
||||||
v, _ = goaes.Encrypt(s.udpLocalKey, v)
|
|
||||||
}
|
|
||||||
_, err = udpListener.WriteTo(v, srcAddr)
|
|
||||||
// _, err = udpListener.WriteTo(buf[:n], srcAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.udpRelatedPacketConns.Remove(srcAddr.String())
|
|
||||||
s.log.Printf("write out data to local fail , %s , from : %s", err, srcAddr)
|
|
||||||
if isClosedErr(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
//s.log.Printf("send udp data to local success , len %d, for : %s", dlen, srcAddr)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
v = data
|
||||||
}
|
}
|
||||||
}()
|
//now v is raw, try convert v to local
|
||||||
|
if len(s.udpLocalKey) > 0 {
|
||||||
|
v, _ = goaes.Encrypt(s.udpLocalKey, v)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}, func(err interface{}) {
|
||||||
|
s.udpRelatedPacketConns.Remove(srcAddr.String())
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("udp out->local io copy crashed:\n%s\n%s", err, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
outUDPConn = v.(*net.UDPConn)
|
outUDPConn = v.(*net.UDPConn)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package sps
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -13,70 +15,96 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/conncrypt"
|
"bitbucket.org/snail/proxy/utils/conncrypt"
|
||||||
"github.com/snail007/goproxy/utils/sni"
|
"bitbucket.org/snail/proxy/utils/datasize"
|
||||||
"github.com/snail007/goproxy/utils/socks"
|
"bitbucket.org/snail/proxy/utils/dnsx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/iolimiter"
|
||||||
|
"bitbucket.org/snail/proxy/utils/lb"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/sni"
|
||||||
|
"bitbucket.org/snail/proxy/utils/socks"
|
||||||
|
"bitbucket.org/snail/proxy/utils/ss"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SPSArgs struct {
|
type SPSArgs struct {
|
||||||
Parent *string
|
Parent *[]string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
KeyFile *string
|
KeyFile *string
|
||||||
CaCertFile *string
|
CaCertFile *string
|
||||||
CaCertBytes []byte
|
CaCertBytes []byte
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
LocalType *string
|
LocalType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
KCP kcpcfg.KCPConfigArgs
|
KCP kcpcfg.KCPConfigArgs
|
||||||
ParentServiceType *string
|
ParentServiceType *string
|
||||||
DNSAddress *string
|
DNSAddress *string
|
||||||
DNSTTL *int
|
DNSTTL *int
|
||||||
AuthFile *string
|
AuthFile *string
|
||||||
Auth *[]string
|
Auth *[]string
|
||||||
AuthURL *string
|
AuthURL *string
|
||||||
AuthURLOkCode *int
|
AuthURLOkCode *int
|
||||||
AuthURLTimeout *int
|
AuthURLTimeout *int
|
||||||
AuthURLRetry *int
|
AuthURLRetry *int
|
||||||
LocalIPS *[]string
|
LocalIPS *[]string
|
||||||
ParentAuth *string
|
ParentAuth *string
|
||||||
LocalKey *string
|
LocalKey *string
|
||||||
ParentKey *string
|
ParentKey *string
|
||||||
LocalCompress *bool
|
LocalCompress *bool
|
||||||
ParentCompress *bool
|
ParentCompress *bool
|
||||||
DisableHTTP *bool
|
SSMethod *string
|
||||||
DisableSocks5 *bool
|
SSKey *string
|
||||||
|
ParentSSMethod *string
|
||||||
|
ParentSSKey *string
|
||||||
|
DisableHTTP *bool
|
||||||
|
DisableSocks5 *bool
|
||||||
|
DisableSS *bool
|
||||||
|
LoadBalanceMethod *string
|
||||||
|
LoadBalanceTimeout *int
|
||||||
|
LoadBalanceRetryTime *int
|
||||||
|
LoadBalanceHashTarget *bool
|
||||||
|
LoadBalanceOnlyHA *bool
|
||||||
|
|
||||||
|
RateLimit *string
|
||||||
|
RateLimitBytes float64
|
||||||
|
Debug *bool
|
||||||
}
|
}
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
outPool utils.OutConn
|
|
||||||
cfg SPSArgs
|
cfg SPSArgs
|
||||||
domainResolver utils.DomainResolver
|
domainResolver dnsx.DomainResolver
|
||||||
basicAuth utils.BasicAuth
|
basicAuth utils.BasicAuth
|
||||||
serverChannels []*utils.ServerChannel
|
serverChannels []*utils.ServerChannel
|
||||||
userConns utils.ConcurrentMap
|
userConns mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
udpRelatedPacketConns utils.ConcurrentMap
|
localCipher *ss.Cipher
|
||||||
|
parentCipher *ss.Cipher
|
||||||
|
udpRelatedPacketConns mapx.ConcurrentMap
|
||||||
|
lb *lb.Group
|
||||||
udpLocalKey []byte
|
udpLocalKey []byte
|
||||||
udpParentKey []byte
|
udpParentKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() services.Service {
|
func NewSPS() services.Service {
|
||||||
return &SPS{
|
return &SPS{
|
||||||
outPool: utils.OutConn{},
|
|
||||||
cfg: SPSArgs{},
|
cfg: SPSArgs{},
|
||||||
basicAuth: utils.BasicAuth{},
|
basicAuth: utils.BasicAuth{},
|
||||||
serverChannels: []*utils.ServerChannel{},
|
serverChannels: []*utils.ServerChannel{},
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
udpRelatedPacketConns: utils.NewConcurrentMap(),
|
udpRelatedPacketConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) CheckArgs() (err error) {
|
func (s *SPS) CheckArgs() (err error) {
|
||||||
if *s.cfg.Parent == "" {
|
|
||||||
|
if len(*s.cfg.Parent) == 1 && (*s.cfg.Parent)[0] == "" {
|
||||||
|
(*s.cfg.Parent) = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*s.cfg.Parent) == 0 {
|
||||||
err = fmt.Errorf("parent required for %s %s", *s.cfg.LocalType, *s.cfg.Local)
|
err = fmt.Errorf("parent required for %s %s", *s.cfg.LocalType, *s.cfg.Local)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -84,6 +112,10 @@ func (s *SPS) CheckArgs() (err error) {
|
|||||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp>")
|
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentType == "ss" && (*s.cfg.ParentSSKey == "" || *s.cfg.ParentSSMethod == "") {
|
||||||
|
err = fmt.Errorf("ss parent need a ss key, set it by : -J <sskey>")
|
||||||
|
return
|
||||||
|
}
|
||||||
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,31 +129,45 @@ func (s *SPS) CheckArgs() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if *s.cfg.RateLimit != "0" && *s.cfg.RateLimit != "" {
|
||||||
|
var size uint64
|
||||||
|
size, err = datasize.Parse(*s.cfg.RateLimit)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("parse rate limit size error,ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.cfg.RateLimitBytes = float64(size)
|
||||||
|
}
|
||||||
s.udpLocalKey = s.LocalUDPKey()
|
s.udpLocalKey = s.LocalUDPKey()
|
||||||
s.udpParentKey = s.ParentUDPKey()
|
s.udpParentKey = s.ParentUDPKey()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *SPS) InitService() (err error) {
|
func (s *SPS) InitService() (err error) {
|
||||||
|
|
||||||
if *s.cfg.DNSAddress != "" {
|
if *s.cfg.DNSAddress != "" {
|
||||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
(*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
|
||||||
}
|
}
|
||||||
s.InitOutConnPool()
|
|
||||||
|
if len(*s.cfg.Parent) > 0 {
|
||||||
|
s.InitLB()
|
||||||
|
}
|
||||||
|
|
||||||
err = s.InitBasicAuth()
|
err = s.InitBasicAuth()
|
||||||
return
|
if *s.cfg.SSMethod != "" && *s.cfg.SSKey != "" {
|
||||||
}
|
s.localCipher, err = ss.NewCipher(*s.cfg.SSMethod, *s.cfg.SSKey)
|
||||||
func (s *SPS) InitOutConnPool() {
|
if err != nil {
|
||||||
if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" || *s.cfg.ParentType == "kcp" {
|
s.log.Printf("error generating cipher : %s", err)
|
||||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
return
|
||||||
//parent string, timeout int, InitialCap int, MaxCap int
|
}
|
||||||
s.outPool = utils.NewOutConn(
|
|
||||||
0,
|
|
||||||
*s.cfg.ParentType,
|
|
||||||
s.cfg.KCP,
|
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
|
|
||||||
*s.cfg.Parent,
|
|
||||||
*s.cfg.Timeout,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentServiceType == "ss" {
|
||||||
|
s.parentCipher, err = ss.NewCipher(*s.cfg.ParentSSMethod, *s.cfg.ParentSSKey)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Printf("error generating cipher : %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SPS) StopService() {
|
func (s *SPS) StopService() {
|
||||||
@ -130,7 +176,7 @@ func (s *SPS) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop sps service crashed,%s", e)
|
s.log.Printf("stop sps service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service sps stopped")
|
s.log.Printf("service sps stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for _, sc := range s.serverChannels {
|
for _, sc := range s.serverChannels {
|
||||||
@ -149,6 +195,12 @@ func (s *SPS) StopService() {
|
|||||||
(*(*c.(**net.Conn))).Close()
|
(*(*c.(**net.Conn))).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if s.lb != nil {
|
||||||
|
s.lb.Stop()
|
||||||
|
}
|
||||||
|
for _, c := range s.udpRelatedPacketConns.Items() {
|
||||||
|
(*c.(*net.UDPConn)).Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
|
func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
|
||||||
s.log = log
|
s.log = log
|
||||||
@ -159,24 +211,30 @@ func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
if err = s.InitService(); err != nil {
|
if err = s.InitService(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent)
|
|
||||||
|
s.log.Printf("use %s %s parent %v [ %s ]", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent, strings.ToUpper(*s.cfg.LoadBalanceMethod))
|
||||||
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
for _, addr := range strings.Split(*s.cfg.Local, ",") {
|
||||||
if addr != "" {
|
if addr != "" {
|
||||||
host, port, _ := net.SplitHostPort(addr)
|
host, port, _ := net.SplitHostPort(addr)
|
||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
sc := utils.NewServerChannel(host, p, s.log)
|
sc := utils.NewServerChannel(host, p, s.log)
|
||||||
|
s.serverChannels = append(s.serverChannels, &sc)
|
||||||
if *s.cfg.LocalType == "tcp" {
|
if *s.cfg.LocalType == "tcp" {
|
||||||
err = sc.ListenTCP(s.callback)
|
err = sc.ListenTCP(s.callback)
|
||||||
} else if *s.cfg.LocalType == "tls" {
|
} else if *s.cfg.LocalType == "tls" {
|
||||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||||
} else if *s.cfg.LocalType == "kcp" {
|
} else if *s.cfg.LocalType == "tcp" {
|
||||||
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
|
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
|
||||||
}
|
}
|
||||||
|
if *s.cfg.ParentServiceType == "socks" {
|
||||||
|
err = s.RunSSUDP(addr)
|
||||||
|
} else {
|
||||||
|
s.log.Println("warn : udp only for socks parent ")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.log.Printf("%s http(s)+socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
s.log.Printf("%s http(s)+socks+ss proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||||
s.serverChannels = append(s.serverChannels, &sc)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -200,22 +258,23 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
|
lbAddr := ""
|
||||||
switch *s.cfg.ParentType {
|
switch *s.cfg.ParentType {
|
||||||
case "kcp":
|
case "kcp":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "tcp":
|
case "tcp":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "tls":
|
case "tls":
|
||||||
err = s.OutToTCP(&inConn)
|
lbAddr, err = s.OutToTCP(&inConn)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
|
s.log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, lbAddr, err, inConn.RemoteAddr())
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
|
||||||
enableUDP := *s.cfg.ParentServiceType == "socks"
|
enableUDP := *s.cfg.ParentServiceType == "socks"
|
||||||
udpIP, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
udpIP, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
|
||||||
if len(*s.cfg.LocalIPS) > 0 {
|
if len(*s.cfg.LocalIPS) > 0 {
|
||||||
@ -243,9 +302,9 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
isSNI, _ := sni.ServerNameFromBytes(h)
|
isSNI, _ := sni.ServerNameFromBytes(h)
|
||||||
*inConn = bInConn
|
*inConn = bInConn
|
||||||
address := ""
|
address := ""
|
||||||
var auth socks.Auth
|
var auth = socks.Auth{}
|
||||||
var forwardBytes []byte
|
var forwardBytes []byte
|
||||||
//fmt.Printf("%v", h)
|
//fmt.Printf("%v", header)
|
||||||
if utils.IsSocks5(h) {
|
if utils.IsSocks5(h) {
|
||||||
if *s.cfg.DisableSocks5 {
|
if *s.cfg.DisableSocks5 {
|
||||||
(*inConn).Close()
|
(*inConn).Close()
|
||||||
@ -306,6 +365,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//ss
|
||||||
|
if *s.cfg.DisableSS {
|
||||||
|
(*inConn).Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*inConn).SetDeadline(time.Now().Add(time.Second * 5))
|
||||||
|
ssConn := ss.NewConn(*inConn, s.localCipher.Copy())
|
||||||
|
address, err = ss.GetRequest(ssConn)
|
||||||
|
(*inConn).SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ensure the host does not contain some illegal characters, NUL may panic on Win32
|
||||||
|
if strings.ContainsRune(address, 0x00) {
|
||||||
|
err = errors.New("invalid domain name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*inConn = ssConn
|
||||||
}
|
}
|
||||||
if err != nil || address == "" {
|
if err != nil || address == "" {
|
||||||
s.log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(h))
|
s.log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(h))
|
||||||
@ -316,22 +394,20 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
}
|
}
|
||||||
//connect to parent
|
//connect to parent
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
outConn, err = s.outPool.Get()
|
selectAddr := (*inConn).RemoteAddr().String()
|
||||||
|
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||||
|
selectAddr = address
|
||||||
|
}
|
||||||
|
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||||
|
//lbAddr = s.lb.Select((*inConn).RemoteAddr().String())
|
||||||
|
outConn, err = s.GetParentConn(lbAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
|
s.log.Printf("connect to %s , err:%s", lbAddr, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if *s.cfg.ParentCompress {
|
|
||||||
outConn = utils.NewCompConn(outConn)
|
|
||||||
}
|
|
||||||
if *s.cfg.ParentKey != "" {
|
|
||||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
|
||||||
Password: *s.cfg.ParentKey,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if *s.cfg.ParentAuth != "" || s.IsBasicAuth() {
|
if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
|
||||||
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
|
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +456,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
_, err = outConn.Write(pb.Bytes())
|
_, err = outConn.Write(pb.Bytes())
|
||||||
outConn.SetDeadline(time.Time{})
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
|
s.log.Printf("write CONNECT to %s , err:%s", lbAddr, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
return
|
return
|
||||||
@ -392,7 +468,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
_, err = outConn.Read(reply)
|
_, err = outConn.Read(reply)
|
||||||
outConn.SetDeadline(time.Time{})
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
s.log.Printf("read reply from %s , err:%s", lbAddr, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
utils.CloseConn(&outConn)
|
utils.CloseConn(&outConn)
|
||||||
return
|
return
|
||||||
@ -401,23 +477,24 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
}
|
}
|
||||||
} else if *s.cfg.ParentServiceType == "socks" {
|
} else if *s.cfg.ParentServiceType == "socks" {
|
||||||
s.log.Printf("connect %s", address)
|
s.log.Printf("connect %s", address)
|
||||||
|
|
||||||
//socks client
|
//socks client
|
||||||
var clientConn *socks.ClientConn
|
_, err = s.HandshakeSocksParent(&outConn, "tcp", address, auth, false)
|
||||||
if *s.cfg.ParentAuth != "" {
|
if err != nil {
|
||||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
s.log.Printf("handshake fail, %s", err)
|
||||||
if len(a) != 2 {
|
return
|
||||||
err = fmt.Errorf("parent auth data format error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
|
||||||
} else {
|
|
||||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
|
||||||
} else {
|
|
||||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err = clientConn.Handshake(); err != nil {
|
|
||||||
|
} else if *s.cfg.ParentServiceType == "ss" {
|
||||||
|
ra, e := ss.RawAddr(address)
|
||||||
|
if e != nil {
|
||||||
|
err = fmt.Errorf("build ss raw addr fail, err: %s", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy())
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("dial ss parent fail, err : %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,18 +504,27 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
outConn.Write(forwardBytes)
|
outConn.Write(forwardBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.cfg.RateLimitBytes > 0 {
|
||||||
|
outConn = iolimiter.NewReaderConn(outConn, s.cfg.RateLimitBytes)
|
||||||
|
}
|
||||||
|
|
||||||
//bind
|
//bind
|
||||||
inAddr := (*inConn).RemoteAddr().String()
|
inAddr := (*inConn).RemoteAddr().String()
|
||||||
outAddr := outConn.RemoteAddr().String()
|
outAddr := outConn.RemoteAddr().String()
|
||||||
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
utils.IoBind((*inConn), outConn, func(err interface{}) {
|
||||||
s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, address)
|
s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, address)
|
||||||
s.userConns.Remove(inAddr)
|
s.userConns.Remove(inAddr)
|
||||||
|
s.lb.DecreaseConns(lbAddr)
|
||||||
}, s.log)
|
}, s.log)
|
||||||
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, address)
|
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, address)
|
||||||
|
|
||||||
|
s.lb.IncreasConns(lbAddr)
|
||||||
|
|
||||||
if c, ok := s.userConns.Get(inAddr); ok {
|
if c, ok := s.userConns.Get(inAddr); ok {
|
||||||
(*c.(*net.Conn)).Close()
|
(*c.(*net.Conn)).Close()
|
||||||
}
|
}
|
||||||
s.userConns.Set(inAddr, inConn)
|
s.userConns.Set(inAddr, inConn)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *SPS) InitBasicAuth() (err error) {
|
func (s *SPS) InitBasicAuth() (err error) {
|
||||||
@ -466,6 +552,27 @@ func (s *SPS) InitBasicAuth() (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *SPS) InitLB() {
|
||||||
|
configs := lb.BackendsConfig{}
|
||||||
|
for _, addr := range *s.cfg.Parent {
|
||||||
|
_addrInfo := strings.Split(addr, "@")
|
||||||
|
_addr := _addrInfo[0]
|
||||||
|
weight := 1
|
||||||
|
if len(_addrInfo) == 2 {
|
||||||
|
weight, _ = strconv.Atoi(_addrInfo[1])
|
||||||
|
}
|
||||||
|
configs = append(configs, &lb.BackendConfig{
|
||||||
|
Address: _addr,
|
||||||
|
Weight: weight,
|
||||||
|
ActiveAfter: 1,
|
||||||
|
InactiveAfter: 2,
|
||||||
|
Timeout: time.Duration(*s.cfg.LoadBalanceTimeout) * time.Millisecond,
|
||||||
|
RetryTime: time.Duration(*s.cfg.LoadBalanceRetryTime) * time.Millisecond,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
|
||||||
|
s.lb = &LB
|
||||||
|
}
|
||||||
func (s *SPS) IsBasicAuth() bool {
|
func (s *SPS) IsBasicAuth() bool {
|
||||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||||
}
|
}
|
||||||
@ -518,3 +625,75 @@ func (s *SPS) Resolve(address string) string {
|
|||||||
}
|
}
|
||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
|
||||||
|
if *s.cfg.ParentType == "tls" {
|
||||||
|
var _conn tls.Conn
|
||||||
|
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
|
||||||
|
if err == nil {
|
||||||
|
conn = net.Conn(&_conn)
|
||||||
|
}
|
||||||
|
} else if *s.cfg.ParentType == "kcp" {
|
||||||
|
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
|
||||||
|
} else {
|
||||||
|
conn, err = utils.ConnectHost(address, *s.cfg.Timeout)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if *s.cfg.ParentCompress {
|
||||||
|
conn = utils.NewCompConn(conn)
|
||||||
|
}
|
||||||
|
if *s.cfg.ParentKey != "" {
|
||||||
|
conn = conncrypt.New(conn, &conncrypt.Config{
|
||||||
|
Password: *s.cfg.ParentKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
|
||||||
|
if *s.cfg.ParentAuth != "" {
|
||||||
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
|
if len(a) != 2 {
|
||||||
|
err = fmt.Errorf("parent auth data format error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
|
||||||
|
} else {
|
||||||
|
if !fromSS && !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
|
||||||
|
} else {
|
||||||
|
client = socks.NewClientConn(outconn, network, dstAddr, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = client.Handshake()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) ParentUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.ParentType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.ParentKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.ParentKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) LocalUDPKey() (key []byte) {
|
||||||
|
switch *s.cfg.LocalType {
|
||||||
|
case "tcp":
|
||||||
|
if *s.cfg.LocalKey != "" {
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.LocalKey)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
case "tls":
|
||||||
|
return s.cfg.KeyBytes[:24]
|
||||||
|
case "kcp":
|
||||||
|
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||||
|
return []byte(v)[:24]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@ -10,33 +10,35 @@ import (
|
|||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/jumper"
|
"bitbucket.org/snail/proxy/utils/jumper"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TCPArgs struct {
|
type TCPArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
KeyFile *string
|
KeyFile *string
|
||||||
CertBytes []byte
|
CertBytes []byte
|
||||||
KeyBytes []byte
|
KeyBytes []byte
|
||||||
Local *string
|
Local *string
|
||||||
ParentType *string
|
ParentType *string
|
||||||
LocalType *string
|
LocalType *string
|
||||||
Timeout *int
|
Timeout *int
|
||||||
KCP kcpcfg.KCPConfigArgs
|
CheckParentInterval *int
|
||||||
Jumper *string
|
KCP kcpcfg.KCPConfigArgs
|
||||||
|
Jumper *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCP struct {
|
type TCP struct {
|
||||||
cfg TCPArgs
|
cfg TCPArgs
|
||||||
sc *utils.ServerChannel
|
sc *utils.ServerChannel
|
||||||
isStop bool
|
isStop bool
|
||||||
userConns utils.ConcurrentMap
|
userConns mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
jumper *jumper.Jumper
|
jumper *jumper.Jumper
|
||||||
}
|
}
|
||||||
@ -45,11 +47,11 @@ func NewTCP() services.Service {
|
|||||||
return &TCP{
|
return &TCP{
|
||||||
cfg: TCPArgs{},
|
cfg: TCPArgs{},
|
||||||
isStop: false,
|
isStop: false,
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *TCP) CheckArgs() (err error) {
|
func (s *TCP) CheckArgs() (err error) {
|
||||||
if *s.cfg.Parent == "" {
|
if len(*s.cfg.Parent) == 0 {
|
||||||
err = fmt.Errorf("parent required for %s %s", *s.cfg.LocalType, *s.cfg.Local)
|
err = fmt.Errorf("parent required for %s %s", *s.cfg.LocalType, *s.cfg.Local)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -88,7 +90,7 @@ func (s *TCP) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop tcp service crashed,%s", e)
|
s.log.Printf("stop tcp service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service tcp stopped")
|
s.log.Printf("service tcp stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -111,7 +113,7 @@ func (s *TCP) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
if err = s.InitService(); err != nil {
|
if err = s.InitService(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
s.log.Printf("use %s parent %v", *s.cfg.ParentType, *s.cfg.Parent)
|
||||||
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, s.log)
|
sc := utils.NewServerChannel(host, p, s.log)
|
||||||
@ -141,6 +143,7 @@ func (s *TCP) callback(inConn net.Conn) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var err error
|
var err error
|
||||||
|
lbAddr := ""
|
||||||
switch *s.cfg.ParentType {
|
switch *s.cfg.ParentType {
|
||||||
case "kcp":
|
case "kcp":
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -154,11 +157,12 @@ func (s *TCP) callback(inConn net.Conn) {
|
|||||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, lbAddr, err)
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||||
|
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
outConn, err = s.GetParentConn()
|
outConn, err = s.GetParentConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -9,8 +9,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
@ -37,8 +38,8 @@ type ServerConn struct {
|
|||||||
}
|
}
|
||||||
type TunnelBridge struct {
|
type TunnelBridge struct {
|
||||||
cfg TunnelBridgeArgs
|
cfg TunnelBridgeArgs
|
||||||
serverConns utils.ConcurrentMap
|
serverConns mapx.ConcurrentMap
|
||||||
clientControlConns utils.ConcurrentMap
|
clientControlConns mapx.ConcurrentMap
|
||||||
isStop bool
|
isStop bool
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
@ -46,8 +47,8 @@ type TunnelBridge struct {
|
|||||||
func NewTunnelBridge() services.Service {
|
func NewTunnelBridge() services.Service {
|
||||||
return &TunnelBridge{
|
return &TunnelBridge{
|
||||||
cfg: TunnelBridgeArgs{},
|
cfg: TunnelBridgeArgs{},
|
||||||
serverConns: utils.NewConcurrentMap(),
|
serverConns: mapx.NewConcurrentMap(),
|
||||||
clientControlConns: utils.NewConcurrentMap(),
|
clientControlConns: mapx.NewConcurrentMap(),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +70,7 @@ func (s *TunnelBridge) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop tbridge service crashed,%s", e)
|
s.log.Printf("stop tbridge service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service tbridge stopped")
|
s.log.Printf("service tbridge stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
|
|||||||
@ -9,18 +9,15 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/jumper"
|
"bitbucket.org/snail/proxy/utils/jumper"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
CONN_SERVER_MUX = uint8(6)
|
|
||||||
CONN_CLIENT_MUX = uint8(7)
|
|
||||||
)
|
|
||||||
|
|
||||||
type TunnelClientArgs struct {
|
type TunnelClientArgs struct {
|
||||||
Parent *string
|
Parent *string
|
||||||
CertFile *string
|
CertFile *string
|
||||||
@ -35,7 +32,7 @@ type TunnelClient struct {
|
|||||||
cfg TunnelClientArgs
|
cfg TunnelClientArgs
|
||||||
ctrlConn net.Conn
|
ctrlConn net.Conn
|
||||||
isStop bool
|
isStop bool
|
||||||
userConns utils.ConcurrentMap
|
userConns mapx.ConcurrentMap
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
jumper *jumper.Jumper
|
jumper *jumper.Jumper
|
||||||
}
|
}
|
||||||
@ -43,7 +40,7 @@ type TunnelClient struct {
|
|||||||
func NewTunnelClient() services.Service {
|
func NewTunnelClient() services.Service {
|
||||||
return &TunnelClient{
|
return &TunnelClient{
|
||||||
cfg: TunnelClientArgs{},
|
cfg: TunnelClientArgs{},
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +81,7 @@ func (s *TunnelClient) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop tclient service crashed,%s", e)
|
s.log.Printf("stop tclient service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service tclient stopped")
|
s.log.Printf("service tclient stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
|
|||||||
@ -12,9 +12,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils/jumper"
|
"bitbucket.org/snail/proxy/utils/jumper"
|
||||||
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
|
||||||
//"github.com/xtaci/smux"
|
//"github.com/xtaci/smux"
|
||||||
smux "github.com/hashicorp/yamux"
|
smux "github.com/hashicorp/yamux"
|
||||||
@ -35,11 +36,17 @@ type TunnelServerArgs struct {
|
|||||||
Mgr *TunnelServerManager
|
Mgr *TunnelServerManager
|
||||||
Jumper *string
|
Jumper *string
|
||||||
}
|
}
|
||||||
type UDPItem struct {
|
type TunnelServer struct {
|
||||||
packet *[]byte
|
cfg TunnelServerArgs
|
||||||
localAddr *net.UDPAddr
|
udpChn chan UDPItem
|
||||||
srcAddr *net.UDPAddr
|
sc utils.ServerChannel
|
||||||
|
isStop bool
|
||||||
|
udpConn *net.Conn
|
||||||
|
userConns mapx.ConcurrentMap
|
||||||
|
log *logger.Logger
|
||||||
|
jumper *jumper.Jumper
|
||||||
}
|
}
|
||||||
|
|
||||||
type TunnelServerManager struct {
|
type TunnelServerManager struct {
|
||||||
cfg TunnelServerArgs
|
cfg TunnelServerArgs
|
||||||
udpChn chan UDPItem
|
udpChn chan UDPItem
|
||||||
@ -136,33 +143,28 @@ func (s *TunnelServerManager) InitService() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type TunnelServer struct {
|
|
||||||
cfg TunnelServerArgs
|
|
||||||
udpChn chan UDPItem
|
|
||||||
sc utils.ServerChannel
|
|
||||||
isStop bool
|
|
||||||
udpConn *net.Conn
|
|
||||||
userConns utils.ConcurrentMap
|
|
||||||
log *logger.Logger
|
|
||||||
jumper *jumper.Jumper
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTunnelServer() services.Service {
|
func NewTunnelServer() services.Service {
|
||||||
return &TunnelServer{
|
return &TunnelServer{
|
||||||
cfg: TunnelServerArgs{},
|
cfg: TunnelServerArgs{},
|
||||||
udpChn: make(chan UDPItem, 50000),
|
udpChn: make(chan UDPItem, 50000),
|
||||||
isStop: false,
|
isStop: false,
|
||||||
userConns: utils.NewConcurrentMap(),
|
userConns: mapx.NewConcurrentMap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UDPItem struct {
|
||||||
|
packet *[]byte
|
||||||
|
localAddr *net.UDPAddr
|
||||||
|
srcAddr *net.UDPAddr
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TunnelServer) StopService() {
|
func (s *TunnelServer) StopService() {
|
||||||
defer func() {
|
defer func() {
|
||||||
e := recover()
|
e := recover()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop server service crashed,%s", e)
|
s.log.Printf("stop server service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service server stopped")
|
s.log.Printf("service server stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -214,7 +216,7 @@ func (s *TunnelServer) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
p, _ := strconv.Atoi(port)
|
p, _ := strconv.Atoi(port)
|
||||||
s.sc = utils.NewServerChannel(host, p, s.log)
|
s.sc = utils.NewServerChannel(host, p, s.log)
|
||||||
if *s.cfg.IsUDP {
|
if *s.cfg.IsUDP {
|
||||||
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
err = s.sc.ListenUDP(func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||||
s.udpChn <- UDPItem{
|
s.udpChn <- UDPItem{
|
||||||
packet: &packet,
|
packet: &packet,
|
||||||
localAddr: localAddr,
|
localAddr: localAddr,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package udp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
@ -12,9 +13,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services"
|
"bitbucket.org/snail/proxy/services"
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPArgs struct {
|
type UDPArgs struct {
|
||||||
@ -29,23 +30,21 @@ type UDPArgs struct {
|
|||||||
CheckParentInterval *int
|
CheckParentInterval *int
|
||||||
}
|
}
|
||||||
type UDP struct {
|
type UDP struct {
|
||||||
p utils.ConcurrentMap
|
p mapx.ConcurrentMap
|
||||||
outPool utils.OutConn
|
cfg UDPArgs
|
||||||
cfg UDPArgs
|
sc *utils.ServerChannel
|
||||||
sc *utils.ServerChannel
|
isStop bool
|
||||||
isStop bool
|
log *logger.Logger
|
||||||
log *logger.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUDP() services.Service {
|
func NewUDP() services.Service {
|
||||||
return &UDP{
|
return &UDP{
|
||||||
outPool: utils.OutConn{},
|
p: mapx.NewConcurrentMap(),
|
||||||
p: utils.NewConcurrentMap(),
|
isStop: false,
|
||||||
isStop: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *UDP) CheckArgs() (err error) {
|
func (s *UDP) CheckArgs() (err error) {
|
||||||
if *s.cfg.Parent == "" {
|
if len(*s.cfg.Parent) == 0 {
|
||||||
err = fmt.Errorf("parent required for udp %s", *s.cfg.Local)
|
err = fmt.Errorf("parent required for udp %s", *s.cfg.Local)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,9 +61,7 @@ func (s *UDP) CheckArgs() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *UDP) InitService() (err error) {
|
func (s *UDP) InitService() (err error) {
|
||||||
if *s.cfg.ParentType != "udp" {
|
|
||||||
s.InitOutConnPool()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *UDP) StopService() {
|
func (s *UDP) StopService() {
|
||||||
@ -73,7 +70,7 @@ func (s *UDP) StopService() {
|
|||||||
if e != nil {
|
if e != nil {
|
||||||
s.log.Printf("stop udp service crashed,%s", e)
|
s.log.Printf("stop udp service crashed,%s", e)
|
||||||
} else {
|
} else {
|
||||||
s.log.Printf("service udp stopped")
|
s.log.Printf("service udp stoped")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.isStop = true
|
s.isStop = true
|
||||||
@ -109,7 +106,7 @@ func (s *UDP) Start(args interface{}, log *logger.Logger) (err error) {
|
|||||||
func (s *UDP) Clean() {
|
func (s *UDP) Clean() {
|
||||||
s.StopService()
|
s.StopService()
|
||||||
}
|
}
|
||||||
func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
func (s *UDP) callback(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
s.log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
s.log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||||
@ -134,7 +131,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
|
|||||||
isNew = !s.p.Has(connKey)
|
isNew = !s.p.Has(connKey)
|
||||||
var _conn interface{}
|
var _conn interface{}
|
||||||
if isNew {
|
if isNew {
|
||||||
_conn, err = s.outPool.Get()
|
_conn, err = s.GetParentConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -245,17 +242,15 @@ func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
|
|||||||
//s.log.Printf("send udp response to cluster success ,from:%s", dstAddr.String())
|
//s.log.Printf("send udp response to cluster success ,from:%s", dstAddr.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (s *UDP) InitOutConnPool() {
|
func (s *UDP) GetParentConn() (conn net.Conn, err error) {
|
||||||
if *s.cfg.ParentType == "tls" || *s.cfg.ParentType == "tcp" {
|
if *s.cfg.ParentType == "tls" {
|
||||||
//dur int, isTLS bool, certBytes, keyBytes []byte,
|
var _conn tls.Conn
|
||||||
//parent string, timeout int, InitialCap int, MaxCap int
|
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||||
s.outPool = utils.NewOutConn(
|
if err == nil {
|
||||||
*s.cfg.CheckParentInterval,
|
conn = net.Conn(&_conn)
|
||||||
*s.cfg.ParentType,
|
}
|
||||||
kcpcfg.KCPConfigArgs{},
|
} else {
|
||||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||||
*s.cfg.Parent,
|
|
||||||
*s.cfg.Timeout,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//Confg defaults
|
//Confg defaults
|
||||||
const DefaultIterations = 1024
|
const DefaultIterations = 2048
|
||||||
const DefaultKeySize = 24 //256bits
|
const DefaultKeySize = 32 //256bits
|
||||||
var DefaultHashFunc = sha256.New
|
var DefaultHashFunc = sha256.New
|
||||||
var DefaultSalt = []byte(`
|
var DefaultSalt = []byte(`
|
||||||
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
|
||||||
|
|||||||
@ -3,10 +3,13 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -17,22 +20,30 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
|
"bitbucket.org/snail/proxy/utils/lb"
|
||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
"context"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils/id"
|
"bitbucket.org/snail/proxy/utils/id"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
|
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
|
||||||
|
ioBind(dst, src, fn, log, true)
|
||||||
|
}
|
||||||
|
func IoBindNoClose(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
|
||||||
|
ioBind(dst, src, fn, log, false)
|
||||||
|
}
|
||||||
|
func ioBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger, close bool) {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
@ -68,20 +79,41 @@ func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interfac
|
|||||||
case err = <-e2:
|
case err = <-e2:
|
||||||
//log.Printf("e2")
|
//log.Printf("e2")
|
||||||
}
|
}
|
||||||
src.Close()
|
func() {
|
||||||
dst.Close()
|
defer func() {
|
||||||
|
_ = recover()
|
||||||
|
}()
|
||||||
|
if close {
|
||||||
|
src.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
func() {
|
||||||
|
defer func() {
|
||||||
|
_ = recover()
|
||||||
|
}()
|
||||||
|
if close {
|
||||||
|
dst.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fn(err)
|
fn(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
}
|
||||||
|
}()
|
||||||
buf := LeakyBuffer.Get()
|
buf := LeakyBuffer.Get()
|
||||||
defer LeakyBuffer.Put(buf)
|
defer LeakyBuffer.Put(buf)
|
||||||
n := 0
|
n := 0
|
||||||
for {
|
for {
|
||||||
n, err = src.Read(buf)
|
n, err = src.Read(buf)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
|
if n > len(buf) {
|
||||||
|
n = len(buf)
|
||||||
|
}
|
||||||
if _, e := dst.Write(buf[0:n]); e != nil {
|
if _, e := dst.Write(buf[0:n]); e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@ -122,6 +154,7 @@ func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Con
|
|||||||
caBytes := certBytes
|
caBytes := certBytes
|
||||||
if caCertBytes != nil {
|
if caCertBytes != nil {
|
||||||
caBytes = caCertBytes
|
caBytes = caCertBytes
|
||||||
|
|
||||||
}
|
}
|
||||||
ok := serverCertPool.AppendCertsFromPEM(caBytes)
|
ok := serverCertPool.AppendCertsFromPEM(caBytes)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -212,6 +245,98 @@ func CloseConn(conn *net.Conn) {
|
|||||||
(*conn).Close()
|
(*conn).Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func Keygen() (err error) {
|
||||||
|
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
|
||||||
|
domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"}
|
||||||
|
C := CList[int(RandInt(4))%len(CList)]
|
||||||
|
ST := RandString(int(RandInt(4) % 10))
|
||||||
|
O := RandString(int(RandInt(4) % 10))
|
||||||
|
CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)])
|
||||||
|
//log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
|
||||||
|
var out []byte
|
||||||
|
if len(os.Args) == 3 && os.Args[2] == "ca" {
|
||||||
|
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN)
|
||||||
|
cmd = exec.Command("sh", "-c", cmdStr)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
} else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" {
|
||||||
|
certBytes, _ := ioutil.ReadFile("ca.crt")
|
||||||
|
block, _ := pem.Decode(certBytes)
|
||||||
|
if block == nil || certBytes == nil {
|
||||||
|
panic("failed to parse ca certificate PEM")
|
||||||
|
}
|
||||||
|
x509Cert, _ := x509.ParseCertificate(block.Bytes)
|
||||||
|
if x509Cert == nil {
|
||||||
|
panic("failed to parse block")
|
||||||
|
}
|
||||||
|
name := os.Args[3]
|
||||||
|
days := os.Args[4]
|
||||||
|
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN)
|
||||||
|
fmt.Printf("%s", cmdStr)
|
||||||
|
cmd = exec.Command("sh", "-c", cmdStr)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name)
|
||||||
|
fmt.Printf("%s", cmdStr)
|
||||||
|
cmd = exec.Command("sh", "-c", cmdStr)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
|
} else if len(os.Args) == 3 && os.Args[2] == "usage" {
|
||||||
|
fmt.Println(`proxy keygen //generate proxy.crt and proxy.key
|
||||||
|
proxy keygen ca //generate ca.crt and ca.key
|
||||||
|
proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days
|
||||||
|
`)
|
||||||
|
} else if len(os.Args) == 2 {
|
||||||
|
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
|
||||||
|
cmd = exec.Command("sh", "-c", cmdStr)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("err:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var allInterfaceAddrCache []net.IP
|
var allInterfaceAddrCache []net.IP
|
||||||
|
|
||||||
@ -310,10 +435,10 @@ func ReadUDPPacket(_reader io.Reader) (srcAddr string, packet []byte, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func Uniqueid() string {
|
func Uniqueid() string {
|
||||||
return xid.New().String()
|
str := fmt.Sprintf("%d%s", time.Now().UnixNano(), xid.New().String())
|
||||||
// var src = rand.NewSource(time.Now().UnixNano())
|
hash := sha1.New()
|
||||||
// s := fmt.Sprintf("%d", src.Int63())
|
hash.Write([]byte(str))
|
||||||
// return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
|
return hex.EncodeToString(hash.Sum(nil))
|
||||||
}
|
}
|
||||||
func RandString(strlen int) string {
|
func RandString(strlen int) string {
|
||||||
codes := "QWERTYUIOPLKJHGFDSAZXCVBNMabcdefghijklmnopqrstuvwxyz0123456789"
|
codes := "QWERTYUIOPLKJHGFDSAZXCVBNMabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
@ -338,15 +463,15 @@ func RandInt(strLen int) int64 {
|
|||||||
i, _ := strconv.ParseInt(string(data), 10, 64)
|
i, _ := strconv.ParseInt(string(data), 10, 64)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
func ReadData(r io.Reader) (data string, err error) {
|
func ReadBytes(r io.Reader) (data []byte, err error) {
|
||||||
var len uint16
|
var len uint64
|
||||||
err = binary.Read(r, binary.LittleEndian, &len)
|
err = binary.Read(r, binary.LittleEndian, &len)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var n int
|
var n int
|
||||||
_data := make([]byte, len)
|
data = make([]byte, len)
|
||||||
n, err = r.Read(_data)
|
n, err = r.Read(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -354,9 +479,37 @@ func ReadData(r io.Reader) (data string, err error) {
|
|||||||
err = fmt.Errorf("error data len")
|
err = fmt.Errorf("error data len")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func ReadData(r io.Reader) (data string, err error) {
|
||||||
|
_data, err := ReadBytes(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
data = string(_data)
|
data = string(_data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//non typed packet with Bytes
|
||||||
|
func ReadPacketBytes(r io.Reader, data ...*[]byte) (err error) {
|
||||||
|
for _, d := range data {
|
||||||
|
*d, err = ReadBytes(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func BuildPacketBytes(data ...[]byte) []byte {
|
||||||
|
pkg := new(bytes.Buffer)
|
||||||
|
for _, d := range data {
|
||||||
|
binary.Write(pkg, binary.LittleEndian, uint64(len(d)))
|
||||||
|
binary.Write(pkg, binary.LittleEndian, d)
|
||||||
|
}
|
||||||
|
return pkg.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
//non typed packet with string
|
||||||
func ReadPacketData(r io.Reader, data ...*string) (err error) {
|
func ReadPacketData(r io.Reader, data ...*string) (err error) {
|
||||||
for _, d := range data {
|
for _, d := range data {
|
||||||
*d, err = ReadData(r)
|
*d, err = ReadData(r)
|
||||||
@ -366,13 +519,50 @@ func ReadPacketData(r io.Reader, data ...*string) (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func ReadPacket(r io.Reader, typ *uint8, data ...*string) (err error) {
|
func BuildPacketData(data ...string) []byte {
|
||||||
|
pkg := new(bytes.Buffer)
|
||||||
|
for _, d := range data {
|
||||||
|
bytes := []byte(d)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, uint64(len(bytes)))
|
||||||
|
binary.Write(pkg, binary.LittleEndian, bytes)
|
||||||
|
}
|
||||||
|
return pkg.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
//typed packet with bytes
|
||||||
|
func ReadBytesPacket(r io.Reader, packetType *uint8, data ...*[]byte) (err error) {
|
||||||
var connType uint8
|
var connType uint8
|
||||||
err = binary.Read(r, binary.LittleEndian, &connType)
|
err = binary.Read(r, binary.LittleEndian, &connType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*typ = connType
|
*packetType = connType
|
||||||
|
for _, d := range data {
|
||||||
|
*d, err = ReadBytes(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func BuildBytesPacket(packetType uint8, data ...[]byte) []byte {
|
||||||
|
pkg := new(bytes.Buffer)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, packetType)
|
||||||
|
for _, d := range data {
|
||||||
|
binary.Write(pkg, binary.LittleEndian, uint64(len(d)))
|
||||||
|
binary.Write(pkg, binary.LittleEndian, d)
|
||||||
|
}
|
||||||
|
return pkg.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
//typed packet with string
|
||||||
|
func ReadPacket(r io.Reader, packetType *uint8, data ...*string) (err error) {
|
||||||
|
var connType uint8
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &connType)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*packetType = connType
|
||||||
for _, d := range data {
|
for _, d := range data {
|
||||||
*d, err = ReadData(r)
|
*d, err = ReadData(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -381,18 +571,10 @@ func ReadPacket(r io.Reader, typ *uint8, data ...*string) (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func BuildPacket(typ uint8, data ...string) []byte {
|
|
||||||
pkg := new(bytes.Buffer)
|
func BuildPacket(packetType uint8, data ...string) []byte {
|
||||||
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)
|
pkg := new(bytes.Buffer)
|
||||||
|
binary.Write(pkg, binary.LittleEndian, packetType)
|
||||||
for _, d := range data {
|
for _, d := range data {
|
||||||
bytes := []byte(d)
|
bytes := []byte(d)
|
||||||
binary.Write(pkg, binary.LittleEndian, uint16(len(bytes)))
|
binary.Write(pkg, binary.LittleEndian, uint16(len(bytes)))
|
||||||
@ -400,6 +582,7 @@ func BuildPacketData(data ...string) []byte {
|
|||||||
}
|
}
|
||||||
return pkg.Bytes()
|
return pkg.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubStr(str string, start, end int) string {
|
func SubStr(str string, start, end int) string {
|
||||||
if len(str) == 0 {
|
if len(str) == 0 {
|
||||||
return ""
|
return ""
|
||||||
@ -419,12 +602,21 @@ func SubBytes(bytes []byte, start, end int) []byte {
|
|||||||
return bytes[start:end]
|
return bytes[start:end]
|
||||||
}
|
}
|
||||||
func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) {
|
func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) {
|
||||||
certBytes, err = ioutil.ReadFile(cert)
|
base64Prefix := "base64://"
|
||||||
|
if strings.HasPrefix(cert, base64Prefix) {
|
||||||
|
certBytes, err = base64.StdEncoding.DecodeString(cert[len(base64Prefix):])
|
||||||
|
} else {
|
||||||
|
certBytes, err = ioutil.ReadFile(cert)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("err : %s", err)
|
err = fmt.Errorf("err : %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyBytes, err = ioutil.ReadFile(key)
|
if strings.HasPrefix(key, base64Prefix) {
|
||||||
|
keyBytes, err = base64.StdEncoding.DecodeString(key[len(base64Prefix):])
|
||||||
|
} else {
|
||||||
|
keyBytes, err = ioutil.ReadFile(key)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("err : %s", err)
|
err = fmt.Errorf("err : %s", err)
|
||||||
return
|
return
|
||||||
@ -495,7 +687,7 @@ func HttpGet(URL string, timeout int, host ...string) (body []byte, code int, er
|
|||||||
body, err = ioutil.ReadAll(resp.Body)
|
body, err = ioutil.ReadAll(resp.Body)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func IsIternalIP(domainOrIP string, always bool) bool {
|
func IsInternalIP(domainOrIP string, always bool) bool {
|
||||||
var outIPs []net.IP
|
var outIPs []net.IP
|
||||||
var err error
|
var err error
|
||||||
var isDomain bool
|
var isDomain bool
|
||||||
@ -507,7 +699,7 @@ func IsIternalIP(domainOrIP string, always bool) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isDomain {
|
if isDomain {
|
||||||
outIPs, err = MyLookupIP(domainOrIP)
|
outIPs, err = LookupIP(domainOrIP)
|
||||||
} else {
|
} else {
|
||||||
outIPs = []net.IP{net.ParseIP(domainOrIP)}
|
outIPs = []net.IP{net.ParseIP(domainOrIP)}
|
||||||
}
|
}
|
||||||
@ -515,6 +707,7 @@ func IsIternalIP(domainOrIP string, always bool) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ip := range outIPs {
|
for _, ip := range outIPs {
|
||||||
if ip.IsLoopback() {
|
if ip.IsLoopback() {
|
||||||
return true
|
return true
|
||||||
@ -522,7 +715,7 @@ func IsIternalIP(domainOrIP string, always bool) bool {
|
|||||||
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "10.0.0.0" {
|
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "10.0.0.0" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "192.168.0.0" {
|
if ip.To4().Mask(net.IPv4Mask(255, 255, 0, 0)).String() == "192.168.0.0" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "172.0.0.0" {
|
if ip.To4().Mask(net.IPv4Mask(255, 0, 0, 0)).String() == "172.0.0.0" {
|
||||||
@ -585,6 +778,41 @@ func RemoveProxyHeaders(head []byte) []byte {
|
|||||||
func InsertProxyHeaders(head []byte, headers string) []byte {
|
func InsertProxyHeaders(head []byte, headers string) []byte {
|
||||||
return bytes.Replace(head, []byte("\r\n"), []byte("\r\n"+headers), 1)
|
return bytes.Replace(head, []byte("\r\n"), []byte("\r\n"+headers), 1)
|
||||||
}
|
}
|
||||||
|
func LBMethod(key string) int {
|
||||||
|
typs := map[string]int{"weight": lb.SELECT_WEITHT, "leasttime": lb.SELECT_LEASTTIME, "leastconn": lb.SELECT_LEASTCONN, "hash": lb.SELECT_HASH, "roundrobin": lb.SELECT_ROUNDROBIN}
|
||||||
|
return typs[key]
|
||||||
|
}
|
||||||
|
func UDPCopy(dst, src *net.UDPConn, dstAddr net.Addr, readTimeout time.Duration, beforeWriteFn func(data []byte) []byte, deferFn func(e interface{})) {
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
deferFn(recover())
|
||||||
|
}()
|
||||||
|
buf := LeakyBuffer.Get()
|
||||||
|
defer LeakyBuffer.Put(buf)
|
||||||
|
for {
|
||||||
|
if readTimeout > 0 {
|
||||||
|
src.SetReadDeadline(time.Now().Add(readTimeout))
|
||||||
|
}
|
||||||
|
n, err := src.Read(buf)
|
||||||
|
if readTimeout > 0 {
|
||||||
|
src.SetReadDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if IsNetClosedErr(err) || IsNetTimeoutErr(err) || IsNetRefusedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = dst.WriteTo(beforeWriteFn(buf[:n]), dstAddr)
|
||||||
|
if err != nil {
|
||||||
|
if IsNetClosedErr(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
func IsNetClosedErr(err error) bool {
|
func IsNetClosedErr(err error) bool {
|
||||||
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
|
return err != nil && strings.Contains(err.Error(), "use of closed network connection")
|
||||||
}
|
}
|
||||||
@ -595,16 +823,18 @@ func IsNetTimeoutErr(err error) bool {
|
|||||||
e, ok := err.(net.Error)
|
e, ok := err.(net.Error)
|
||||||
return ok && e.Timeout()
|
return ok && e.Timeout()
|
||||||
}
|
}
|
||||||
func IsNetDeadlineErr(err error) bool {
|
|
||||||
return err != nil && strings.Contains(err.Error(), "i/o deadline reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsNetRefusedErr(err error) bool {
|
func IsNetRefusedErr(err error) bool {
|
||||||
return err != nil && strings.Contains(err.Error(), "connection refused")
|
return err != nil && strings.Contains(err.Error(), "connection refused")
|
||||||
}
|
}
|
||||||
|
func IsNetDeadlineErr(err error) bool {
|
||||||
|
return err != nil && strings.Contains(err.Error(), "i/o deadline reached")
|
||||||
|
}
|
||||||
func IsNetSocketNotConnectedErr(err error) bool {
|
func IsNetSocketNotConnectedErr(err error) bool {
|
||||||
return err != nil && strings.Contains(err.Error(), "socket is not connected")
|
return err != nil && strings.Contains(err.Error(), "socket is not connected")
|
||||||
}
|
}
|
||||||
|
func NewDefaultLogger() *logger.Logger {
|
||||||
|
return logger.New(os.Stderr, "", logger.LstdFlags)
|
||||||
|
}
|
||||||
|
|
||||||
// type sockaddr struct {
|
// type sockaddr struct {
|
||||||
// family uint16
|
// family uint16
|
||||||
@ -667,7 +897,8 @@ func IsNetSocketNotConnectedErr(err error) bool {
|
|||||||
net.LookupIP may cause deadlock in windows
|
net.LookupIP may cause deadlock in windows
|
||||||
https://github.com/golang/go/issues/24178
|
https://github.com/golang/go/issues/24178
|
||||||
*/
|
*/
|
||||||
func MyLookupIP(host string) ([]net.IP, error) {
|
|
||||||
|
func LookupIP(host string) ([]net.IP, error) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(3))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(3))
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@ -1,97 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/time/rate"
|
|
||||||
)
|
|
||||||
|
|
||||||
const burstLimit = 1000 * 1000 * 1000
|
|
||||||
|
|
||||||
type Reader struct {
|
|
||||||
r io.Reader
|
|
||||||
limiter *rate.Limiter
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
type Writer struct {
|
|
||||||
w io.Writer
|
|
||||||
limiter *rate.Limiter
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader returns a reader that implements io.Reader with rate limiting.
|
|
||||||
func NewReader(r io.Reader) *Reader {
|
|
||||||
return &Reader{
|
|
||||||
r: r,
|
|
||||||
ctx: context.Background(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReaderWithContext returns a reader that implements io.Reader with rate limiting.
|
|
||||||
func NewReaderWithContext(r io.Reader, ctx context.Context) *Reader {
|
|
||||||
return &Reader{
|
|
||||||
r: r,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriter returns a writer that implements io.Writer with rate limiting.
|
|
||||||
func NewWriter(w io.Writer) *Writer {
|
|
||||||
return &Writer{
|
|
||||||
w: w,
|
|
||||||
ctx: context.Background(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWriterWithContext returns a writer that implements io.Writer with rate limiting.
|
|
||||||
func NewWriterWithContext(w io.Writer, ctx context.Context) *Writer {
|
|
||||||
return &Writer{
|
|
||||||
w: w,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRateLimit sets rate limit (bytes/sec) to the reader.
|
|
||||||
func (s *Reader) SetRateLimit(bytesPerSec float64) {
|
|
||||||
s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
|
|
||||||
s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read reads bytes into p.
|
|
||||||
func (s *Reader) Read(p []byte) (int, error) {
|
|
||||||
if s.limiter == nil {
|
|
||||||
return s.r.Read(p)
|
|
||||||
}
|
|
||||||
n, err := s.r.Read(p)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
if err := s.limiter.WaitN(s.ctx, n); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRateLimit sets rate limit (bytes/sec) to the writer.
|
|
||||||
func (s *Writer) SetRateLimit(bytesPerSec float64) {
|
|
||||||
s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
|
|
||||||
s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes bytes from p.
|
|
||||||
func (s *Writer) Write(p []byte) (int, error) {
|
|
||||||
if s.limiter == nil {
|
|
||||||
return s.w.Write(p)
|
|
||||||
}
|
|
||||||
n, err := s.w.Write(p)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
if err := s.limiter.WaitN(s.ctx, n); err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
@ -10,7 +10,7 @@ import (
|
|||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/services/kcpcfg"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/xtaci/kcp-go"
|
||||||
)
|
)
|
||||||
@ -139,7 +139,7 @@ func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
|
func (sc *ServerChannel) ListenUDP(fn func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
|
||||||
addr := &net.UDPAddr{IP: net.ParseIP(sc.ip), Port: sc.port}
|
addr := &net.UDPAddr{IP: net.ParseIP(sc.ip), Port: sc.port}
|
||||||
l, err := net.ListenUDP("udp", addr)
|
l, err := net.ListenUDP("udp", addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -161,7 +161,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
|||||||
sc.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
sc.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fn(packet, addr, srcAddr)
|
fn(l, packet, addr, srcAddr)
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
sc.errAcceptHandler(err)
|
sc.errAcceptHandler(err)
|
||||||
@ -172,6 +172,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
|
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
|
||||||
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
|
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@ -54,7 +54,7 @@ func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration
|
|||||||
s.header = header
|
s.header = header
|
||||||
}
|
}
|
||||||
if network == "udp" && target == "" {
|
if network == "udp" && target == "" {
|
||||||
target = "0.0.0.0:1"
|
target = "0.0.0.0:0"
|
||||||
}
|
}
|
||||||
s.addr = target
|
s.addr = target
|
||||||
return s
|
return s
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/utils"
|
"bitbucket.org/snail/proxy/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -98,6 +98,12 @@ func (s *ServerConn) Method() uint8 {
|
|||||||
func (s *ServerConn) Target() string {
|
func (s *ServerConn) Target() string {
|
||||||
return s.target
|
return s.target
|
||||||
}
|
}
|
||||||
|
func (s *ServerConn) Host() string {
|
||||||
|
return s.dstHost
|
||||||
|
}
|
||||||
|
func (s *ServerConn) Port() string {
|
||||||
|
return s.dstPort
|
||||||
|
}
|
||||||
func (s *ServerConn) Handshake() (err error) {
|
func (s *ServerConn) Handshake() (err error) {
|
||||||
remoteAddr := (*s.conn).RemoteAddr()
|
remoteAddr := (*s.conn).RemoteAddr()
|
||||||
//协商开始
|
//协商开始
|
||||||
|
|||||||
@ -281,6 +281,9 @@ func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (p *PacketUDP) Parse(b []byte) (err error) {
|
func (p *PacketUDP) Parse(b []byte) (err error) {
|
||||||
|
if len(b) < 9 {
|
||||||
|
return fmt.Errorf("too short packet")
|
||||||
|
}
|
||||||
p.frag = uint8(b[2])
|
p.frag = uint8(b[2])
|
||||||
if p.frag != 0 {
|
if p.frag != 0 {
|
||||||
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
||||||
@ -290,13 +293,22 @@ func (p *PacketUDP) Parse(b []byte) (err error) {
|
|||||||
p.atype = b[3]
|
p.atype = b[3]
|
||||||
switch p.atype {
|
switch p.atype {
|
||||||
case ATYP_IPV4: //IP V4
|
case ATYP_IPV4: //IP V4
|
||||||
|
if len(b) < 11 {
|
||||||
|
return fmt.Errorf("too short packet")
|
||||||
|
}
|
||||||
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||||
portIndex = 8
|
portIndex = 8
|
||||||
case ATYP_DOMAIN: //域名
|
case ATYP_DOMAIN: //域名
|
||||||
domainLen := uint8(b[4])
|
domainLen := uint8(b[4])
|
||||||
|
if len(b) < int(domainLen)+7 {
|
||||||
|
return fmt.Errorf("too short packet")
|
||||||
|
}
|
||||||
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
||||||
portIndex = int(5 + domainLen)
|
portIndex = int(5 + domainLen)
|
||||||
case ATYP_IPV6: //IP V6
|
case ATYP_IPV6: //IP V6
|
||||||
|
if len(b) < 22 {
|
||||||
|
return fmt.Errorf("too short packet")
|
||||||
|
}
|
||||||
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()
|
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
|
portIndex = 20
|
||||||
}
|
}
|
||||||
@ -333,7 +345,9 @@ func (p *PacketUDP) Bytes() []byte {
|
|||||||
func (p *PacketUDP) Host() string {
|
func (p *PacketUDP) Host() string {
|
||||||
return p.dstHost
|
return p.dstHost
|
||||||
}
|
}
|
||||||
|
func (p *PacketUDP) Addr() string {
|
||||||
|
return net.JoinHostPort(p.dstHost, p.dstPort)
|
||||||
|
}
|
||||||
func (p *PacketUDP) Port() string {
|
func (p *PacketUDP) Port() string {
|
||||||
return p.dstPort
|
return p.dstPort
|
||||||
}
|
}
|
||||||
|
|||||||
184
utils/structs.go
184
utils/structs.go
@ -3,7 +3,6 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -16,17 +15,17 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/snail007/goproxy/services/kcpcfg"
|
"bitbucket.org/snail/proxy/utils/dnsx"
|
||||||
"github.com/snail007/goproxy/utils/sni"
|
"bitbucket.org/snail/proxy/utils/mapx"
|
||||||
|
"bitbucket.org/snail/proxy/utils/sni"
|
||||||
|
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Checker struct {
|
type Checker struct {
|
||||||
data ConcurrentMap
|
data mapx.ConcurrentMap
|
||||||
blockedMap ConcurrentMap
|
blockedMap mapx.ConcurrentMap
|
||||||
directMap ConcurrentMap
|
directMap mapx.ConcurrentMap
|
||||||
interval int64
|
interval int64
|
||||||
timeout int
|
timeout int
|
||||||
isStop bool
|
isStop bool
|
||||||
@ -45,7 +44,7 @@ type CheckerItem struct {
|
|||||||
//interval: recheck domain interval seconds
|
//interval: recheck domain interval seconds
|
||||||
func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger) Checker {
|
func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger) Checker {
|
||||||
ch := Checker{
|
ch := Checker{
|
||||||
data: NewConcurrentMap(),
|
data: mapx.NewConcurrentMap(),
|
||||||
interval: interval,
|
interval: interval,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
isStop: false,
|
isStop: false,
|
||||||
@ -66,8 +65,8 @@ func NewChecker(timeout int, interval int64, blockedFile, directFile string, log
|
|||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
|
func (c *Checker) loadMap(f string) (dataMap mapx.ConcurrentMap) {
|
||||||
dataMap = NewConcurrentMap()
|
dataMap = mapx.NewConcurrentMap()
|
||||||
if PathExists(f) {
|
if PathExists(f) {
|
||||||
_contents, err := ioutil.ReadFile(f)
|
_contents, err := ioutil.ReadFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -198,18 +197,18 @@ func (c *Checker) Add(domain, address string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BasicAuth struct {
|
type BasicAuth struct {
|
||||||
data ConcurrentMap
|
data mapx.ConcurrentMap
|
||||||
authURL string
|
authURL string
|
||||||
authOkCode int
|
authOkCode int
|
||||||
authTimeout int
|
authTimeout int
|
||||||
authRetry int
|
authRetry int
|
||||||
dns *DomainResolver
|
dns *dnsx.DomainResolver
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBasicAuth(dns *DomainResolver, log *logger.Logger) BasicAuth {
|
func NewBasicAuth(dns *dnsx.DomainResolver, log *logger.Logger) BasicAuth {
|
||||||
return BasicAuth{
|
return BasicAuth{
|
||||||
data: NewConcurrentMap(),
|
data: mapx.NewConcurrentMap(),
|
||||||
dns: dns,
|
dns: dns,
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
@ -528,53 +527,15 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutConn struct {
|
|
||||||
dur int
|
|
||||||
typ string
|
|
||||||
certBytes []byte
|
|
||||||
keyBytes []byte
|
|
||||||
caCertBytes []byte
|
|
||||||
kcp kcpcfg.KCPConfigArgs
|
|
||||||
address string
|
|
||||||
timeout int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int) (op OutConn) {
|
|
||||||
return OutConn{
|
|
||||||
dur: dur,
|
|
||||||
typ: typ,
|
|
||||||
certBytes: certBytes,
|
|
||||||
keyBytes: keyBytes,
|
|
||||||
caCertBytes: caCertBytes,
|
|
||||||
kcp: kcp,
|
|
||||||
address: address,
|
|
||||||
timeout: timeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (op *OutConn) Get() (conn net.Conn, err error) {
|
|
||||||
if op.typ == "tls" {
|
|
||||||
var _conn tls.Conn
|
|
||||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes, op.caCertBytes)
|
|
||||||
if err == nil {
|
|
||||||
conn = net.Conn(&_conn)
|
|
||||||
}
|
|
||||||
} else if op.typ == "kcp" {
|
|
||||||
conn, err = ConnectKCPHost(op.address, op.kcp)
|
|
||||||
} else {
|
|
||||||
conn, err = ConnectHost(op.address, op.timeout)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnManager struct {
|
type ConnManager struct {
|
||||||
pool ConcurrentMap
|
pool mapx.ConcurrentMap
|
||||||
l *sync.Mutex
|
l *sync.Mutex
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnManager(log *logger.Logger) ConnManager {
|
func NewConnManager(log *logger.Logger) ConnManager {
|
||||||
cm := ConnManager{
|
cm := ConnManager{
|
||||||
pool: NewConcurrentMap(),
|
pool: mapx.NewConcurrentMap(),
|
||||||
l: &sync.Mutex{},
|
l: &sync.Mutex{},
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
@ -582,11 +543,11 @@ func NewConnManager(log *logger.Logger) ConnManager {
|
|||||||
}
|
}
|
||||||
func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
|
func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
|
||||||
cm.pool.Upsert(key, nil, func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
|
cm.pool.Upsert(key, nil, func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
|
||||||
var conns ConcurrentMap
|
var conns mapx.ConcurrentMap
|
||||||
if !exist {
|
if !exist {
|
||||||
conns = NewConcurrentMap()
|
conns = mapx.NewConcurrentMap()
|
||||||
} else {
|
} else {
|
||||||
conns = valueInMap.(ConcurrentMap)
|
conns = valueInMap.(mapx.ConcurrentMap)
|
||||||
}
|
}
|
||||||
if conns.Has(ID) {
|
if conns.Has(ID) {
|
||||||
v, _ := conns.Get(ID)
|
v, _ := conns.Get(ID)
|
||||||
@ -598,9 +559,9 @@ func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
func (cm *ConnManager) Remove(key string) {
|
func (cm *ConnManager) Remove(key string) {
|
||||||
var conns ConcurrentMap
|
var conns mapx.ConcurrentMap
|
||||||
if v, ok := cm.pool.Get(key); ok {
|
if v, ok := cm.pool.Get(key); ok {
|
||||||
conns = v.(ConcurrentMap)
|
conns = v.(mapx.ConcurrentMap)
|
||||||
conns.IterCb(func(key string, v interface{}) {
|
conns.IterCb(func(key string, v interface{}) {
|
||||||
CloseConn(v.(*net.Conn))
|
CloseConn(v.(*net.Conn))
|
||||||
})
|
})
|
||||||
@ -611,9 +572,9 @@ func (cm *ConnManager) Remove(key string) {
|
|||||||
func (cm *ConnManager) RemoveOne(key string, ID string) {
|
func (cm *ConnManager) RemoveOne(key string, ID string) {
|
||||||
defer cm.l.Unlock()
|
defer cm.l.Unlock()
|
||||||
cm.l.Lock()
|
cm.l.Lock()
|
||||||
var conns ConcurrentMap
|
var conns mapx.ConcurrentMap
|
||||||
if v, ok := cm.pool.Get(key); ok {
|
if v, ok := cm.pool.Get(key); ok {
|
||||||
conns = v.(ConcurrentMap)
|
conns = v.(mapx.ConcurrentMap)
|
||||||
if conns.Has(ID) {
|
if conns.Has(ID) {
|
||||||
v, _ := conns.Get(ID)
|
v, _ := conns.Get(ID)
|
||||||
(*v.(*net.Conn)).Close()
|
(*v.(*net.Conn)).Close()
|
||||||
@ -631,11 +592,11 @@ func (cm *ConnManager) RemoveAll() {
|
|||||||
|
|
||||||
type ClientKeyRouter struct {
|
type ClientKeyRouter struct {
|
||||||
keyChan chan string
|
keyChan chan string
|
||||||
ctrl *ConcurrentMap
|
ctrl *mapx.ConcurrentMap
|
||||||
lock *sync.Mutex
|
lock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientKeyRouter(ctrl *ConcurrentMap, size int) ClientKeyRouter {
|
func NewClientKeyRouter(ctrl *mapx.ConcurrentMap, size int) ClientKeyRouter {
|
||||||
return ClientKeyRouter{
|
return ClientKeyRouter{
|
||||||
keyChan: make(chan string, size),
|
keyChan: make(chan string, size),
|
||||||
ctrl: ctrl,
|
ctrl: ctrl,
|
||||||
@ -671,103 +632,6 @@ func (c *ClientKeyRouter) GetKey() string {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DomainResolver struct {
|
|
||||||
ttl int
|
|
||||||
dnsAddrress string
|
|
||||||
data ConcurrentMap
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
type DomainResolverItem struct {
|
|
||||||
ip string
|
|
||||||
domain string
|
|
||||||
expiredAt int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDomainResolver(dnsAddrress string, ttl int, log *logger.Logger) DomainResolver {
|
|
||||||
return DomainResolver{
|
|
||||||
ttl: ttl,
|
|
||||||
dnsAddrress: dnsAddrress,
|
|
||||||
data: NewConcurrentMap(),
|
|
||||||
log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (a *DomainResolver) MustResolve(address string) (ip string) {
|
|
||||||
ip, _ = a.Resolve(address)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (a *DomainResolver) Resolve(address string) (ip string, err error) {
|
|
||||||
domain := address
|
|
||||||
port := ""
|
|
||||||
fromCache := "false"
|
|
||||||
defer func() {
|
|
||||||
if port != "" {
|
|
||||||
ip = net.JoinHostPort(ip, port)
|
|
||||||
}
|
|
||||||
a.log.Printf("dns:%s->%s,cache:%s", address, ip, fromCache)
|
|
||||||
//a.PrintData()
|
|
||||||
}()
|
|
||||||
if strings.Contains(domain, ":") {
|
|
||||||
domain, port, err = net.SplitHostPort(domain)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if net.ParseIP(domain) != nil {
|
|
||||||
ip = domain
|
|
||||||
fromCache = "ip ignore"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
item, ok := a.data.Get(domain)
|
|
||||||
if ok {
|
|
||||||
//log.Println("find ", domain)
|
|
||||||
if (*item.(*DomainResolverItem)).expiredAt > time.Now().Unix() {
|
|
||||||
ip = (*item.(*DomainResolverItem)).ip
|
|
||||||
fromCache = "true"
|
|
||||||
//log.Println("from cache ", domain)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item = &DomainResolverItem{
|
|
||||||
domain: domain,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
c := new(dns.Client)
|
|
||||||
c.DialTimeout = time.Millisecond * 5000
|
|
||||||
c.ReadTimeout = time.Millisecond * 5000
|
|
||||||
c.WriteTimeout = time.Millisecond * 5000
|
|
||||||
m := new(dns.Msg)
|
|
||||||
m.SetQuestion(dns.Fqdn(domain), dns.TypeA)
|
|
||||||
m.RecursionDesired = true
|
|
||||||
r, _, err := c.Exchange(m, a.dnsAddrress)
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.Rcode != dns.RcodeSuccess {
|
|
||||||
err = fmt.Errorf(" *** invalid answer name %s after A query for %s", domain, a.dnsAddrress)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, answer := range r.Answer {
|
|
||||||
if answer.Header().Rrtype == dns.TypeA {
|
|
||||||
info := strings.Fields(answer.String())
|
|
||||||
if len(info) >= 5 {
|
|
||||||
ip = info[4]
|
|
||||||
_item := item.(*DomainResolverItem)
|
|
||||||
(*_item).expiredAt = time.Now().Unix() + int64(a.ttl)
|
|
||||||
(*_item).ip = ip
|
|
||||||
a.data.Set(domain, item)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (a *DomainResolver) PrintData() {
|
|
||||||
for k, item := range a.data.Items() {
|
|
||||||
d := item.(*DomainResolverItem)
|
|
||||||
a.log.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func NewCompStream(conn net.Conn) *CompStream {
|
func NewCompStream(conn net.Conn) *CompStream {
|
||||||
c := new(CompStream)
|
c := new(CompStream)
|
||||||
c.conn = conn
|
c.conn = conn
|
||||||
|
|||||||
Reference in New Issue
Block a user