Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7df2d990e7 | ||
|
|
900b75ddcd | ||
|
|
a5d199fb1c | ||
|
|
2d8190873f | ||
|
|
3eff793ac2 | ||
|
|
27ce6e1bd2 | ||
|
|
b11c7e632b | ||
|
|
d911be7d80 | ||
|
|
bd056d74cc | ||
|
|
69b65a37ca | ||
|
|
dd52ad8a8a | ||
|
|
59b5ef2df4 | ||
|
|
4a34566f08 | ||
|
|
d81d5ffe06 | ||
|
|
59c9148875 | ||
|
|
40bce3e736 | ||
|
|
d4c0775b4a | ||
|
|
7f983152b7 | ||
|
|
bab4325414 | ||
|
|
0d85c7dd7d | ||
|
|
f756d62b19 | ||
|
|
2d1c1449aa | ||
|
|
f348298acd | ||
|
|
ad47104fc7 | ||
|
|
4d4fb64b59 | ||
|
|
9ce3a6e468 | ||
|
|
34e9e362b9 | ||
|
|
f87cbf73e8 | ||
|
|
362ada2ebb | ||
|
|
b4b7221dab | ||
|
|
2d8dc56f4e | ||
|
|
1cf4313d12 | ||
|
|
7bb8f19b90 |
12
CHANGELOG
12
CHANGELOG
@ -1,4 +1,16 @@
|
||||
proxy更新日志
|
||||
v4.6
|
||||
1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定.
|
||||
2.sps增加了强大的树形级联认证支持,可以轻松构建你的认证代理网络.
|
||||
3.手册增加了6.6对sps认证功能的介绍.
|
||||
|
||||
|
||||
v4.5
|
||||
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
||||
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
||||
3.keygen参数增加了用法: proxy keygen usage.
|
||||
4.http(s)/socks5代理,tls增加了自签名证书支持.
|
||||
5.建议升级.
|
||||
v4.4
|
||||
1.增加了协议转换sps功能,代理协议转换使用的是sps子命令(socks+https的缩写),
|
||||
sps本身不提供代理功能,只是接受代理请求"转换并转发"给已经存在的http(s)代理
|
||||
|
||||
71
README.md
71
README.md
@ -22,7 +22,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
||||
- The integrated external API, HTTP (S): SOCKS5 proxy authentication can be integrated with the external HTTP API, which can easily control the user's access through the external system.
|
||||
- Reverse proxy: goproxy supports directly parsing the domain to proxy monitor IP, and then proxy will help you to access the HTTP (S) site that you need to access.
|
||||
- Transparent proxy: with the iptables, goproxy can directly forward the 80 and 443 port's traffic to proxy in the gateway, and can realize the unaware intelligent router proxy.
|
||||
- Protocol conversion: The existing HTTP (S) or SOCKS5 proxy can be converted to a proxy which support both HTTP (S) and SOCKS5 by one port, but the converted SOCKS5 proxy does not support the UDP function.
|
||||
- Protocol conversion: The existing HTTP (S) or SOCKS5 proxy can be converted to a proxy which support both HTTP (S) and SOCKS5 by one port, but the converted SOCKS5 proxy does not support the UDP function.Also support powerful cascading authentication.
|
||||
|
||||
### Why need these?
|
||||
- Because for some reason, we cannot access our services elsewhere. We can build a secure tunnel to access our services through multiple connected proxy nodes.
|
||||
@ -34,7 +34,9 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
||||
- ...
|
||||
|
||||
|
||||
This page is the v4.4 manual, and the other version of the manual can be checked by the following link.
|
||||
This page is the v4.6 manual, and the other version of the manual can be checked by the following link.
|
||||
- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
|
||||
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
|
||||
- [v4.3 manual](https://github.com/snail007/goproxy/tree/v4.3)
|
||||
- [v4.2 manual](https://github.com/snail007/goproxy/tree/v4.2)
|
||||
- [v4.0-4.1 manual](https://github.com/snail007/goproxy/tree/v4.1)
|
||||
@ -126,7 +128,8 @@ This page is the v4.4 manual, and the other version of the manual can be checked
|
||||
- [6.3 SOCKS5 to HTTP(S) + SOCKS5](#63socks5-to-http-socks5)
|
||||
- [6.4 Chain style connection](#64chain-style-connection)
|
||||
- [6.5 Listening on multiple ports](#65listening-on-multiple-ports)
|
||||
- [6.6 View Help](#56transfer-through-ssh)
|
||||
- [6.6 Authentication](#66authentication)
|
||||
- [6.7 View Help](#67view-help)
|
||||
- [7.KCP Configuration](#7kcp-configuration)
|
||||
- [7.1 Configuration introduction](#71configuration-introduction)
|
||||
- [7.2 Configuration details](#72configuration-details)
|
||||
@ -148,7 +151,7 @@ If the installation fails or your VPS is not a linux64 system, please follow the
|
||||
Download address: https://github.com/snail007/goproxy/releases
|
||||
```shell
|
||||
cd /root/proxy/
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.4/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||
```
|
||||
#### **2.Download the automatic installation script**
|
||||
```shell
|
||||
@ -281,13 +284,13 @@ Local HTTP (S) proxy use 28080 port,excute:
|
||||
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||
|
||||
#### **1.8.KCP protocol transmission**
|
||||
The KCP protocol requires a -B parameter to set a password which can encrypt and decrypt data.
|
||||
The KCP protocol requires a --kcp-key parameter to set a password which can encrypt and decrypt data.
|
||||
|
||||
Http first level proxy(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy http -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
Http second level proxy(os is Linux)
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
Then access to the local 8080 port is access to the proxy's port 38080 on the VPS, and the data is transmitted through the KCP protocol.
|
||||
#### **1.9.HTTP reverse proxy**
|
||||
Proxy supports not only set up a proxy through in other software, to provide services for other software, but support the request directly to the website domain to proxy monitor IP when proxy monitors 80 and 443 ports, then proxy will automatically access to the HTTP proxy access website for you.
|
||||
@ -657,13 +660,13 @@ ip: user's IP, for example: 192.168.1.200
|
||||
If there is no -a or -F or --auth-url parameters, it means to turn off the authentication.
|
||||
|
||||
#### **5.8.KCP protocol transmission**
|
||||
The KCP protocol requires a -B parameter which can set a password to encrypt and decrypt data.
|
||||
The KCP protocol requires a --kcp-key parameter which can set a password to encrypt and decrypt data.
|
||||
|
||||
HTTP first level proxy(VPS,IP:22.22.22.22)
|
||||
`./proxy socks -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy socks -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
HTTP two level proxy(local os is Linux)
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
Then access to the local 8080 port is access to the proxy port 38080 on the VPS, and the data is transmitted through the KCP protocol.
|
||||
|
||||
#### **5.9.Custom DNS**
|
||||
@ -692,7 +695,7 @@ command:
|
||||
|
||||
Suppose there is a KCP HTTP (s) proxy (password: demo123): 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080.
|
||||
command:
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.3.SOCKS5 to HTTP(S) + SOCKS5**
|
||||
Suppose there is a common Socks5 proxy: 127.0.0.1:8080, now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
|
||||
@ -705,7 +708,7 @@ command:
|
||||
|
||||
Suppose there is a KCP Socks5 proxy (password: demo123): 127.0.0.1:8080, now we turn it into a common proxy that support HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
|
||||
command:
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.4.Chain style connection**
|
||||
It is mentioned above that multiple SPS nodes can be connected to build encrypted channels, assuming you have the following VPS and a PC.
|
||||
@ -730,7 +733,49 @@ finish。
|
||||
In general, listening one port is enough, but if you need to monitor 80 and 443 ports at the same time as a reverse proxy, the -p parameter can support it.
|
||||
The format is:`-p 0.0.0.0:80,0.0.0.0:443`, Multiple bindings are separated by a comma.
|
||||
|
||||
#### **6.6.view help**
|
||||
#### **6.6.Authentication**
|
||||
SPS supports HTTP(s)\socks5 proxy authentication, which can concatenate authentication, there are four important information:
|
||||
1:Users send authentication information`user-auth`。
|
||||
2:Local authentication information set up`local-auth`。
|
||||
3:Set the authentication information accessing to the father proxy`parent-auth`。
|
||||
4:The final authentication information sent to the father proxy`auth-info-to-parent`。
|
||||
The relationship between them is as follows:
|
||||
|
||||
| user-auth | local-auth | parent-auth | auth-info-to-paren
|
||||
| ------ | ------ | ------ | ------
|
||||
| yes/no | yes | yes | come from parent-auth
|
||||
| yes/no | no | yes | come from parent-auth
|
||||
| yes/no | yes | no | no
|
||||
| no | no | no | no
|
||||
| yes | no | no | come from user-auth
|
||||
|
||||
For SPS proxy we can have username and password to authenticate, and the authentication username and password can be specified on the command line
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
if there are multiple users, repeat the -a parameters.
|
||||
It can also be placed in a file, which is a line to a username: password, and then specified in -F parameter.
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||
|
||||
If the father proxy is authenticated, the lower level can set the authentication information through the -A parameters, such as:
|
||||
father proxy:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
local proxy:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||
|
||||
In addition, SPS proxy, local authentication is integrated with external HTTP API authentication, and we can specify a HTTP URL interface address through the --auth-url parameter,
|
||||
Then, when there is a user connection, proxy will request this URL by GET way, with the following four parameters, and if the HTTP state code 204 is returned, the authentication is successful.
|
||||
Other cases consider authentication failure.
|
||||
for example:
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
When the user is connected, proxy will request this URL by GET way("http://test.com/auth.php"),
|
||||
Four parameters with user, pass, IP, and target:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||
user:username
|
||||
pass:password
|
||||
ip:user's ip,for example:192.168.1.200
|
||||
target: if the client is the HTTP (s) proxy request, this represents the complete URL of the request, and the other cases are empty.
|
||||
|
||||
If there is no -a or -F or --auth-url parameters, local authentication is closed.
|
||||
If there is no -A parameter, the connection to the father proxy does not use authentication.
|
||||
|
||||
#### **6.7.view help**
|
||||
`./proxy help sps`
|
||||
|
||||
### **7.KCP Configuration**
|
||||
|
||||
88
README_ZH.md
88
README_ZH.md
@ -23,7 +23,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- 集成外部API,HTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成,可以方便的通过外部系统控制代理用户.
|
||||
- 反向代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.
|
||||
- 透明HTTP(S)代理,配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理.
|
||||
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能。
|
||||
- 协议转换,可以把已经存在的HTTP(S)或SOCKS5代理转换为一个端口同时支持HTTP(S)和SOCKS5代理,转换后的SOCKS5代理不支持UDP功能,同时支持强大的级联认证功能。
|
||||
|
||||
### Why need these?
|
||||
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
|
||||
@ -35,7 +35,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- ...
|
||||
|
||||
|
||||
本页是v4.4手册,其他版本手册请点击下面链接查看.
|
||||
本页是v4.6手册,其他版本手册请点击下面链接查看.
|
||||
- [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5)
|
||||
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4)
|
||||
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3)
|
||||
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
|
||||
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1)
|
||||
@ -125,7 +127,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
||||
- [6.4 链式连接](#64-链式连接)
|
||||
- [6.5 监听多个端口](#65-监听多个端口)
|
||||
- [6.6 查看帮助](#66-查看帮助)
|
||||
- [6.6 认证功能](#66-认证功能)
|
||||
- [6.7 查看帮助](#67-查看帮助)
|
||||
- [7. KCP配置](#7kcp配置)
|
||||
- [7.1 配置介绍](#71-配置介绍)
|
||||
- [7.2 详细配置](#72-详细配置)
|
||||
@ -146,7 +149,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
|
||||
下载地址:https://github.com/snail007/goproxy/releases
|
||||
```shell
|
||||
cd /root/proxy/
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.4/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||
```
|
||||
#### **2.下载自动安装脚本**
|
||||
```shell
|
||||
@ -187,7 +190,8 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
|
||||
在linux上并安装了openssl命令,可以直接通过下面的命令生成证书和key文件.
|
||||
`./proxy keygen`
|
||||
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
|
||||
|
||||
更多用法:`proxy keygen usage`。
|
||||
|
||||
### **后台运行**
|
||||
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
|
||||
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
|
||||
@ -281,13 +285,13 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
|
||||
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
|
||||
|
||||
#### **1.8.KCP协议传输**
|
||||
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
|
||||
|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy http -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
二级HTTP代理(本地Linux)
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||
|
||||
#### **1.9 HTTP(S)反向代理**
|
||||
@ -386,16 +390,16 @@ VPS(IP:22.22.22.33)执行:
|
||||
|
||||
#### **2.4.加密二级TCP代理**
|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -t tcp -p ":33080" -T tcp -P "127.0.0.1:8080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":33080" -T tcp -P "127.0.0.1:8080" -C proxy.crt -K proxy.key`
|
||||
本地执行:
|
||||
`./proxy tcp -p ":23080" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地23080端口就是通过加密TCP隧道访问22.22.22.33的8080端口.
|
||||
|
||||
#### **2.5.加密三级TCP代理**
|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -t tcp -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
`./proxy tcp -t tcp -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
三级TCP代理(本地)
|
||||
`./proxy tcp -p ":8080" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
|
||||
@ -428,16 +432,16 @@ VPS(IP:22.22.22.33)执行:
|
||||
|
||||
#### **3.4.加密二级UDP代理**
|
||||
VPS(IP:22.22.22.33)执行:
|
||||
`./proxy tcp -t tcp -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
本地执行:
|
||||
`./proxy udp -p ":5353" -T tls -P "22.22.22.33:33080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地UDP:5353端口就是通过加密TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
|
||||
|
||||
#### **3.5.加密三级UDP代理**
|
||||
一级TCP代理VPS_01,IP:22.22.22.22
|
||||
`./proxy tcp -t tcp -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
|
||||
二级TCP代理VPS_02,IP:33.33.33.33
|
||||
`./proxy tcp -t tcp -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
`./proxy tcp -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
|
||||
三级TCP代理(本地)
|
||||
`./proxy udp -p ":5353" -T tls -P "33.33.33.33:28080" -C proxy.crt -K proxy.key`
|
||||
那么访问本地5353端口就是通过加密TCP隧道,通过VPS_01访问8.8.8.8的53端口.
|
||||
@ -596,7 +600,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
||||

|
||||
使用本地端口8090,假设上级SOCKS5代理是`22.22.22.22:8080`
|
||||
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理;如果域名即在黑名单又在白名单中,那么黑名单起作用.
|
||||
`./proxy socks -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
|
||||
|
||||
#### **5.3.SOCKS二级代理(加密)**
|
||||
@ -661,13 +665,13 @@ ip:用户的IP,比如:192.168.1.200
|
||||
如果没有-a或-F或--auth-url参数,就是关闭认证.
|
||||
|
||||
#### **5.8.KCP协议传输**
|
||||
KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
|
||||
|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy socks -t kcp -p ":38080" -B mypassword`
|
||||
`./proxy socks -t kcp -p ":38080" --kcp-key mypassword`
|
||||
|
||||
二级HTTP代理(本地Linux)
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
|
||||
`./proxy socks -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
|
||||
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
|
||||
|
||||
#### **5.9.自定义DNS**
|
||||
@ -695,7 +699,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
|
||||
假设已经存在一个kcp的http(s)代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
命令如下:
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.3 SOCKS5转HTTP(S)+SOCKS5**
|
||||
假设已经存在一个普通的socks5代理:127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
@ -708,7 +712,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
|
||||
|
||||
假设已经存在一个kcp的socks5代理(密码是:demo123):127.0.0.1:8080,现在我们把它转为同时支持http(s)和socks5的普通代理,转换后的本地端口为18080。
|
||||
命令如下:
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 -B demo123`
|
||||
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
|
||||
|
||||
#### **6.4 链式连接**
|
||||
上面提过多个sps结点可以层级连接构建加密通道,假设有如下vps和家里的pc电脑。
|
||||
@ -733,7 +737,49 @@ vps02:3.3.3.3
|
||||
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
||||
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
||||
|
||||
#### **6.6 查看帮助**
|
||||
#### **6.6 认证功能**
|
||||
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
||||
1:用户发送认证信息`user-auth`。
|
||||
2:设置的本地认证信息`local-auth`。
|
||||
3:设置的连接上级使用的认证信息`parent-auth`。
|
||||
4:最终发送给上级的认证信息`auth-info-to-parent`。
|
||||
他们的情况关系如下:
|
||||
|
||||
| user-auth | local-auth | parent-auth | auth-info-to-paren
|
||||
| ------ | ------ | ------ | ------
|
||||
| 有/没有 | 有 | 有 | 来自parent-auth
|
||||
| 有/没有 | 没有 | 有 | 来自parent-auth
|
||||
| 有/没有 | 有 | 没有 | 无
|
||||
| 没有 | 没有 | 没有 | 无
|
||||
| 有 | 没有 | 没有 | 来自user-auth
|
||||
|
||||
对于sps代理我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
多个用户,重复-a参数即可.
|
||||
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||
|
||||
如果上级有认证,下级可以通过-A参数设置认证信息,比如:
|
||||
上级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||
下级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||
|
||||
另外,sps代理,本地认证集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
|
||||
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
|
||||
其它情况认为认证失败.
|
||||
比如:
|
||||
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
|
||||
带上user,pass,ip,target四个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||
user:用户名
|
||||
pass:密码
|
||||
ip:用户的IP,比如:192.168.1.200
|
||||
target:如果客户端是http(s)代理请求,这里代表的是请求的完整url,其它情况为空.
|
||||
|
||||
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
|
||||
如果没有-A参数,连接上级不使用认证.
|
||||
|
||||
#### **6.7 查看帮助**
|
||||
`./proxy help sps`
|
||||
|
||||
### **7.KCP配置**
|
||||
|
||||
34
config.go
34
config.go
@ -73,6 +73,7 @@ func initConfig() (err error) {
|
||||
//########http#########
|
||||
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.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.KeyFile = http.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
httpArgs.LocalType = http.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
@ -126,31 +127,34 @@ func initConfig() (err error) {
|
||||
//########mux-server#########
|
||||
muxServer := app.Command("server", "proxy on mux server mode")
|
||||
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxServerArgs.IsUDP = muxServer.Flag("udp", "proxy on udp mux server mode").Default("false").Bool()
|
||||
muxServerArgs.Key = muxServer.Flag("k", "client key").Default("default").String()
|
||||
muxServerArgs.Route = muxServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
|
||||
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-client#########
|
||||
muxClient := app.Command("client", "proxy on mux client mode")
|
||||
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
|
||||
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxClientArgs.Key = muxClient.Flag("k", "key same with server").Default("default").String()
|
||||
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp mode").Default("false").Bool()
|
||||
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
|
||||
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
|
||||
|
||||
//########mux-bridge#########
|
||||
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
|
||||
muxBridgeArgs.CertFile = muxBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
|
||||
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
|
||||
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
|
||||
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tls").Short('t').Enum("tls", "tcp", "kcp")
|
||||
|
||||
//########tunnel-server#########
|
||||
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
|
||||
@ -186,6 +190,7 @@ func initConfig() (err error) {
|
||||
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
|
||||
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
|
||||
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
socksArgs.CaCertFile = socks.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
socksArgs.KeyFile = socks.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
socksArgs.SSHUser = socks.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
|
||||
socksArgs.SSHKeyFile = socks.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
|
||||
@ -210,6 +215,7 @@ func initConfig() (err error) {
|
||||
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').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.CaCertFile = sps.Flag("ca", "ca cert file for tls").Default("").String()
|
||||
spsArgs.Timeout = sps.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('i').Default("2000").Int()
|
||||
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")
|
||||
@ -217,7 +223,14 @@ func initConfig() (err error) {
|
||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||
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.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.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.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.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||
//parse args
|
||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
|
||||
@ -264,6 +277,15 @@ func initConfig() (err error) {
|
||||
*kcpArgs.Crypt = "aes"
|
||||
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass)
|
||||
}
|
||||
//attach kcp config
|
||||
tcpArgs.KCP = kcpArgs
|
||||
httpArgs.KCP = kcpArgs
|
||||
socksArgs.KCP = kcpArgs
|
||||
spsArgs.KCP = kcpArgs
|
||||
muxBridgeArgs.KCP = kcpArgs
|
||||
muxServerArgs.KCP = kcpArgs
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
|
||||
flags := log.Ldate
|
||||
if *debug {
|
||||
flags |= log.Lshortfile | log.Lmicroseconds
|
||||
|
||||
@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
|
||||
fi
|
||||
mkdir /tmp/proxy
|
||||
cd /tmp/proxy
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.4/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.6/proxy-linux-amd64.tar.gz
|
||||
|
||||
# #install proxy
|
||||
tar zxvf proxy-linux-amd64.tar.gz
|
||||
|
||||
2
main.go
2
main.go
@ -8,7 +8,7 @@ import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const APP_VERSION = "4.4"
|
||||
const APP_VERSION = "4.6"
|
||||
|
||||
func main() {
|
||||
err := initConfig()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="4.4"
|
||||
VER="4.6"
|
||||
RELEASE="release-${VER}"
|
||||
rm -rf .cert
|
||||
mkdir .cert
|
||||
|
||||
@ -26,6 +26,7 @@ const (
|
||||
|
||||
type MuxServerArgs struct {
|
||||
Parent *string
|
||||
ParentType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
@ -39,9 +40,11 @@ type MuxServerArgs struct {
|
||||
Mgr *MuxServerManager
|
||||
IsCompress *bool
|
||||
SessionCount *int
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type MuxClientArgs struct {
|
||||
Parent *string
|
||||
ParentType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
@ -50,16 +53,18 @@ type MuxClientArgs struct {
|
||||
Timeout *int
|
||||
IsCompress *bool
|
||||
SessionCount *int
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type MuxBridgeArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
LocalType *string
|
||||
Timeout *int
|
||||
IsCompress *bool
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
}
|
||||
type TunnelServerArgs struct {
|
||||
Parent *string
|
||||
@ -115,6 +120,8 @@ type HTTPArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
@ -164,6 +171,8 @@ type SocksArgs struct {
|
||||
LocalType *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
SSHKeyFile *string
|
||||
@ -194,6 +203,8 @@ type SPSArgs struct {
|
||||
Parent *string
|
||||
CertFile *string
|
||||
KeyFile *string
|
||||
CaCertFile *string
|
||||
CaCertBytes []byte
|
||||
CertBytes []byte
|
||||
KeyBytes []byte
|
||||
Local *string
|
||||
@ -204,6 +215,14 @@ type SPSArgs struct {
|
||||
ParentServiceType *string
|
||||
DNSAddress *string
|
||||
DNSTTL *int
|
||||
AuthFile *string
|
||||
Auth *[]string
|
||||
AuthURL *string
|
||||
AuthURLOkCode *int
|
||||
AuthURLTimeout *int
|
||||
AuthURLRetry *int
|
||||
LocalIPS *[]string
|
||||
ParentAuth *string
|
||||
}
|
||||
|
||||
func (a *SPSArgs) Protocol() string {
|
||||
|
||||
@ -41,6 +41,12 @@ func (s *HTTP) CheckArgs() {
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
log.Fatalf("read ca file error,ERR:%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
if *s.cfg.SSHUser == "" {
|
||||
@ -88,7 +94,9 @@ func (s *HTTP) InitService() {
|
||||
for {
|
||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||
if err == nil {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write([]byte{0})
|
||||
conn.SetDeadline(time.Time{})
|
||||
}
|
||||
if err != nil {
|
||||
if s.sshClient != nil {
|
||||
@ -128,7 +136,7 @@ func (s *HTTP) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
@ -209,7 +217,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
outConn, err = s.getSSHConn(address)
|
||||
} else {
|
||||
//log.Printf("%v", s.outPool)
|
||||
// log.Printf("%v", s.outPool)
|
||||
_outConn, err = s.outPool.Pool.Get()
|
||||
if err == nil {
|
||||
outConn = _outConn.(net.Conn)
|
||||
@ -231,16 +239,16 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
|
||||
if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
|
||||
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
|
||||
err = req.HTTPSReply()
|
||||
} else {
|
||||
//https或者http,上级是代理,proxy需要转发
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(req.HeadBuf)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -321,7 +329,7 @@ func (s *HTTP) InitOutConnPool() {
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
|
||||
s.Resolve(*s.cfg.Parent),
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"snail007/proxy/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
@ -18,12 +19,14 @@ type MuxBridge struct {
|
||||
cfg MuxBridgeArgs
|
||||
clientControlConns utils.ConcurrentMap
|
||||
router utils.ClientKeyRouter
|
||||
l *sync.Mutex
|
||||
}
|
||||
|
||||
func NewMuxBridge() Service {
|
||||
b := &MuxBridge{
|
||||
cfg: MuxBridgeArgs{},
|
||||
clientControlConns: utils.NewConcurrentMap(),
|
||||
l: &sync.Mutex{},
|
||||
}
|
||||
b.router = utils.NewClientKeyRouter(&b.clientControlConns, 50000)
|
||||
return b
|
||||
@ -36,7 +39,9 @@ func (s *MuxBridge) CheckArgs() {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.LocalType == TYPE_TLS {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
}
|
||||
func (s *MuxBridge) StopService() {
|
||||
|
||||
@ -48,86 +53,110 @@ func (s *MuxBridge) Start(args interface{}) (err error) {
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
|
||||
reader := bufio.NewReader(inConn)
|
||||
|
||||
var err error
|
||||
var connType uint8
|
||||
var key string
|
||||
err = utils.ReadPacket(reader, &connType, &key)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var serverID string
|
||||
err = utils.ReadPacketData(reader, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("server connection %s %s connected", serverID, key)
|
||||
session, err := smux.Server(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("server session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
go s.callback(stream, serverID, key)
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
log.Printf("client connection %s connected", key)
|
||||
session, err := smux.Client(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
keyInfo := strings.Split(key, "-")
|
||||
groupKey := keyInfo[0]
|
||||
index := keyInfo[1]
|
||||
if !s.clientControlConns.Has(groupKey) {
|
||||
item := utils.NewConcurrentMap()
|
||||
s.clientControlConns.Set(groupKey, &item)
|
||||
}
|
||||
_group, _ := s.clientControlConns.Get(groupKey)
|
||||
group := _group.(*utils.ConcurrentMap)
|
||||
group.Set(index, session)
|
||||
// s.clientControlConns.Set(key, session)
|
||||
go func() {
|
||||
for {
|
||||
if session.IsClosed() {
|
||||
group.Remove(index)
|
||||
if group.IsEmpty() {
|
||||
s.clientControlConns.Remove(groupKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
//log.Printf("set client session,key: %s", key)
|
||||
}
|
||||
|
||||
})
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.handler)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on mux bridge mode %s", (*sc.Listener).Addr())
|
||||
log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
|
||||
return
|
||||
}
|
||||
func (s *MuxBridge) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
reader := bufio.NewReader(inConn)
|
||||
|
||||
var err error
|
||||
var connType uint8
|
||||
var key string
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacket(reader, &connType, &key)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
case CONN_SERVER:
|
||||
var serverID string
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacketData(reader, &serverID)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("server connection %s %s connected", serverID, key)
|
||||
session, err := smux.Server(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("server session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
session.Close()
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
go s.callback(stream, serverID, key)
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
log.Printf("client connection %s connected", key)
|
||||
session, err := smux.Client(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
keyInfo := strings.Split(key, "-")
|
||||
if len(keyInfo) != 2 {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client key format error,key:%s", key)
|
||||
return
|
||||
}
|
||||
groupKey := keyInfo[0]
|
||||
index := keyInfo[1]
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
if !s.clientControlConns.Has(groupKey) {
|
||||
item := utils.NewConcurrentMap()
|
||||
s.clientControlConns.Set(groupKey, &item)
|
||||
}
|
||||
_group, _ := s.clientControlConns.Get(groupKey)
|
||||
group := _group.(*utils.ConcurrentMap)
|
||||
if v, ok := group.Get(index); ok {
|
||||
v.(*smux.Session).Close()
|
||||
}
|
||||
group.Set(index, session)
|
||||
// s.clientControlConns.Set(key, session)
|
||||
go func() {
|
||||
for {
|
||||
if session.IsClosed() {
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
|
||||
group.Remove(index)
|
||||
}
|
||||
if group.IsEmpty() {
|
||||
s.clientControlConns.Remove(groupKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
//log.Printf("set client session,key: %s", key)
|
||||
}
|
||||
|
||||
}
|
||||
func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
try := 20
|
||||
for {
|
||||
@ -140,15 +169,27 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
}
|
||||
_group, ok := s.clientControlConns.Get(key)
|
||||
if !ok {
|
||||
log.Printf("client %s session not exists for server stream %s", key, serverID)
|
||||
log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
group := _group.(*utils.ConcurrentMap)
|
||||
index := group.Keys()[rand.Intn(group.Count())]
|
||||
keys := group.Keys()
|
||||
keysLen := len(keys)
|
||||
i := 0
|
||||
if keysLen > 0 {
|
||||
i = rand.Intn(keysLen)
|
||||
} else {
|
||||
log.Printf("client %s session empty for server stream %s, retrying...", key, serverID)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
index := keys[i]
|
||||
log.Printf("select client : %s-%s", key, index)
|
||||
session, _ := group.Get(index)
|
||||
session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
stream, err := session.(*smux.Session).OpenStream()
|
||||
session.(*smux.Session).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
@ -36,7 +36,9 @@ func (s *MuxClient) CheckArgs() {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
}
|
||||
func (s *MuxClient) StopService() {
|
||||
|
||||
@ -45,8 +47,12 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxClientArgs)
|
||||
s.CheckArgs()
|
||||
s.InitService()
|
||||
log.Printf("proxy on mux client mode, compress %v", *s.cfg.IsCompress)
|
||||
for i := 1; i <= *s.cfg.SessionCount; i++ {
|
||||
log.Printf("client started")
|
||||
count := 1
|
||||
if *s.cfg.SessionCount > 0 {
|
||||
count = *s.cfg.SessionCount
|
||||
}
|
||||
for i := 1; i <= count; i++ {
|
||||
log.Printf("session worker[%d] started", i)
|
||||
go func(i int) {
|
||||
defer func() {
|
||||
@ -56,15 +62,15 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
}
|
||||
}()
|
||||
for {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
conn, err := s.getParentConn()
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
conn := net.Conn(&_conn)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
@ -94,7 +100,9 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
}
|
||||
}()
|
||||
var ID, clientLocalAddr, serverID string
|
||||
stream.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||
stream.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read stream signal err: %s", err)
|
||||
stream.Close()
|
||||
@ -119,11 +127,26 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
func (s *MuxClient) Clean() {
|
||||
s.StopService()
|
||||
}
|
||||
|
||||
func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
|
||||
} else {
|
||||
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||
|
||||
for {
|
||||
inConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp packet revecived fail, err: %s", err)
|
||||
log.Printf("connection %s released", ID)
|
||||
@ -152,13 +175,16 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
@ -166,7 +192,9 @@ func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr str
|
||||
respBody := buf[0:length]
|
||||
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||
bs := utils.UDPPacket(srcAddr, respBody)
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*inConn).Write(bs)
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("send udp response fail ,ERR:%s", err)
|
||||
inConn.Close()
|
||||
|
||||
@ -43,7 +43,7 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
s.cfg = args.(MuxServerArgs)
|
||||
s.CheckArgs()
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
} else {
|
||||
log.Fatalf("parent required")
|
||||
}
|
||||
@ -88,6 +88,8 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
Mgr: s,
|
||||
IsCompress: s.cfg.IsCompress,
|
||||
SessionCount: s.cfg.SessionCount,
|
||||
KCP: s.cfg.KCP,
|
||||
ParentType: s.cfg.ParentType,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -105,7 +107,9 @@ func (s *MuxServerManager) CheckArgs() {
|
||||
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
|
||||
log.Fatalf("cert and key file required")
|
||||
}
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
}
|
||||
func (s *MuxServerManager) InitService() {
|
||||
}
|
||||
@ -152,7 +156,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on udp mux server mode %s", (*s.sc.UDPListener).LocalAddr())
|
||||
log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
|
||||
} else {
|
||||
err = s.sc.ListenTCP(func(inConn net.Conn) {
|
||||
defer func() {
|
||||
@ -201,7 +205,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on mux server mode %s, compress %v", (*s.sc.Listener).Addr(), *s.cfg.IsCompress)
|
||||
log.Printf("server on %s", (*s.sc.Listener).Addr())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -209,7 +213,11 @@ func (s *MuxServer) Clean() {
|
||||
|
||||
}
|
||||
func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
outConn, err = s.GetConn(fmt.Sprintf("%d", rand.Intn(*s.cfg.SessionCount)))
|
||||
i := 1
|
||||
if *s.cfg.SessionCount > 0 {
|
||||
i = rand.Intn(*s.cfg.SessionCount)
|
||||
}
|
||||
outConn, err = s.GetConn(fmt.Sprintf("%d", i))
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s", err)
|
||||
return
|
||||
@ -219,7 +227,9 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
remoteAddr = "udp:" + *s.cfg.Remote
|
||||
}
|
||||
ID = utils.Uniqueid()
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write stream data err: %s ,retrying...", err)
|
||||
utils.CloseConn(&outConn)
|
||||
@ -240,13 +250,14 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
||||
var session *smux.Session
|
||||
_session, ok := s.sessions.Get(index)
|
||||
if !ok {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
var c net.Conn
|
||||
c, err = s.getParentConn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := net.Conn(&_conn)
|
||||
c.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = c.Write(utils.BuildPacket(CONN_SERVER, *s.cfg.Key, s.cfg.Mgr.serverID))
|
||||
c.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return
|
||||
@ -259,6 +270,15 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
||||
}
|
||||
s.sessions.Set(index, session)
|
||||
log.Printf("session[%s] created", index)
|
||||
go func() {
|
||||
for {
|
||||
if session.IsClosed() {
|
||||
s.sessions.Remove(index)
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
session = _session.(*smux.Session)
|
||||
}
|
||||
@ -267,7 +287,20 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
||||
session.Close()
|
||||
s.sessions.Remove(index)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
|
||||
} else {
|
||||
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *MuxServer) UDPConnDeamon() {
|
||||
@ -298,7 +331,9 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
// outConn.Close()
|
||||
}()
|
||||
for {
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||
log.Printf("UDP deamon connection %s exited", ID)
|
||||
@ -312,7 +347,9 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||
s.sc.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
s.sc.UDPListener.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||
continue
|
||||
|
||||
@ -37,16 +37,28 @@ func NewSocks() Service {
|
||||
|
||||
func (s *Socks) CheckArgs() {
|
||||
var err error
|
||||
if *s.cfg.LocalType == "tls" {
|
||||
if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *s.cfg.ParentType == "tls") {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
log.Fatalf("read ca file error,ERR:%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
if *s.cfg.ParentType == "" {
|
||||
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
}
|
||||
// if *s.cfg.ParentType == "tls" {
|
||||
// s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
// if *s.cfg.CaCertFile != "" {
|
||||
// s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
// if err != nil {
|
||||
// log.Fatalf("read ca file error,ERR:%s", err)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
if *s.cfg.SSHUser == "" {
|
||||
log.Fatalf("ssh user required")
|
||||
@ -92,7 +104,9 @@ func (s *Socks) InitService() {
|
||||
for {
|
||||
conn, err := utils.ConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout*2)
|
||||
if err == nil {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write([]byte{0})
|
||||
conn.SetDeadline(time.Time{})
|
||||
}
|
||||
if err != nil {
|
||||
if s.sshClient != nil {
|
||||
@ -138,7 +152,7 @@ func (s *Socks) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback)
|
||||
}
|
||||
@ -204,6 +218,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
||||
_, err = conn.Write(rawB)
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp request:%v", len(rawB))
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
@ -213,7 +228,9 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 10*1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
@ -238,10 +255,14 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(d))
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(respBody))
|
||||
}
|
||||
|
||||
@ -260,6 +281,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
||||
_, err = conn.Write(p.Data())
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp send:%v", len(p.Data()))
|
||||
if err != nil {
|
||||
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
@ -268,7 +290,10 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
//log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 10*1024)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
@ -285,9 +310,13 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
}
|
||||
log.Printf("udp reply:%v", len(respPacket))
|
||||
}
|
||||
@ -359,9 +388,15 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
//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
|
||||
}
|
||||
@ -471,7 +506,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
case "tcp":
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
var _outConn tls.Conn
|
||||
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_outConn, err = utils.TlsConnectHost(s.Resolve(*s.cfg.Parent), *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
outConn = net.Conn(&_outConn)
|
||||
} else if *s.cfg.ParentType == "kcp" {
|
||||
outConn, err = utils.ConnectKCPHost(s.Resolve(*s.cfg.Parent), s.cfg.KCP)
|
||||
@ -484,25 +519,32 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
}
|
||||
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]
|
||||
//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
|
||||
|
||||
216
services/sps.go
216
services/sps.go
@ -2,8 +2,10 @@ package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
@ -11,18 +13,21 @@ import (
|
||||
"snail007/proxy/utils/socks"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SPS struct {
|
||||
outPool utils.OutPool
|
||||
cfg SPSArgs
|
||||
domainResolver utils.DomainResolver
|
||||
basicAuth utils.BasicAuth
|
||||
}
|
||||
|
||||
func NewSPS() Service {
|
||||
return &SPS{
|
||||
outPool: utils.OutPool{},
|
||||
cfg: SPSArgs{},
|
||||
outPool: utils.OutPool{},
|
||||
cfg: SPSArgs{},
|
||||
basicAuth: utils.BasicAuth{},
|
||||
}
|
||||
}
|
||||
func (s *SPS) CheckArgs() {
|
||||
@ -34,10 +39,21 @@ func (s *SPS) CheckArgs() {
|
||||
}
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
var err error
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
if err != nil {
|
||||
log.Fatalf("read ca file error,ERR:%s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func (s *SPS) InitService() {
|
||||
s.InitOutConnPool()
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||
}
|
||||
s.InitBasicAuth()
|
||||
}
|
||||
func (s *SPS) InitOutConnPool() {
|
||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||
@ -47,7 +63,7 @@ func (s *SPS) InitOutConnPool() {
|
||||
0,
|
||||
*s.cfg.ParentType,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
0,
|
||||
@ -75,7 +91,7 @@ func (s *SPS) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
@ -109,7 +125,7 @@ func (s *SPS) callback(inConn net.Conn) {
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
|
||||
utils.CloseConn(&inConn)
|
||||
}
|
||||
}
|
||||
@ -123,51 +139,32 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
return
|
||||
}
|
||||
address := ""
|
||||
var auth socks.Auth
|
||||
var forwardBytes []byte
|
||||
//fmt.Printf("%v", header)
|
||||
if header[0] == socks.VERSION_V5 {
|
||||
//socks
|
||||
methodReq, e := socks.NewMethodsRequest(*inConn, header)
|
||||
if e != nil {
|
||||
log.Printf("new method request err:%s", e)
|
||||
utils.CloseConn(inConn)
|
||||
err = e.(error)
|
||||
//socks5 server
|
||||
var serverConn *socks.ServerConn
|
||||
if s.IsBasicAuth() {
|
||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
|
||||
} else {
|
||||
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
|
||||
}
|
||||
if err = serverConn.Handshake(); err != nil {
|
||||
return
|
||||
}
|
||||
if !methodReq.Select(socks.Method_NO_AUTH) {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(inConn)
|
||||
log.Printf("none method found : Method_NO_AUTH")
|
||||
return
|
||||
}
|
||||
//method select reply
|
||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
||||
if err != nil {
|
||||
log.Printf("reply answer data fail,ERR: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
//request detail
|
||||
request, e := socks.NewRequest(*inConn)
|
||||
if e != nil {
|
||||
log.Printf("read request data fail,ERR: %s", e)
|
||||
utils.CloseConn(inConn)
|
||||
err = e.(error)
|
||||
return
|
||||
}
|
||||
if request.CMD() != socks.CMD_CONNECT {
|
||||
//只支持tcp
|
||||
request.TCPReply(socks.REP_UNKNOWN)
|
||||
utils.CloseConn(inConn)
|
||||
err = errors.New("cmd not supported")
|
||||
return
|
||||
}
|
||||
address = request.Addr()
|
||||
request.TCPReply(socks.REP_SUCCESS)
|
||||
address = serverConn.Target()
|
||||
auth = serverConn.AuthData()
|
||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
||||
//http
|
||||
var request utils.HTTPRequest
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
if s.IsBasicAuth() {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
||||
} else {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||
}
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("new http request fail,ERR: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -181,6 +178,17 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
forwardBytes = request.HeadBuf
|
||||
}
|
||||
address = request.Host
|
||||
var userpass string
|
||||
if s.IsBasicAuth() {
|
||||
userpass, err = request.GetAuthDataStr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userpassA := strings.Split(userpass, ":")
|
||||
if len(userpassA) == 2 {
|
||||
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
||||
utils.CloseConn(inConn)
|
||||
@ -199,12 +207,42 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
|
||||
//ask parent for connect to target address
|
||||
if *s.cfg.ParentServiceType == "http" {
|
||||
//http parent
|
||||
fmt.Fprintf(outConn, "CONNECT %s HTTP/1.1\r\n", address)
|
||||
pb := new(bytes.Buffer)
|
||||
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
||||
//Proxy-Authorization:\r\n
|
||||
u := ""
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
err = fmt.Errorf("parent auth data format error")
|
||||
return
|
||||
}
|
||||
u = fmt.Sprintf("%s:%s", a[0], a[1])
|
||||
} else {
|
||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||
u = fmt.Sprintf("%s:%s", auth.User, auth.Password)
|
||||
}
|
||||
}
|
||||
if u != "" {
|
||||
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization:Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
|
||||
}
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(pb.Bytes())
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
reply := make([]byte, 100)
|
||||
n, err = outConn.Read(reply)
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(reply)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
@ -214,53 +252,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
//log.Printf("reply: %s", string(reply[:n]))
|
||||
} else {
|
||||
log.Printf("connect %s", address)
|
||||
//socks parent
|
||||
//send auth type
|
||||
_, err = outConn.Write([]byte{0x05, 0x01, 0x00})
|
||||
if err != nil {
|
||||
log.Printf("write method to %s fail, err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
//socks client
|
||||
var clientConn *socks.ClientConn
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
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]}, header)
|
||||
} else {
|
||||
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header)
|
||||
} else {
|
||||
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header)
|
||||
}
|
||||
}
|
||||
if err = clientConn.Handshake(); err != nil {
|
||||
return
|
||||
}
|
||||
//read reply
|
||||
reply := make([]byte, 512)
|
||||
n, err = outConn.Read(reply)
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//log.Printf("method reply %v", reply[:n])
|
||||
|
||||
//build request
|
||||
buf, err = s.buildRequest(address)
|
||||
if err != nil {
|
||||
log.Printf("build request to %s fail , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//send address request
|
||||
_, err = outConn.Write(buf)
|
||||
if err != nil {
|
||||
log.Printf("write request to %s fail, err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//read reply
|
||||
reply = make([]byte, 512)
|
||||
n, err = outConn.Read(reply)
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
|
||||
//log.Printf("request reply %v", reply[:n])
|
||||
}
|
||||
//forward client data to target,if necessary.
|
||||
if len(forwardBytes) > 0 {
|
||||
@ -275,6 +285,34 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitBasicAuth() (err error) {
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||
} else {
|
||||
s.basicAuth = utils.NewBasicAuth(nil)
|
||||
}
|
||||
if *s.cfg.AuthURL != "" {
|
||||
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
}
|
||||
if *s.cfg.AuthFile != "" {
|
||||
var n = 0
|
||||
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||
}
|
||||
if len(*s.cfg.Auth) > 0 {
|
||||
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SPS) IsBasicAuth() bool {
|
||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||
}
|
||||
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
||||
host, portStr, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
|
||||
@ -56,7 +56,7 @@ func (s *TCP) Start(args interface{}) (err error) {
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback)
|
||||
}
|
||||
@ -172,7 +172,7 @@ func (s *TCP) InitOutConnPool() {
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
s.cfg.KCP,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
|
||||
@ -51,7 +51,7 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, func(inConn net.Conn) {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, func(inConn net.Conn) {
|
||||
//log.Printf("connection from %s ", inConn.RemoteAddr())
|
||||
|
||||
reader := bufio.NewReader(inConn)
|
||||
|
||||
@ -161,7 +161,7 @@ func (s *TunnelClient) GetInConn(typ uint8, data ...string) (outConn net.Conn, e
|
||||
}
|
||||
func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string
|
||||
}
|
||||
func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
@ -280,7 +280,7 @@ func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err e
|
||||
}
|
||||
func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes)
|
||||
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ func (s *UDP) InitOutConnPool() {
|
||||
*s.cfg.CheckParentInterval,
|
||||
*s.cfg.ParentType,
|
||||
kcpcfg.KCPConfigArgs{},
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes,
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, nil,
|
||||
*s.cfg.Parent,
|
||||
*s.cfg.Timeout,
|
||||
*s.cfg.PoolSize,
|
||||
|
||||
@ -86,14 +86,14 @@ func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func TlsConnectHost(host string, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
|
||||
func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
|
||||
h := strings.Split(host, ":")
|
||||
port, _ := strconv.Atoi(h[1])
|
||||
return TlsConnect(h[0], port, timeout, certBytes, keyBytes)
|
||||
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
|
||||
}
|
||||
|
||||
func TlsConnect(host string, port, timeout int, certBytes, keyBytes []byte) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(certBytes, keyBytes)
|
||||
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -103,8 +103,24 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes []byte) (con
|
||||
}
|
||||
return *tls.Client(_conn, conf), err
|
||||
}
|
||||
func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err error) {
|
||||
block, _ := pem.Decode(certBytes)
|
||||
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
|
||||
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverCertPool := x509.NewCertPool()
|
||||
caBytes := certBytes
|
||||
if caCertBytes != nil {
|
||||
caBytes = caCertBytes
|
||||
|
||||
}
|
||||
ok := serverCertPool.AppendCertsFromPEM(caBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
block, _ := pem.Decode(caBytes)
|
||||
if block == nil {
|
||||
panic("failed to parse certificate PEM")
|
||||
}
|
||||
@ -112,34 +128,24 @@ func getRequestTlsConfig(certBytes, keyBytes []byte) (conf *tls.Config, err erro
|
||||
if x509Cert == nil {
|
||||
panic("failed to parse block")
|
||||
}
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverCertPool := x509.NewCertPool()
|
||||
ok := serverCertPool.AppendCertsFromPEM(certBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
conf = &tls.Config{
|
||||
RootCAs: serverCertPool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: false,
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: x509Cert.Subject.CommonName,
|
||||
// VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// opts := x509.VerifyOptions{
|
||||
// Roots: serverCertPool,
|
||||
// }
|
||||
// for _, rawCert := range rawCerts {
|
||||
// cert, _ := x509.ParseCertificate(rawCert)
|
||||
// _, err := cert.Verify(opts)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// },
|
||||
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: serverCertPool,
|
||||
}
|
||||
for _, rawCert := range rawCerts {
|
||||
cert, _ := x509.ParseCertificate(rawCert)
|
||||
_, err := cert.Verify(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -165,22 +171,19 @@ func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.C
|
||||
return NewCompStream(kcpconn), err
|
||||
}
|
||||
|
||||
func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listener, err error) {
|
||||
block, _ := pem.Decode(certBytes)
|
||||
if block == nil {
|
||||
panic("failed to parse certificate PEM")
|
||||
}
|
||||
x509Cert, _ := x509.ParseCertificate(block.Bytes)
|
||||
if x509Cert == nil {
|
||||
panic("failed to parse block")
|
||||
}
|
||||
func ListenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
|
||||
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(certBytes, keyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clientCertPool := x509.NewCertPool()
|
||||
ok := clientCertPool.AppendCertsFromPEM(certBytes)
|
||||
caBytes := certBytes
|
||||
if caCertBytes != nil {
|
||||
caBytes = caCertBytes
|
||||
}
|
||||
ok := clientCertPool.AppendCertsFromPEM(caBytes)
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
@ -188,21 +191,6 @@ func ListenTls(ip string, port int, certBytes, keyBytes []byte) (ln *net.Listene
|
||||
ClientCAs: clientCertPool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ServerName: x509Cert.Subject.CommonName,
|
||||
// VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// opts := x509.VerifyOptions{
|
||||
// Roots: clientCertPool,
|
||||
// }
|
||||
// for _, rawCert := range rawCerts {
|
||||
// cert, _ := x509.ParseCertificate(rawCert)
|
||||
// _, err := cert.Verify(opts)
|
||||
// fmt.Println("SERVER ERR:", err)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// },
|
||||
}
|
||||
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
|
||||
if err == nil {
|
||||
@ -245,27 +233,95 @@ func CloseConn(conn *net.Conn) {
|
||||
}
|
||||
}
|
||||
func Keygen() (err error) {
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
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)])
|
||||
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 {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
//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 {
|
||||
log.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 {
|
||||
log.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 {
|
||||
log.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 {
|
||||
log.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 {
|
||||
log.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 {
|
||||
log.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 {
|
||||
log.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
return
|
||||
}
|
||||
func GetAllInterfaceAddr() ([]net.IP, error) {
|
||||
|
||||
@ -42,8 +42,8 @@ func NewServerChannelHost(host string) ServerChannel {
|
||||
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||
sc.errAcceptHandler = fn
|
||||
}
|
||||
func (sc *ServerChannel) ListenTls(certBytes, keyBytes []byte, fn func(conn net.Conn)) (err error) {
|
||||
sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes)
|
||||
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
|
||||
sc.Listener, err = ListenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
|
||||
if err == nil {
|
||||
go func() {
|
||||
defer func() {
|
||||
@ -142,15 +142,19 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
||||
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) {
|
||||
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
|
||||
if err == nil {
|
||||
if err := lis.SetDSCP(*config.DSCP); err != nil {
|
||||
if err = lis.SetDSCP(*config.DSCP); err != nil {
|
||||
log.Println("SetDSCP:", err)
|
||||
return
|
||||
}
|
||||
if err := lis.SetReadBuffer(*config.SockBuf); err != nil {
|
||||
if err = lis.SetReadBuffer(*config.SockBuf); err != nil {
|
||||
log.Println("SetReadBuffer:", err)
|
||||
return
|
||||
}
|
||||
if err := lis.SetWriteBuffer(*config.SockBuf); err != nil {
|
||||
if err = lis.SetWriteBuffer(*config.SockBuf); err != nil {
|
||||
log.Println("SetWriteBuffer:", err)
|
||||
return
|
||||
}
|
||||
sc.Listener = new(net.Listener)
|
||||
*sc.Listener = lis
|
||||
go func() {
|
||||
defer func() {
|
||||
|
||||
253
utils/socks/client.go
Normal file
253
utils/socks/client.go
Normal file
@ -0,0 +1,253 @@
|
||||
package socks
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var socks5Errors = []string{
|
||||
"",
|
||||
"general failure",
|
||||
"connection forbidden",
|
||||
"network unreachable",
|
||||
"host unreachable",
|
||||
"connection refused",
|
||||
"TTL expired",
|
||||
"command not supported",
|
||||
"address type not supported",
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
User, Password string
|
||||
}
|
||||
type ClientConn struct {
|
||||
user string
|
||||
password string
|
||||
conn *net.Conn
|
||||
header []byte
|
||||
timeout time.Duration
|
||||
addr string
|
||||
network string
|
||||
udpAddr string
|
||||
}
|
||||
|
||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
||||
// with an optional username and password. See RFC 1928 and RFC 1929.
|
||||
// target must be a canonical address with a host and port.
|
||||
// network : tcp udp
|
||||
func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration, auth *Auth, header []byte) *ClientConn {
|
||||
s := &ClientConn{
|
||||
conn: conn,
|
||||
network: network,
|
||||
timeout: timeout,
|
||||
}
|
||||
if auth != nil {
|
||||
s.user = auth.User
|
||||
s.password = auth.Password
|
||||
}
|
||||
if header != nil && len(header) > 0 {
|
||||
s.header = header
|
||||
}
|
||||
if network == "udp" && target == "" {
|
||||
target = "0.0.0.0:1"
|
||||
}
|
||||
s.addr = target
|
||||
return s
|
||||
}
|
||||
|
||||
// connect takes an existing connection to a socks5 proxy server,
|
||||
// and commands the server to extend that connection to target,
|
||||
// which must be a canonical address with a host and port.
|
||||
func (s *ClientConn) Handshake() error {
|
||||
host, portStr, err := net.SplitHostPort(s.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to parse port number: " + portStr)
|
||||
}
|
||||
if port < 1 || port > 0xffff {
|
||||
return errors.New("proxy: port number out of range: " + portStr)
|
||||
}
|
||||
|
||||
if err := s.handshake(host); err != nil {
|
||||
return err
|
||||
}
|
||||
buf := []byte{}
|
||||
if s.network == "tcp" {
|
||||
buf = append(buf, VERSION_V5, CMD_CONNECT, 0 /* reserved */)
|
||||
|
||||
} else {
|
||||
buf = append(buf, VERSION_V5, CMD_ASSOCIATE, 0 /* reserved */)
|
||||
}
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
buf = append(buf, ATYP_IPV4)
|
||||
ip = ip4
|
||||
} else {
|
||||
buf = append(buf, ATYP_IPV6)
|
||||
}
|
||||
buf = append(buf, ip...)
|
||||
} else {
|
||||
if len(host) > 255 {
|
||||
return errors.New("proxy: destination host name too long: " + host)
|
||||
}
|
||||
buf = append(buf, ATYP_DOMAIN)
|
||||
buf = append(buf, byte(len(host)))
|
||||
buf = append(buf, host...)
|
||||
}
|
||||
buf = append(buf, byte(port>>8), byte(port))
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:4]); err != nil {
|
||||
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
failure := "unknown error"
|
||||
if int(buf[1]) < len(socks5Errors) {
|
||||
failure = socks5Errors[buf[1]]
|
||||
}
|
||||
|
||||
if len(failure) > 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
||||
}
|
||||
|
||||
bytesToDiscard := 0
|
||||
switch buf[3] {
|
||||
case ATYP_IPV4:
|
||||
bytesToDiscard = net.IPv4len
|
||||
case ATYP_IPV6:
|
||||
bytesToDiscard = net.IPv6len
|
||||
case ATYP_DOMAIN:
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err := io.ReadFull((*s.conn), buf[:1])
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
bytesToDiscard = int(buf[0])
|
||||
default:
|
||||
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
||||
}
|
||||
|
||||
if cap(buf) < bytesToDiscard {
|
||||
buf = make([]byte, bytesToDiscard)
|
||||
} else {
|
||||
buf = buf[:bytesToDiscard]
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf); err != nil {
|
||||
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
var ip net.IP
|
||||
ip = buf
|
||||
ipStr := ""
|
||||
if bytesToDiscard == net.IPv4len || bytesToDiscard == net.IPv6len {
|
||||
if ipv4 := ip.To4(); ipv4 != nil {
|
||||
ipStr = ipv4.String()
|
||||
} else {
|
||||
ipStr = ip.To16().String()
|
||||
}
|
||||
}
|
||||
//log.Printf("%v", ipStr)
|
||||
// Also need to discard the port number
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
p := binary.BigEndian.Uint16([]byte{buf[0], buf[1]})
|
||||
//log.Printf("%v", p)
|
||||
s.udpAddr = net.JoinHostPort(ipStr, fmt.Sprintf("%d", p))
|
||||
//log.Printf("%v", s.udpAddr)
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
return nil
|
||||
}
|
||||
func (s *ClientConn) SendUDP(data []byte, addr string) (respData []byte, err error) {
|
||||
|
||||
c, err := net.DialTimeout("udp", s.udpAddr, s.timeout)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn := c.(*net.UDPConn)
|
||||
|
||||
p := NewPacketUDP()
|
||||
p.Build(addr, data)
|
||||
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||
conn.Write(p.Bytes())
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
buf := make([]byte, 1024)
|
||||
conn.SetDeadline(time.Now().Add(s.timeout))
|
||||
n, _, err := conn.ReadFrom(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
respData = buf[:n]
|
||||
return
|
||||
}
|
||||
func (s *ClientConn) handshake(host string) error {
|
||||
|
||||
// the size here is just an estimate
|
||||
buf := make([]byte, 0, 6+len(host))
|
||||
|
||||
buf = append(buf, VERSION_V5)
|
||||
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
||||
buf = append(buf, 2 /* num auth methods */, Method_NO_AUTH, Method_USER_PASS)
|
||||
} else {
|
||||
buf = append(buf, 1 /* num auth methods */, Method_NO_AUTH)
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
|
||||
if buf[0] != 5 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
||||
}
|
||||
if buf[1] == 0xff {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
||||
}
|
||||
|
||||
// See RFC 1929
|
||||
if buf[1] == Method_USER_PASS {
|
||||
buf = buf[:0]
|
||||
buf = append(buf, 1 /* password protocol version */)
|
||||
buf = append(buf, uint8(len(s.user)))
|
||||
buf = append(buf, s.user...)
|
||||
buf = append(buf, uint8(len(s.password)))
|
||||
buf = append(buf, s.password...)
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := (*s.conn).Write(buf); err != nil {
|
||||
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
if _, err := io.ReadFull((*s.conn), buf[:2]); err != nil {
|
||||
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
||||
}
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if buf[1] != 0 {
|
||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
226
utils/socks/server.go
Normal file
226
utils/socks/server.go
Normal file
@ -0,0 +1,226 @@
|
||||
package socks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"snail007/proxy/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Method_NO_AUTH = uint8(0x00)
|
||||
Method_GSSAPI = uint8(0x01)
|
||||
Method_USER_PASS = uint8(0x02)
|
||||
Method_IANA = uint8(0x7F)
|
||||
Method_RESVERVE = uint8(0x80)
|
||||
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||
VERSION_V5 = uint8(0x05)
|
||||
CMD_CONNECT = uint8(0x01)
|
||||
CMD_BIND = uint8(0x02)
|
||||
CMD_ASSOCIATE = uint8(0x03)
|
||||
ATYP_IPV4 = uint8(0x01)
|
||||
ATYP_DOMAIN = uint8(0x03)
|
||||
ATYP_IPV6 = uint8(0x04)
|
||||
REP_SUCCESS = uint8(0x00)
|
||||
REP_REQ_FAIL = uint8(0x01)
|
||||
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||
REP_TTL_TIMEOUT = uint8(0x06)
|
||||
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||
REP_UNKNOWN = uint8(0x09)
|
||||
RSV = uint8(0x00)
|
||||
)
|
||||
|
||||
var (
|
||||
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
ZERO_PORT = []byte{0x00, 0x00}
|
||||
)
|
||||
|
||||
type ServerConn struct {
|
||||
target string
|
||||
user string
|
||||
password string
|
||||
conn *net.Conn
|
||||
timeout time.Duration
|
||||
auth *utils.BasicAuth
|
||||
header []byte
|
||||
ver uint8
|
||||
//method
|
||||
methodsCount uint8
|
||||
methods []uint8
|
||||
method uint8
|
||||
//request
|
||||
cmd uint8
|
||||
reserve uint8
|
||||
addressType uint8
|
||||
dstAddr string
|
||||
dstPort string
|
||||
dstHost string
|
||||
udpAddress string
|
||||
}
|
||||
|
||||
func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, udpAddress string, header []byte) *ServerConn {
|
||||
if udpAddress == "" {
|
||||
udpAddress = "0.0.0.0:16666"
|
||||
}
|
||||
s := &ServerConn{
|
||||
conn: conn,
|
||||
timeout: timeout,
|
||||
auth: auth,
|
||||
header: header,
|
||||
ver: VERSION_V5,
|
||||
udpAddress: udpAddress,
|
||||
}
|
||||
return s
|
||||
|
||||
}
|
||||
func (s *ServerConn) Close() {
|
||||
utils.CloseConn(s.conn)
|
||||
}
|
||||
func (s *ServerConn) AuthData() Auth {
|
||||
return Auth{s.user, s.password}
|
||||
}
|
||||
func (s *ServerConn) Method() uint8 {
|
||||
return s.method
|
||||
}
|
||||
func (s *ServerConn) Target() string {
|
||||
return s.target
|
||||
}
|
||||
func (s *ServerConn) Handshake() (err error) {
|
||||
remoteAddr := (*s.conn).RemoteAddr()
|
||||
//协商开始
|
||||
//method select request
|
||||
var methodReq MethodsRequest
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
|
||||
methodReq, e := NewMethodsRequest((*s.conn), s.header)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||
return
|
||||
}
|
||||
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
|
||||
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
|
||||
// if !methodReq.Select(Method_NO_AUTH) {
|
||||
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
// methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
// (*s.conn).SetReadDeadline(time.Time{})
|
||||
// err = fmt.Errorf("none method found : Method_NO_AUTH")
|
||||
// return
|
||||
// }
|
||||
s.method = Method_NO_AUTH
|
||||
//method select reply
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
err = methodReq.Reply(Method_NO_AUTH)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
// err = fmt.Errorf("% x", methodReq.Bytes())
|
||||
} else {
|
||||
//auth
|
||||
if !methodReq.Select(Method_USER_PASS) {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("none method found : Method_USER_PASS")
|
||||
return
|
||||
}
|
||||
s.method = Method_USER_PASS
|
||||
//method reply need auth
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
err = methodReq.Reply(Method_USER_PASS)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("reply answer data fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
//read auth
|
||||
buf := make([]byte, 500)
|
||||
var n int
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
n, err = (*s.conn).Read(buf)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read auth info fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
r := buf[:n]
|
||||
s.user = string(r[2 : r[1]+2])
|
||||
s.password = string(r[2+r[1]+1:])
|
||||
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
|
||||
//auth
|
||||
_addr := strings.Split(remoteAddr.String(), ":")
|
||||
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x00})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x01})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("auth fail from %s", remoteAddr)
|
||||
return
|
||||
}
|
||||
}
|
||||
//request detail
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
request, e := NewRequest(*s.conn)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
err = fmt.Errorf("read request data fail,ERR: %s", e)
|
||||
return
|
||||
}
|
||||
//协商结束
|
||||
|
||||
switch request.CMD() {
|
||||
case CMD_BIND:
|
||||
err = request.TCPReply(REP_UNKNOWN)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr)
|
||||
return
|
||||
case CMD_CONNECT:
|
||||
err = request.TCPReply(REP_SUCCESS)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
case CMD_ASSOCIATE:
|
||||
err = request.UDPReply(REP_SUCCESS, s.udpAddress)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//fill socks info
|
||||
s.target = request.Addr()
|
||||
s.methodsCount = methodReq.MethodsCount()
|
||||
s.methods = methodReq.Methods()
|
||||
s.cmd = request.CMD()
|
||||
s.reserve = request.reserve
|
||||
s.addressType = request.addressType
|
||||
s.dstAddr = request.dstAddr
|
||||
s.dstHost = request.dstHost
|
||||
s.dstPort = request.dstPort
|
||||
return
|
||||
}
|
||||
@ -3,44 +3,13 @@ package socks
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
Method_NO_AUTH = uint8(0x00)
|
||||
Method_GSSAPI = uint8(0x01)
|
||||
Method_USER_PASS = uint8(0x02)
|
||||
Method_IANA = uint8(0x7F)
|
||||
Method_RESVERVE = uint8(0x80)
|
||||
Method_NONE_ACCEPTABLE = uint8(0xFF)
|
||||
VERSION_V5 = uint8(0x05)
|
||||
CMD_CONNECT = uint8(0x01)
|
||||
CMD_BIND = uint8(0x02)
|
||||
CMD_ASSOCIATE = uint8(0x03)
|
||||
ATYP_IPV4 = uint8(0x01)
|
||||
ATYP_DOMAIN = uint8(0x03)
|
||||
ATYP_IPV6 = uint8(0x04)
|
||||
REP_SUCCESS = uint8(0x00)
|
||||
REP_REQ_FAIL = uint8(0x01)
|
||||
REP_RULE_FORBIDDEN = uint8(0x02)
|
||||
REP_NETWOR_UNREACHABLE = uint8(0x03)
|
||||
REP_HOST_UNREACHABLE = uint8(0x04)
|
||||
REP_CONNECTION_REFUSED = uint8(0x05)
|
||||
REP_TTL_TIMEOUT = uint8(0x06)
|
||||
REP_CMD_UNSUPPORTED = uint8(0x07)
|
||||
REP_ATYP_UNSUPPORTED = uint8(0x08)
|
||||
REP_UNKNOWN = uint8(0x09)
|
||||
RSV = uint8(0x00)
|
||||
)
|
||||
|
||||
var (
|
||||
ZERO_IP = []byte{0x00, 0x00, 0x00, 0x00}
|
||||
ZERO_PORT = []byte{0x00, 0x00}
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
ver uint8
|
||||
cmd uint8
|
||||
@ -57,7 +26,7 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
||||
var b = make([]byte, 1024)
|
||||
var n int
|
||||
req = Request{rw: rw}
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
b = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -71,7 +40,6 @@ func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{
|
||||
req.cmd = uint8(b[1])
|
||||
req.reserve = uint8(b[2])
|
||||
req.addressType = uint8(b[3])
|
||||
|
||||
if b[0] != 0x5 {
|
||||
err = fmt.Errorf("sosck version supported")
|
||||
req.TCPReply(REP_REQ_FAIL)
|
||||
@ -129,7 +97,7 @@ func (s *Request) NewReply(rep uint8, addr string) []byte {
|
||||
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
|
||||
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
|
||||
)
|
||||
if ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||
if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
|
||||
atyp = ATYP_IPV6
|
||||
ipb = ip.To16()
|
||||
}
|
||||
@ -165,7 +133,7 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
||||
s.rw = &r
|
||||
var buf = make([]byte, 300)
|
||||
var n int
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
buf = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -182,7 +150,6 @@ func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err
|
||||
err = fmt.Errorf("socks methods data length error")
|
||||
return
|
||||
}
|
||||
|
||||
s.ver = buf[0]
|
||||
s.methodsCount = buf[1]
|
||||
s.methods = buf[2:n]
|
||||
@ -195,6 +162,9 @@ func (s *MethodsRequest) Version() uint8 {
|
||||
func (s *MethodsRequest) MethodsCount() uint8 {
|
||||
return s.methodsCount
|
||||
}
|
||||
func (s *MethodsRequest) Methods() []uint8 {
|
||||
return s.methods
|
||||
}
|
||||
func (s *MethodsRequest) Select(method uint8) bool {
|
||||
for _, m := range s.methods {
|
||||
if m == method {
|
||||
@ -211,17 +181,6 @@ func (s *MethodsRequest) Bytes() []byte {
|
||||
return s.bytes
|
||||
}
|
||||
|
||||
type UDPPacket struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
header []byte
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||
p = UDPPacket{}
|
||||
p.frag = uint8(b[2])
|
||||
@ -249,6 +208,18 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
|
||||
p.header = b[:portIndex+2]
|
||||
return
|
||||
}
|
||||
|
||||
type UDPPacket struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
header []byte
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
func (s *UDPPacket) Header() []byte {
|
||||
return s.header
|
||||
}
|
||||
@ -268,3 +239,104 @@ func (s *UDPPacket) Port() string {
|
||||
func (s *UDPPacket) Data() []byte {
|
||||
return s.data
|
||||
}
|
||||
|
||||
type PacketUDP struct {
|
||||
rsv uint16
|
||||
frag uint8
|
||||
atype uint8
|
||||
dstHost string
|
||||
dstPort string
|
||||
data []byte
|
||||
}
|
||||
|
||||
func NewPacketUDP() (p PacketUDP) {
|
||||
return PacketUDP{}
|
||||
}
|
||||
func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
|
||||
host, port, err := net.SplitHostPort(destAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.rsv = 0
|
||||
p.frag = 0
|
||||
p.dstHost = host
|
||||
p.dstPort = port
|
||||
p.atype = ATYP_IPV4
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
p.atype = ATYP_IPV4
|
||||
ip = ip4
|
||||
} else {
|
||||
p.atype = ATYP_IPV6
|
||||
}
|
||||
} else {
|
||||
if len(host) > 255 {
|
||||
err = errors.New("proxy: destination host name too long: " + host)
|
||||
return
|
||||
}
|
||||
p.atype = ATYP_DOMAIN
|
||||
}
|
||||
p.data = data
|
||||
|
||||
return
|
||||
}
|
||||
func (p *PacketUDP) Parse(b []byte) (err error) {
|
||||
p.frag = uint8(b[2])
|
||||
if p.frag != 0 {
|
||||
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
|
||||
return
|
||||
}
|
||||
portIndex := 0
|
||||
p.atype = b[3]
|
||||
switch p.atype {
|
||||
case ATYP_IPV4: //IP V4
|
||||
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
|
||||
portIndex = 8
|
||||
case ATYP_DOMAIN: //域名
|
||||
domainLen := uint8(b[4])
|
||||
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
|
||||
portIndex = int(5 + domainLen)
|
||||
case ATYP_IPV6: //IP V6
|
||||
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
|
||||
portIndex = 20
|
||||
}
|
||||
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
|
||||
p.data = b[portIndex+2:]
|
||||
return
|
||||
}
|
||||
func (p *PacketUDP) Header() []byte {
|
||||
header := new(bytes.Buffer)
|
||||
header.Write([]byte{0x00, 0x00, p.frag, p.atype})
|
||||
if p.atype == ATYP_IPV4 {
|
||||
ip := net.ParseIP(p.dstHost)
|
||||
header.Write(ip.To4())
|
||||
} else if p.atype == ATYP_IPV6 {
|
||||
ip := net.ParseIP(p.dstHost)
|
||||
header.Write(ip.To16())
|
||||
} else if p.atype == ATYP_DOMAIN {
|
||||
hBytes := []byte(p.dstHost)
|
||||
header.WriteByte(byte(len(hBytes)))
|
||||
header.Write(hBytes)
|
||||
}
|
||||
port, _ := strconv.ParseUint(p.dstPort, 10, 64)
|
||||
portBytes := new(bytes.Buffer)
|
||||
binary.Write(portBytes, binary.BigEndian, port)
|
||||
header.Write(portBytes.Bytes()[portBytes.Len()-2:])
|
||||
return header.Bytes()
|
||||
}
|
||||
func (p *PacketUDP) Bytes() []byte {
|
||||
packBytes := new(bytes.Buffer)
|
||||
packBytes.Write(p.Header())
|
||||
packBytes.Write(p.data)
|
||||
return packBytes.Bytes()
|
||||
}
|
||||
func (p *PacketUDP) Host() string {
|
||||
return p.dstHost
|
||||
}
|
||||
|
||||
func (p *PacketUDP) Port() string {
|
||||
return p.dstPort
|
||||
}
|
||||
func (p *PacketUDP) Data() []byte {
|
||||
return p.data
|
||||
}
|
||||
|
||||
@ -317,7 +317,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
||||
req = HTTPRequest{
|
||||
conn: inConn,
|
||||
}
|
||||
if len(header) == 1 {
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
buf = header[0]
|
||||
n = len(header[0])
|
||||
} else {
|
||||
@ -402,17 +402,13 @@ func (req *HTTPRequest) IsHTTPS() bool {
|
||||
return req.Method == "CONNECT"
|
||||
}
|
||||
|
||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
|
||||
func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||
// log.Printf("request :%s", string(req.HeadBuf))
|
||||
code := "407"
|
||||
authorization := req.getHeader("Proxy-Authorization")
|
||||
// if authorization == "" {
|
||||
// authorization = req.getHeader("Authorization")
|
||||
// code = "401"
|
||||
// }
|
||||
|
||||
authorization = strings.Trim(authorization, " \r\n\t")
|
||||
if authorization == "" {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", code)
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "407")
|
||||
CloseConn(req.conn)
|
||||
err = errors.New("require auth header data")
|
||||
return
|
||||
@ -430,6 +426,10 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
CloseConn(req.conn)
|
||||
return
|
||||
}
|
||||
basicInfo = string(user)
|
||||
return
|
||||
}
|
||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||
URL := ""
|
||||
if req.IsHTTPS() {
|
||||
@ -437,10 +437,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
} else {
|
||||
URL = req.getHTTPURL()
|
||||
}
|
||||
user, err := req.GetAuthDataStr()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
||||
//log.Printf("auth %s,%v", string(user), authOk)
|
||||
if !authOk {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", code)
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407")
|
||||
CloseConn(req.conn)
|
||||
err = fmt.Errorf("basic auth fail")
|
||||
return
|
||||
@ -491,25 +495,27 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
|
||||
}
|
||||
|
||||
type OutPool struct {
|
||||
Pool ConnPool
|
||||
dur int
|
||||
typ string
|
||||
certBytes []byte
|
||||
keyBytes []byte
|
||||
kcp kcpcfg.KCPConfigArgs
|
||||
address string
|
||||
timeout int
|
||||
Pool ConnPool
|
||||
dur int
|
||||
typ string
|
||||
certBytes []byte
|
||||
keyBytes []byte
|
||||
caCertBytes []byte
|
||||
kcp kcpcfg.KCPConfigArgs
|
||||
address string
|
||||
timeout int
|
||||
}
|
||||
|
||||
func NewOutPool(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
|
||||
func NewOutPool(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int, InitialCap int, MaxCap int) (op OutPool) {
|
||||
op = OutPool{
|
||||
dur: dur,
|
||||
typ: typ,
|
||||
certBytes: certBytes,
|
||||
keyBytes: keyBytes,
|
||||
kcp: kcp,
|
||||
address: address,
|
||||
timeout: timeout,
|
||||
dur: dur,
|
||||
typ: typ,
|
||||
certBytes: certBytes,
|
||||
keyBytes: keyBytes,
|
||||
caCertBytes: caCertBytes,
|
||||
kcp: kcp,
|
||||
address: address,
|
||||
timeout: timeout,
|
||||
}
|
||||
var err error
|
||||
op.Pool, err = NewConnPool(poolConfig{
|
||||
@ -543,7 +549,7 @@ func NewOutPool(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyByt
|
||||
func (op *OutPool) getConn() (conn interface{}, err error) {
|
||||
if op.typ == "tls" {
|
||||
var _conn tls.Conn
|
||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes)
|
||||
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes, op.caCertBytes)
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user