98 Commits
v4.4 ... v4.7

Author SHA1 Message Date
arraykeys@gmail.com
515dcdbf1f Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 14:59:02 +08:00
arraykeys@gmail.com
0e033c1d85 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 12:22:37 +08:00
arraykeys@gmail.com
ad2441de3b Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 12:08:31 +08:00
arraykeys@gmail.com
7a881b3625 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-04-27 11:58:50 +08:00
arraykeys@gmail.com
faf61fdd60 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 11:58:27 +08:00
snail007
2b3d23f77c Merge pull request #63 from yincongcyincong/dev
Update README.md
2018-04-26 21:42:48 +08:00
yincongcyincong
06e1247706 Update README.md 2018-04-26 18:56:57 +08:00
arraykeys@gmail.com
6b5fdef8c7 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-26 17:43:53 +08:00
arraykeys@gmail.com
48b1621ee4 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-04-26 17:37:56 +08:00
snail007
c2ce973f61 Merge pull request #61 from onetwotrip/dev
Fix imports path
2018-04-26 17:37:35 +08:00
arraykeys@gmail.com
cac648cc32 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-26 17:37:03 +08:00
Maxim Pogozhiy
b9bffcdf4b Fix imports path 2018-04-25 11:28:20 +03:00
snail007
7a1e5c5de7 Merge pull request #62 from yincongcyincong/dev
en doc
2018-04-25 15:54:41 +08:00
yc
e24dfc856a Merge branch 'snail007-dev' into dev 2018-04-24 19:53:43 +08:00
yc
66a115c764 update readme 2018-04-24 19:53:27 +08:00
yincongcyincong
a6e80a30dc Update README.md 2018-04-24 19:36:30 +08:00
arraykeys@gmail.com
52a2771382 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-24 18:25:04 +08:00
arraykeys@gmail.com
6b2b75bc50 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-24 18:18:49 +08:00
arraykeys@gmail.com
893baff6c6 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev
# Conflicts:
#	sdk/windows-linux/release_linux.sh

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-24 18:17:25 +08:00
arraykeys@gmail.com
de62d956dd Merge branch 'master' of https://github.com/snail007/goproxy.git into dev 2018-04-24 18:13:28 +08:00
arraykeys@gmail.com
b59cf1f144 增加了大量插图,优化了多链接版本内网穿透,实现了心跳机制.
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-24 18:09:33 +08:00
arraykeys
8b5cc3fb89 no message 2018-04-21 11:21:04 +08:00
arraykeys@gmail.com
fbd8c67649 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-20 13:35:05 +08:00
arraykeys
c6f6266592 no message 2018-04-20 13:31:58 +08:00
arraykeys
ab72640ffd Merge branch 'dev' of github.com:snail007/goproxy into dev
* 'dev' of github.com:snail007/goproxy:
  fix #56
  Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-20 13:23:31 +08:00
arraykeys
905bfff92b no message 2018-04-20 13:23:08 +08:00
arraykeys@gmail.com
4ef33d0ffd fix #56
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-19 14:55:56 +08:00
arraykeys@gmail.com
1597363dd1 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-18 15:27:32 +08:00
arraykeys
27896a0563 no message 2018-04-18 13:22:44 +08:00
arraykeys
bef385cfd1 no message 2018-04-18 13:11:43 +08:00
arraykeys@gmail.com
98e0154baa Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-18 11:19:51 +08:00
arraykeys@gmail.com
01961a798a Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-04-18 10:57:06 +08:00
arraykeys
d5a460bd09 no message 2018-04-18 10:55:54 +08:00
arraykeys@gmail.com
e94605644f Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-04-18 10:53:39 +08:00
arraykeys@gmail.com
8dc206e2d6 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-18 10:53:14 +08:00
arraykeys
e8acbbfabf mac sdk 2018-04-18 10:52:57 +08:00
arraykeys
17335eb92b no message 2018-04-17 22:25:10 +08:00
arraykeys
d2051e6e37 no message 2018-04-17 18:24:01 +08:00
arraykeys
0aa0e7c550 add windows sdk demo 2018-04-17 17:44:16 +08:00
arraykeys
57935c2296 no message 2018-04-17 13:57:52 +08:00
arraykeys@gmail.com
9d4930b29d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-17 13:45:31 +08:00
arraykeys@gmail.com
66206e63b3 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-17 13:36:19 +08:00
arraykeys@gmail.com
19baccb91a add linux .so and windows .dll sdk support,
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-16 18:33:10 +08:00
yincongcyincong
98bbd68448 Update README.md 2018-04-14 11:37:09 +08:00
yincongcyincong
45dee58203 Update README.md 2018-04-14 11:30:29 +08:00
yincongcyincong
e2557c44c4 Update README.md 2018-04-14 10:29:21 +08:00
arraykeys@gmail.com
f0ed6d73e4 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-13 18:31:12 +08:00
arraykeys@gmail.com
47790d1d58 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-13 18:23:26 +08:00
arraykeys@gmail.com
9aff5eda38 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-13 18:21:26 +08:00
arraykeys@gmail.com
eb2f055e07 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-13 18:14:32 +08:00
arraykeys@gmail.com
0998c06195 Add compress and encryt support on (tcp|tls|kcp) transport layer
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-13 17:23:42 +08:00
arraykeys@gmail.com
cf22866b2a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-13 14:12:05 +08:00
arraykeys@gmail.com
16bb452640 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-12 17:03:16 +08:00
arraykeys@gmail.com
6f1d826ef5 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-12 16:45:39 +08:00
arraykeys@gmail.com
5a68fb3c3d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-12 16:42:28 +08:00
arraykeys@gmail.com
350eb5b6ed Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-12 16:41:03 +08:00
arraykeys@gmail.com
d48f3b3323 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-12 16:36:36 +08:00
arraykeys@gmail.com
7a1491c7b3 android sdk
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-12 16:32:56 +08:00
arraykeys@gmail.com
68deae6bf8 优化服务stop方法,方便sdk开发.
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-10 18:32:17 +08:00
arraykeys@gmail.com
2086966a89 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-09 16:21:27 +08:00
arraykeys@gmail.com
3aba428b76 增加gomobile sdk对android/ios进行支持.
优化错误控制

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-04-09 16:16:55 +08:00
arraykeys@gmail.com
a11ce38747 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-03 17:34:33 +08:00
arraykeys@gmail.com
f7b363ec73 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-29 17:31:38 +08:00
arraykeys@gmail.com
4c33a1e9b2 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-29 17:25:32 +08:00
arraykeys@gmail.com
c4d9382ac7 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-29 16:59:52 +08:00
arraykeys@gmail.com
7df2d990e7 Merge branch 'dev' 2018-03-28 14:10:10 +08:00
snail007
900b75ddcd Merge pull request #48 from yincongcyincong/dev
Dev
2018-03-28 14:08:28 +08:00
yincongcyincong
a5d199fb1c Update README.md 2018-03-28 14:06:19 +08:00
yincongcyincong
2d8190873f Update README.md 2018-03-28 13:56:02 +08:00
yincongcyincong
3eff793ac2 Update README.md 2018-03-28 13:53:09 +08:00
arraykeys@gmail.com
27ce6e1bd2 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:34:08 +08:00
arraykeys@gmail.com
b11c7e632b fix #47
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-28 13:30:09 +08:00
arraykeys@gmail.com
d911be7d80 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:27:59 +08:00
arraykeys@gmail.com
bd056d74cc Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:25:47 +08:00
arraykeys@gmail.com
69b65a37ca Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:25:17 +08:00
arraykeys@gmail.com
dd52ad8a8a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:22:37 +08:00
arraykeys@gmail.com
59b5ef2df4 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:21:02 +08:00
arraykeys@gmail.com
4a34566f08 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-28 13:14:06 +08:00
arraykeys@gmail.com
d81d5ffe06 socks5 client server done
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-26 18:42:44 +08:00
arraykeys@gmail.com
59c9148875 optimize timeout of http(s)\socks\nat
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-21 18:17:20 +08:00
arraykeys@gmail.com
40bce3e736 optimize http basic auth
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-21 16:57:46 +08:00
arraykeys@gmail.com
d4c0775b4a Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-16 16:16:11 +08:00
arraykeys@gmail.com
7f983152b7 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-14 09:37:57 +08:00
arraykeys@gmail.com
bab4325414 server add safe close user conn
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-13 18:36:34 +08:00
arraykeys@gmail.com
0d85c7dd7d bridge add timeout
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-13 17:31:51 +08:00
arraykeys@gmail.com
f756d62b19 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-13 17:14:25 +08:00
arraykeys@gmail.com
2d1c1449aa Merge branch 'master' of https://github.com/snail007/goproxy.git 2018-03-13 10:29:50 +08:00
arraykeys@gmail.com
f348298acd v4.5 2018-03-13 10:29:26 +08:00
arraykeys@gmail.com
ad47104fc7 v4.5 2018-03-13 10:04:18 +08:00
snail007
4d4fb64b59 Update mux_bridge.go 2018-03-12 19:27:37 +08:00
arraykeys@gmail.com
9ce3a6e468 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-12 18:15:14 +08:00
arraykeys@gmail.com
34e9e362b9 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-12 17:31:35 +08:00
arraykeys@gmail.com
f87cbf73e8 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-03-12 13:59:47 +08:00
arraykeys@gmail.com
362ada2ebb v4.5
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-03-12 13:59:25 +08:00
snail007
b4b7221dab Merge pull request #44 from snail007/dev
Update README_ZH.md
2018-03-10 17:00:50 +08:00
snail007
2d8dc56f4e Update README_ZH.md 2018-03-10 17:00:03 +08:00
arraykeys@gmail.com
1cf4313d12 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-09 17:16:21 +08:00
arraykeys@gmail.com
7bb8f19b90 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-03-09 16:02:05 +08:00
72 changed files with 3819 additions and 1380 deletions

2
.gitignore vendored
View File

@ -1,7 +1,9 @@
proxy
goproxy
*.exe
*.exe~
.*
!.gitignore
release-*
proxy.crt
proxy.key

View File

@ -1,4 +1,35 @@
proxy更新日志
v4.7
1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持.
2.优化了bridge的日志,增加了client和server的掉线日志.
3.优化了sps读取http(s)代理响应的缓冲大小,同时优化了CONNECT请求,
避免了某些代理服务器返回过多数据导致不能正常通讯的问题.
4.去除了鸡肋连接池功能.
5.优化了所有服务代码,方便对sdk提供支持.
6.增加了SDK手册.
7.增加了GUI客户端(windows/web/android/ios)介绍主页.
8.SPS\HTTP(s)\Socks代理增加了自定义加密传输,只需要通过参数-z和-Z设置一个密码即可.
9.SPS\HTTP(s)\Socks代理增加了压缩传输,只需要通过参数-m和-M设置即可.
10.手册增加了SPS\HTTP(s)\Socks自定义加密的使用示例.
11.手册增加了SPS\HTTP(s)\Socks压缩传输的使用示例.
12.优化了多链接版本的内网穿透,融合了多链接和smux的优点,即能够拥有大的吞吐量,
同时又具备mux的心跳机制保证了链接的稳定性.
13.手册增加了大量配图.
14.优化了socks代理udp上级的设置逻辑,智能判断parent上级填充udp parent.
15.优化了项目文件夹结构,使用源码可以直接go get.
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)代理

2
Godeps/Godeps.json generated
View File

@ -1,5 +1,5 @@
{
"ImportPath": "snail007/proxy",
"ImportPath": "github.com/snail007/goproxy",
"GoVersion": "go1.9",
"GodepVersion": "v80",
"Packages": [

252
README.md
View File

@ -22,7 +22,9 @@ 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.  
- Custom underlying encrypted transmission, HTTP(s)\sps\socks proxy can encrypt TCP data through TLS standard encryption and KCP protocol encryption. In addition, it also supports custom encryption after TLS and KCP. That is to say, custom encryption and tls|kcp can be used together. The internal uses AES256 encryption, and it only needs to define one password by yourself when is used.
- Low level compression and efficient transmissionThe HTTP(s)\sps\socks proxy can encrypt TCP data through a custom encryption and TLS standard encryption and KCP protocol encryption, and can also compress the data after encryption. That is to say, the compression and custom encryption and tls|kcp can be used together.
### 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 +36,10 @@ 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.7 manual, and the other version of the manual can be checked by the following link.
- [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6)
- [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)
@ -83,7 +88,9 @@ This page is the v4.4 manual, and the other version of the manual can be checked
- [1.9 HTTP(S) reverse proxy](#19http-reverse-proxy)
- [1.10 HTTP(S) transparent proxy](#110http-transparent-proxy)
- [1.11 Custom DNS](#111custom-dns)
- [1.12 View help](#112view-help)
- [1.12 Custom encryption](#112-custom-encryption)
- [1.13 Compressed transmission](#113-compressed-transmission)
- [1.14 View help](#114view-help)
- [2.TCP proxy](#2tcp-proxy)
- [2.1 Common TCP first level proxy](#21common-tcp-first-level-proxy)
- [2.2 Common TCP second level proxy](#22common-tcp-second-level-proxy)
@ -119,14 +126,19 @@ This page is the v4.4 manual, and the other version of the manual can be checked
- [5.7 Authentication](#57authentication)
- [5.8 KCP protocol transmission](#58kcp-protocol-transmission)
- [5.9 Custom DNS](#59custom-dns)
- [5.10 View help](#510view-help)
- [5.10 Custom encryption](#510custom-encryption)
- [5.11 Compressed transmission](#511compressed-transmission)
- [5.12 View help](#512view-help)
- [6.Proxy protocol conversion](#6proxy-protocol-conversion)
- [6.1 Functional introduction](#61functional-introduction)
- [6.2 HTTP(S) to HTTP(S) + SOCKS5](#62http-to-http-socks5)
- [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 Custom encryption](#67-custom-encryption)
- [6.8 Compressed transmission](#68-compressed-transmission)
- [6.9 View Help](#69view-help)
- [7.KCP Configuration](#7kcp-configuration)
- [7.1 Configuration introduction](#71configuration-introduction)
- [7.2 Configuration details](#72configuration-details)
@ -148,7 +160,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.7/proxy-linux-amd64.tar.gz
```
#### **2.Download the automatic installation script**
```shell
@ -207,10 +219,11 @@ Assuming that your VPS outer external network IP is 23.23.23.23, the following c
### **1.HTTP proxy**
#### **1.1.common HTTP proxy**
![1.1](/docs/images/1.1.jpg)
![1.1](/docs/images/http-1.png)
`./proxy http -t tcp -p "0.0.0.0:38080"`
#### **1.2.Common HTTP second level proxy**
![1.2](/docs/images/http-2.png)
Using local port 8090, assume the parent HTTP proxy is: `22.22.22.22:8080`
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
The connection pool is closed by default. If you want to speed up access speed, -L can open the connection pool, the 10 is the size of the connection pool, and the 0 is closed.
@ -220,6 +233,7 @@ We can also specify the black and white list files of the domain name, one line
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
#### **1.3.HTTP second level encrypted proxy**
![1.3](/docs/images/http-tls-2.png)
HTTP first level proxy(VPS,IP:22.22.22.22)
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
@ -232,6 +246,7 @@ HTTP second level proxy(local windows)
In your windos system, the mode of the program that needs to surf the Internet by proxy is setted up as HTTP mode, the address is 127.0.0.1, the port is: 8080, the program can go through the encrypted channel through VPS to surf on the internet.
#### **1.4.HTTP third level encrypted proxy**
![1.4](/docs/images/http-tls-3.png)
HTTP first level proxy VPS_01,IP:22.22.22.22
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
HTTP second level proxy VPS_02,IP:33.33.33.33
@ -268,6 +283,7 @@ Through --always, all HTTP proxy traffic can be coercion to the parent HTTP prox
`./proxy http --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
#### **1.7.Transfer through SSH**
![1.7](/docs/images/http-ssh-1.png)
Explanation: the principle of SSH transfer is to take advantage of SSH's forwarding function, which is, after you connect to SSH, you can access to the target address through the SSH proxy.
Suppose there is a vps
- IP is 2.2.2.2, ssh port is 22, ssh username is user, ssh password is demo
@ -281,15 +297,17 @@ 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.
![1.8](/docs/images/http-kcp.png)
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**
![1.9](/docs/images/fxdl.png)
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.  
How to use:  
@ -355,19 +373,61 @@ they also can specify dns result cache time (--dns-ttl) which unit is second. th
for example:
`./proxy http -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
#### **1.12.view help**
#### **1.12 Custom encryption**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy http -t tcp -z demo_password -p :7777`
Local second level execution:
`proxy http -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy http -t tcp -z demo_password -p :7777`
Second level VPS (ip:2.2.2.2) execution:
`proxy http -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
Local third level execution:
`proxy http -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
#### **1.13 Compressed transmission**
HTTP(s) proxy can encrypt TCP data through TCP standard encryption and KCP protocol encryption, and can also compress data before custom encryption.
That is to say, compression and custom encryption and tls|kcp can be used together, compression is divided into two parts, the one is whether the local (-z) is compressed transmission, the other is whether the parents (-Z) is compressed transmission.
The compression requires both ends are proxy. Compression also protects the (encryption) data in certain extent. we use two level example and three level example as examples:
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy http -t tcp -m -p :7777`
Local second level execution:
`proxy http -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.  
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy http -t tcp -m -p :7777`
Second level VPS (ip:3.3.3.3) execution:
`proxy http -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
Local third level execution:
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **1.14.view help**
`./proxy help http`
### **2.TCP proxy**
#### **2.1.Common TCP first level proxy**
![2.1](/docs/images/2.1.png)
![2.1](/docs/images/tcp-1.png)
Local execution:
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22" -L 0`
Then access to the local 33080 port is the 22 port of access to 192.168.22.33.
#### **2.2.Common TCP second level proxy**
![2.2](/docs/images/2.2.png)
![2.2](/docs/images/tcp-2.png)
VPS(IP:22.22.22.33) execute:  
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0`  
local execution:  
@ -375,6 +435,7 @@ local execution:  
Then access to the local 23080 port is the 8080 port of access to 22.22.22.33.
#### **2.3.Common TCP third level proxy**
![2.3](/docs/images/tcp-3.png)
TCP first level proxy VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080" -L 0`
TCP second level proxy VPS_02,IP:33.33.33.33
@ -384,6 +445,7 @@ TCP third level proxy (local)
Then access to the local 8080 port is to access the 8080 port of the 66.66.66.66 by encrypting the TCP tunnel.
#### **2.4.TCP second level encrypted proxy**
![2.4](/docs/images/tcp-tls-2.png)
VPS(IP:22.22.22.33) execute:
`./proxy tcp --tls -p ":33080" -T tcp -P "127.0.0.1:8080" -L 0 -C proxy.crt -K proxy.key`
local execution:
@ -391,6 +453,7 @@ local execution:
Then access to the local 23080 port is to access the 8080 port of the 22.22.22.33 by encrypting the TCP tunnel.
#### **2.5.TCP third level encrypted proxy**
![2.5](/docs/images/tcp-tls-3.png)
TCP first level proxy VPS_01,IP:22.22.22.22
`./proxy tcp --tls -p ":38080" -T tcp -P "66.66.66.66:8080" -C proxy.crt -K proxy.key`
TCP second level proxy VPS_02,IP:33.33.33.33
@ -405,11 +468,13 @@ Then access to the local 8080 port is to access the 8080 port of the 66.66.66.66
### **3.UDP proxy**
#### **3.1.Common UDP first level proxy**
![3.1](/docs/images/udp-1.png)
local execution:
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
Then access to the local UDP:5353 port is access to the UDP:53 port of the 8.8.8.8.
#### **3.2.Common UDP second level proxy**
![3.2](/docs/images/udp-2.png)
VPS(IP:22.22.22.33) execute:
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"`
local execution:
@ -417,6 +482,7 @@ local execution:
Then access to the local UDP:5353 port is access to the UDP:53 port of the 8.8.8.8 through the TCP tunnel.
#### **3.3.Common UDP third level proxy**
![3.3](/docs/images/udp-3.png)
TCP first level proxy VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
TCP second level proxy VPS_02,IP:33.33.33.33
@ -426,6 +492,7 @@ TCP third level proxy (local)
Then access to the local 5353 port is access to the 53 port of the 8.8.8.8 through the TCP tunnel.
#### **3.4.UDP second level encrypted proxy**
![3.4](/docs/images/udp-tls-2.png)
VPS(IP:22.22.22.33) execute:
`./proxy tcp --tls -p ":33080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
local execution:
@ -433,6 +500,7 @@ local execution:
Then access to the local UDP:5353 port is access to the UDP:53 port of the 8.8.8.8 by the encrypting TCP tunnel.
#### **3.5.UDP third level encrypted proxy**
![3.5](/docs/images/udp-tls-3.png)
TCP first level proxy VPS_01,IP:22.22.22.22
`./proxy tcp --tls -p ":38080" -T udp -P "8.8.8.8:53" -C proxy.crt -K proxy.key`
TCP second level proxy VPS_02,IP:33.33.33.33
@ -589,6 +657,7 @@ Tips: SOCKS5 proxy, support CONNECT, UDP protocol and don't support BIND and sup
`./proxy socks -t tcp -p "0.0.0.0:38080"`
#### **5.2.Common SOCKS5 second level proxy**
![5.2](/docs/images/socks-2.png)
![5.2](/docs/images/5.2.png)
Using local port 8090, assume that the parent SOCKS5 proxy is `22.22.22.22:8080`
`./proxy socks -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
@ -596,6 +665,7 @@ We can also specify the black and white list files of the domain name, one line
`./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 second level encrypted proxy**
![5.3](/docs/images/socks-tls-2.png)
SOCKS5 first level proxy(VPS,IP:22.22.22.22)
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
@ -608,6 +678,7 @@ SOCKS5 second level proxy(local windows)
Then set up your windows system, the proxy that needs to surf the Internet by proxy is Socks5 mode, the address is: 127.0.0.1, the port is: 8080. the program can surf the Internet through the encrypted channel which is running on VPS.  
#### **5.4.SOCKS third level encrypted proxy**
![5.4](/docs/images/socks-tls-3.png)
SOCKS5 first level proxy VPS_01,IP:22.22.22.22
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
SOCKS5 second level proxy VPS_02,IP:33.33.33.33
@ -621,6 +692,7 @@ By default, proxy will intelligently judge whether a domain name can be accessed
`./proxy socks --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
#### **5.6.Transfer through SSH**
![5.6](/docs/images/socks-ssh.png)
Explanation: the principle of SSH transfer is to take advantage of SSH's forwarding function, which is, after you connect to SSH, you can access the target address by the SSH.  
Suppose there is a vps
- IP is 2.2.2.2, SSH port is 22, SSH username is user, SSH password is Demo
@ -657,13 +729,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**
@ -672,8 +744,49 @@ they also can specify dns result cache time (--dns-ttl) which unit is second. th
for example:
`./proxy socks -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
#### **5.10.Custom encryption**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
#### **5.10.view help**
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy socks -t tcp -z demo_password -p :7777`
Local second level execution:
`proxy socks -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy socks -t tcp -z demo_password -p :7777`
Second level VPS (ip:2.2.2.2) execution:
`proxy socks -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
Local third level execution:
`proxy socks -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
#### **5.11.Compressed transmission**
HTTP(s) proxy can encrypt TCP data through TCP standard encryption and KCP protocol encryption, and can also compress data before custom encryption.
That is to say, compression and custom encryption and tls|kcp can be used together, compression is divided into two parts, the one is whether the local (-z) is compressed transmission, the other is whether the parents (-Z) is compressed transmission.
The compression requires both ends are proxy. Compression also protects the (encryption) data in certain extent. we use two level example and three level example as examples:
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy socks -t tcp -m -p :7777`
Local second level execution:
`proxy socks -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy socks -t tcp -m -p :7777`
Second level VPS (ip:3.3.3.3) execution:
`proxy socks -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
Local third level execution:
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **5.12.view help**
`./proxy help socks`
### **6.Proxy protocol conversion**
@ -692,7 +805,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,9 +818,10 @@ 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**
![6.4](/docs/images/sps-tls.png)
It is mentioned above that multiple SPS nodes can be connected to build encrypted channels, assuming you have the following VPS and a PC.
vps012.2.2.2
vps023.3.3.3
@ -730,7 +844,91 @@ 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 Custom encryption**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
Suppose there is already a HTTP (s) proxy:`6.6.6.6:6666`
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
Local second level execution:
`proxy sps -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
Second level VPS (ip:2.2.2.2) execution:
`proxy sps -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
Local third level execution:
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
#### **6.8 Compressed transmission**
HTTP(s) proxy can encrypt TCP data through TCP standard encryption and KCP protocol encryption, and can also compress data before custom encryption.
That is to say, compression and custom encryption and tls|kcp can be used together, compression is divided into two parts, the one is whether the local (-z) is compressed transmission, the other is whether the parents (-Z) is compressed transmission.
The compression requires both ends are proxy. Compression also protects the (encryption) data in certain extent. we use two level example and three level example as examples:
**two level example**
First level VPS (ip:2.2.2.2) execution:
`proxy sps -t tcp -m -p :7777`
Local second level execution:
`proxy sps -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy sps -t tcp -m -p :7777`
Second level VPS (ip:3.3.3.3) execution::
`proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
Local third level execution:
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **6.9.view help**
`./proxy help sps`
### **7.KCP Configuration**
@ -767,13 +965,13 @@ If you want to get a more detailed configuration and explanation of the KCP para
### TODO
- Welcome joining group feedback...
### How to use the source code?
use command cd to enter your go SRC directory and then
mkdir snail007
cd snail007
execute `git clone https://github.com/snail007/goproxy.git ./proxy`
Direct compilation: `go build`
execution: `go run *.go`
### How to use the source code?
Recommend go1.8.5, which does not guarantee that version >=1.9 can be used.
`go get github.com/snail007/goproxy`
use command cd to enter your go SRC directory
then cd to enter `github.com/snail007/goproxy`.
Direct compilation:`go build -o proxy`
execution: `go run *.go`
`utils` is a toolkit, and `service` is a specific service class.
### License

View File

@ -23,7 +23,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- 集成外部APIHTTP(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功能,同时支持强大的级联认证功能。
- 自定义底层加密传输http(s)\sps\socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可。
- 底层压缩高效传输http(s)\sps\socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在加密之后还可以对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的。
### Why need these?
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.
@ -35,7 +37,10 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- ...
本页是v4.4手册,其他版本手册请点击下面链接查看.
本页是v4.7手册,其他版本手册请点击下面链接查看.
- [v4.6手册](https://github.com/snail007/goproxy/tree/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)
@ -82,7 +87,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [1.9 HTTP(S)反向代理](#19-https反向代理)
- [1.10 HTTP(S)透明代理](#110-https透明代理)
- [1.11 自定义DNS](#111-自定义dns)
- [1.12 查看帮助](#112-查看帮助)
- [1.12 自定义加密](#112-自定义加密)
- [1.13 压缩传输](#113-压缩传输)
- [1.14 查看帮助](#114-查看帮助)
- [2. TCP代理](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
@ -118,14 +125,19 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [5.7 认证](#57认证)
- [5.8 KCP协议传输](#58kcp协议传输)
- [5.9 自定义DNS](#59自定义dns)
- [5.10 查看帮助](#510查看帮助)
- [5.10 自定义加密](#510-自定义加密)
- [5.11 压缩传输](#511-压缩传输)
- [5.12 查看帮助](#512查看帮助)
- [6. 代理协议转换](#6代理协议转换)
- [6.1 功能介绍](#61-功能介绍)
- [6.2 HTTP(S)转HTTP(S)+SOCKS5](#62-https转httpssocks5)
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
- [6.4 链式连接](#64-链式连接)
- [6.5 监听多个端口](#65-监听多个端口)
- [6.6 查看帮助](#66-查看帮助)
- [6.6 认证功能](#66-认证功能)
- [6.7 自定义加密](#67-自定义加密)
- [6.8 压缩传输](#68-压缩传输)
- [6.9 查看帮助](#69-查看帮助)
- [7. KCP配置](#7kcp配置)
- [7.1 配置介绍](#71-配置介绍)
- [7.2 详细配置](#72-详细配置)
@ -146,7 +158,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.7/proxy-linux-amd64.tar.gz
```
#### **2.下载自动安装脚本**
```shell
@ -187,7 +199,8 @@ http,tcp,udp代理过程会和上级通讯,为了安全我们采用加密通讯,
在linux上并安装了openssl命令可以直接通过下面的命令生成证书和key文件.
`./proxy keygen`
默认会在当前程序目录下面生成证书文件proxy.crt和key文件proxy.key。
更多用法:`proxy keygen usage`
### **后台运行**
默认执行proxy之后,如果要保持proxy运行,不能关闭命令行.
如果想在后台运行proxy,命令行可以关闭,只需要在命令最后加上--daemon参数即可.
@ -207,20 +220,19 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
`./proxy http -g "23.23.23.23"`
### **1.HTTP代理**
#### **1.1.普通HTTP代理**
![1.1](/docs/images/1.1.jpg)
#### **1.1.普通一级HTTP代理**
![1.1](/docs/images/http-1.png)
`./proxy http -t tcp -p "0.0.0.0:38080"`
#### **1.2.普通二级HTTP代理**
![1.2](/docs/images/http-2.png)
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080`
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
默认关闭了连接池,如果要加快访问速度,-L可以开启连接池,10就是连接池大小,0为关闭,
开启连接池在网络不好的情况下,稳定不是很好.
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -L 10`
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理.
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
#### **1.3.HTTP二级代理(加密)**
![1.3](/docs/images/http-tls-2.png)
一级HTTP代理(VPS,IP:22.22.22.22)
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
@ -233,6 +245,7 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
然后设置你的windos系统中需要通过代理上网的程序的代理为http模式地址为127.0.0.1端口为8080,程序即可通过加密通道通过vps上网。
#### **1.4.HTTP三级代理(加密)**
![1.3](/docs/images/http-tls-3.png)
一级HTTP代理VPS_01,IP:22.22.22.22
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
二级HTTP代理VPS_02,IP:33.33.33.33
@ -268,6 +281,7 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
`./proxy http --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
#### **1.7.HTTP(S)通过SSH中转**
![1.7](/docs/images/http-ssh-1.png)
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
假设有:vps
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
@ -281,16 +295,18 @@ 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参数设置一个密码用于加密解密数据
![1.8](/docs/images/http-kcp.png)
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)反向代理**
#### **1.9 HTTP(S)反向代理**
![1.9](/docs/images/fxdl.png)
proxy不仅支持在其他软件里面通过设置代理的方式,为其他软件提供代理服务,而且支持直接把请求的网站域名解析到proxy监听的ip上,然后proxy监听80和443端口,那么proxy就会自动为你代理访问需要访问的HTTP(S)网站.
使用方式:
@ -303,7 +319,7 @@ proxy不仅支持在其他软件里面通过设置代理的方式,为其他软
`./proxy http -t tcp -p :80,:443 -T tls -P "2.2.2.2:33080" -C proxy.crt -K proxy.key`
注意:
proxy所在的服务器的DNS解析结果不能受到自定义的解析影响,不然就死循环了.
proxy所在的服务器的DNS解析结果不能受到自定义的解析影响,不然就死循环了,proxy代理最好指定`--dns 8.8.8.8`参数.
#### **1.10 HTTP(S)透明代理**
该模式需要具有一定的网络基础,相关概念不懂的请自行搜索解决.
@ -356,19 +372,65 @@ iptables -t nat -A OUTPUT -p tcp -j PROXY
比如:
`./proxy http -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
#### **1.12 查看帮助**
#### **1.12 自定义加密**
proxy的http(s)代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义
加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可,
加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
自定义加密要求两端都是proxy才可以,下面分别用二级,三级为例:
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy http -t tcp -z demo_password -p :7777`
本地二级执行:
`proxy http -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy http -t tcp -z demo_password -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy http -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
本地三级执行:
`proxy http -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
#### **1.13 压缩传输**
proxy的http(s)代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以对数据进行压缩,
也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,一部分是本地(-m)是否压缩传输,
一部分是与上级(-M)传输是否压缩.
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据,下面分别用二级,三级为例:
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy http -t tcp -m -p :7777`
本地二级执行:
`proxy http -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy http -t tcp -m -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy http -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
本地三级执行:
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
#### **1.14 查看帮助**
`./proxy help http`
### **2.TCP代理**
#### **2.1.普通一级TCP代理**
![2.1](/docs/images/2.1.png)
![2.1](/docs/images/tcp-1.png)
本地执行:
`./proxy tcp -p ":33080" -T tcp -P "192.168.22.33:22"`
那么访问本地33080端口就是访问192.168.22.33的22端口.
#### **2.2.普通二级TCP代理**
![2.2](/docs/images/2.2.png)
![2.2](/docs/images/tcp-2.png)
VPS(IP:22.22.22.33)执行:
`./proxy tcp -p ":33080" -T tcp -P "127.0.0.1:8080"`
本地执行:
@ -376,6 +438,7 @@ VPS(IP:22.22.22.33)执行:
那么访问本地23080端口就是访问22.22.22.33的8080端口.
#### **2.3.普通三级TCP代理**
![2.3](/docs/images/tcp-3.png)
一级TCP代理VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T tcp -P "66.66.66.66:8080"`
二级TCP代理VPS_02,IP:33.33.33.33
@ -385,17 +448,19 @@ VPS(IP:22.22.22.33)执行:
那么访问本地8080端口就是通过加密TCP隧道访问66.66.66.66的8080端口.
#### **2.4.加密二级TCP代理**
![2.4](/docs/images/tcp-tls-2.png)
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代理**
![2.5](/docs/images/tcp-tls-3.png)
一级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端口.
@ -406,11 +471,13 @@ VPS(IP:22.22.22.33)执行:
### **3.UDP代理**
#### **3.1.普通一级UDP代理**
![3.1](/docs/images/udp-1.png)
本地执行:
`./proxy udp -p ":5353" -T udp -P "8.8.8.8:53"`
那么访问本地UDP:5353端口就是访问8.8.8.8的UDP:53端口.
#### **3.2.普通二级UDP代理**
![3.2](/docs/images/udp-2.png)
VPS(IP:22.22.22.33)执行:
`./proxy tcp -p ":33080" -T udp -P "8.8.8.8:53"`
本地执行:
@ -418,6 +485,7 @@ VPS(IP:22.22.22.33)执行:
那么访问本地UDP:5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的UDP:53端口.
#### **3.3.普通三级UDP代理**
![3.3](/docs/images/udp-3.png)
一级TCP代理VPS_01,IP:22.22.22.22
`./proxy tcp -p ":38080" -T udp -P "8.8.8.8:53"`
二级TCP代理VPS_02,IP:33.33.33.33
@ -427,17 +495,19 @@ VPS(IP:22.22.22.33)执行:
那么访问本地5353端口就是通过TCP隧道,通过VPS访问8.8.8.8的53端口.
#### **3.4.加密二级UDP代理**
![3.4](/docs/images/udp-tls-2.png)
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代理**
![3.5](/docs/images/udp-tls-3.png)
一级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端口.
@ -593,13 +663,14 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
`./proxy socks -t tcp -p "0.0.0.0:38080"`
#### **5.2.普通二级SOCKS5代理**
![5.2](/docs/images/5.2.png)
![5.2](/docs/images/socks-2.png)
使用本地端口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二级代理(加密)**
![5.3](/docs/images/socks-tls-2.png)
一级SOCKS代理(VPS,IP:22.22.22.22)
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
@ -612,6 +683,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
然后设置你的windos系统中需要通过代理上网的程序的代理为socks5模式地址为127.0.0.1端口为8080,程序即可通过加密通道通过vps上网。
#### **5.4.SOCKS三级代理(加密)**
![5.4](/docs/images/socks-tls-3.png)
一级SOCKS代理VPS_01,IP:22.22.22.22
`./proxy socks -t tls -p ":38080" -C proxy.crt -K proxy.key`
二级SOCKS代理VPS_02,IP:33.33.33.33
@ -625,6 +697,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
`./proxy socks --always -t tls -p ":28080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
#### **5.6.SOCKS通过SSH中转**
![5.6](/docs/images/socks-ssh.png)
说明:ssh中转的原理是利用了ssh的转发功能,就是你连接上ssh之后,可以通过ssh代理访问目标地址.
假设有:vps
- IP是2.2.2.2, ssh端口是22, ssh用户名是:user, ssh用户密码是:demo
@ -661,13 +734,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**
@ -676,7 +749,58 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
比如:
`./proxy socks -p ":33080" --dns-address "8.8.8.8:53" --dns-ttl 300`
#### **5.10.查看帮助**
#### **5.10 自定义加密**
proxy的socks代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义一个密码即可,
加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
自定义加密要求两端都是proxy才可以.
下面分别用二级,三级为例:
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy socks -t tcp -z demo_password -p :7777`
本地二级执行:
`proxy socks -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy socks -t tcp -z demo_password -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy socks -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
本地三级执行:
`proxy socks -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
#### **5.11 压缩传输**
proxy的socks代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据.
下面分别用二级,三级为例:
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy socks -t tcp -m -p :7777`
本地二级执行:
`proxy socks -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy socks -t tcp -m -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy socks -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
本地三级执行:
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
#### **5.12.查看帮助**
`./proxy help socks`
### **6.代理协议转换**
@ -695,7 +819,7 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
假设已经存在一个kcp的http(s)代理密码是demo123127.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,9 +832,10 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
假设已经存在一个kcp的socks5代理密码是demo123127.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 链式连接**
#### **6.4 链式连接**
![6.4](/docs/images/sps-tls.png)
上面提过多个sps结点可以层级连接构建加密通道假设有如下vps和家里的pc电脑。
vps012.2.2.2
vps023.3.3.3
@ -733,7 +858,105 @@ vps023.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的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
自定义加密,也就是说自定义加密和tls|kcp是可以联合使用的,内部采用AES256加密,使用的时候只需要自己定义
一个密码即可,加密分为两个部分,一部分是本地(-z)是否加密解密,一部分是与上级(-Z)传输是否加密解密.
自定义加密要求两端都是proxy才可以.
下面分别用二级,三级为例:
假设已经存在一个http(s)代理:`6.6.6.6:6666`
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
本地二级执行:
`proxy sps -T tcp -P 2.2.2.2:777 -Z demo_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy sps -S http -T tcp -P 6.6.6.6:6666 -t tcp -z demo_password -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy sps -T tcp -P 2.2.2.2:7777 -Z demo_password -t tcp -z other_password -p :8888`
本地三级执行:
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级加密传输访问目标网站.
#### **6.8 压缩传输**
proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及kcp协议加密tcp数据,在自定义加密之前还可以
对数据进行压缩,也就是说压缩功能和自定义加密和tls|kcp是可以联合使用的,压缩分为两个部分,
一部分是本地(-m)是否压缩传输,一部分是与上级(-M)传输是否压缩.
压缩要求两端都是proxy才可以,压缩也在一定程度上保护了(加密)数据.
下面分别用二级,三级为例:
**二级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy sps -t tcp -m -p :7777`
本地二级执行:
`proxy sps -T tcp -P 2.2.2.2:777 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
**三级实例**
一级vps(ip:2.2.2.2)上执行:
`proxy sps -t tcp -m -p :7777`
二级vps(ip:3.3.3.3)上执行:
`proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
本地三级执行:
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
#### **6.9 查看帮助**
`./proxy help sps`
### **7.KCP配置**
@ -780,12 +1003,13 @@ fast3`--nodelay=1 --interval=10 --resend=2 --nc=1`
- 欢迎加群反馈...
### 如何使用源码?
建议go1.8.5,不保证>=1.9能用.
cd进入你的go src目录,新建文件夹snail007,
cd进入snail007,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.
编译直接:go build
运行: go run *.go
utils是工具包,service是具体的每个服务类.
建议go1.8.5,不保证>=1.9能用.
`go get github.com/snail007/goproxy`
cd进入你的go src目录
cd进入`github.com/snail007/goproxy`即可.
编译直接:`go build -o proxy`
运行: `go run *.go`
utils是工具包,service是具体的每个服务类.
### License
Proxy is licensed under GPLv3 license.

View File

@ -4,12 +4,12 @@ import (
"bufio"
"crypto/sha1"
"fmt"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"log"
"os"
"os/exec"
"snail007/proxy/services"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils"
"time"
kcp "github.com/xtaci/kcp-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")
@ -85,7 +86,6 @@ func initConfig() (err error) {
httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
@ -99,6 +99,10 @@ func initConfig() (err error) {
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode")
@ -108,7 +112,6 @@ func initConfig() (err error) {
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.PoolSize = tcp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
@ -119,38 +122,40 @@ func initConfig() (err error) {
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
udpArgs.PoolSize = udp.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########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 +191,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()
@ -205,11 +211,17 @@ func initConfig() (err error) {
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//########socks+http(s)#########
sps := app.Command("sps", "proxy on socks+http(s) mode")
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
spsArgs.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,6 +229,18 @@ 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()
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
@ -264,6 +288,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

BIN
docs/images/fxdl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/images/http-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/images/http-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/http-kcp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/http-ssh-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/images/http-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/http-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
docs/images/socks-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/images/socks-ssh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/images/socks-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/images/socks-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/sps-tls.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/images/tcp-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/images/tcp-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/images/tcp-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/tcp-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/images/tcp-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/udp-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/images/udp-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/images/udp-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/images/udp-tls-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/images/udp-tls-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

27
gui/README.md Normal file
View File

@ -0,0 +1,27 @@
# Proxy-GUI
基于proxy的各平台SDK,作者和众多热心人士开发了各平台的GUI版本的proxy,下面分平台介绍.
## Windows
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## Linux
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## MacOS
- Coming Soon ...
## Android
- proxy-go,一个非官方实现版本,界面比较简陋,但是够用.下载地址:[proxy-go](https://github.com/snail007/goproxy-gui-stuff/releases/tag/proxy-go-release)
## IOS
- Coming Soon ...
## 跨平台
- proxy-web,一个跨平台的web UI版本,项目主页:[proxy-web](https://github.com/yincongcyincong/proxy-web)

View File

@ -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.7/proxy-linux-amd64.tar.gz
# #install proxy
tar zxvf proxy-linux-amd64.tar.gz

View File

@ -1,14 +1,14 @@
package main
import (
"github.com/snail007/goproxy/services"
"log"
"os"
"os/signal"
"snail007/proxy/services"
"syscall"
)
const APP_VERSION = "4.4"
const APP_VERSION = "4.7"
func main() {
err := initConfig()

View File

@ -1,72 +1,74 @@
#!/bin/bash
VER="4.4"
VER="4.7"
RELEASE="release-${VER}"
rm -rf .cert
mkdir .cert
go build
go build -o proxy
cd .cert
../proxy keygen
cd ..
rm -rf ${RELEASE}
mkdir ${RELEASE}
#linux
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-linux-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-linux-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v6.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=6 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v6.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v7.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=7 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v7.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build && tar zcfv "${RELEASE}/proxy-linux-arm-v5.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=5 go build && tar zcfv "${RELEASE}/proxy-linux-arm64-v5.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build && tar zcfv "${RELEASE}/proxy-linux-mips.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build && tar zcfv "${RELEASE}/proxy-linux-mips64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build && tar zcfv "${RELEASE}/proxy-linux-mips64le.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build && tar zcfv "${RELEASE}/proxy-linux-mipsle.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64 go build && tar zcfv "${RELEASE}/proxy-linux-ppc64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le go build && tar zcfv "${RELEASE}/proxy-linux-ppc64le.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=s390x go build && tar zcfv "${RELEASE}/proxy-linux-s390x.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm-v6.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=6 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm64-v6.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm-v7.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=7 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm64-v7.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm-v5.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=5 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-arm64-v5.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-mips.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-mips64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-mips64le.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-mipsle.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64 go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-ppc64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=ppc64le go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-ppc64le.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=linux GOARCH=s390x go build -o proxy && tar zcfv "${RELEASE}/proxy-linux-s390x.tar.gz" proxy direct blocked
#android
CGO_ENABLED=0 GOOS=android GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-android-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-android-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-android-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-android-arm64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-android-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-android-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-android-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=android GOARCH=arm64 go build -o proxy && tar zcfv "${RELEASE}/proxy-android-arm64.tar.gz" proxy direct blocked
#darwin
CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-darwin-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-darwin-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-darwin-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build && tar zcfv "${RELEASE}/proxy-darwin-arm64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-darwin-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-darwin-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-darwin-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o proxy && tar zcfv "${RELEASE}/proxy-darwin-arm64.tar.gz" proxy direct blocked
#dragonfly
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-dragonfly-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-dragonfly-amd64.tar.gz" proxy direct blocked
#freebsd
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-freebsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-freebsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-freebsd-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-freebsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-freebsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-freebsd-arm.tar.gz" proxy direct blocked
#nacl
CGO_ENABLED=0 GOOS=nacl GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-nacl-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=nacl GOARCH=amd64p32 go build && tar zcfv "${RELEASE}/proxy-nacl-amd64p32.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=nacl GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-nacl-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=nacl GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-nacl-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=nacl GOARCH=amd64p32 go build -o proxy && tar zcfv "${RELEASE}/proxy-nacl-amd64p32.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=nacl GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-nacl-arm.tar.gz" proxy direct blocked
#netbsd
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-netbsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-netbsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-netbsd-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-netbsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-netbsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-netbsd-arm.tar.gz" proxy direct blocked
#openbsd
CGO_ENABLED=0 GOOS=openbsd GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-openbsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-openbsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-openbsd-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=openbsd GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-openbsd-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-openbsd-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-openbsd-arm.tar.gz" proxy direct blocked
#plan9
CGO_ENABLED=0 GOOS=plan9 GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-plan9-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=plan9 GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-plan9-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=plan9 GOARCH=arm go build && tar zcfv "${RELEASE}/proxy-plan9-arm.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=plan9 GOARCH=386 go build -o proxy && tar zcfv "${RELEASE}/proxy-plan9-386.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=plan9 GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-plan9-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=plan9 GOARCH=arm go build -o proxy && tar zcfv "${RELEASE}/proxy-plan9-arm.tar.gz" proxy direct blocked
#solaris
CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
CGO_ENABLED=0 GOOS=solaris GOARCH=amd64 go build -o proxy && tar zcfv "${RELEASE}/proxy-solaris-amd64.tar.gz" proxy direct blocked
#windows
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-386.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-H=windowsgui" -o proxy-wingui.exe
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o proxy.exe && tar zcfv "${RELEASE}/proxy-windows-amd64.tar.gz" proxy.exe proxy-wingui.exe direct blocked .cert/proxy.crt .cert/proxy.key
rm -rf proxy proxy.exe .cert
rm -rf proxy proxy.exe proxy-wingui.exe .cert
#todo
#1.release.sh VER="xxx"
#2.main.go APP_VERSION="xxx"
#3.install_auto.sh goproxy/releases/download/vxxx
#4.README goproxy/releases/download/vxxx
#4.README goproxy/releases/download/vxxx

259
sdk/README.md Normal file
View File

@ -0,0 +1,259 @@
# Proxy SDK 使用说明
支持以下平台:
- Android,`.arr`
- IOS,`.framework`
- Windows,`.dll`
- Linux,`.so`
- MacOS,`.dylib`
proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库,
另外还为linux和windows提供sdk支持基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。
# 下面分平台介绍SDK的用法
## Android SDK
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-android/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-android.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-android/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-android/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-android.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-android/releases)
[点击下载Android-SDK](https://github.com/snail007/goproxy-sdk-android/releases)
在Android系统提供的sdk形式是一个后缀为.aar的类库文件,开发的时候只需要把arr类库文件引入android项目即可.
### Android-SDK使用实例
#### 1.导入包
```java
import snail007.proxy.Porxy
```
#### 2.启动一个服务
```java
String serviceID="http01";//这里serviceID是自定义的唯一标识字符串,保证每个启动的服务不一样即可
String serviceArgs="http -p :8080";
String err=Proxy.start(serviceID,serviceArgs);
if (!err.isEmpty()){
//启动失败
System.out.println("start fail,error:"+err);
}else{
//启动成功
}
```
#### 3.停止一个服务
```java
String serviceID="http01";
Proxy.stop(serviceID);
//停止完毕
```
## IOS SDK
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-ios/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-ios.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-ios/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-ios/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-ios.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-ios/releases)
[点击下载IOS-SDK](https://github.com/snail007/goproxy-sdk-ios/releases)
在IOS系统提供的sdk形式是一个后缀为.framework的类库文件夹,开发的时候只需要把类库文件引入项目,然后调用方法即可.
### IOS-SDK使用实例
#### 导入包
```objc
#import <Proxy/Proxy.objc.h>
```
#### 2.启动一个服务
```objc
-(IBAction)doStart:(id)sender
{
//这里serviceID是自定义的唯一标识字符串,保证每个启动的服务不一样
NSString *serviceID = @"http01";
NSString *serviceArgs = @"http -p :8080";
NSString *error = ProxyStart(serviceID,serviceArgs);
if (error != nil && error.length > 0)
{
NSLog(@"start error %@",error);
}else{
NSLog(@"启动成功");
}
}
```
#### 3.停止一个服务
```objc
-(IBAction)doStop:(id)sender
{
NSString *serviceID = @"http01";
ProxyStop(serviceID);
//停止完毕
}
```
## Windows SDK
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-windows/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-windows.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-windows/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-windows/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-windows.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-windows/releases)
[点击下载Windows-SDK](https://github.com/snail007/goproxy-sdk-windows/releases)
在Windows系统提供的sdk形式是一个后缀为.dll的类库文件,开发的时候只需要把dll类库文件加载,然后调用方法即可.
### Windows-SDK使用实例
C++示例不需要包含头文件只需要加载proxy-sdk.dll即可ieshims.dll需要和proxy-sdk.dll在一起。
作者:[yjbdsky](https://github.com/yjbdsky)
```cpp
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include<pthread.h>
#include<Windows.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef char *(*GOSTART)(char *s);
typedef char *(*GOSTOP)(char *s);
typedef int(*GOISRUN)(char *s);
HMODULE GODLL = LoadLibrary("proxy-sdk.dll");
char * Start(char * p0,char * p1)
{
if (GODLL != NULL)
{
GOSTART gostart = *(GOSTART)(GetProcAddress(GODLL, "Start"));
if (gostart != NULL){
printf("%s:%s\n",p0, p1);
char *ret = gostart(p0,p1);
return ret;
}
}
return "Cannot Find dll";
}
char * Stop(char * p)
{
if (GODLL != NULL)
{
GOSTOP gostop = *(GOSTOP)(GetProcAddress(GODLL, "Stop"));
if (gostop != NULL){
printf("%s\n", p);
char *ret = gostop(p);
return ret;
}
}
return "Cannot Find dll";
}
int main()
{
//这里p0是自定义的唯一标识字符串,保证每个启动的服务不一样
char *p0 = "http01";
char *p1 = "http -t tcp -p :38080";
printf("This is demo application.\n");
//启动服务,返回空字符串说明启动成功;返回非空字符串说明启动失败,返回的字符串是错误原因
printf("start result %s\n", Start(p0,p1));
//停止服务,没有返回值
Stop(p0);
return 0;
}
#ifdef __cplusplus
}
#endif
```
C++示例2请移步[GoProxyForC](https://github.com/SuperPowerLF2/GoProxyForC)
## Linux SDK
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-linux/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-linux.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-linux/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-linux/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-linux.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-linux/releases)
[点击下载Linux-SDK](https://github.com/snail007/goproxy-sdk-linux/releases)
在Linux系统提供的sdk形式是一个后缀为.so的类库文件,开发的时候只需要把so类库加载,调用方法即可.
### Linux-SDK使用实例
Linux下面使用的sdk是so文件即libproxy-sdk.so,下面写一个简单的C程序示例,调用so库里面的方法.
`vi test-proxy.c`
```c
#include <stdio.h>
#include "libproxy-sdk.h"
int main() {
printf("This is demo application.\n");
//这里p0是自定义的唯一标识字符串,保证每个启动的服务不一样
char *p0 = "http01";
char *p1 = "http -t tcp -p :38080";
//启动服务,返回空字符串说明启动成功;返回非空字符串说明启动失败,返回的字符串是错误原因
printf("start result %s\n",Start(p0,p1));
//停止服务,没有返回值
Stop(p0);
return 0;
}
```
#### 编译test-proxy.c ####
`export LD_LIBRARY_PATH=./ && gcc -o test-proxy test.c libproxy-sdk.so`
#### 执行 ####
`./test-proxy`
## MacOS SDK
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy-sdk-mac/) [![license](https://img.shields.io/github/license/snail007/goproxy-sdk-mac.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy-sdk-mac/total.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-mac/releases) [![download](https://img.shields.io/github/release/snail007/goproxy-sdk-mac.svg?style=plastic)](https://github.com/snail007/goproxy-sdk-mac/releases)
[点击下载MacOS-SDK](https://github.com/snail007/goproxy-sdk-mac/releases)
在MacOS系统提供的sdk形式是一个后缀为.dylib的类库文件,开发的时候只需要把so类库加载,调用方法即可.
### MacOS-SDK使用实例
MacOS下面使用的sdk是dylib文件即libproxy-sdk.dylib,下面写一个简单的Obj-C程序示例,调用dylib库里面的方法.
```objc
#import "libproxy-sdk.h"
-(IBAction)doStart:(id)sender
{
char *result = Start("http01", "http -t tcp -p :38080");
if (result)
{
printf("started");
}else{
printf("not started");
}
}
-(IBAction)doStop:(id)sender
{
Stop("http01");
}
```
### 关于服务
proxy的服务有11种,分别是:
```shell
http
socks
sps
tcp
udp
bridge
server
client
tbridge
tserver
tclient
```
服务启动时,如果存在正在运行的相同ID的服务,那么之前的服务会被停掉,后面启动的服务覆盖之前的服务.
所以要保证每次启动服务的时候,第一个ID参数唯一.
上面这些服务的具体使用方式和具体参数,可以参考[proxy手册](https://github.com/snail007/goproxy/blob/master/README_ZH.md)
sdk里面的服务不支持手册里面的--daemon和--forever参数.

7
sdk/android-ios/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.jar
*.aar
*.tar.gz
ios
android
Proxy.framework

View File

@ -0,0 +1,15 @@
#/bin/bash
VER="v4.7"
rm -rf sdk-android-*.tar.gz
rm -rf android
mkdir android
#android
gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w"
mv proxy.aar android/snail007.goproxy.sdk.aar
mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar
cp ../README.md android
tar zcfv sdk-android-${VER}.tar.gz android
rm -rf android
echo "done."

14
sdk/android-ios/release_ios.sh Executable file
View File

@ -0,0 +1,14 @@
#/bin/bash
VER="v4.7"
rm -rf sdk-ios-*.tar.gz
rm -rf ios
mkdir ios
#ios XCode required
gomobile bind -v -target=ios -ldflags="-s -w"
mv Proxy.framework ios
cp ../README.md ios
tar zcfv sdk-ios-${VER}.tar.gz ios
rm -rf ios
echo "done."

351
sdk/android-ios/sdk.go Normal file
View File

@ -0,0 +1,351 @@
package proxy
import (
"crypto/sha1"
"fmt"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"log"
"os"
"strings"
kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
var (
app *kingpin.Application
)
//Start
//serviceID : is service identify id,different service's id should be difference
//serviceArgsStr: is the whole command line args string
//such as :
//1."http -t tcp -p :8989"
//2."socks -t tcp -p :8989"
//and so on.
//if an error occured , errStr will be the error reason
//if start success, errStr is empty.
func Start(serviceID, serviceArgsStr string) (errStr string) {
//define args
tcpArgs := services.TCPArgs{}
httpArgs := services.HTTPArgs{}
tunnelServerArgs := services.TunnelServerArgs{}
tunnelClientArgs := services.TunnelClientArgs{}
tunnelBridgeArgs := services.TunnelBridgeArgs{}
muxServerArgs := services.MuxServerArgs{}
muxClientArgs := services.MuxClientArgs{}
muxBridgeArgs := services.MuxBridgeArgs{}
udpArgs := services.UDPArgs{}
socksArgs := services.SocksArgs{}
spsArgs := services.SPSArgs{}
kcpArgs := kcpcfg.KCPConfigArgs{}
//build srvice args
app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version("4.7")
debug := app.Flag("debug", "debug log output").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String()
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
kcpArgs.ParityShard = app.Flag("kcp-ps", "set reed-solomon erasure coding - parityshard").Default("3").Int()
kcpArgs.DSCP = app.Flag("kcp-dscp", "set DSCP(6bit)").Default("0").Int()
kcpArgs.NoComp = app.Flag("kcp-nocomp", "disable compression").Default("false").Bool()
kcpArgs.AckNodelay = app.Flag("kcp-acknodelay", "be carefull! flush ack immediately when a packet is received").Default("true").Bool()
kcpArgs.NoDelay = app.Flag("kcp-nodelay", "be carefull!").Default("0").Int()
kcpArgs.Interval = app.Flag("kcp-interval", "be carefull!").Default("50").Int()
kcpArgs.Resend = app.Flag("kcp-resend", "be carefull!").Default("0").Int()
kcpArgs.NoCongestion = app.Flag("kcp-nc", "be carefull! no congestion").Default("0").Int()
kcpArgs.SockBuf = app.Flag("kcp-sockbuf", "be carefull!").Default("4194304").Int()
kcpArgs.KeepAlive = app.Flag("kcp-keepalive", "be carefull!").Default("10").Int()
//########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")
httpArgs.ParentType = http.Flag("parent-type", "parent protocol type <tls|tcp|ssh|kcp>").Short('T').Enum("tls", "tcp", "ssh", "kcp")
httpArgs.Always = http.Flag("always", "always use parent proxy").Default("false").Bool()
httpArgs.Timeout = http.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("2000").Int()
httpArgs.HTTPTimeout = http.Flag("http-timeout", "check domain if blocked , http request timeout milliseconds when connect to host").Default("3000").Int()
httpArgs.Interval = http.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
httpArgs.Blocked = http.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
httpArgs.Direct = http.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
httpArgs.AuthFile = http.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
httpArgs.Local = http.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
httpArgs.SSHPassword = http.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
httpArgs.LocalIPS = http.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
httpArgs.AuthURL = http.Flag("auth-url", "http basic auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
httpArgs.AuthURLTimeout = http.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
httpArgs.AuthURLOkCode = http.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
httpArgs.AuthURLRetry = http.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("1").Int()
httpArgs.DNSAddress = http.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
httpArgs.DNSTTL = http.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
httpArgs.LocalKey = http.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode")
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
tcpArgs.ParentType = tcp.Flag("parent-type", "parent protocol type <tls|tcp|kcp|udp>").Short('T').Enum("tls", "tcp", "udp", "kcp")
tcpArgs.LocalType = tcp.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
tcpArgs.CheckParentInterval = tcp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
tcpArgs.Local = tcp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########udp#########
udp := app.Command("udp", "proxy on udp mode")
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
udpArgs.ParentType = udp.Flag("parent-type", "parent protocol type <tls|tcp|udp>").Short('T').Enum("tls", "tcp", "udp")
udpArgs.CheckParentInterval = udp.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
udpArgs.Local = udp.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########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('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|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('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|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('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")
tunnelServerArgs.Parent = tunnelServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
tunnelServerArgs.CertFile = tunnelServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
tunnelServerArgs.KeyFile = tunnelServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tunnelServerArgs.Timeout = tunnelServer.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelServerArgs.IsUDP = tunnelServer.Flag("udp", "proxy on udp tunnel server mode").Default("false").Bool()
tunnelServerArgs.Key = tunnelServer.Flag("k", "client key").Default("default").String()
tunnelServerArgs.Route = tunnelServer.Flag("route", "local route to client's network, such as: PROTOCOL://LOCAL_IP:LOCAL_PORT@[CLIENT_KEY]CLIENT_LOCAL_HOST:CLIENT_LOCAL_PORT").Short('r').Default("").Strings()
//########tunnel-client#########
tunnelClient := app.Command("tclient", "proxy on tunnel client mode")
tunnelClientArgs.Parent = tunnelClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
tunnelClientArgs.CertFile = tunnelClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
tunnelClientArgs.KeyFile = tunnelClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tunnelClientArgs.Timeout = tunnelClient.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelClientArgs.Key = tunnelClient.Flag("k", "key same with server").Default("default").String()
//########tunnel-bridge#########
tunnelBridge := app.Command("tbridge", "proxy on tunnel bridge mode")
tunnelBridgeArgs.CertFile = tunnelBridge.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
tunnelBridgeArgs.KeyFile = tunnelBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########ssh#########
socks := app.Command("socks", "proxy on ssh mode")
socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').String()
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
socksArgs.LocalType = socks.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
socksArgs.Local = socks.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
socksArgs.UDPParent = socks.Flag("udp-parent", "udp parent address, such as: \"23.32.32.19:33090\"").Default("").Short('X').String()
socksArgs.UDPLocal = socks.Flag("udp-local", "udp local ip:port to listen").Short('x').Default(":33090").String()
socksArgs.CertFile = socks.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
socksArgs.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()
socksArgs.SSHKeyFileSalt = socks.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()
socksArgs.SSHPassword = socks.Flag("ssh-password", "password for ssh").Short('A').Default("").String()
socksArgs.Always = socks.Flag("always", "always use parent proxy").Default("false").Bool()
socksArgs.Timeout = socks.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Default("5000").Int()
socksArgs.Interval = socks.Flag("interval", "check domain if blocked every interval seconds").Default("10").Int()
socksArgs.Blocked = socks.Flag("blocked", "blocked domain file , one domain each line").Default("blocked").Short('b').String()
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
socksArgs.AuthFile = socks.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
socksArgs.Auth = socks.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
socksArgs.LocalIPS = socks.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
socksArgs.AuthURL = socks.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
socksArgs.AuthURLTimeout = socks.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
socksArgs.AuthURLOkCode = socks.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
socksArgs.AuthURLRetry = socks.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
socksArgs.DNSAddress = socks.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
socksArgs.DNSTTL = socks.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
socksArgs.LocalKey = socks.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//########socks+http(s)#########
sps := app.Command("sps", "proxy on socks+http(s) mode")
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
spsArgs.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")
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
spsArgs.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()
spsArgs.LocalKey = sps.Flag("local-key", "the password for auto encrypt/decrypt local connection data").Short('z').Default("").String()
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
//parse args
_args := strings.Fields(strings.Trim(serviceArgsStr, " "))
args := []string{}
for _, a := range _args {
args = append(args, strings.Trim(a, "\""))
}
serviceName, err := app.Parse(args)
if err != nil {
return fmt.Sprintf("parse args fail,err: %s", err)
}
//set kcp config
switch *kcpArgs.Mode {
case "normal":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 40, 2, 1
case "fast":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 0, 30, 2, 1
case "fast2":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 20, 2, 1
case "fast3":
*kcpArgs.NoDelay, *kcpArgs.Interval, *kcpArgs.Resend, *kcpArgs.NoCongestion = 1, 10, 2, 1
}
pass := pbkdf2.Key([]byte(*kcpArgs.Key), []byte("snail007-goproxy"), 4096, 32, sha1.New)
switch *kcpArgs.Crypt {
case "sm4":
kcpArgs.Block, _ = kcp.NewSM4BlockCrypt(pass[:16])
case "tea":
kcpArgs.Block, _ = kcp.NewTEABlockCrypt(pass[:16])
case "xor":
kcpArgs.Block, _ = kcp.NewSimpleXORBlockCrypt(pass)
case "none":
kcpArgs.Block, _ = kcp.NewNoneBlockCrypt(pass)
case "aes-128":
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:16])
case "aes-192":
kcpArgs.Block, _ = kcp.NewAESBlockCrypt(pass[:24])
case "blowfish":
kcpArgs.Block, _ = kcp.NewBlowfishBlockCrypt(pass)
case "twofish":
kcpArgs.Block, _ = kcp.NewTwofishBlockCrypt(pass)
case "cast5":
kcpArgs.Block, _ = kcp.NewCast5BlockCrypt(pass[:16])
case "3des":
kcpArgs.Block, _ = kcp.NewTripleDESBlockCrypt(pass[:24])
case "xtea":
kcpArgs.Block, _ = kcp.NewXTEABlockCrypt(pass[:16])
case "salsa20":
kcpArgs.Block, _ = kcp.NewSalsa20BlockCrypt(pass)
default:
*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
} else {
flags |= log.Ltime
}
log.SetFlags(flags)
if *logfile != "" {
f, e := os.OpenFile(*logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if e != nil {
log.Fatal(e)
}
log.SetOutput(f)
}
//regist services and run service
switch serviceName {
case "http":
services.Regist(serviceID, services.NewHTTP(), httpArgs)
case "tcp":
services.Regist(serviceID, services.NewTCP(), tcpArgs)
case "udp":
services.Regist(serviceID, services.NewUDP(), udpArgs)
case "tserver":
services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs)
case "tclient":
services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs)
case "tbridge":
services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs)
case "server":
services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs)
case "client":
services.Regist(serviceID, services.NewMuxClient(), muxClientArgs)
case "bridge":
services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs)
case "socks":
services.Regist(serviceID, services.NewSocks(), socksArgs)
case "sps":
services.Regist(serviceID, services.NewSPS(), spsArgs)
}
_, err = services.Run(serviceID)
if err != nil {
return fmt.Sprintf("run service [%s:%s] fail, ERR:%s", serviceID, serviceName, err)
}
return
}
func Stop(serviceID string) {
services.Stop(serviceID)
}

6
sdk/windows-linux/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
proxy-sdk.dll
proxy-sdk.h
proxy-sdk.so
proxy-sdk.a
*.tar.gz
test.c

Binary file not shown.

View File

@ -0,0 +1,24 @@
#/bin/bash
VER="v4.7"
rm -rf sdk-linux-*.tar.gz
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
#linux 32bit
CGO_ENABLED=1 GOARCH=386 GOOS=linux go build -buildmode=c-archive -ldflags "-s -w" -o libproxy-sdk.a sdk.go
CGO_ENABLED=1 GOARCH=386 GOOS=linux go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.so sdk.go
cp ../README.md .
tar zcf sdk-linux-32bit-${VER}.tar.gz README.md libproxy-sdk.so libproxy-sdk.a libproxy-sdk.h
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
#linux 64bit
CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -buildmode=c-archive -ldflags "-s -w" -o libproxy-sdk.a sdk.go
CGO_ENABLED=1 GOARCH=amd64 GOOS=linux go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.so sdk.go
cp ../README.md .
tar zcf sdk-linux-64bit-${VER}.tar.gz README.md libproxy-sdk.so libproxy-sdk.a libproxy-sdk.h
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
echo "done."

View File

@ -0,0 +1,13 @@
#/bin/bash
VER="v4.7"
rm -rf *.tar.gz
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
#mac , macos required
CGO_ENABLED=1 GOARCH=amd64 GOOS=darwin go build -buildmode=c-shared -ldflags "-s -w" -o libproxy-sdk.dylib sdk.go
cp ../README.md .
tar zcf sdk-mac-${VER}.tar.gz README.md libproxy-sdk.dylib libproxy-sdk.h
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
echo "done."

View File

@ -0,0 +1,28 @@
#/bin/bash
VER="v4.7"
sudo rm /usr/local/go
sudo ln -s /usr/local/go1.10.1 /usr/local/go
rm -rf sdk-windows-*.tar.gz
rm -rf README.md proxy-sdk.h proxy-sdk.dll
#apt-get install gcc-multilib
#apt-get install gcc-mingw-w64
#windows 64bit
CC=x86_64-w64-mingw32-gcc GOARCH=amd64 CGO_ENABLED=1 GOOS=windows go build -buildmode=c-shared -ldflags "-s -w" -o proxy-sdk.dll sdk.go
cp ../README.md .
tar zcf sdk-windows-64bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll
rm -rf README.md proxy-sdk.h proxy-sdk.dll
#windows 32bit
CC=i686-w64-mingw32-gcc-win32 GOARCH=386 CGO_ENABLED=1 GOOS=windows go build -buildmode=c-shared -ldflags "-s -w" -o proxy-sdk.dll sdk.go
cp ../README.md .
tar zcf sdk-windows-32bit-${VER}.tar.gz README.md proxy-sdk.dll proxy-sdk.h ieshims.dll
rm -rf README.md proxy-sdk.h proxy-sdk.dll
sudo rm /usr/local/go
sudo ln -s /usr/local/go1.8.5 /usr/local/go
echo "done."

19
sdk/windows-linux/sdk.go Normal file
View File

@ -0,0 +1,19 @@
package main
import (
"C"
sdk "github.com/snail007/goproxy/sdk/android-ios"
)
//export Start
func Start(serviceID *C.char, serviceArgsStr *C.char) (errStr *C.char) {
return C.CString(sdk.Start(C.GoString(serviceID), C.GoString(serviceArgsStr)))
}
//export Stop
func Stop(serviceID *C.char) {
sdk.Stop(C.GoString(serviceID))
}
func main() {
}

View File

@ -1,7 +1,7 @@
package services
import (
"snail007/proxy/services/kcpcfg"
"github.com/snail007/goproxy/services/kcpcfg"
"golang.org/x/crypto/ssh"
)
@ -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
@ -106,7 +111,6 @@ type TCPArgs struct {
ParentType *string
LocalType *string
Timeout *int
PoolSize *int
CheckParentInterval *int
KCP kcpcfg.KCPConfigArgs
}
@ -115,6 +119,8 @@ type HTTPArgs struct {
Parent *string
CertFile *string
KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte
KeyBytes []byte
Local *string
@ -132,7 +138,6 @@ type HTTPArgs struct {
ParentType *string
LocalType *string
Timeout *int
PoolSize *int
CheckParentInterval *int
SSHKeyFile *string
SSHKeyFileSalt *string
@ -144,6 +149,10 @@ type HTTPArgs struct {
LocalIPS *[]string
DNSAddress *string
DNSTTL *int
LocalKey *string
ParentKey *string
LocalCompress *bool
ParentCompress *bool
}
type UDPArgs struct {
Parent *string
@ -154,7 +163,6 @@ type UDPArgs struct {
Local *string
ParentType *string
Timeout *int
PoolSize *int
CheckParentInterval *int
}
type SocksArgs struct {
@ -164,6 +172,8 @@ type SocksArgs struct {
LocalType *string
CertFile *string
KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte
KeyBytes []byte
SSHKeyFile *string
@ -189,11 +199,17 @@ type SocksArgs struct {
LocalIPS *[]string
DNSAddress *string
DNSTTL *int
LocalKey *string
ParentKey *string
LocalCompress *bool
ParentCompress *bool
}
type SPSArgs struct {
Parent *string
CertFile *string
KeyFile *string
CaCertFile *string
CaCertBytes []byte
CertBytes []byte
KeyBytes []byte
Local *string
@ -204,6 +220,18 @@ 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
LocalKey *string
ParentKey *string
LocalCompress *bool
ParentCompress *bool
}
func (a *SPSArgs) Protocol() string {

View File

@ -2,12 +2,13 @@ package services
import (
"fmt"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
"io"
"io/ioutil"
"log"
"net"
"runtime/debug"
"snail007/proxy/utils"
"strconv"
"strings"
"time"
@ -16,38 +17,56 @@ import (
)
type HTTP struct {
outPool utils.OutPool
outPool utils.OutConn
cfg HTTPArgs
checker utils.Checker
basicAuth utils.BasicAuth
sshClient *ssh.Client
lockChn chan bool
domainResolver utils.DomainResolver
isStop bool
serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap
}
func NewHTTP() Service {
return &HTTP{
outPool: utils.OutPool{},
cfg: HTTPArgs{},
checker: utils.Checker{},
basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1),
outPool: utils.OutConn{},
cfg: HTTPArgs{},
checker: utils.Checker{},
basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1),
isStop: false,
serverChannels: []*utils.ServerChannel{},
userConns: utils.NewConcurrentMap(),
}
}
func (s *HTTP) CheckArgs() {
var err error
func (s *HTTP) CheckArgs() (err error) {
if *s.cfg.Parent != "" && *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
return
}
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
if err != nil {
err = fmt.Errorf("read ca file error,ERR:%s", err)
return
}
}
}
if *s.cfg.ParentType == "ssh" {
if *s.cfg.SSHUser == "" {
log.Fatalf("ssh user required")
err = fmt.Errorf("ssh user required")
return
}
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
log.Fatalf("ssh password or key required")
err = fmt.Errorf("ssh password or key required")
return
}
if *s.cfg.SSHPassword != "" {
@ -56,7 +75,8 @@ func (s *HTTP) CheckArgs() {
var SSHSigner ssh.Signer
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
if err != nil {
log.Fatalf("read key file ERR: %s", err)
err = fmt.Errorf("read key file ERR: %s", err)
return
}
if *s.cfg.SSHKeyFileSalt != "" {
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
@ -64,13 +84,15 @@ func (s *HTTP) CheckArgs() {
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
}
if err != nil {
log.Fatalf("parse ssh private key fail,ERR: %s", err)
err = fmt.Errorf("parse ssh private key fail,ERR: %s", err)
return
}
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
}
}
return
}
func (s *HTTP) InitService() {
func (s *HTTP) InitService() (err error) {
s.InitBasicAuth()
if *s.cfg.Parent != "" {
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
@ -79,16 +101,22 @@ func (s *HTTP) InitService() {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
}
if *s.cfg.ParentType == "ssh" {
err := s.ConnectSSH()
err = s.ConnectSSH()
if err != nil {
log.Fatalf("init service fail, ERR: %s", err)
err = fmt.Errorf("init service fail, ERR: %s", err)
return
}
go func() {
//循环检查ssh网络连通性
for {
if s.isStop {
return
}
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 {
@ -106,20 +134,43 @@ func (s *HTTP) InitService() {
}
}()
}
return
}
func (s *HTTP) StopService() {
if s.outPool.Pool != nil {
s.outPool.Pool.ReleaseAll()
defer func() {
e := recover()
if e != nil {
log.Printf("stop http(s) service crashed,%s", e)
} else {
log.Printf("service http(s) stoped")
}
}()
s.isStop = true
s.checker.Stop()
if s.sshClient != nil {
s.sshClient.Close()
}
for _, sc := range s.serverChannels {
if sc.Listener != nil && *sc.Listener != nil {
(*sc.Listener).Close()
}
if sc.UDPListener != nil {
(*sc.UDPListener).Close()
}
}
}
func (s *HTTP) Start(args interface{}) (err error) {
s.cfg = args.(HTTPArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitOutConnPool()
}
s.InitService()
if err = s.InitService(); err != nil {
return
}
for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" {
host, port, _ := net.SplitHostPort(addr)
@ -128,7 +179,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)
}
@ -136,6 +187,7 @@ func (s *HTTP) Start(args interface{}) (err error) {
return
}
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc)
}
}
return
@ -150,6 +202,14 @@ func (s *HTTP) callback(inConn net.Conn) {
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
}
}()
if *s.cfg.LocalCompress {
inConn = utils.NewCompConn(inConn)
}
if *s.cfg.LocalKey != "" {
inConn = conncrypt.New(inConn, &conncrypt.Config{
Password: *s.cfg.LocalKey,
})
}
var err interface{}
var req utils.HTTPRequest
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
@ -181,7 +241,6 @@ func (s *HTTP) callback(inConn net.Conn) {
log.Printf("use proxy : %v, %s", useProxy, address)
err = s.OutToTCP(useProxy, address, &inConn, &req)
if err != nil {
if *s.cfg.Parent == "" {
log.Printf("connect to %s fail, ERR:%s", address, err)
@ -201,19 +260,18 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
return
}
var outConn net.Conn
var _outConn interface{}
tryCount := 0
maxTryCount := 5
for {
if s.isStop {
return
}
if useProxy {
if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(address)
} else {
//log.Printf("%v", s.outPool)
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
// log.Printf("%v", s.outPool)
outConn, err = s.outPool.Get()
}
} else {
outConn, err = utils.ConnectHost(s.Resolve(address), *s.cfg.Timeout)
@ -231,16 +289,25 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
utils.CloseConn(inConn)
return
}
if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn)
}
if *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey,
})
}
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)
@ -250,9 +317,13 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
s.userConns.Remove(inAddr)
})
log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, inConn)
return
}
@ -260,7 +331,7 @@ func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
maxTryCount := 1
tryCount := 0
RETRY:
if tryCount >= maxTryCount {
if tryCount >= maxTryCount || s.isStop {
return
}
wait := make(chan bool, 1)
@ -317,15 +388,13 @@ func (s *HTTP) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
s.outPool = utils.NewOutConn(
*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,
*s.cfg.PoolSize*2,
)
}
}

View File

@ -2,13 +2,15 @@ package services
import (
"bufio"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"math/rand"
"net"
"snail007/proxy/utils"
"strconv"
"strings"
"sync"
"time"
"github.com/xtaci/smux"
@ -17,120 +19,207 @@ import (
type MuxBridge struct {
cfg MuxBridgeArgs
clientControlConns utils.ConcurrentMap
serverConns utils.ConcurrentMap
router utils.ClientKeyRouter
l *sync.Mutex
isStop bool
sc *utils.ServerChannel
}
func NewMuxBridge() Service {
b := &MuxBridge{
cfg: MuxBridgeArgs{},
clientControlConns: utils.NewConcurrentMap(),
serverConns: utils.NewConcurrentMap(),
l: &sync.Mutex{},
isStop: false,
}
b.router = utils.NewClientKeyRouter(&b.clientControlConns, 50000)
return b
}
func (s *MuxBridge) InitService() {
func (s *MuxBridge) InitService() (err error) {
return
}
func (s *MuxBridge) CheckArgs() {
func (s *MuxBridge) CheckArgs() (err error) {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
err = fmt.Errorf("cert and key file required")
return
}
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, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
return
}
func (s *MuxBridge) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop bridge service crashed,%s", e)
} else {
log.Printf("service bridge stoped")
}
}()
s.isStop = true
if s.sc != nil && (*s.sc).Listener != nil {
(*(*s.sc).Listener).Close()
}
for _, g := range s.clientControlConns.Items() {
for _, session := range g.(utils.ConcurrentMap).Items() {
(session.(*smux.Session)).Close()
}
}
for _, c := range s.serverConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *MuxBridge) Start(args interface{}) (err error) {
s.cfg = args.(MuxBridgeArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
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())
s.sc = &sc
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
inAddr := inConn.RemoteAddr().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)
if c, ok := s.serverConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.serverConns.Set(inAddr, &inConn)
session, err := smux.Server(inConn, nil)
if err != nil {
utils.CloseConn(&inConn)
log.Printf("server session error,ERR:%s", err)
return
}
for {
if s.isStop {
return
}
stream, err := session.AcceptStream()
if err != nil {
session.Close()
utils.CloseConn(&inConn)
s.serverConns.Remove(inAddr)
log.Printf("server connection %s %s released", serverID, key)
return
}
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("bridge callback crashed,err: %s", e)
}
}()
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 s.isStop {
return
}
if session.IsClosed() {
s.l.Lock()
defer s.l.Unlock()
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
group.Remove(index)
log.Printf("client connection %s released", key)
}
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 {
if s.isStop {
return
}
try--
if try == 0 {
break
@ -140,15 +229,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)

View File

@ -3,10 +3,10 @@ package services
import (
"crypto/tls"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"net"
"snail007/proxy/utils"
"time"
"github.com/golang/snappy"
@ -14,40 +14,72 @@ import (
)
type MuxClient struct {
cfg MuxClientArgs
cfg MuxClientArgs
isStop bool
sessions utils.ConcurrentMap
}
func NewMuxClient() Service {
return &MuxClient{
cfg: MuxClientArgs{},
cfg: MuxClientArgs{},
isStop: false,
sessions: utils.NewConcurrentMap(),
}
}
func (s *MuxClient) InitService() {
func (s *MuxClient) InitService() (err error) {
return
}
func (s *MuxClient) CheckArgs() {
func (s *MuxClient) CheckArgs() (err error) {
if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent)
} else {
log.Fatalf("parent required")
err = fmt.Errorf("parent required")
return
}
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
err = fmt.Errorf("cert and key file required")
return
}
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, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
return
}
func (s *MuxClient) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop client service crashed,%s", e)
} else {
log.Printf("service client stoped")
}
}()
s.isStop = true
for _, sess := range s.sessions.Items() {
sess.(*smux.Session).Close()
}
}
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("session worker[%d] started", i)
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
log.Printf("client started")
count := 1
if *s.cfg.SessionCount > 0 {
count = *s.cfg.SessionCount
}
for i := 1; i <= count; i++ {
key := fmt.Sprintf("worker[%d]", i)
log.Printf("session %s started", key)
go func(i int) {
defer func() {
e := recover()
@ -56,15 +88,18 @@ 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)
if s.isStop {
return
}
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)
@ -78,7 +113,14 @@ func (s *MuxClient) Start(args interface{}) (err error) {
time.Sleep(time.Second * 3)
continue
}
if _sess, ok := s.sessions.Get(key); ok {
_sess.(*smux.Session).Close()
}
s.sessions.Set(key, session)
for {
if s.isStop {
return
}
stream, err := session.AcceptStream()
if err != nil {
log.Printf("accept stream err: %s, retrying...", err)
@ -94,7 +136,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()
@ -111,7 +155,6 @@ func (s *MuxClient) Start(args interface{}) (err error) {
}()
}
}
}(i)
}
return
@ -119,11 +162,29 @@ 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 {
if s.isStop {
return
}
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)
@ -131,7 +192,15 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
break
} else {
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
go s.processUDPPacket(inConn, srcAddr, localAddr, body)
go func() {
defer func() {
if e := recover(); e != nil {
log.Printf("client processUDPPacket crashed,err: %s", e)
}
}()
s.processUDPPacket(inConn, srcAddr, localAddr, body)
}()
}
}
@ -152,13 +221,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 +238,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()
@ -179,6 +253,9 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
var outConn net.Conn
i := 0
for {
if s.isStop {
return
}
i++
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
if err == nil || i == 3 {

View File

@ -3,12 +3,12 @@ package services
import (
"crypto/tls"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"math/rand"
"net"
"runtime/debug"
"snail007/proxy/utils"
"strconv"
"strings"
"time"
@ -23,13 +23,15 @@ type MuxServer struct {
sc utils.ServerChannel
sessions utils.ConcurrentMap
lockChn chan bool
isStop bool
udpConn *net.Conn
}
type MuxServerManager struct {
cfg MuxServerArgs
udpChn chan MuxUDPItem
sc utils.ServerChannel
serverID string
servers []*Service
}
func NewMuxServerManager() Service {
@ -37,18 +39,25 @@ func NewMuxServerManager() Service {
cfg: MuxServerArgs{},
udpChn: make(chan MuxUDPItem, 50000),
serverID: utils.Uniqueid(),
servers: []*Service{},
}
}
func (s *MuxServerManager) Start(args interface{}) (err error) {
s.cfg = args.(MuxServerArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
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")
err = fmt.Errorf("parent required")
return
}
s.InitService()
if err = s.InitService(); err != nil {
return
}
log.Printf("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route)
@ -88,11 +97,14 @@ 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 {
return
}
s.servers = append(s.servers, &server)
}
return
}
@ -100,14 +112,25 @@ func (s *MuxServerManager) Clean() {
s.StopService()
}
func (s *MuxServerManager) StopService() {
}
func (s *MuxServerManager) CheckArgs() {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
for _, server := range s.servers {
(*server).Clean()
}
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
}
func (s *MuxServerManager) InitService() {
func (s *MuxServerManager) CheckArgs() (err error) {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
err = fmt.Errorf("cert and key file required")
return
}
if *s.cfg.ParentType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
return
}
func (s *MuxServerManager) InitService() (err error) {
return
}
func NewMuxServer() Service {
@ -116,6 +139,7 @@ func NewMuxServer() Service {
udpChn: make(chan MuxUDPItem, 50000),
lockChn: make(chan bool, 1),
sessions: utils.NewConcurrentMap(),
isStop: false,
}
}
@ -125,19 +149,49 @@ type MuxUDPItem struct {
srcAddr *net.UDPAddr
}
func (s *MuxServer) InitService() {
s.UDPConnDeamon()
}
func (s *MuxServer) CheckArgs() {
if *s.cfg.Remote == "" {
log.Fatalf("remote required")
func (s *MuxServer) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop server service crashed,%s", e)
} else {
log.Printf("service server stoped")
}
}()
s.isStop = true
for _, sess := range s.sessions.Items() {
sess.(*smux.Session).Close()
}
if s.sc.Listener != nil {
(*s.sc.Listener).Close()
}
if s.sc.UDPListener != nil {
(*s.sc.UDPListener).Close()
}
if s.udpConn != nil {
(*s.udpConn).Close()
}
}
func (s *MuxServer) InitService() (err error) {
s.UDPConnDeamon()
return
}
func (s *MuxServer) CheckArgs() (err error) {
if *s.cfg.Remote == "" {
err = fmt.Errorf("remote required")
return
}
return
}
func (s *MuxServer) Start(args interface{}) (err error) {
s.cfg = args.(MuxServerArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p)
@ -152,7 +206,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() {
@ -163,6 +217,9 @@ func (s *MuxServer) Start(args interface{}) (err error) {
var outConn net.Conn
var ID string
for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn()
if err != nil {
utils.CloseConn(&outConn)
@ -201,15 +258,19 @@ 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
}
func (s *MuxServer) Clean() {
s.StopService()
}
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 +280,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 +303,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
@ -257,8 +321,23 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
return
}
}
if _sess, ok := s.sessions.Get(index); ok {
_sess.(*smux.Session).Close()
}
s.sessions.Set(index, session)
log.Printf("session[%s] created", index)
go func() {
for {
if s.isStop {
return
}
if session.IsClosed() {
s.sessions.Remove(index)
break
}
time.Sleep(time.Second * 5)
}
}()
} else {
session = _session.(*smux.Session)
}
@ -267,7 +346,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() {
@ -281,10 +373,19 @@ func (s *MuxServer) UDPConnDeamon() {
var ID string
var err error
for {
if s.isStop {
return
}
item := <-s.udpChn
RETRY:
if s.isStop {
return
}
if outConn == nil {
for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn()
if err != nil {
outConn = nil
@ -294,11 +395,17 @@ func (s *MuxServer) UDPConnDeamon() {
continue
} else {
go func(outConn net.Conn, ID string) {
go func() {
// outConn.Close()
}()
if s.udpConn != nil {
(*s.udpConn).Close()
}
s.udpConn = &outConn
for {
if s.isStop {
return
}
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 +419,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

View File

@ -2,7 +2,6 @@ package services
import (
"fmt"
"log"
"runtime/debug"
)
@ -19,33 +18,43 @@ type ServiceItem struct {
var servicesMap = map[string]*ServiceItem{}
func Regist(name string, s Service, args interface{}) {
Stop(name)
servicesMap[name] = &ServiceItem{
S: s,
Args: args,
Name: name,
}
}
func GetService(name string) *ServiceItem {
if s, ok := servicesMap[name]; ok && s.S != nil {
return s
}
return nil
}
func Stop(name string) {
if s, ok := servicesMap[name]; ok && s.S != nil {
s.S.Clean()
}
}
func Run(name string, args ...interface{}) (service *ServiceItem, err error) {
service, ok := servicesMap[name]
if ok {
go func() {
defer func() {
err := recover()
if err != nil {
log.Fatalf("%s servcie crashed, ERR: %s\ntrace:%s", name, err, string(debug.Stack()))
}
}()
if len(args) == 1 {
err = service.S.Start(args[0])
} else {
err = service.S.Start(service.Args)
}
if err != nil {
log.Fatalf("%s servcie fail, ERR: %s", name, err)
defer func() {
e := recover()
if e != nil {
err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
}
}()
}
if !ok {
if len(args) == 1 {
err = service.S.Start(args[0])
} else {
err = service.S.Start(service.Args)
}
if err != nil {
err = fmt.Errorf("%s servcie fail, ERR: %s", name, err)
}
} else {
err = fmt.Errorf("service %s not found", name)
}
return

View File

@ -3,13 +3,14 @@ package services
import (
"crypto/tls"
"fmt"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/aes"
"github.com/snail007/goproxy/utils/socks"
"github.com/snail007/goproxy/utils/conncrypt"
"io/ioutil"
"log"
"net"
"runtime/debug"
"snail007/proxy/utils"
"snail007/proxy/utils/aes"
"snail007/proxy/utils/socks"
"strings"
"time"
@ -23,7 +24,10 @@ type Socks struct {
sshClient *ssh.Client
lockChn chan bool
udpSC utils.ServerChannel
sc *utils.ServerChannel
domainResolver utils.DomainResolver
isStop bool
userConns utils.ConcurrentMap
}
func NewSocks() Service {
@ -32,27 +36,50 @@ func NewSocks() Service {
checker: utils.Checker{},
basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1),
isStop: false,
userConns: utils.NewConcurrentMap(),
}
}
func (s *Socks) CheckArgs() {
var err error
if *s.cfg.LocalType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
func (s *Socks) CheckArgs() (err error) {
if *s.cfg.LocalType == "tls" || (*s.cfg.Parent != "" && *s.cfg.ParentType == "tls") {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
if err != nil {
err = fmt.Errorf("read ca file error,ERR:%s", err)
return
}
}
}
if *s.cfg.Parent != "" {
if *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
return
}
if *s.cfg.ParentType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
host, _, e := net.SplitHostPort(*s.cfg.Parent)
if e != nil {
err = fmt.Errorf("parent format error : %s", e)
return
}
if *s.cfg.UDPParent == "" {
*s.cfg.UDPParent = net.JoinHostPort(host, "33090")
}
if strings.HasPrefix(*s.cfg.UDPParent, ":") {
*s.cfg.UDPParent = net.JoinHostPort(host, strings.TrimLeft(*s.cfg.UDPParent, ":"))
}
if *s.cfg.ParentType == "ssh" {
if *s.cfg.SSHUser == "" {
log.Fatalf("ssh user required")
err = fmt.Errorf("ssh user required")
return
}
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
log.Fatalf("ssh password or key required")
err = fmt.Errorf("ssh password or key required")
return
}
if *s.cfg.SSHPassword != "" {
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
@ -60,7 +87,8 @@ func (s *Socks) CheckArgs() {
var SSHSigner ssh.Signer
s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
if err != nil {
log.Fatalf("read key file ERR: %s", err)
err = fmt.Errorf("read key file ERR: %s", err)
return
}
if *s.cfg.SSHKeyFileSalt != "" {
SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
@ -68,31 +96,38 @@ func (s *Socks) CheckArgs() {
SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
}
if err != nil {
log.Fatalf("parse ssh private key fail,ERR: %s", err)
err = fmt.Errorf("parse ssh private key fail,ERR: %s", err)
return
}
s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
}
}
}
return
}
func (s *Socks) InitService() {
func (s *Socks) InitService() (err error) {
s.InitBasicAuth()
if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
}
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
if *s.cfg.ParentType == "ssh" {
err := s.ConnectSSH()
if err != nil {
log.Fatalf("init service fail, ERR: %s", err)
e := s.ConnectSSH()
if e != nil {
err = fmt.Errorf("init service fail, ERR: %s", e)
return
}
go func() {
//循环检查ssh网络连通性
for {
if s.isStop {
return
}
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 {
@ -111,40 +146,66 @@ func (s *Socks) InitService() {
log.Println("warn: socks udp not suppored for ssh")
} else {
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
err := s.udpSC.ListenUDP(s.udpCallback)
if err != nil {
log.Fatalf("init udp service fail, ERR: %s", err)
e := s.udpSC.ListenUDP(s.udpCallback)
if e != nil {
err = fmt.Errorf("init udp service fail, ERR: %s", e)
return
}
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
}
return
}
func (s *Socks) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop socks service crashed,%s", e)
} else {
log.Printf("service socks stoped")
}
}()
s.isStop = true
s.checker.Stop()
if s.sshClient != nil {
s.sshClient.Close()
}
if s.udpSC.UDPListener != nil {
s.udpSC.UDPListener.Close()
}
if s.sc != nil && (*s.sc).Listener != nil {
(*(*s.sc).Listener).Close()
}
for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *Socks) Start(args interface{}) (err error) {
//start()
s.cfg = args.(SocksArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
s.InitService()
}
if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
}
if *s.cfg.UDPParent != "" {
log.Printf("use socks udp parent %s", *s.cfg.UDPParent)
}
sc := utils.NewServerChannelHost(*s.cfg.Local)
if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.socksConnCallback)
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)
}
if err != nil {
return
}
s.sc = &sc
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
return
}
@ -204,6 +265,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 +275,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 +302,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 +328,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 +337,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 +357,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))
}
@ -300,6 +376,14 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
inConn.Close()
}
}()
if *s.cfg.LocalCompress {
inConn = utils.NewCompConn(inConn)
}
if *s.cfg.LocalKey != "" {
inConn = conncrypt.New(inConn, &conncrypt.Config{
Password: *s.cfg.LocalKey,
})
}
//协商开始
//method select request
@ -359,9 +443,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
}
@ -415,6 +505,9 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
return
}
for {
if s.isStop {
return
}
if *s.cfg.Always {
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
} else {
@ -451,6 +544,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
return
}
log.Printf("use proxy %v : %s", useProxy, request.Addr())
request.TCPReply(socks.REP_SUCCESS)
@ -461,6 +555,11 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
utils.IoBind(*inConn, outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, request.Addr())
})
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
s.userConns.Remove(inAddr)
}
s.userConns.Set(inAddr, inConn)
}
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
switch *s.cfg.ParentType {
@ -471,7 +570,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)
@ -482,27 +581,42 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
err = fmt.Errorf("connect fail,%s", err)
return
}
if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn)
}
if *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey,
})
}
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
@ -514,7 +628,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
maxTryCount := 1
tryCount := 0
RETRY:
if tryCount >= maxTryCount {
if tryCount >= maxTryCount || s.isStop {
return
}
wait := make(chan bool, 1)

View File

@ -2,71 +2,116 @@ package services
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/socks"
"github.com/snail007/goproxy/utils/conncrypt"
"io/ioutil"
"log"
"net"
"runtime/debug"
"snail007/proxy/utils"
"snail007/proxy/utils/socks"
"strconv"
"strings"
"time"
)
type SPS struct {
outPool utils.OutPool
outPool utils.OutConn
cfg SPSArgs
domainResolver utils.DomainResolver
basicAuth utils.BasicAuth
serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap
}
func NewSPS() Service {
return &SPS{
outPool: utils.OutPool{},
cfg: SPSArgs{},
outPool: utils.OutConn{},
cfg: SPSArgs{},
basicAuth: utils.BasicAuth{},
serverChannels: []*utils.ServerChannel{},
userConns: utils.NewConcurrentMap(),
}
}
func (s *SPS) CheckArgs() {
func (s *SPS) CheckArgs() (err error) {
if *s.cfg.Parent == "" {
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
return
}
if *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp|kcp>")
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp>")
return
}
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
if err != nil {
err = fmt.Errorf("read ca file error,ERR:%s", err)
return
}
}
}
return
}
func (s *SPS) InitService() {
func (s *SPS) InitService() (err error) {
s.InitOutConnPool()
if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
}
err = s.InitBasicAuth()
return
}
func (s *SPS) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
s.outPool = utils.NewOutConn(
0,
*s.cfg.ParentType,
s.cfg.KCP,
s.cfg.CertBytes, s.cfg.KeyBytes,
s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes,
*s.cfg.Parent,
*s.cfg.Timeout,
0,
0,
)
}
}
func (s *SPS) StopService() {
if s.outPool.Pool != nil {
s.outPool.Pool.ReleaseAll()
defer func() {
e := recover()
if e != nil {
log.Printf("stop sps service crashed,%s", e)
} else {
log.Printf("service sps stoped")
}
}()
for _, sc := range s.serverChannels {
if sc.Listener != nil && *sc.Listener != nil {
(*sc.Listener).Close()
}
if sc.UDPListener != nil {
(*sc.UDPListener).Close()
}
}
for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *SPS) Start(args interface{}) (err error) {
s.cfg = args.(SPSArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent)
s.InitService()
for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" {
host, port, _ := net.SplitHostPort(*s.cfg.Local)
@ -75,7 +120,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, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.callback)
}
@ -83,6 +128,7 @@ func (s *SPS) Start(args interface{}) (err error) {
return
}
log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc)
}
}
return
@ -97,6 +143,14 @@ func (s *SPS) callback(inConn net.Conn) {
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
}
}()
if *s.cfg.LocalCompress {
inConn = utils.NewCompConn(inConn)
}
if *s.cfg.LocalKey != "" {
inConn = conncrypt.New(inConn, &conncrypt.Config{
Password: *s.cfg.LocalKey,
})
}
var err error
switch *s.cfg.ParentType {
case TYPE_KCP:
@ -109,7 +163,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 +177,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 +216,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)
@ -189,22 +235,56 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
}
//connect to parent
var outConn net.Conn
var _outConn interface{}
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
outConn, err = s.outPool.Get()
if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn)
return
}
if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn)
}
if *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey,
})
}
//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)
reply := make([]byte, 100)
n, err = outConn.Read(reply)
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)))))
}
pb.Write([]byte("\r\n"))
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, 1024)
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 +294,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 {
@ -271,10 +323,43 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
outAddr := outConn.RemoteAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr)
s.userConns.Remove(inAddr)
})
log.Printf("conn %s - %s connected", inAddr, outAddr)
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, &inConn)
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 {

View File

@ -3,52 +3,82 @@ package services
import (
"bufio"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"net"
"runtime/debug"
"snail007/proxy/utils"
"time"
"strconv"
)
type TCP struct {
outPool utils.OutPool
cfg TCPArgs
outPool utils.OutConn
cfg TCPArgs
sc *utils.ServerChannel
isStop bool
userConns utils.ConcurrentMap
}
func NewTCP() Service {
return &TCP{
outPool: utils.OutPool{},
cfg: TCPArgs{},
outPool: utils.OutConn{},
cfg: TCPArgs{},
isStop: false,
userConns: utils.NewConcurrentMap(),
}
}
func (s *TCP) CheckArgs() {
func (s *TCP) CheckArgs() (err error) {
if *s.cfg.Parent == "" {
log.Fatalf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
err = fmt.Errorf("parent required for %s %s", s.cfg.Protocol(), *s.cfg.Local)
return
}
if *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp|kcp|udp>")
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp|udp>")
return
}
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
return
}
func (s *TCP) InitService() {
func (s *TCP) InitService() (err error) {
s.InitOutConnPool()
return
}
func (s *TCP) StopService() {
if s.outPool.Pool != nil {
s.outPool.Pool.ReleaseAll()
defer func() {
e := recover()
if e != nil {
log.Printf("stop tcp service crashed,%s", e)
} else {
log.Printf("service tcp stoped")
}
}()
s.isStop = true
if s.sc.Listener != nil && *s.sc.Listener != nil {
(*s.sc.Listener).Close()
}
if s.sc.UDPListener != nil {
(*s.sc.UDPListener).Close()
}
for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *TCP) Start(args interface{}) (err error) {
s.cfg = args.(TCPArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitService()
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p)
@ -56,7 +86,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)
}
@ -64,6 +94,7 @@ func (s *TCP) Start(args interface{}) (err error) {
return
}
log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.sc = &sc
return
}
@ -96,11 +127,7 @@ func (s *TCP) callback(inConn net.Conn) {
}
func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn
var _outConn interface{}
_outConn, err = s.outPool.Pool.Get()
if err == nil {
outConn = _outConn.(net.Conn)
}
outConn, err = s.outPool.Get()
if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn)
@ -112,13 +139,22 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
//outLocalAddr := outConn.LocalAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr)
s.userConns.Remove(inAddr)
})
log.Printf("conn %s - %s connected", inAddr, outAddr)
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, &inConn)
return
}
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
for {
if s.isStop {
(*inConn).Close()
return
}
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %s released", srcAddr)
@ -168,15 +204,13 @@ func (s *TCP) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
s.outPool = utils.NewOutConn(
*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,
*s.cfg.PoolSize*2,
)
}
}

View File

@ -1,12 +1,15 @@
package services
import (
"bufio"
"bytes"
"fmt"
"github.com/snail007/goproxy/utils"
"log"
"net"
"snail007/proxy/utils"
"strconv"
"time"
"github.com/xtaci/smux"
)
type ServerConn struct {
@ -17,8 +20,7 @@ type TunnelBridge struct {
cfg TunnelBridgeArgs
serverConns utils.ConcurrentMap
clientControlConns utils.ConcurrentMap
// cmServer utils.ConnManager
// cmClient utils.ConnManager
isStop bool
}
func NewTunnelBridge() Service {
@ -26,213 +28,51 @@ func NewTunnelBridge() Service {
cfg: TunnelBridgeArgs{},
serverConns: utils.NewConcurrentMap(),
clientControlConns: utils.NewConcurrentMap(),
// cmServer: utils.NewConnManager(),
// cmClient: utils.NewConnManager(),
isStop: false,
}
}
func (s *TunnelBridge) InitService() {
func (s *TunnelBridge) InitService() (err error) {
return
}
func (s *TunnelBridge) CheckArgs() {
func (s *TunnelBridge) CheckArgs() (err error) {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
err = fmt.Errorf("cert and key file required")
return
}
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
return
}
func (s *TunnelBridge) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop tbridge service crashed,%s", e)
} else {
log.Printf("service tbridge stoped")
}
}()
s.isStop = true
for _, sess := range s.clientControlConns.Items() {
(*sess.(*net.Conn)).Close()
}
for _, sess := range s.serverConns.Items() {
(*sess.(ServerConn).Conn).Close()
}
}
func (s *TunnelBridge) Start(args interface{}) (err error) {
s.cfg = args.(TunnelBridgeArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
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) {
//log.Printf("connection from %s ", inConn.RemoteAddr())
reader := bufio.NewReader(inConn)
var err error
var connType uint8
err = utils.ReadPacket(reader, &connType)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
switch connType {
case CONN_SERVER:
var key, ID, clientLocalAddr, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
//addr := clientLocalAddr + "@" + ID
s.serverConns.Set(ID, ServerConn{
Conn: &inConn,
})
for {
item, ok := s.clientControlConns.Get(key)
if !ok {
log.Printf("client %s control conn not exists", key)
time.Sleep(time.Second * 3)
continue
}
(*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
_, err := (*item.(*net.Conn)).Write(packet)
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
if err != nil {
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
time.Sleep(time.Second * 3)
continue
} else {
// s.cmServer.Add(serverID, ID, &inConn)
break
}
}
case CONN_CLIENT:
var key, ID, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
serverConnItem, ok := s.serverConns.Get(ID)
if !ok {
inConn.Close()
log.Printf("server conn %s exists", ID)
return
}
serverConn := serverConnItem.(ServerConn).Conn
utils.IoBind(*serverConn, inConn, func(err interface{}) {
s.serverConns.Remove(ID)
// s.cmClient.RemoveOne(key, ID)
// s.cmServer.RemoveOne(serverID, ID)
log.Printf("conn %s released", ID)
})
// s.cmClient.Add(key, ID, &inConn)
log.Printf("conn %s created", ID)
case CONN_CLIENT_CONTROL:
var key string
err = utils.ReadPacketData(reader, &key)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
log.Printf("client control connection, key: %s", key)
if s.clientControlConns.Has(key) {
item, _ := s.clientControlConns.Get(key)
(*item.(*net.Conn)).Close()
}
s.clientControlConns.Set(key, &inConn)
log.Printf("set client %s control conn", key)
// case CONN_SERVER_HEARBEAT:
// var serverID string
// err = utils.ReadPacketData(reader, &serverID)
// if err != nil {
// log.Printf("read error,ERR:%s", err)
// return
// }
// log.Printf("server heartbeat connection, id: %s", serverID)
// writeDie := make(chan bool)
// readDie := make(chan bool)
// go func() {
// for {
// inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
// _, err = inConn.Write([]byte{0x00})
// inConn.SetWriteDeadline(time.Time{})
// if err != nil {
// log.Printf("server heartbeat connection write err %s", err)
// break
// }
// time.Sleep(time.Second * 3)
// }
// close(writeDie)
// }()
// go func() {
// for {
// signal := make([]byte, 1)
// inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
// _, err := inConn.Read(signal)
// inConn.SetReadDeadline(time.Time{})
// if err != nil {
// log.Printf("server heartbeat connection read err: %s", err)
// break
// } else {
// // log.Printf("heartbeat from server ,id:%s", serverID)
// }
// }
// close(readDie)
// }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// utils.CloseConn(&inConn)
// s.cmServer.Remove(serverID)
// log.Printf("server heartbeat conn %s released", serverID)
// case CONN_CLIENT_HEARBEAT:
// var clientID string
// err = utils.ReadPacketData(reader, &clientID)
// if err != nil {
// log.Printf("read error,ERR:%s", err)
// return
// }
// log.Printf("client heartbeat connection, id: %s", clientID)
// writeDie := make(chan bool)
// readDie := make(chan bool)
// go func() {
// for {
// inConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
// _, err = inConn.Write([]byte{0x00})
// inConn.SetWriteDeadline(time.Time{})
// if err != nil {
// log.Printf("client heartbeat connection write err %s", err)
// break
// }
// time.Sleep(time.Second * 3)
// }
// close(writeDie)
// }()
// go func() {
// for {
// signal := make([]byte, 1)
// inConn.SetReadDeadline(time.Now().Add(time.Second * 6))
// _, err := inConn.Read(signal)
// inConn.SetReadDeadline(time.Time{})
// if err != nil {
// log.Printf("client control connection read err: %s", err)
// break
// } else {
// // log.Printf("heartbeat from client ,id:%s", clientID)
// }
// }
// close(readDie)
// }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// utils.CloseConn(&inConn)
// s.cmClient.Remove(clientID)
// if s.clientControlConns.Has(clientID) {
// item, _ := s.clientControlConns.Get(clientID)
// (*item.(*net.Conn)).Close()
// }
// s.clientControlConns.Remove(clientID)
// log.Printf("client heartbeat conn %s released", clientID)
}
})
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
if err != nil {
return
}
@ -242,3 +82,111 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
func (s *TunnelBridge) Clean() {
s.StopService()
}
func (s *TunnelBridge) callback(inConn net.Conn) {
var err error
//log.Printf("connection from %s ", inConn.RemoteAddr())
sess, err := smux.Server(inConn, &smux.Config{
KeepAliveInterval: 10 * time.Second,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
MaxFrameSize: 4096,
MaxReceiveBuffer: 4194304,
})
if err != nil {
log.Printf("new mux server conn error,ERR:%s", err)
return
}
inConn, err = sess.AcceptStream()
if err != nil {
log.Printf("mux server conn accept error,ERR:%s", err)
return
}
var buf = make([]byte, 1024)
n, _ := inConn.Read(buf)
reader := bytes.NewReader(buf[:n])
//reader := bufio.NewReader(inConn)
var connType uint8
err = utils.ReadPacket(reader, &connType)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
switch connType {
case CONN_SERVER:
var key, ID, clientLocalAddr, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
//addr := clientLocalAddr + "@" + ID
s.serverConns.Set(ID, ServerConn{
Conn: &inConn,
})
for {
if s.isStop {
return
}
item, ok := s.clientControlConns.Get(key)
if !ok {
log.Printf("client %s control conn not exists", key)
time.Sleep(time.Second * 3)
continue
}
(*item.(*net.Conn)).SetWriteDeadline(time.Now().Add(time.Second * 3))
_, err := (*item.(*net.Conn)).Write(packet)
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
if err != nil {
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
time.Sleep(time.Second * 3)
continue
} else {
// s.cmServer.Add(serverID, ID, &inConn)
break
}
}
case CONN_CLIENT:
var key, ID, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
serverConnItem, ok := s.serverConns.Get(ID)
if !ok {
inConn.Close()
log.Printf("server conn %s exists", ID)
return
}
serverConn := serverConnItem.(ServerConn).Conn
utils.IoBind(*serverConn, inConn, func(err interface{}) {
s.serverConns.Remove(ID)
// s.cmClient.RemoveOne(key, ID)
// s.cmServer.RemoveOne(serverID, ID)
log.Printf("conn %s released", ID)
})
// s.cmClient.Add(key, ID, &inConn)
log.Printf("conn %s created", ID)
case CONN_CLIENT_CONTROL:
var key string
err = utils.ReadPacketData(reader, &key)
if err != nil {
log.Printf("read error,ERR:%s", err)
return
}
log.Printf("client control connection, key: %s", key)
if s.clientControlConns.Has(key) {
item, _ := s.clientControlConns.Get(key)
(*item.(*net.Conn)).Close()
}
s.clientControlConns.Set(key, &inConn)
log.Printf("set client %s control conn", key)
}
}

View File

@ -3,111 +3,79 @@ package services
import (
"crypto/tls"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"net"
"snail007/proxy/utils"
"time"
"github.com/xtaci/smux"
)
type TunnelClient struct {
cfg TunnelClientArgs
// cm utils.ConnManager
ctrlConn net.Conn
cfg TunnelClientArgs
ctrlConn net.Conn
isStop bool
userConns utils.ConcurrentMap
}
func NewTunnelClient() Service {
return &TunnelClient{
cfg: TunnelClientArgs{},
// cm: utils.NewConnManager(),
cfg: TunnelClientArgs{},
userConns: utils.NewConcurrentMap(),
isStop: false,
}
}
func (s *TunnelClient) InitService() {
// s.InitHeartbeatDeamon()
func (s *TunnelClient) InitService() (err error) {
return
}
// func (s *TunnelClient) InitHeartbeatDeamon() {
// log.Printf("heartbeat started")
// go func() {
// var heartbeatConn net.Conn
// var ID = *s.cfg.Key
// for {
// //close all connection
// s.cm.RemoveAll()
// if s.ctrlConn != nil {
// s.ctrlConn.Close()
// }
// utils.CloseConn(&heartbeatConn)
// heartbeatConn, err := s.GetInConn(CONN_CLIENT_HEARBEAT, ID)
// if err != nil {
// log.Printf("heartbeat connection err: %s, retrying...", err)
// time.Sleep(time.Second * 3)
// utils.CloseConn(&heartbeatConn)
// continue
// }
// log.Printf("heartbeat connection created,id:%s", ID)
// writeDie := make(chan bool)
// readDie := make(chan bool)
// go func() {
// for {
// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
// _, err = heartbeatConn.Write([]byte{0x00})
// heartbeatConn.SetWriteDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection write err %s", err)
// break
// }
// time.Sleep(time.Second * 3)
// }
// close(writeDie)
// }()
// go func() {
// for {
// signal := make([]byte, 1)
// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
// _, err := heartbeatConn.Read(signal)
// heartbeatConn.SetReadDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection read err: %s", err)
// break
// } else {
// //log.Printf("heartbeat from bridge")
// }
// }
// close(readDie)
// }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// }
// }()
// }
func (s *TunnelClient) CheckArgs() {
func (s *TunnelClient) CheckArgs() (err error) {
if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent)
} else {
log.Fatalf("parent required")
err = fmt.Errorf("parent required")
return
}
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
err = fmt.Errorf("cert and key file required")
return
}
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
return
}
func (s *TunnelClient) StopService() {
// s.cm.RemoveAll()
defer func() {
e := recover()
if e != nil {
log.Printf("stop tclient service crashed,%s", e)
} else {
log.Printf("service tclient stoped")
}
}()
s.isStop = true
if s.ctrlConn != nil {
s.ctrlConn.Close()
}
for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *TunnelClient) Start(args interface{}) (err error) {
s.cfg = args.(TunnelClientArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
log.Printf("proxy on tunnel client mode")
for {
//close all conn
// s.cm.Remove(*s.cfg.Key)
if s.isStop {
return
}
if s.ctrlConn != nil {
s.ctrlConn.Close()
}
@ -122,6 +90,9 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
continue
}
for {
if s.isStop {
return
}
var ID, clientLocalAddr, serverID string
err = utils.ReadPacketData(s.ctrlConn, &ID, &clientLocalAddr, &serverID)
if err != nil {
@ -161,9 +132,26 @@ 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)
c, e := smux.Client(conn, &smux.Config{
KeepAliveInterval: 10 * time.Second,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
MaxFrameSize: 4096,
MaxReceiveBuffer: 4194304,
})
if e != nil {
log.Printf("new mux client conn error,ERR:%s", e)
err = e
return
}
conn, e = c.OpenStream()
if e != nil {
log.Printf("mux client conn open stream error,ERR:%s", e)
err = e
return
}
}
return
}
@ -172,6 +160,12 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
var err error
// for {
for {
if s.isStop {
if inConn != nil {
inConn.Close()
}
return
}
// s.cm.RemoveOne(*s.cfg.Key, ID)
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil {
@ -187,6 +181,9 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
log.Printf("conn %s created", ID)
for {
if s.isStop {
return
}
srcAddr, body, err := utils.ReadUDPPacket(inConn)
if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("connection %s released", ID)
@ -243,6 +240,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
var inConn, outConn net.Conn
var err error
for {
if s.isStop {
return
}
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil {
utils.CloseConn(&inConn)
@ -256,6 +256,9 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
i := 0
for {
if s.isStop {
return
}
i++
outConn, err = utils.ConnectHost(localAddr, *s.cfg.Timeout)
if err == nil || i == 3 {
@ -274,10 +277,14 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
log.Printf("build connection error, err: %s", err)
return
}
inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("conn %s released", ID)
// s.cm.RemoveOne(*s.cfg.Key, ID)
s.userConns.Remove(inAddr)
})
// s.cm.Add(*s.cfg.Key, ID, &inConn)
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, &inConn)
log.Printf("conn %s created", ID)
}

View File

@ -3,28 +3,32 @@ package services
import (
"crypto/tls"
"fmt"
"github.com/snail007/goproxy/utils"
"io"
"log"
"net"
"runtime/debug"
"snail007/proxy/utils"
"strconv"
"strings"
"time"
"github.com/xtaci/smux"
)
type TunnelServer struct {
cfg TunnelServerArgs
udpChn chan UDPItem
sc utils.ServerChannel
cfg TunnelServerArgs
udpChn chan UDPItem
sc utils.ServerChannel
isStop bool
udpConn *net.Conn
userConns utils.ConcurrentMap
}
type TunnelServerManager struct {
cfg TunnelServerArgs
udpChn chan UDPItem
sc utils.ServerChannel
serverID string
// cm utils.ConnManager
servers []*Service
}
func NewTunnelServerManager() Service {
@ -32,19 +36,24 @@ func NewTunnelServerManager() Service {
cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000),
serverID: utils.Uniqueid(),
// cm: utils.NewConnManager(),
servers: []*Service{},
}
}
func (s *TunnelServerManager) Start(args interface{}) (err error) {
s.cfg = args.(TunnelServerArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent)
} else {
log.Fatalf("parent required")
err = fmt.Errorf("parent required")
return
}
s.InitService()
if err = s.InitService(); err != nil {
return
}
log.Printf("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route)
@ -84,6 +93,7 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
if err != nil {
return
}
s.servers = append(s.servers, &server)
}
return
}
@ -91,72 +101,22 @@ func (s *TunnelServerManager) Clean() {
s.StopService()
}
func (s *TunnelServerManager) StopService() {
// s.cm.RemoveAll()
}
func (s *TunnelServerManager) CheckArgs() {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
log.Fatalf("cert and key file required")
for _, server := range s.servers {
(*server).Clean()
}
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
}
func (s *TunnelServerManager) InitService() {
// s.InitHeartbeatDeamon()
func (s *TunnelServerManager) CheckArgs() (err error) {
if *s.cfg.CertFile == "" || *s.cfg.KeyFile == "" {
err = fmt.Errorf("cert and key file required")
return
}
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
return
}
func (s *TunnelServerManager) InitService() (err error) {
return
}
// func (s *TunnelServerManager) InitHeartbeatDeamon() {
// log.Printf("heartbeat started")
// go func() {
// var heartbeatConn net.Conn
// var ID string
// for {
// //close all connection
// s.cm.Remove(ID)
// utils.CloseConn(&heartbeatConn)
// heartbeatConn, ID, err := s.GetOutConn(CONN_SERVER_HEARBEAT)
// if err != nil {
// log.Printf("heartbeat connection err: %s, retrying...", err)
// time.Sleep(time.Second * 3)
// utils.CloseConn(&heartbeatConn)
// continue
// }
// log.Printf("heartbeat connection created,id:%s", ID)
// writeDie := make(chan bool)
// readDie := make(chan bool)
// go func() {
// for {
// heartbeatConn.SetWriteDeadline(time.Now().Add(time.Second * 3))
// _, err = heartbeatConn.Write([]byte{0x00})
// heartbeatConn.SetWriteDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection write err %s", err)
// break
// }
// time.Sleep(time.Second * 3)
// }
// close(writeDie)
// }()
// go func() {
// for {
// signal := make([]byte, 1)
// heartbeatConn.SetReadDeadline(time.Now().Add(time.Second * 6))
// _, err := heartbeatConn.Read(signal)
// heartbeatConn.SetReadDeadline(time.Time{})
// if err != nil {
// log.Printf("heartbeat connection read err: %s", err)
// break
// } else {
// // log.Printf("heartbeat from bridge")
// }
// }
// close(readDie)
// }()
// select {
// case <-readDie:
// case <-writeDie:
// }
// }
// }()
// }
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn()
if err != nil {
@ -174,7 +134,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)
}
@ -182,8 +142,10 @@ func (s *TunnelServerManager) GetConn() (conn net.Conn, err error) {
}
func NewTunnelServer() Service {
return &TunnelServer{
cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000),
cfg: TunnelServerArgs{},
udpChn: make(chan UDPItem, 50000),
isStop: false,
userConns: utils.NewConcurrentMap(),
}
}
@ -193,19 +155,50 @@ type UDPItem struct {
srcAddr *net.UDPAddr
}
func (s *TunnelServer) InitService() {
s.UDPConnDeamon()
}
func (s *TunnelServer) CheckArgs() {
if *s.cfg.Remote == "" {
log.Fatalf("remote required")
func (s *TunnelServer) StopService() {
defer func() {
e := recover()
if e != nil {
log.Printf("stop server service crashed,%s", e)
} else {
log.Printf("service server stoped")
}
}()
s.isStop = true
if s.sc.Listener != nil {
(*s.sc.Listener).Close()
}
if s.sc.UDPListener != nil {
(*s.sc.UDPListener).Close()
}
if s.udpConn != nil {
(*s.udpConn).Close()
}
for _, c := range s.userConns.Items() {
(*c.(*net.Conn)).Close()
}
}
func (s *TunnelServer) InitService() (err error) {
s.UDPConnDeamon()
return
}
func (s *TunnelServer) CheckArgs() (err error) {
if *s.cfg.Remote == "" {
err = fmt.Errorf("remote required")
return
}
return
}
func (s *TunnelServer) Start(args interface{}) (err error) {
s.cfg = args.(TunnelServerArgs)
s.CheckArgs()
s.InitService()
if err = s.CheckArgs(); err != nil {
return
}
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p)
@ -231,6 +224,9 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
var outConn net.Conn
var ID string
for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn(CONN_SERVER)
if err != nil {
utils.CloseConn(&outConn)
@ -241,12 +237,15 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
break
}
}
inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) {
// s.cfg.Mgr.cm.RemoveOne(s.cfg.Mgr.serverID, ID)
s.userConns.Remove(inAddr)
log.Printf("%s conn %s released", *s.cfg.Key, ID)
})
//add conn
// s.cfg.Mgr.cm.Add(s.cfg.Mgr.serverID, ID, &inConn)
if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close()
}
s.userConns.Set(inAddr, &inConn)
log.Printf("%s conn %s created", *s.cfg.Key, ID)
})
if err != nil {
@ -280,9 +279,26 @@ 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)
c, e := smux.Client(conn, &smux.Config{
KeepAliveInterval: 10 * time.Second,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
MaxFrameSize: 4096,
MaxReceiveBuffer: 4194304,
})
if e != nil {
log.Printf("new mux client conn error,ERR:%s", e)
err = e
return
}
conn, e = c.OpenStream()
if e != nil {
log.Printf("mux client conn open stream error,ERR:%s", e)
err = e
return
}
}
return
}
@ -299,10 +315,19 @@ func (s *TunnelServer) UDPConnDeamon() {
// var cmdChn = make(chan bool, 1000)
var err error
for {
if s.isStop {
return
}
item := <-s.udpChn
RETRY:
if s.isStop {
return
}
if outConn == nil {
for {
if s.isStop {
return
}
outConn, ID, err = s.GetOutConn(CONN_SERVER)
if err != nil {
// cmdChn <- true
@ -313,11 +338,14 @@ func (s *TunnelServer) UDPConnDeamon() {
continue
} else {
go func(outConn net.Conn, ID string) {
go func() {
// <-cmdChn
// outConn.Close()
}()
if s.udpConn != nil {
(*s.udpConn).Close()
}
s.udpConn = &outConn
for {
if s.isStop {
return
}
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("UDP deamon connection %s exited", ID)

View File

@ -3,13 +3,13 @@ package services
import (
"bufio"
"fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"hash/crc32"
"io"
"log"
"net"
"runtime/debug"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils"
"strconv"
"strings"
"time"
@ -17,44 +17,68 @@ import (
type UDP struct {
p utils.ConcurrentMap
outPool utils.OutPool
outPool utils.OutConn
cfg UDPArgs
sc *utils.ServerChannel
isStop bool
}
func NewUDP() Service {
return &UDP{
outPool: utils.OutPool{},
outPool: utils.OutConn{},
p: utils.NewConcurrentMap(),
isStop: false,
}
}
func (s *UDP) CheckArgs() {
func (s *UDP) CheckArgs() (err error) {
if *s.cfg.Parent == "" {
log.Fatalf("parent required for udp %s", *s.cfg.Local)
err = fmt.Errorf("parent required for udp %s", *s.cfg.Local)
return
}
if *s.cfg.ParentType == "" {
log.Fatalf("parent type unkown,use -T <tls|tcp>")
err = fmt.Errorf("parent type unkown,use -T <tls|tcp>")
return
}
if *s.cfg.ParentType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
return
}
func (s *UDP) InitService() {
func (s *UDP) InitService() (err error) {
if *s.cfg.ParentType != TYPE_UDP {
s.InitOutConnPool()
}
return
}
func (s *UDP) StopService() {
if s.outPool.Pool != nil {
s.outPool.Pool.ReleaseAll()
defer func() {
e := recover()
if e != nil {
log.Printf("stop udp service crashed,%s", e)
} else {
log.Printf("service udp stoped")
}
}()
s.isStop = true
if s.sc.Listener != nil && *s.sc.Listener != nil {
(*s.sc.Listener).Close()
}
if s.sc.UDPListener != nil {
(*s.sc.UDPListener).Close()
}
}
func (s *UDP) Start(args interface{}) (err error) {
s.cfg = args.(UDPArgs)
s.CheckArgs()
if err = s.CheckArgs(); err != nil {
return
}
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitService()
if err = s.InitService(); err != nil {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p)
@ -95,7 +119,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
isNew = !s.p.Has(connKey)
var _conn interface{}
if isNew {
_conn, err = s.outPool.Pool.Get()
_conn, err = s.outPool.Get()
if err != nil {
return nil, false, err
}
@ -109,7 +133,7 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
numLocal := crc32.ChecksumIEEE([]byte(localAddr.String()))
numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String()))
mod := uint32(*s.cfg.PoolSize)
mod := uint32(10)
if mod == 0 {
mod = 10
}
@ -128,6 +152,10 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
}()
log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
for {
if s.isStop {
conn.Close()
return
}
srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn))
if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %d released", connKey)
@ -206,15 +234,13 @@ func (s *UDP) InitOutConnPool() {
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP {
//dur int, isTLS bool, certBytes, keyBytes []byte,
//parent string, timeout int, InitialCap int, MaxCap int
s.outPool = utils.NewOutPool(
s.outPool = utils.NewOutConn(
*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,
*s.cfg.PoolSize*2,
)
}
}

View File

@ -0,0 +1,95 @@
package conncrypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"hash"
"io"
"net"
"golang.org/x/crypto/pbkdf2"
)
//Confg defaults
const DefaultIterations = 2048
const DefaultKeySize = 32 //256bits
var DefaultHashFunc = sha256.New
var DefaultSalt = []byte(`
(;QUHj.BQ?RXzYSO]ifkXp/G!kFmWyXyEV6Nt!d|@bo+N$L9+<d$|g6e26T}
Ao<:>SOd,6acYKY_ec+(x"R";\'4&fTAVu92GVA-wxBptOTM^2,iP5%)wnhW
hwk=]Snsgymt!3gbP2pe=J//}1a?lp9ej=&TB!C_V(cT2?z8wyoL_-13fd[]
`) //salt must be predefined in order to derive the same key
//Config stores the PBKDF2 key generation parameters
type Config struct {
Password string
Salt []byte
Iterations int
KeySize int
HashFunc func() hash.Hash
}
//New creates an AES encrypted net.Conn by generating
//a key using PBKDF2 with the provided configuration
func New(conn net.Conn, c *Config) net.Conn {
//set defaults
if len(c.Salt) == 0 {
c.Salt = DefaultSalt
}
if c.Iterations == 0 {
c.Iterations = DefaultIterations
}
if c.KeySize != 16 && c.KeySize != 24 && c.KeySize != 32 {
c.KeySize = DefaultKeySize
}
if c.HashFunc == nil {
c.HashFunc = DefaultHashFunc
}
//generate key
key := pbkdf2.Key([]byte(c.Password), c.Salt, c.Iterations, c.KeySize, c.HashFunc)
// could use scrypt, but it's a bit slow...
// dk, err := scrypt.Key([]byte(c.Password), c.Salt, 16384, 8, 1, 32)
//key will be always be the correct size so this will never error
conn, _ = NewFromKey(conn, key)
return conn
}
//NewFromKey creates an AES encrypted net.Conn using the provided key
func NewFromKey(conn net.Conn, key []byte) (net.Conn, error) {
block, err := aes.NewCipher([]byte(key))
if err != nil {
return nil, err
}
//hash(key) -> read IV
riv := DefaultHashFunc().Sum(key)
rstream := cipher.NewCFBDecrypter(block, riv[:aes.BlockSize])
reader := &cipher.StreamReader{S: rstream, R: conn}
//hash(read IV) -> write IV
wiv := DefaultHashFunc().Sum(riv)
wstream := cipher.NewCFBEncrypter(block, wiv[:aes.BlockSize])
writer := &cipher.StreamWriter{S: wstream, W: conn}
return &cryptoConn{
Conn: conn,
r: reader,
w: writer,
}, nil
}
type cryptoConn struct {
net.Conn
r io.Reader
w io.Writer
}
//replace read and write methods
func (c *cryptoConn) Read(p []byte) (int, error) {
return c.r.Read(p)
}
func (c *cryptoConn) Write(p []byte) (int, error) {
return c.w.Write(p)
}

View File

@ -10,6 +10,7 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"io"
"io/ioutil"
"log"
@ -18,11 +19,10 @@ import (
"net/http"
"os"
"os/exec"
"snail007/proxy/services/kcpcfg"
"golang.org/x/crypto/pbkdf2"
"snail007/proxy/utils/id"
"github.com/snail007/goproxy/utils/id"
"strconv"
"strings"
"time"
@ -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) {
@ -468,15 +524,15 @@ func SubBytes(bytes []byte, start, end int) []byte {
}
return bytes[start:end]
}
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
certBytes, err := ioutil.ReadFile(cert)
func TlsBytes(cert, key string) (certBytes, keyBytes []byte, err error) {
certBytes, err = ioutil.ReadFile(cert)
if err != nil {
log.Fatalf("err : %s", err)
err = fmt.Errorf("err : %s", err)
return
}
keyBytes, err = ioutil.ReadFile(key)
if err != nil {
log.Fatalf("err : %s", err)
err = fmt.Errorf("err : %s", err)
return
}
return

View File

@ -1,145 +0,0 @@
package utils
import (
"log"
"sync"
"time"
)
//ConnPool to use
type ConnPool interface {
Get() (conn interface{}, err error)
Put(conn interface{})
ReleaseAll()
Len() (length int)
}
type poolConfig struct {
Factory func() (interface{}, error)
IsActive func(interface{}) bool
Release func(interface{})
InitialCap int
MaxCap int
}
func NewConnPool(poolConfig poolConfig) (pool ConnPool, err error) {
p := netPool{
config: poolConfig,
conns: make(chan interface{}, poolConfig.MaxCap),
lock: &sync.Mutex{},
}
//log.Printf("pool MaxCap:%d", poolConfig.MaxCap)
if poolConfig.MaxCap > 0 {
err = p.initAutoFill(false)
if err == nil {
p.initAutoFill(true)
}
}
return &p, nil
}
type netPool struct {
conns chan interface{}
lock *sync.Mutex
config poolConfig
}
func (p *netPool) initAutoFill(async bool) (err error) {
var worker = func() (err error) {
for {
//log.Printf("pool fill: %v , len: %d", p.Len() <= p.config.InitialCap/2, p.Len())
if p.Len() <= p.config.InitialCap/2 {
p.lock.Lock()
errN := 0
for i := 0; i < p.config.InitialCap; i++ {
c, err := p.config.Factory()
if err != nil {
errN++
if async {
continue
} else {
p.lock.Unlock()
return err
}
}
select {
case p.conns <- c:
default:
p.config.Release(c)
break
}
if p.Len() >= p.config.InitialCap {
break
}
}
if errN > 0 {
log.Printf("fill conn pool fail , ERRN:%d", errN)
}
p.lock.Unlock()
}
if !async {
return
}
time.Sleep(time.Second * 2)
}
}
if async {
go worker()
} else {
err = worker()
}
return
}
func (p *netPool) Get() (conn interface{}, err error) {
// defer func() {
// log.Printf("pool len : %d", p.Len())
// }()
p.lock.Lock()
defer p.lock.Unlock()
// for {
select {
case conn = <-p.conns:
if p.config.IsActive(conn) {
return
}
p.config.Release(conn)
default:
conn, err = p.config.Factory()
if err != nil {
return nil, err
}
return conn, nil
}
// }
return
}
func (p *netPool) Put(conn interface{}) {
if conn == nil {
return
}
p.lock.Lock()
defer p.lock.Unlock()
if !p.config.IsActive(conn) {
p.config.Release(conn)
}
select {
case p.conns <- conn:
default:
p.config.Release(conn)
}
}
func (p *netPool) ReleaseAll() {
p.lock.Lock()
defer p.lock.Unlock()
close(p.conns)
for c := range p.conns {
p.config.Release(c)
}
p.conns = make(chan interface{}, p.config.InitialCap)
}
func (p *netPool) Len() (length int) {
return len(p.conns)
}

View File

@ -2,10 +2,10 @@ package utils
import (
"fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"log"
"net"
"runtime/debug"
"snail007/proxy/services/kcpcfg"
"strconv"
kcp "github.com/xtaci/kcp-go"
@ -24,7 +24,7 @@ func NewServerChannel(ip string, port int) ServerChannel {
ip: ip,
port: port,
errAcceptHandler: func(err error) {
fmt.Printf("accept error , ERR:%s", err)
log.Printf("accept error , ERR:%s", err)
},
}
}
@ -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
View 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
View File

@ -0,0 +1,226 @@
package socks
import (
"fmt"
"github.com/snail007/goproxy/utils"
"net"
"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
}

View File

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

View File

@ -4,16 +4,15 @@ import (
"bytes"
"crypto/tls"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils/sni"
"io"
"io/ioutil"
"log"
"net"
"net/url"
"snail007/proxy/services/kcpcfg"
"snail007/proxy/utils/sni"
"strings"
"sync"
"time"
@ -28,6 +27,7 @@ type Checker struct {
directMap ConcurrentMap
interval int64
timeout int
isStop bool
}
type CheckerItem struct {
IsHTTPS bool
@ -48,6 +48,7 @@ func NewChecker(timeout int, interval int64, blockedFile, directFile string) Che
data: NewConcurrentMap(),
interval: interval,
timeout: timeout,
isStop: false,
}
ch.blockedMap = ch.loadMap(blockedFile)
ch.directMap = ch.loadMap(directFile)
@ -81,6 +82,9 @@ func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
}
return
}
func (c *Checker) Stop() {
c.isStop = true
}
func (c *Checker) start() {
go func() {
//log.Printf("checker started")
@ -107,6 +111,9 @@ func (c *Checker) start() {
}(v.(CheckerItem))
}
time.Sleep(time.Second * time.Duration(c.interval))
if c.isStop {
return
}
}
}()
}
@ -280,7 +287,11 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
} else {
err = fmt.Errorf("token error")
}
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, string(body))
b := string(body)
if len(b) > 50 {
b = b[:50]
}
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b)
}
if err != nil && tryCount < ba.authRetry {
log.Print(err)
@ -317,7 +328,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 +413,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 +437,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 +448,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
@ -490,60 +505,33 @@ func (req *HTTPRequest) addPortIfNot() (newHost string) {
return
}
type OutPool struct {
Pool ConnPool
dur int
typ string
certBytes []byte
keyBytes []byte
kcp kcpcfg.KCPConfigArgs
address string
timeout int
type OutConn struct {
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) {
op = OutPool{
dur: dur,
typ: typ,
certBytes: certBytes,
keyBytes: keyBytes,
kcp: kcp,
address: address,
timeout: timeout,
func NewOutConn(dur int, typ string, kcp kcpcfg.KCPConfigArgs, certBytes, keyBytes, caCertBytes []byte, address string, timeout int) (op OutConn) {
return OutConn{
dur: dur,
typ: typ,
certBytes: certBytes,
keyBytes: keyBytes,
caCertBytes: caCertBytes,
kcp: kcp,
address: address,
timeout: timeout,
}
var err error
op.Pool, err = NewConnPool(poolConfig{
IsActive: func(conn interface{}) bool { return true },
Release: func(conn interface{}) {
if conn != nil {
conn.(net.Conn).SetDeadline(time.Now().Add(time.Millisecond))
conn.(net.Conn).Close()
// log.Println("conn released")
}
},
InitialCap: InitialCap,
MaxCap: MaxCap,
Factory: func() (conn interface{}, err error) {
conn, err = op.getConn()
return
},
})
if err != nil {
log.Fatalf("init conn pool fail ,%s", err)
} else {
if InitialCap > 0 {
log.Printf("init conn pool success")
op.initPoolDeamon()
} else {
log.Printf("conn pool closed")
}
}
return
}
func (op *OutPool) getConn() (conn interface{}, err error) {
func (op *OutConn) Get() (conn net.Conn, err error) {
if op.typ == "tls" {
var _conn tls.Conn
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes)
_conn, err = TlsConnectHost(op.address, op.timeout, op.certBytes, op.keyBytes, op.caCertBytes)
if err == nil {
conn = net.Conn(&_conn)
}
@ -555,176 +543,6 @@ func (op *OutPool) getConn() (conn interface{}, err error) {
return
}
func (op *OutPool) initPoolDeamon() {
go func() {
if op.dur <= 0 {
return
}
log.Printf("pool deamon started")
for {
time.Sleep(time.Second * time.Duration(op.dur))
conn, err := op.getConn()
if err != nil {
log.Printf("pool deamon err %s , release pool", err)
op.Pool.ReleaseAll()
} else {
conn.(net.Conn).SetDeadline(time.Now().Add(time.Millisecond))
conn.(net.Conn).Close()
}
}
}()
}
type HeartbeatData struct {
Data []byte
N int
Error error
}
type HeartbeatReadWriter struct {
conn *net.Conn
// rchn chan HeartbeatData
l *sync.Mutex
dur int
errHandler func(err error, hb *HeartbeatReadWriter)
once *sync.Once
datachn chan byte
// rbuf bytes.Buffer
// signal chan bool
rerrchn chan error
}
func NewHeartbeatReadWriter(conn *net.Conn, dur int, fn func(err error, hb *HeartbeatReadWriter)) (hrw HeartbeatReadWriter) {
hrw = HeartbeatReadWriter{
conn: conn,
l: &sync.Mutex{},
dur: dur,
// rchn: make(chan HeartbeatData, 10000),
// signal: make(chan bool, 1),
errHandler: fn,
datachn: make(chan byte, 4*1024),
once: &sync.Once{},
rerrchn: make(chan error, 1),
// rbuf: bytes.Buffer{},
}
hrw.heartbeat()
hrw.reader()
return
}
func (rw *HeartbeatReadWriter) Close() {
CloseConn(rw.conn)
}
func (rw *HeartbeatReadWriter) reader() {
go func() {
//log.Printf("heartbeat read started")
for {
n, data, err := rw.read()
if n == -1 {
continue
}
//log.Printf("n:%d , data:%s ,err:%s", n, string(data), err)
if err == nil {
//fmt.Printf("write data %s\n", string(data))
for _, b := range data {
rw.datachn <- b
}
}
if err != nil {
//log.Printf("heartbeat reader err: %s", err)
select {
case rw.rerrchn <- err:
default:
}
rw.once.Do(func() {
rw.errHandler(err, rw)
})
break
}
}
//log.Printf("heartbeat read exited")
}()
}
func (rw *HeartbeatReadWriter) read() (n int, data []byte, err error) {
var typ uint8
err = binary.Read((*rw.conn), binary.LittleEndian, &typ)
if err != nil {
return
}
if typ == 0 {
// log.Printf("heartbeat revecived")
n = -1
return
}
var dataLength uint32
binary.Read((*rw.conn), binary.LittleEndian, &dataLength)
_data := make([]byte, dataLength)
// log.Printf("dataLength:%d , data:%s", dataLength, string(data))
n, err = (*rw.conn).Read(_data)
//log.Printf("n:%d , data:%s ,err:%s", n, string(data), err)
if err != nil {
return
}
if uint32(n) != dataLength {
err = fmt.Errorf("read short data body")
return
}
data = _data[:n]
return
}
func (rw *HeartbeatReadWriter) heartbeat() {
go func() {
//log.Printf("heartbeat started")
for {
if rw.conn == nil || *rw.conn == nil {
//log.Printf("heartbeat err: conn nil")
break
}
rw.l.Lock()
_, err := (*rw.conn).Write([]byte{0})
rw.l.Unlock()
if err != nil {
//log.Printf("heartbeat err: %s", err)
rw.once.Do(func() {
rw.errHandler(err, rw)
})
break
} else {
// log.Printf("heartbeat send ok")
}
time.Sleep(time.Second * time.Duration(rw.dur))
}
//log.Printf("heartbeat exited")
}()
}
func (rw *HeartbeatReadWriter) Read(p []byte) (n int, err error) {
data := make([]byte, cap(p))
for i := 0; i < cap(p); i++ {
data[i] = <-rw.datachn
n++
//fmt.Printf("read %d %v\n", i, data[:n])
if len(rw.datachn) == 0 {
n = i + 1
copy(p, data[:n])
return
}
}
return
}
func (rw *HeartbeatReadWriter) Write(p []byte) (n int, err error) {
defer rw.l.Unlock()
rw.l.Lock()
pkg := new(bytes.Buffer)
binary.Write(pkg, binary.LittleEndian, uint8(1))
binary.Write(pkg, binary.LittleEndian, uint32(len(p)))
binary.Write(pkg, binary.LittleEndian, p)
bs := pkg.Bytes()
n, err = (*rw.conn).Write(bs)
if err == nil {
n = len(p)
}
return
}
type ConnManager struct {
pool ConcurrentMap
l *sync.Mutex
@ -931,8 +749,16 @@ func NewCompStream(conn net.Conn) *CompStream {
c.r = snappy.NewReader(conn)
return c
}
func NewCompConn(conn net.Conn) net.Conn {
c := CompStream{}
c.conn = conn
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
return &c
}
type CompStream struct {
net.Conn
conn net.Conn
w *snappy.Writer
r *snappy.Reader

16
vendor/github.com/golang/snappy/.gitignore generated vendored Normal file
View File

@ -0,0 +1,16 @@
cmd/snappytool/snappytool
testdata/bench
# These explicitly listed benchmark data files are for an obsolete version of
# snappy_test.go.
testdata/alice29.txt
testdata/asyoulik.txt
testdata/fireworks.jpeg
testdata/geo.protodata
testdata/html
testdata/html_x_4
testdata/kppkn.gtb
testdata/lcet10.txt
testdata/paper-100k.pdf
testdata/plrabn12.txt
testdata/urls.10K

4
vendor/github.com/miekg/dns/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
*.6
tags
test.out
a.out

24
vendor/github.com/pkg/errors/.gitignore generated vendored Executable file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

14
vendor/github.com/templexxx/cpufeat/.gitignore generated vendored Normal file
View File

@ -0,0 +1,14 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

40
vendor/github.com/templexxx/reedsolomon/.gitignore generated vendored Normal file
View File

@ -0,0 +1,40 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
/.idea
/backup
/loopunroll/
cpu.out
mathtool/galois/
mathtool/matrix/
mem.out
/examples/
/.DS_Store
/mathtool/cntinverse
/invert
/bakcup
/buf.svg
*.svg
*.out
/escape

18
vendor/github.com/templexxx/xor/.gitignore generated vendored Normal file
View File

@ -0,0 +1,18 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
/backup/
/backup2/
/.idea
/backup3/

24
vendor/github.com/xtaci/kcp-go/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

24
vendor/github.com/xtaci/smux/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof