54 Commits
v4.7 ... v5.0

Author SHA1 Message Date
arraykeys@gmail.com
4214ec4239 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-06 15:06:56 +08:00
arraykeys@gmail.com
504de47999 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-06-06 14:44:04 +08:00
arraykeys@gmail.com
e185d734d0 mux内网穿透切换smux到yamux
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-31 16:26:40 +08:00
arraykeys@gmail.com
9b1ef52649 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-05-31 11:39:50 +08:00
arraykeys@gmail.com
5c9fc850d8 fix #84
fix #81

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-31 11:39:29 +08:00
snail007
ff96e52a33 Merge pull request #89 from moonfruit/dev
HTTP Basic 认证失败返回的 WWW-Authenticate 更正为 Proxy-Authenticate
2018-05-24 11:22:35 +08:00
MoonFruit
78004bcd39 HTTP Basic 认证失败返回的 WWW-Authenticate 更正为 Proxy-Authenticate 2018-05-24 09:58:04 +08:00
arraykeys@gmail.com
b16decf976 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-23 14:38:19 +08:00
arraykeys@gmail.com
828636553d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-23 14:23:43 +08:00
arraykeys@gmail.com
bfcc27e70f fix #85
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-22 12:34:18 +08:00
arraykeys@gmail.com
7cb7d34d42 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-22 12:01:55 +08:00
arraykeys@gmail.com
5276154401 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-22 11:32:31 +08:00
arraykeys@gmail.com
dad091441e Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-22 11:30:19 +08:00
arraykeys@gmail.com
81ff3dadd5 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-22 11:26:34 +08:00
arraykeys@gmail.com
f559fb1cae fix #58
fix #80

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-22 11:21:58 +08:00
arraykeys@gmail.com
8649bbc191 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-21 16:04:40 +08:00
snail007
d775339948 Merge pull request #83 from yelongyu/dev
Update README_ZH.md
2018-05-20 22:46:51 +08:00
yelongyu
69a5b906e0 Update README_ZH.md
删除多余的"域名"
2018-05-20 17:33:49 +08:00
yelongyu
2d66cc6215 Update README_ZH.md
添加多级加密HTTP代理设置注意事项
2018-05-20 17:26:46 +08:00
arraykeys@gmail.com
8d74baf48c Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-16 15:59:53 +08:00
arraykeys@gmail.com
d7641c4483 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-16 11:23:54 +08:00
arraykeys@gmail.com
ffe54c3af7 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-05-15 10:58:17 +08:00
arraykeys@gmail.com
53df3b5578 add docker support
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-15 10:56:57 +08:00
snail007
54c22f1410 Merge pull request #77 from FarhadF/dev
Added Dockerfile
2018-05-15 08:58:30 +08:00
FarhadF
366b7e04f3 Added Dockerfile 2018-05-14 17:33:00 +04:30
snail007
a33a4d2bd3 Merge pull request #74 from whgfu/dev
Dev-更新说明文件中socks5 http api认证中的 url参数为三个
2018-05-14 20:53:01 +08:00
粥冰涅槃
eb00d570a8 更新说明文件中socks5 http api认证中的 url参数为三个 2018-05-14 18:42:01 +08:00
whgfu
500142f4c8 Merge pull request #1 from snail007/dev
Dev
2018-05-14 18:31:11 +08:00
arraykeys
bffd5891cc no message 2018-05-08 08:45:29 +08:00
arraykeys
cf2e6f9ff0 no message 2018-05-08 07:28:05 +08:00
arraykeys
ed4b8d11e3 no message 2018-05-07 20:58:59 +08:00
arraykeys
905c1eac63 no message 2018-05-07 20:48:32 +08:00
arraykeys@gmail.com
61872133b1 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 17:46:23 +08:00
arraykeys@gmail.com
e18f53a5bb Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 17:32:38 +08:00
arraykeys@gmail.com
947fb51963 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 17:25:47 +08:00
arraykeys@gmail.com
7aeef3f8ba Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 17:14:20 +08:00
arraykeys@gmail.com
b42f6a6364 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 16:23:47 +08:00
arraykeys@gmail.com
92f4d31dfc Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-05-07 16:23:01 +08:00
arraykeys@gmail.com
4f11593f26 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-05-07 16:21:58 +08:00
arraykeys
795d63879f no message 2018-05-04 18:24:52 +08:00
arraykeys
1c46eeaf43 no message 2018-05-04 18:10:09 +08:00
arraykeys
6f47d12498 no message 2018-05-04 17:49:56 +08:00
arraykeys
e6c56675ca no message 2018-05-04 17:42:59 +08:00
snail007
ff92c96d8d Merge pull request #70 from yincongcyincong/dev
Update README.md
2018-05-03 23:15:19 +08:00
yincongcyincong
fed2afb964 Update README.md 2018-05-03 18:42:42 +08:00
arraykeys@gmail.com
b3feff7843 1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
2.增加了获取sdk版本的Version()方法.

Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
2018-05-03 17:59:06 +08:00
arraykeys@gmail.com
edb2fb3458 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-28 14:18:03 +08:00
arraykeys@gmail.com
dc51a0bd9d Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-28 14:15:47 +08:00
arraykeys@gmail.com
34b30ac8c9 Merge branch 'dev' of https://github.com/snail007/goproxy.git into dev 2018-04-28 14:13:50 +08:00
arraykeys@gmail.com
8122af9096 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-28 14:13:20 +08:00
snail007
2b267fe4bb Merge pull request #66 from shoaly/patch-4
good job
2018-04-28 13:54:32 +08:00
shoaly
90bf483976 Update README_ZH.md 2018-04-28 13:45:41 +08:00
arraykeys@gmail.com
b109f273a5 Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 16:28:14 +08:00
arraykeys@gmail.com
482977a4ac Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com> 2018-04-27 15:27:13 +08:00
44 changed files with 4904 additions and 652 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ goproxy
*.exe *.exe
*.exe~ *.exe~
.* .*
*.prof
!.gitignore !.gitignore
release-* release-*
proxy.crt proxy.crt

View File

@ -1,4 +1,24 @@
proxy更新日志 proxy更新日志
v4.9
1.修复了HTTP Basic代理返回不合适的头部,导致浏览器不会弹框,个别代理插件无法认证的问题.
2.内网穿透切换smux到yamux.
3.优化了HTTP(S)\SOCKS5代理--always的处理逻辑.
v4.8
1.优化了SPS连接HTTP上级的指令,避免了某些代理不响应的问题.
2.SPS功能增加了参数:
--disable-http:禁用http(s)代理
--disable-socks:禁用socks代理
默认都是false(开启).
3.重构了部分代码的日志部分,保证了日志按着预期输出.
4.修复了sps\http代理初始化服务的时机不正确,导致nil异常的bug.
5.优化了sps日志输出.
6.--debug参数增加了Profiling功能,可以保存cpu,内存等多种调试数据到文件.
7.优化了服务注册,避免了不必要的内存开销.
8.增加了Dockerfile和docker安装手册.
9.优化了ioCopy避免了内存泄漏,大大提升了内存占用的稳定性.
v4.7 v4.7
1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持. 1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持.
2.优化了bridge的日志,增加了client和server的掉线日志. 2.优化了bridge的日志,增加了client和server的掉线日志.

9
Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM golang:1.8.5-alpine as builder
ARG GOPROXY_VERSION=master
RUN apk update && apk upgrade && \
apk add --no-cache git && cd /go/src/ && git clone https://github.com/snail007/goproxy && \
cd goproxy && git checkout ${GOPROXY_VERSION} && \
go get && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o proxy
FROM alpine:3.7
COPY --from=builder /go/src/goproxy/proxy /
CMD /proxy ${OPTS}

140
Godeps/Godeps.json generated
View File

@ -1,11 +1,27 @@
{ {
"ImportPath": "github.com/snail007/goproxy", "ImportPath": "github.com/snail007/goproxy",
"GoVersion": "go1.9", "GoVersion": "go1.8",
"GodepVersion": "v80", "GodepVersion": "v80",
"Packages": [ "Packages": [
"./..." "./..."
], ],
"Deps": [ "Deps": [
{
"ImportPath": "github.com/Yawning/chacha20",
"Rev": "e3b1f968fc6397b51d963fee8ec8711a47bc0ce8"
},
{
"ImportPath": "github.com/alecthomas/template",
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
},
{
"ImportPath": "github.com/alecthomas/template/parse",
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
},
{
"ImportPath": "github.com/alecthomas/units",
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
},
{ {
"ImportPath": "github.com/golang/snappy", "ImportPath": "github.com/golang/snappy",
"Rev": "553a641470496b2327abcac10b36396bd98e45c9" "Rev": "553a641470496b2327abcac10b36396bd98e45c9"
@ -15,66 +31,15 @@
"Comment": "v1.0.4-1-g40b5202", "Comment": "v1.0.4-1-g40b5202",
"Rev": "40b520211179dbf7eaafaa7fe1ffaa1b7d929ee0" "Rev": "40b520211179dbf7eaafaa7fe1ffaa1b7d929ee0"
}, },
{
"ImportPath": "github.com/xtaci/kcp-go",
"Comment": "v3.19-6-g21da33a",
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
},
{
"ImportPath": "github.com/xtaci/smux",
"Comment": "v1.0.6",
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
},
{
"ImportPath": "golang.org/x/crypto/pbkdf2",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/crypto/ssh",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/time/rate",
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
},
{
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
"Comment": "v2.2.5",
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
},
{
"ImportPath": "golang.org/x/crypto/ed25519",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/net/ipv4",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
},
{
"ImportPath": "golang.org/x/net/ipv6",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
},
{
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/net/bpf",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
},
{
"ImportPath": "golang.org/x/net/internal/iana",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
},
{
"ImportPath": "golang.org/x/net/internal/socket",
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
},
{ {
"ImportPath": "github.com/pkg/errors", "ImportPath": "github.com/pkg/errors",
"Comment": "v0.8.0-6-g602255c", "Comment": "v0.8.0-6-g602255c",
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9" "Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
}, },
{
"ImportPath": "github.com/templexxx/cpufeat",
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
},
{ {
"ImportPath": "github.com/templexxx/reedsolomon", "ImportPath": "github.com/templexxx/reedsolomon",
"Comment": "0.1.1-4-g7092926", "Comment": "0.1.1-4-g7092926",
@ -90,6 +55,16 @@
"Comment": "v1.0.1-3-g9d99fac", "Comment": "v1.0.1-3-g9d99fac",
"Rev": "9d99face20b0dd300b7db50b3f69758de41c096a" "Rev": "9d99face20b0dd300b7db50b3f69758de41c096a"
}, },
{
"ImportPath": "github.com/xtaci/kcp-go",
"Comment": "v3.19-6-g21da33a",
"Rev": "21da33a6696d67c1bffb3c954366499d613097a6"
},
{
"ImportPath": "github.com/xtaci/smux",
"Comment": "v1.0.6",
"Rev": "ebec7ef2574b42a7088cd7751176483e0a27d458"
},
{ {
"ImportPath": "golang.org/x/crypto/blowfish", "ImportPath": "golang.org/x/crypto/blowfish",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
@ -98,10 +73,34 @@
"ImportPath": "golang.org/x/crypto/cast5", "ImportPath": "golang.org/x/crypto/cast5",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{
"ImportPath": "golang.org/x/crypto/curve25519",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/crypto/ed25519",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/crypto/ed25519/internal/edwards25519",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/crypto/pbkdf2",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{ {
"ImportPath": "golang.org/x/crypto/salsa20", "ImportPath": "golang.org/x/crypto/salsa20",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{
"ImportPath": "golang.org/x/crypto/ssh",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
},
{ {
"ImportPath": "golang.org/x/crypto/tea", "ImportPath": "golang.org/x/crypto/tea",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
@ -115,28 +114,33 @@
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
}, },
{ {
"ImportPath": "github.com/templexxx/cpufeat", "ImportPath": "golang.org/x/net/bpf",
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e" "Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
}, },
{ {
"ImportPath": "golang.org/x/crypto/salsa20/salsa", "ImportPath": "golang.org/x/net/internal/iana",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
}, },
{ {
"ImportPath": "golang.org/x/crypto/curve25519", "ImportPath": "golang.org/x/net/internal/socket",
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8" "Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
}, },
{ {
"ImportPath": "github.com/alecthomas/template", "ImportPath": "golang.org/x/net/ipv4",
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c" "Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
}, },
{ {
"ImportPath": "github.com/alecthomas/units", "ImportPath": "golang.org/x/net/ipv6",
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" "Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
}, },
{ {
"ImportPath": "github.com/alecthomas/template/parse", "ImportPath": "golang.org/x/time/rate",
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c" "Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
},
{
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
"Comment": "v2.2.5",
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
} }
] ]
} }

View File

@ -6,7 +6,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases)
[中文手册](/README_ZH.md) [中文手册](/README_ZH.md) **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
### Features ### Features
- chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy. - chain-style proxy: the program itself can be a primary proxy, and if a parent proxy is set, it can be used as a second level proxy or even a N level proxy.
@ -36,7 +36,9 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
- ...   - ...  
This page is the v4.7 manual, and the other version of the manual can be checked by the following link. This page is the v4.9 manual, and the other version of the manual can be checked by the following link.
- [v4.8 manual](https://github.com/snail007/goproxy/tree/v4.8)
- [v4.7 manual](https://github.com/snail007/goproxy/tree/v4.7)
- [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6) - [v4.6 manual](https://github.com/snail007/goproxy/tree/v4.6)
- [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5) - [v4.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
- [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4) - [v4.4 manual](https://github.com/snail007/goproxy/tree/v4.4)
@ -62,6 +64,7 @@ This page is the v4.7 manual, and the other version of the manual can be checked
### Installation ### Installation
- [Quick installation](#quick-installation) - [Quick installation](#quick-installation)
- [Manual installation](#manual-installation) - [Manual installation](#manual-installation)
- [Docker installation](#docker-installation)
### First use must read ### First use must read
- [Environmental Science](#environmental-science) - [Environmental Science](#environmental-science)
@ -160,7 +163,7 @@ If the installation fails or your VPS is not a linux64 system, please follow the
Download address: https://github.com/snail007/goproxy/releases Download address: https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v4.9/proxy-linux-amd64.tar.gz
``` ```
#### **2.Download the automatic installation script** #### **2.Download the automatic installation script**
```shell ```shell
@ -170,6 +173,36 @@ chmod +x install.sh
./install.sh ./install.sh
``` ```
#### Docker installation
Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.8.5 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy version 4.7.
The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 4.7:
```
ARG GOPROXY_VERSION=v4.7
```
To Run:
1. Clone the repository and cd into it.
```
sudo docker build .
```
2. Tag the image:
```
sudo docker tag <id from previous step> goproxy/goproxy:latest
```
3. Run!
Just put your arguments to proxy binary in the OPTS environmental variable (this is just a sample http proxy):
```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest
```
4. View logs:
```
sudo docker logs -f goproxy
```
## **First use must be read**   ## **First use must be read**  
### **Environmental Science** ### **Environmental Science**
@ -715,7 +748,7 @@ You can also be placed in a file, which is a line, a username: password, a
`./proxy socks -t tcp -p ":33080" -F auth-file.txt` `./proxy socks -t tcp -p ":33080" -F auth-file.txt`
In addition, socks5 proxy also integrates external HTTP API authentication, we can specify a http url interface address through the --auth-url parameter, In addition, socks5 proxy also integrates external HTTP API authentication, we can specify a http url interface address through the --auth-url parameter,
Then when the user is connected, the proxy request this url by get way, with the following four parameters, if the return HTTP status code 204, on behalf of the authentication is successful. Then when the user is connected, the proxy request this url by get way, with the following three parameters, if the return HTTP status code 204, on behalf of the authentication is successful.
In other cases, the authentication fails. In other cases, the authentication fails.
for example: for example:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
@ -963,8 +996,15 @@ If you want to get a more detailed configuration and explanation of the KCP para
``` ```
### TODO ### TODO
- HTTP, socks proxy which has multi parents proxy load balancing?
- HTTP (s) proxy support PAC?
- Welcome joining group feedback... - Welcome joining group feedback...
### How to contribute to the code (Pull Request)?
First, you need to clone the project to your account, and then modify the code on the dev branch.
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
PR needs to explain what changes have been made and why you change them.
### How to use the source code? ### How to use the source code?
Recommend go1.8.5, which does not guarantee that version >=1.9 can be used. Recommend go1.8.5, which does not guarantee that version >=1.9 can be used.
`go get github.com/snail007/goproxy` `go get github.com/snail007/goproxy`

View File

@ -7,7 +7,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
[![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![stable](https://img.shields.io/badge/stable-stable-green.svg)](https://github.com/snail007/goproxy/) [![license](https://img.shields.io/github/license/snail007/goproxy.svg?style=plastic)]() [![download_count](https://img.shields.io/github/downloads/snail007/goproxy/total.svg?style=plastic)](https://github.com/snail007/goproxy/releases) [![download](https://img.shields.io/github/release/snail007/goproxy.svg?style=plastic)](https://github.com/snail007/goproxy/releases)
[English Manual](/README.md) **[English Manual](/README.md)** **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
### Features ### Features
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理. - 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至N级代理.
@ -37,7 +37,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- ... - ...
本页是v4.7手册,其他版本手册请点击下面链接查看. 本页是v4.9手册,其他版本手册请点击下面链接查看.
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8)
- [v4.7手册](https://github.com/snail007/goproxy/tree/v4.7)
- [v4.6手册](https://github.com/snail007/goproxy/tree/v4.6) - [v4.6手册](https://github.com/snail007/goproxy/tree/v4.6)
- [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5) - [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5)
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4) - [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4)
@ -61,6 +63,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
### 安装 ### 安装
1. [快速安装](#自动安装) 1. [快速安装](#自动安装)
1. [手动安装](#手动安装) 1. [手动安装](#手动安装)
1. [Docker安装](#docker安装)
### 首次使用必看 ### 首次使用必看
- [环境](#首次使用必看-1) - [环境](#首次使用必看-1)
@ -137,7 +140,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [6.6 认证功能](#66-认证功能) - [6.6 认证功能](#66-认证功能)
- [6.7 自定义加密](#67-自定义加密) - [6.7 自定义加密](#67-自定义加密)
- [6.8 压缩传输](#68-压缩传输) - [6.8 压缩传输](#68-压缩传输)
- [6.9 查看帮助](#69-查看帮助) - [6.9 禁用协议](#69-禁用协议)
- [6.10 查看帮助](#610-查看帮助)
- [7. KCP配置](#7kcp配置) - [7. KCP配置](#7kcp配置)
- [7.1 配置介绍](#71-配置介绍) - [7.1 配置介绍](#71-配置介绍)
- [7.2 详细配置](#72-详细配置) - [7.2 详细配置](#72-详细配置)
@ -158,7 +162,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
下载地址:https://github.com/snail007/goproxy/releases 下载地址:https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v4.9/proxy-linux-amd64.tar.gz
``` ```
#### **2.下载自动安装脚本** #### **2.下载自动安装脚本**
```shell ```shell
@ -168,6 +172,35 @@ chmod +x install.sh
./install.sh ./install.sh
``` ```
#### Docker安装
项目根目录的Dockerfile文件用来构建,使用golang 1.8.5,构建基于goproxy v4.7,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile,指定构建的goproxy版本.
```
ARG GOPROXY_VERSION=v4.7
```
步骤:
1. 克隆仓库,然后cd进入仓库文件夹,执行:
```
sudo docker build .
```
2. 镜像打标签:
```
sudo docker tag <上一步的结果ID> goproxy/goproxy:latest
```
3. 运行
参数OPTS的值就是传递给proxy的所有参数
比如下面的例子启动了一个http服务:
```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest
```
4. 查看日志:
```
sudo docker logs -f goproxy
```
## **首次使用必看** ## **首次使用必看**
### **环境** ### **环境**
@ -228,10 +261,12 @@ proxy会fork子进程,然后监控子进程,如果子进程异常退出,5秒后
![1.2](/docs/images/http-2.png) ![1.2](/docs/images/http-2.png)
使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080` 使用本地端口8090,假设上级HTTP代理是`22.22.22.22:8080`
`./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" ` `./proxy http -t tcp -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" `
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名域名直接走上级代理,白名单的域名不走上级代理. 我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如:baidu.com,匹配的是*.*.baidu.com,黑名单的域名直接走上级代理,白名单的域名不走上级代理.
`./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt` `./proxy http -p "0.0.0.0:8090" -T tcp -P "22.22.22.22:8080" -b blocked.txt -d direct.txt`
#### **1.3.HTTP二级代理(加密)** #### **1.3.HTTP二级代理(加密)**
> 注意: 后面二级代理使用的`proxy.crt``proxy.key`应与一级代理一致
![1.3](/docs/images/http-tls-2.png) ![1.3](/docs/images/http-tls-2.png)
一级HTTP代理(VPS,IP:22.22.22.22) 一级HTTP代理(VPS,IP:22.22.22.22)
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key` `./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
@ -303,7 +338,7 @@ KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
二级HTTP代理(本地Linux) 二级HTTP代理(本地Linux)
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword` `./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" --kcp-key mypassword`
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输. 那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输,注意kcp走的是udp协议协议,所以防火墙需放开38080的udp协议.  
#### **1.9 HTTP(S)反向代理** #### **1.9 HTTP(S)反向代理**
![1.9](/docs/images/fxdl.png) ![1.9](/docs/images/fxdl.png)
@ -720,7 +755,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
`./proxy socks -t tcp -p ":33080" -F auth-file.txt` `./proxy socks -t tcp -p ":33080" -F auth-file.txt`
另外,socks5代理还集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址, 另外,socks5代理还集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
然后有用户连接的时候,proxy会GET方式请求这url,带上下面个参数,如果返回HTTP状态码204,代表认证成功 然后有用户连接的时候,proxy会GET方式请求这url,带上下面个参数,如果返回HTTP状态码204,代表认证成功
其它情况认为认证失败. 其它情况认为认证失败.
比如: 比如:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
@ -956,7 +991,16 @@ proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及
这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站. 这样通过本地代理8080访问网站的时候就是通过与上级压缩传输访问目标网站.
#### **6.9 查看帮助** #### **6.9 禁用协议**
SPS默认情况下一个端口支持http(s)和socks5两种代理协议,我们可以通过参数禁用某个协议
比如:
1.禁用HTTP(S)代理功能只保留SOCKS5代理功能,参数:`--disable-http`.
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
1.禁用SOCKS5代理功能只保留HTTP(S)代理功能,参数:`--disable-socks`.
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
#### **6.10 查看帮助**
`./proxy help sps` `./proxy help sps`
### **7.KCP配置** ### **7.KCP配置**
@ -1002,6 +1046,11 @@ fast3`--nodelay=1 --interval=10 --resend=2 --nc=1`
- http(s)代理增加pac支持? - http(s)代理增加pac支持?
- 欢迎加群反馈... - 欢迎加群反馈...
### 如何贡献代码(Pull Request)?
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
pr的时候需要说明做了什么变更,原因是什么.
### 如何使用源码? ### 如何使用源码?
建议go1.8.5,不保证>=1.9能用. 建议go1.8.5,不保证>=1.9能用.
`go get github.com/snail007/goproxy` `go get github.com/snail007/goproxy`

View File

@ -4,13 +4,15 @@ import (
"bufio" "bufio"
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
logger "log"
"os"
"os/exec"
"runtime/pprof"
"time"
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg" "github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"log"
"os"
"os/exec"
"time"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
@ -21,6 +23,8 @@ var (
app *kingpin.Application app *kingpin.Application
service *services.ServiceItem service *services.ServiceItem
cmd *exec.Cmd cmd *exec.Cmd
cpuProfilingFile, memProfilingFile, blockProfilingFile, goroutineProfilingFile, threadcreateProfilingFile *os.File
isDebug bool
) )
func initConfig() (err error) { func initConfig() (err error) {
@ -226,7 +230,7 @@ func initConfig() (err error) {
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp") spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp") spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String() spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks") spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks", "ss")
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String() spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int() spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String() spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
@ -241,10 +245,14 @@ func initConfig() (err error) {
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
//parse args //parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
isDebug = *debug
//set kcp config //set kcp config
switch *kcpArgs.Mode { switch *kcpArgs.Mode {
@ -297,11 +305,19 @@ func initConfig() (err error) {
muxServerArgs.KCP = kcpArgs muxServerArgs.KCP = kcpArgs
muxClientArgs.KCP = kcpArgs muxClientArgs.KCP = kcpArgs
flags := log.Ldate log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime)
flags := logger.Ldate
if *debug { if *debug {
flags |= log.Lshortfile | log.Lmicroseconds flags |= logger.Lshortfile | logger.Lmicroseconds
cpuProfilingFile, _ = os.Create("cpu.prof")
memProfilingFile, _ = os.Create("memory.prof")
blockProfilingFile, _ = os.Create("block.prof")
goroutineProfilingFile, _ = os.Create("goroutine.prof")
threadcreateProfilingFile, _ = os.Create("threadcreate.prof")
pprof.StartCPUProfile(cpuProfilingFile)
} else { } else {
flags |= log.Ltime flags |= logger.Ltime
} }
log.SetFlags(flags) log.SetFlags(flags)
@ -381,20 +397,41 @@ func initConfig() (err error) {
} }
if *logfile == "" { if *logfile == "" {
poster() poster()
if *debug {
log.Println("[profiling] cpu profiling save to file : cpu.prof")
log.Println("[profiling] memory profiling save to file : memory.prof")
log.Println("[profiling] block profiling save to file : block.prof")
log.Println("[profiling] goroutine profiling save to file : goroutine.prof")
log.Println("[profiling] threadcreate profiling save to file : threadcreate.prof")
}
} }
//regist services and run service //regist services and run service
services.Regist("http", services.NewHTTP(), httpArgs) //regist services and run service
services.Regist("tcp", services.NewTCP(), tcpArgs) switch serviceName {
services.Regist("udp", services.NewUDP(), udpArgs) case "http":
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs) services.Regist(serviceName, services.NewHTTP(), httpArgs, log)
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs) case "tcp":
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs) services.Regist(serviceName, services.NewTCP(), tcpArgs, log)
services.Regist("server", services.NewMuxServerManager(), muxServerArgs) case "udp":
services.Regist("client", services.NewMuxClient(), muxClientArgs) services.Regist(serviceName, services.NewUDP(), udpArgs, log)
services.Regist("bridge", services.NewMuxBridge(), muxBridgeArgs) case "tserver":
services.Regist("socks", services.NewSocks(), socksArgs) services.Regist(serviceName, services.NewTunnelServerManager(), tunnelServerArgs, log)
services.Regist("sps", services.NewSPS(), spsArgs) case "tclient":
service, err = services.Run(serviceName) services.Regist(serviceName, services.NewTunnelClient(), tunnelClientArgs, log)
case "tbridge":
services.Regist(serviceName, services.NewTunnelBridge(), tunnelBridgeArgs, log)
case "server":
services.Regist(serviceName, services.NewMuxServerManager(), muxServerArgs, log)
case "client":
services.Regist(serviceName, services.NewMuxClient(), muxClientArgs, log)
case "bridge":
services.Regist(serviceName, services.NewMuxBridge(), muxBridgeArgs, log)
case "socks":
services.Regist(serviceName, services.NewSocks(), socksArgs, log)
case "sps":
services.Regist(serviceName, services.NewSPS(), spsArgs, log)
}
service, err = services.Run(serviceName, nil)
if err != nil { if err != nil {
log.Fatalf("run service [%s] fail, ERR:%s", serviceName, err) log.Fatalf("run service [%s] fail, ERR:%s", serviceName, err)
} }
@ -413,3 +450,14 @@ func poster() {
v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION) v%s`+" by snail , blog : http://www.host900.com/\n\n", APP_VERSION)
} }
func saveProfiling() {
goroutine := pprof.Lookup("goroutine")
goroutine.WriteTo(goroutineProfilingFile, 1)
heap := pprof.Lookup("heap")
heap.WriteTo(memProfilingFile, 1)
block := pprof.Lookup("block")
block.WriteTo(blockProfilingFile, 1)
threadcreate := pprof.Lookup("threadcreate")
threadcreate.WriteTo(threadcreateProfilingFile, 1)
pprof.StopCPUProfile()
}

View File

@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
fi fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /tmp/proxy cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v4.9/proxy-linux-amd64.tar.gz
# #install proxy # #install proxy
tar zxvf proxy-linux-amd64.tar.gz tar zxvf proxy-linux-amd64.tar.gz

View File

@ -1,14 +1,15 @@
package main package main
import ( import (
"github.com/snail007/goproxy/services"
"log" "log"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/snail007/goproxy/services"
) )
const APP_VERSION = "4.7" const APP_VERSION = "4.9"
func main() { func main() {
err := initConfig() err := initConfig()
@ -40,6 +41,9 @@ func Clean(s *services.Service) {
log.Printf("clean process %d", cmd.Process.Pid) log.Printf("clean process %d", cmd.Process.Pid)
cmd.Process.Kill() cmd.Process.Kill()
} }
if isDebug {
saveProfiling()
}
cleanupDone <- true cleanupDone <- true
} }
}() }()

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VER="4.7" VER="4.9"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert

3
sdk/CHANGELOG Normal file
View File

@ -0,0 +1,3 @@
v4.8
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
2.增加了获取sdk版本的Version()方法.

View File

@ -9,7 +9,7 @@
- MacOS,`.dylib` - MacOS,`.dylib`
proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库, proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库,
另外还为linux和windows提供sdk支持基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。 另外还为linux和windows,MacOS提供sdk支持基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。
# 下面分平台介绍SDK的用法 # 下面分平台介绍SDK的用法

View File

@ -1,10 +1,19 @@
#/bin/bash #/bin/bash
VER="v4.7" VER="v4.8"
rm -rf sdk-android-*.tar.gz rm -rf sdk-android-*.tar.gz
rm -rf android rm -rf android
mkdir android mkdir android
#android #android ; jdk,android ndk & android sdk required, install gomobile go1.10 required
#export GOPATH="$HOME/go"
#export GOROOT="/usr/local/go"
#export PATH="$GOROOT/bin:$GOPATH/bin:$PATH"
#export ANDROID_HOME="$HOME/Android/Sdk"
#export NDK_ROOT="$HOME/Android/Sdk/ndk-bundle"
#export PATH="$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$NDK_ROOT:$PATH"
#go get -v golang.org/x/mobile/cmd/gomobile
#gomobile init
gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w" gomobile bind -v -target=android -javapkg=snail007 -ldflags="-s -w"
mv proxy.aar android/snail007.goproxy.sdk.aar mv proxy.aar android/snail007.goproxy.sdk.aar
mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v4.7" VER="v4.8"
rm -rf sdk-ios-*.tar.gz rm -rf sdk-ios-*.tar.gz
rm -rf ios rm -rf ios
mkdir ios mkdir ios

View File

@ -3,17 +3,20 @@ package proxy
import ( import (
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"github.com/snail007/goproxy/services" logger "log"
"github.com/snail007/goproxy/services/kcpcfg"
"log"
"os" "os"
"strings" "strings"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
kingpin "gopkg.in/alecthomas/kingpin.v2" kingpin "gopkg.in/alecthomas/kingpin.v2"
) )
const SDK_VERSION = "4.8"
var ( var (
app *kingpin.Application app *kingpin.Application
) )
@ -43,7 +46,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
kcpArgs := kcpcfg.KCPConfigArgs{} kcpArgs := kcpcfg.KCPConfigArgs{}
//build srvice args //build srvice args
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version("4.7") app.Author("snail").Version(SDK_VERSION)
debug := app.Flag("debug", "debug log output").Default("false").Bool() debug := app.Flag("debug", "debug log output").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() 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.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
@ -235,6 +238,8 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() spsArgs.ParentKey = sps.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() spsArgs.LocalCompress = sps.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
//parse args //parse args
_args := strings.Fields(strings.Trim(serviceArgsStr, " ")) _args := strings.Fields(strings.Trim(serviceArgsStr, " "))
@ -298,11 +303,12 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
muxServerArgs.KCP = kcpArgs muxServerArgs.KCP = kcpArgs
muxClientArgs.KCP = kcpArgs muxClientArgs.KCP = kcpArgs
flags := log.Ldate log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime)
flags := logger.Ldate
if *debug { if *debug {
flags |= log.Lshortfile | log.Lmicroseconds flags |= logger.Lshortfile | logger.Lmicroseconds
} else { } else {
flags |= log.Ltime flags |= logger.Ltime
} }
log.SetFlags(flags) log.SetFlags(flags)
@ -317,29 +323,29 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
//regist services and run service //regist services and run service
switch serviceName { switch serviceName {
case "http": case "http":
services.Regist(serviceID, services.NewHTTP(), httpArgs) services.Regist(serviceID, services.NewHTTP(), httpArgs, log)
case "tcp": case "tcp":
services.Regist(serviceID, services.NewTCP(), tcpArgs) services.Regist(serviceID, services.NewTCP(), tcpArgs, log)
case "udp": case "udp":
services.Regist(serviceID, services.NewUDP(), udpArgs) services.Regist(serviceID, services.NewUDP(), udpArgs, log)
case "tserver": case "tserver":
services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs) services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs, log)
case "tclient": case "tclient":
services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs) services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs, log)
case "tbridge": case "tbridge":
services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs) services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs, log)
case "server": case "server":
services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs) services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs, log)
case "client": case "client":
services.Regist(serviceID, services.NewMuxClient(), muxClientArgs) services.Regist(serviceID, services.NewMuxClient(), muxClientArgs, log)
case "bridge": case "bridge":
services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs) services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs, log)
case "socks": case "socks":
services.Regist(serviceID, services.NewSocks(), socksArgs) services.Regist(serviceID, services.NewSocks(), socksArgs, log)
case "sps": case "sps":
services.Regist(serviceID, services.NewSPS(), spsArgs) services.Regist(serviceID, services.NewSPS(), spsArgs, log)
} }
_, err = services.Run(serviceID) _, err = services.Run(serviceID, nil)
if err != nil { if err != nil {
return fmt.Sprintf("run service [%s:%s] fail, ERR:%s", serviceID, serviceName, err) return fmt.Sprintf("run service [%s:%s] fail, ERR:%s", serviceID, serviceName, err)
} }
@ -349,3 +355,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
func Stop(serviceID string) { func Stop(serviceID string) {
services.Stop(serviceID) services.Stop(serviceID)
} }
func Version() string {
return SDK_VERSION
}

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v4.7" VER="v4.8"
rm -rf sdk-linux-*.tar.gz rm -rf sdk-linux-*.tar.gz
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v4.7" VER="v4.8"
rm -rf *.tar.gz rm -rf *.tar.gz
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h

View File

@ -1,5 +1,5 @@
#/bin/bash #/bin/bash
VER="v4.7" VER="v4.8"
sudo rm /usr/local/go sudo rm /usr/local/go
sudo ln -s /usr/local/go1.10.1 /usr/local/go sudo ln -s /usr/local/go1.10.1 /usr/local/go

View File

@ -2,6 +2,7 @@ package main
import ( import (
"C" "C"
sdk "github.com/snail007/goproxy/sdk/android-ios" sdk "github.com/snail007/goproxy/sdk/android-ios"
) )
@ -15,5 +16,10 @@ func Stop(serviceID *C.char) {
sdk.Stop(C.GoString(serviceID)) sdk.Stop(C.GoString(serviceID))
} }
//export Version
func Version() (ver *C.char) {
return C.CString(sdk.Version())
}
func main() { func main() {
} }

View File

@ -232,6 +232,8 @@ type SPSArgs struct {
ParentKey *string ParentKey *string
LocalCompress *bool LocalCompress *bool
ParentCompress *bool ParentCompress *bool
DisableHTTP *bool
DisableSocks5 *bool
} }
func (a *SPSArgs) Protocol() string { func (a *SPSArgs) Protocol() string {

View File

@ -2,17 +2,18 @@ package services
import ( import (
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" logger "log"
"net" "net"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@ -27,6 +28,7 @@ type HTTP struct {
isStop bool isStop bool
serverChannels []*utils.ServerChannel serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
func NewHTTP() Service { func NewHTTP() Service {
@ -95,10 +97,10 @@ func (s *HTTP) CheckArgs() (err error) {
func (s *HTTP) InitService() (err error) { func (s *HTTP) InitService() (err error) {
s.InitBasicAuth() s.InitBasicAuth()
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
} }
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
err = s.ConnectSSH() err = s.ConnectSSH()
@ -125,7 +127,7 @@ func (s *HTTP) InitService() (err error) {
s.sshClient.Conn.Close() s.sshClient.Conn.Close()
} }
} }
log.Printf("ssh offline, retrying...") s.log.Printf("ssh offline, retrying...")
s.ConnectSSH() s.ConnectSSH()
} else { } else {
conn.Close() conn.Close()
@ -140,9 +142,9 @@ func (s *HTTP) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop http(s) service crashed,%s", e) s.log.Printf("stop http(s) service crashed,%s", e)
} else { } else {
log.Printf("service http(s) stoped") s.log.Printf("service http(s) stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -159,34 +161,38 @@ func (s *HTTP) StopService() {
} }
} }
} }
func (s *HTTP) Start(args interface{}) (err error) { func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(HTTPArgs) s.cfg = args.(HTTPArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
} }
if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitOutConnPool()
}
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
if *s.cfg.Parent != "" {
s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
s.InitOutConnPool()
}
for _, addr := range strings.Split(*s.cfg.Local, ",") { for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" { if addr != "" {
host, port, _ := net.SplitHostPort(addr) host, port, _ := net.SplitHostPort(addr)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
} }
if err != nil { if err != nil {
return return
} }
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr()) s.log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc) s.serverChannels = append(s.serverChannels, &sc)
} }
} }
@ -199,7 +205,7 @@ func (s *HTTP) Clean() {
func (s *HTTP) callback(inConn net.Conn) { func (s *HTTP) callback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
if *s.cfg.LocalCompress { if *s.cfg.LocalCompress {
@ -212,10 +218,10 @@ func (s *HTTP) callback(inConn net.Conn) {
} }
var err interface{} var err interface{}
var req utils.HTTPRequest var req utils.HTTPRequest
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth) req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth, s.log)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
log.Printf("decoder error , from %s, ERR:%s", inConn.RemoteAddr(), err) s.log.Printf("decoder error , from %s, ERR:%s", inConn.RemoteAddr(), err)
} }
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
return return
@ -223,7 +229,7 @@ func (s *HTTP) callback(inConn net.Conn) {
address := req.Host address := req.Host
host, _, _ := net.SplitHostPort(address) host, _, _ := net.SplitHostPort(address)
useProxy := false useProxy := false
if !utils.IsIternalIP(host) { if !utils.IsIternalIP(host, *s.cfg.Always) {
useProxy = true useProxy = true
if *s.cfg.Parent == "" { if *s.cfg.Parent == "" {
useProxy = false useProxy = false
@ -234,18 +240,18 @@ func (s *HTTP) callback(inConn net.Conn) {
s.checker.Add(k) s.checker.Add(k)
//var n, m uint //var n, m uint
useProxy, _, _ = s.checker.IsBlocked(k) useProxy, _, _ = s.checker.IsBlocked(k)
//log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m) //s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
} }
} }
log.Printf("use proxy : %v, %s", useProxy, address) s.log.Printf("use proxy : %v, %s", useProxy, address)
err = s.OutToTCP(useProxy, address, &inConn, &req) err = s.OutToTCP(useProxy, address, &inConn, &req)
if err != nil { if err != nil {
if *s.cfg.Parent == "" { if *s.cfg.Parent == "" {
log.Printf("connect to %s fail, ERR:%s", address, err) s.log.Printf("connect to %s fail, ERR:%s", address, err)
} else { } else {
log.Printf("connect to %s parent %s fail", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("connect to %s parent %s fail", *s.cfg.ParentType, *s.cfg.Parent)
} }
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
} }
@ -270,7 +276,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(address) outConn, err = s.getSSHConn(address)
} else { } else {
// log.Printf("%v", s.outPool) // s.log.Printf("%v", s.outPool)
outConn, err = s.outPool.Get() outConn, err = s.outPool.Get()
} }
} else { } else {
@ -280,12 +286,12 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if err == nil || tryCount > maxTryCount { if err == nil || tryCount > maxTryCount {
break break
} else { } else {
log.Printf("connect to %s , err:%s,retrying...", *s.cfg.Parent, err) s.log.Printf("connect to %s , err:%s,retrying...", *s.cfg.Parent, err)
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
} }
} }
if err != nil { if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
@ -306,20 +312,25 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} else { } else {
//https或者http,上级是代理,proxy需要转发 //https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
//直连目标或上级非代理,清理HTTP头部的代理头信息
if !useProxy || *s.cfg.ParentType == "ssh" {
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
} else {
_, err = outConn.Write(req.HeadBuf) _, err = outConn.Write(req.HeadBuf)
}
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("write to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
} }
utils.IoBind((*inConn), outConn, func(err interface{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host) s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
}) }, s.log)
log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host) s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
@ -350,7 +361,7 @@ RETRY:
err = fmt.Errorf("ssh dial %s timeout", host) err = fmt.Errorf("ssh dial %s timeout", host)
} }
if err != nil { if err != nil {
log.Printf("connect ssh fail, ERR: %s, retrying...", err) s.log.Printf("connect ssh fail, ERR: %s, retrying...", err)
e := s.ConnectSSH() e := s.ConnectSSH()
if e == nil { if e == nil {
tryCount++ tryCount++
@ -400,13 +411,13 @@ func (s *HTTP) InitOutConnPool() {
} }
func (s *HTTP) InitBasicAuth() (err error) { func (s *HTTP) InitBasicAuth() (err error) {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver) s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
} else { } else {
s.basicAuth = utils.NewBasicAuth(nil) s.basicAuth = utils.NewBasicAuth(nil, s.log)
} }
if *s.cfg.AuthURL != "" { if *s.cfg.AuthURL != "" {
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry) s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
log.Printf("auth from %s", *s.cfg.AuthURL) s.log.Printf("auth from %s", *s.cfg.AuthURL)
} }
if *s.cfg.AuthFile != "" { if *s.cfg.AuthFile != "" {
var n = 0 var n = 0
@ -415,11 +426,11 @@ func (s *HTTP) InitBasicAuth() (err error) {
err = fmt.Errorf("auth-file ERR:%s", err) err = fmt.Errorf("auth-file ERR:%s", err)
return return
} }
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
} }
if len(*s.cfg.Auth) > 0 { if len(*s.cfg.Auth) > 0 {
n := s.basicAuth.Add(*s.cfg.Auth) n := s.basicAuth.Add(*s.cfg.Auth)
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
} }
return return
} }
@ -471,7 +482,7 @@ func (s *HTTP) Resolve(address string) string {
} }
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
} }
return ip return ip
} }

View File

@ -3,9 +3,8 @@ package services
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"math/rand" "math/rand"
"net" "net"
"strconv" "strconv"
@ -13,7 +12,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/xtaci/smux" "github.com/snail007/goproxy/utils"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type MuxBridge struct { type MuxBridge struct {
@ -24,6 +26,7 @@ type MuxBridge struct {
l *sync.Mutex l *sync.Mutex
isStop bool isStop bool
sc *utils.ServerChannel sc *utils.ServerChannel
log *logger.Logger
} }
func NewMuxBridge() Service { func NewMuxBridge() Service {
@ -58,9 +61,9 @@ func (s *MuxBridge) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop bridge service crashed,%s", e) s.log.Printf("stop bridge service crashed,%s", e)
} else { } else {
log.Printf("service bridge stoped") s.log.Printf("service bridge stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -76,7 +79,8 @@ func (s *MuxBridge) StopService() {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
} }
func (s *MuxBridge) Start(args interface{}) (err error) { func (s *MuxBridge) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(MuxBridgeArgs) s.cfg = args.(MuxBridgeArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -87,19 +91,19 @@ func (s *MuxBridge) Start(args interface{}) (err error) {
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.handler) err = sc.ListenTCP(s.handler)
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.handler) err = sc.ListenKCP(s.cfg.KCP, s.handler, s.log)
} }
if err != nil { if err != nil {
return return
} }
s.sc = &sc s.sc = &sc
log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr()) s.log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
return return
} }
func (s *MuxBridge) Clean() { func (s *MuxBridge) Clean() {
@ -115,7 +119,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
err = utils.ReadPacket(reader, &connType, &key) err = utils.ReadPacket(reader, &connType, &key)
inConn.SetDeadline(time.Time{}) inConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
switch connType { switch connType {
@ -126,10 +130,10 @@ func (s *MuxBridge) handler(inConn net.Conn) {
err = utils.ReadPacketData(reader, &serverID) err = utils.ReadPacketData(reader, &serverID)
inConn.SetDeadline(time.Time{}) inConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
log.Printf("server connection %s %s connected", serverID, key) s.log.Printf("server connection %s %s connected", serverID, key)
if c, ok := s.serverConns.Get(inAddr); ok { if c, ok := s.serverConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
@ -137,7 +141,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
session, err := smux.Server(inConn, nil) session, err := smux.Server(inConn, nil)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("server session error,ERR:%s", err) s.log.Printf("server session error,ERR:%s", err)
return return
} }
for { for {
@ -149,30 +153,30 @@ func (s *MuxBridge) handler(inConn net.Conn) {
session.Close() session.Close()
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
s.serverConns.Remove(inAddr) s.serverConns.Remove(inAddr)
log.Printf("server connection %s %s released", serverID, key) s.log.Printf("server connection %s %s released", serverID, key)
return return
} }
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("bridge callback crashed,err: %s", e) s.log.Printf("bridge callback crashed,err: %s", e)
} }
}() }()
s.callback(stream, serverID, key) s.callback(stream, serverID, key)
}() }()
} }
case CONN_CLIENT: case CONN_CLIENT:
log.Printf("client connection %s connected", key) s.log.Printf("client connection %s connected", key)
session, err := smux.Client(inConn, nil) session, err := smux.Client(inConn, nil)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("client session error,ERR:%s", err) s.log.Printf("client session error,ERR:%s", err)
return return
} }
keyInfo := strings.Split(key, "-") keyInfo := strings.Split(key, "-")
if len(keyInfo) != 2 { if len(keyInfo) != 2 {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("client key format error,key:%s", key) s.log.Printf("client key format error,key:%s", key)
return return
} }
groupKey := keyInfo[0] groupKey := keyInfo[0]
@ -200,7 +204,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
defer s.l.Unlock() defer s.l.Unlock()
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() { if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
group.Remove(index) group.Remove(index)
log.Printf("client connection %s released", key) s.log.Printf("client connection %s released", key)
} }
if group.IsEmpty() { if group.IsEmpty() {
s.clientControlConns.Remove(groupKey) s.clientControlConns.Remove(groupKey)
@ -210,7 +214,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)
} }
}() }()
//log.Printf("set client session,key: %s", key) //s.log.Printf("set client session,key: %s", key)
} }
} }
@ -229,7 +233,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
} }
_group, ok := s.clientControlConns.Get(key) _group, ok := s.clientControlConns.Get(key)
if !ok { if !ok {
log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID) s.log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} }
@ -240,22 +244,22 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
if keysLen > 0 { if keysLen > 0 {
i = rand.Intn(keysLen) i = rand.Intn(keysLen)
} else { } else {
log.Printf("client %s session empty for server stream %s, retrying...", key, serverID) s.log.Printf("client %s session empty for server stream %s, retrying...", key, serverID)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} }
index := keys[i] index := keys[i]
log.Printf("select client : %s-%s", key, index) s.log.Printf("select client : %s-%s", key, index)
session, _ := group.Get(index) session, _ := group.Get(index)
session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) //session.(*smux.Session).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
stream, err := session.(*smux.Session).OpenStream() stream, err := session.(*smux.Session).OpenStream()
session.(*smux.Session).SetDeadline(time.Time{}) //session.(*smux.Session).SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err) s.log.Printf("%s client session open stream %s fail, err: %s, retrying...", key, serverID, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
log.Printf("stream %s -> %s created", serverID, key) s.log.Printf("stream %s -> %s created", serverID, key)
die1 := make(chan bool, 1) die1 := make(chan bool, 1)
die2 := make(chan bool, 1) die2 := make(chan bool, 1)
go func() { go func() {
@ -272,7 +276,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
} }
stream.Close() stream.Close()
inConn.Close() inConn.Close()
log.Printf("%s server %s stream released", key, serverID) s.log.Printf("%s server %s stream released", key, serverID)
break break
} }
} }

View File

@ -3,20 +3,23 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"net" "net"
"time" "time"
"github.com/snail007/goproxy/utils"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/xtaci/smux" //"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type MuxClient struct { type MuxClient struct {
cfg MuxClientArgs cfg MuxClientArgs
isStop bool isStop bool
sessions utils.ConcurrentMap sessions utils.ConcurrentMap
log *logger.Logger
} }
func NewMuxClient() Service { func NewMuxClient() Service {
@ -33,7 +36,7 @@ func (s *MuxClient) InitService() (err error) {
func (s *MuxClient) CheckArgs() (err error) { func (s *MuxClient) CheckArgs() (err error) {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) s.log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } else {
err = fmt.Errorf("parent required") err = fmt.Errorf("parent required")
return return
@ -54,9 +57,9 @@ func (s *MuxClient) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop client service crashed,%s", e) s.log.Printf("stop client service crashed,%s", e)
} else { } else {
log.Printf("service client stoped") s.log.Printf("service client stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -64,7 +67,8 @@ func (s *MuxClient) StopService() {
sess.(*smux.Session).Close() sess.(*smux.Session).Close()
} }
} }
func (s *MuxClient) Start(args interface{}) (err error) { func (s *MuxClient) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(MuxClientArgs) s.cfg = args.(MuxClientArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -72,19 +76,19 @@ func (s *MuxClient) Start(args interface{}) (err error) {
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
log.Printf("client started") s.log.Printf("client started")
count := 1 count := 1
if *s.cfg.SessionCount > 0 { if *s.cfg.SessionCount > 0 {
count = *s.cfg.SessionCount count = *s.cfg.SessionCount
} }
for i := 1; i <= count; i++ { for i := 1; i <= count; i++ {
key := fmt.Sprintf("worker[%d]", i) key := fmt.Sprintf("worker[%d]", i)
log.Printf("session %s started", key) s.log.Printf("session %s started", key)
go func(i int) { go func(i int) {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("session worker crashed: %s", e) s.log.Printf("session worker crashed: %s", e)
} }
}() }()
for { for {
@ -93,7 +97,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
} }
conn, err := s.getParentConn() conn, err := s.getParentConn()
if err != nil { if err != nil {
log.Printf("connection err: %s, retrying...", err) s.log.Printf("connection err: %s, retrying...", err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} }
@ -102,13 +106,13 @@ func (s *MuxClient) Start(args interface{}) (err error) {
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
conn.Close() conn.Close()
log.Printf("connection err: %s, retrying...", err) s.log.Printf("connection err: %s, retrying...", err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} }
session, err := smux.Server(conn, nil) session, err := smux.Server(conn, nil)
if err != nil { if err != nil {
log.Printf("session err: %s, retrying...", err) s.log.Printf("session err: %s, retrying...", err)
conn.Close() conn.Close()
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
@ -123,7 +127,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
} }
stream, err := session.AcceptStream() stream, err := session.AcceptStream()
if err != nil { if err != nil {
log.Printf("accept stream err: %s, retrying...", err) s.log.Printf("accept stream err: %s, retrying...", err)
session.Close() session.Close()
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
break break
@ -132,7 +136,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stream handler crashed: %s", e) s.log.Printf("stream handler crashed: %s", e)
} }
}() }()
var ID, clientLocalAddr, serverID string var ID, clientLocalAddr, serverID string
@ -140,11 +144,11 @@ func (s *MuxClient) Start(args interface{}) (err error) {
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID) err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
stream.SetDeadline(time.Time{}) stream.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read stream signal err: %s", err) s.log.Printf("read stream signal err: %s", err)
stream.Close() stream.Close()
return return
} }
log.Printf("worker[%d] signal revecived,server %s stream %s %s", i, serverID, ID, clientLocalAddr) s.log.Printf("worker[%d] signal revecived,server %s stream %s %s", i, serverID, ID, clientLocalAddr)
protocol := clientLocalAddr[:3] protocol := clientLocalAddr[:3]
localAddr := clientLocalAddr[4:] localAddr := clientLocalAddr[4:]
if protocol == "udp" { if protocol == "udp" {
@ -186,16 +190,16 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
srcAddr, body, err := utils.ReadUDPPacket(inConn) srcAddr, body, err := utils.ReadUDPPacket(inConn)
inConn.SetDeadline(time.Time{}) inConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("udp packet revecived fail, err: %s", err) s.log.Printf("udp packet revecived fail, err: %s", err)
log.Printf("connection %s released", ID) s.log.Printf("connection %s released", ID)
inConn.Close() inConn.Close()
break break
} else { } else {
//log.Printf("udp packet revecived:%s,%v", srcAddr, body) //s.log.Printf("udp packet revecived:%s,%v", srcAddr, body)
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("client processUDPPacket crashed,err: %s", e) s.log.Printf("client processUDPPacket crashed,err: %s", e)
} }
}() }()
s.processUDPPacket(inConn, srcAddr, localAddr, body) s.processUDPPacket(inConn, srcAddr, localAddr, body)
@ -209,44 +213,44 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr string, body []byte) { func (s *MuxClient) processUDPPacket(inConn *smux.Stream, srcAddr, localAddr string, body []byte) {
dstAddr, err := net.ResolveUDPAddr("udp", localAddr) dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
if err != nil { if err != nil {
log.Printf("can't resolve address: %s", err) s.log.Printf("can't resolve address: %s", err)
inConn.Close() inConn.Close()
return return
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write(body) _, err = conn.Write(body)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 1024) buf := make([]byte, 1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody) //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
bs := utils.UDPPacket(srcAddr, respBody) bs := utils.UDPPacket(srcAddr, respBody)
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) (*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = (*inConn).Write(bs) _, err = (*inConn).Write(bs)
(*inConn).SetDeadline(time.Time{}) (*inConn).SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("send udp response fail ,ERR:%s", err) s.log.Printf("send udp response fail ,ERR:%s", err)
inConn.Close() inConn.Close()
return return
} }
//log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs) //s.log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
} }
func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) { func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
var err error var err error
@ -262,7 +266,7 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
break break
} else { } else {
if i == 3 { if i == 3 {
log.Printf("connect to %s err: %s, retrying...", localAddr, err) s.log.Printf("connect to %s err: %s, retrying...", localAddr, err)
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
continue continue
} }
@ -271,11 +275,11 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
if err != nil { if err != nil {
inConn.Close() inConn.Close()
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("build connection error, err: %s", err) s.log.Printf("build connection error, err: %s", err)
return return
} }
log.Printf("stream %s created", ID) s.log.Printf("stream %s created", ID)
if *s.cfg.IsCompress { if *s.cfg.IsCompress {
die1 := make(chan bool, 1) die1 := make(chan bool, 1)
die2 := make(chan bool, 1) die2 := make(chan bool, 1)
@ -293,10 +297,10 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
} }
outConn.Close() outConn.Close()
inConn.Close() inConn.Close()
log.Printf("%s stream %s released", *s.cfg.Key, ID) s.log.Printf("%s stream %s released", *s.cfg.Key, ID)
} else { } else {
utils.IoBind(inConn, outConn, func(err interface{}) { utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("stream %s released", ID) s.log.Printf("stream %s released", ID)
}) }, s.log)
} }
} }

View File

@ -3,9 +3,8 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"math/rand" "math/rand"
"net" "net"
"runtime/debug" "runtime/debug"
@ -13,8 +12,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/xtaci/smux" //"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type MuxServer struct { type MuxServer struct {
@ -25,6 +27,7 @@ type MuxServer struct {
lockChn chan bool lockChn chan bool
isStop bool isStop bool
udpConn *net.Conn udpConn *net.Conn
log *logger.Logger
} }
type MuxServerManager struct { type MuxServerManager struct {
@ -32,6 +35,7 @@ type MuxServerManager struct {
udpChn chan MuxUDPItem udpChn chan MuxUDPItem
serverID string serverID string
servers []*Service servers []*Service
log *logger.Logger
} }
func NewMuxServerManager() Service { func NewMuxServerManager() Service {
@ -43,13 +47,14 @@ func NewMuxServerManager() Service {
} }
} }
func (s *MuxServerManager) Start(args interface{}) (err error) { func (s *MuxServerManager) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(MuxServerArgs) s.cfg = args.(MuxServerArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
} }
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
} else { } else {
err = fmt.Errorf("parent required") err = fmt.Errorf("parent required")
return return
@ -59,8 +64,8 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
return return
} }
log.Printf("server id: %s", s.serverID) s.log.Printf("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route) //s.log.Printf("route:%v", *s.cfg.Route)
for _, _info := range *s.cfg.Route { for _, _info := range *s.cfg.Route {
if _info == "" { if _info == "" {
continue continue
@ -73,6 +78,7 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
info = strings.TrimPrefix(info, "tcp://") info = strings.TrimPrefix(info, "tcp://")
_routeInfo := strings.Split(info, "@") _routeInfo := strings.Split(info, "@")
server := NewMuxServer() server := NewMuxServer()
local := _routeInfo[0] local := _routeInfo[0]
remote := _routeInfo[1] remote := _routeInfo[1]
KEY := *s.cfg.Key KEY := *s.cfg.Key
@ -99,7 +105,7 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
SessionCount: s.cfg.SessionCount, SessionCount: s.cfg.SessionCount,
KCP: s.cfg.KCP, KCP: s.cfg.KCP,
ParentType: s.cfg.ParentType, ParentType: s.cfg.ParentType,
}) }, log)
if err != nil { if err != nil {
return return
@ -153,9 +159,9 @@ func (s *MuxServer) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
log.Printf("service server stoped") s.log.Printf("service server stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -184,7 +190,8 @@ func (s *MuxServer) CheckArgs() (err error) {
return return
} }
func (s *MuxServer) Start(args interface{}) (err error) { func (s *MuxServer) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(MuxServerArgs) s.cfg = args.(MuxServerArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -194,7 +201,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
} }
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p) s.sc = utils.NewServerChannel(host, p, s.log)
if *s.cfg.IsUDP { if *s.cfg.IsUDP {
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) { err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
s.udpChn <- MuxUDPItem{ s.udpChn <- MuxUDPItem{
@ -206,12 +213,12 @@ func (s *MuxServer) Start(args interface{}) (err error) {
if err != nil { if err != nil {
return return
} }
log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr()) s.log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
} else { } else {
err = s.sc.ListenTCP(func(inConn net.Conn) { err = s.sc.ListenTCP(func(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("connection handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("connection handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
var outConn net.Conn var outConn net.Conn
@ -223,14 +230,14 @@ func (s *MuxServer) Start(args interface{}) (err error) {
outConn, ID, err = s.GetOutConn() outConn, ID, err = s.GetOutConn()
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err) s.log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
break break
} }
} }
log.Printf("%s stream %s created", *s.cfg.Key, ID) s.log.Printf("%s stream %s created", *s.cfg.Key, ID)
if *s.cfg.IsCompress { if *s.cfg.IsCompress {
die1 := make(chan bool, 1) die1 := make(chan bool, 1)
die2 := make(chan bool, 1) die2 := make(chan bool, 1)
@ -248,17 +255,17 @@ func (s *MuxServer) Start(args interface{}) (err error) {
} }
outConn.Close() outConn.Close()
inConn.Close() inConn.Close()
log.Printf("%s stream %s released", *s.cfg.Key, ID) s.log.Printf("%s stream %s released", *s.cfg.Key, ID)
} else { } else {
utils.IoBind(inConn, outConn, func(err interface{}) { utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("%s stream %s released", *s.cfg.Key, ID) s.log.Printf("%s stream %s released", *s.cfg.Key, ID)
}) }, s.log)
} }
}) })
if err != nil { if err != nil {
return return
} }
log.Printf("server on %s", (*s.sc.Listener).Addr()) s.log.Printf("server on %s", (*s.sc.Listener).Addr())
} }
return return
} }
@ -272,7 +279,7 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
} }
outConn, err = s.GetConn(fmt.Sprintf("%d", i)) outConn, err = s.GetConn(fmt.Sprintf("%d", i))
if err != nil { if err != nil {
log.Printf("connection err: %s", err) s.log.Printf("connection err: %s", err)
return return
} }
remoteAddr := "tcp:" + *s.cfg.Remote remoteAddr := "tcp:" + *s.cfg.Remote
@ -284,7 +291,7 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
_, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID)) _, err = outConn.Write(utils.BuildPacketData(ID, remoteAddr, s.cfg.Mgr.serverID))
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("write stream data err: %s ,retrying...", err) s.log.Printf("write stream data err: %s ,retrying...", err)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
return return
} }
@ -325,7 +332,7 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
_sess.(*smux.Session).Close() _sess.(*smux.Session).Close()
} }
s.sessions.Set(index, session) s.sessions.Set(index, session)
log.Printf("session[%s] created", index) s.log.Printf("session[%s] created", index)
go func() { go func() {
for { for {
if s.isStop { if s.isStop {
@ -366,7 +373,7 @@ func (s *MuxServer) UDPConnDeamon() {
go func() { go func() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
var outConn net.Conn var outConn net.Conn
@ -390,7 +397,7 @@ func (s *MuxServer) UDPConnDeamon() {
if err != nil { if err != nil {
outConn = nil outConn = nil
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err) s.log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -407,14 +414,14 @@ func (s *MuxServer) UDPConnDeamon() {
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn) srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body) s.log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
log.Printf("UDP deamon connection %s exited", ID) s.log.Printf("UDP deamon connection %s exited", ID)
break break
} }
//log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn) //s.log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
_srcAddr := strings.Split(srcAddrFromConn, ":") _srcAddr := strings.Split(srcAddrFromConn, ":")
if len(_srcAddr) != 2 { if len(_srcAddr) != 2 {
log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn) s.log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
continue continue
} }
port, _ := strconv.Atoi(_srcAddr[1]) port, _ := strconv.Atoi(_srcAddr[1])
@ -423,10 +430,10 @@ func (s *MuxServer) UDPConnDeamon() {
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr) _, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
s.sc.UDPListener.SetDeadline(time.Time{}) s.sc.UDPListener.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err) s.log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
continue continue
} }
//log.Printf("udp response to local %s success , %v", srcAddrFromConn, body) //s.log.Printf("udp response to local %s success , %v", srcAddrFromConn, body)
} }
}(outConn, ID) }(outConn, ID)
break break
@ -439,10 +446,10 @@ func (s *MuxServer) UDPConnDeamon() {
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
outConn = nil outConn = nil
log.Printf("write udp packet to %s fail ,flush err:%s ,retrying...", *s.cfg.Parent, err) s.log.Printf("write udp packet to %s fail ,flush err:%s ,retrying...", *s.cfg.Parent, err)
goto RETRY goto RETRY
} }
//log.Printf("write packet %v", *item.packet) //s.log.Printf("write packet %v", *item.packet)
} }
}() }()
} }

View File

@ -2,27 +2,30 @@ package services
import ( import (
"fmt" "fmt"
logger "log"
"runtime/debug" "runtime/debug"
) )
type Service interface { type Service interface {
Start(args interface{}) (err error) Start(args interface{}, log *logger.Logger) (err error)
Clean() Clean()
} }
type ServiceItem struct { type ServiceItem struct {
S Service S Service
Args interface{} Args interface{}
Name string Name string
Log *logger.Logger
} }
var servicesMap = map[string]*ServiceItem{} var servicesMap = map[string]*ServiceItem{}
func Regist(name string, s Service, args interface{}) { func Regist(name string, s Service, args interface{}, log *logger.Logger) {
Stop(name) Stop(name)
servicesMap[name] = &ServiceItem{ servicesMap[name] = &ServiceItem{
S: s, S: s,
Args: args, Args: args,
Name: name, Name: name,
Log: log,
} }
} }
func GetService(name string) *ServiceItem { func GetService(name string) *ServiceItem {
@ -37,7 +40,7 @@ func Stop(name string) {
s.S.Clean() s.S.Clean()
} }
} }
func Run(name string, args ...interface{}) (service *ServiceItem, err error) { func Run(name string, args interface{}) (service *ServiceItem, err error) {
service, ok := servicesMap[name] service, ok := servicesMap[name]
if ok { if ok {
defer func() { defer func() {
@ -46,10 +49,10 @@ func Run(name string, args ...interface{}) (service *ServiceItem, err error) {
err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack())) err = fmt.Errorf("%s servcie crashed, ERR: %s\ntrace:%s", name, e, string(debug.Stack()))
} }
}() }()
if len(args) == 1 { if args != nil {
err = service.S.Start(args[0]) err = service.S.Start(args, service.Log)
} else { } else {
err = service.S.Start(service.Args) err = service.S.Start(service.Args, service.Log)
} }
if err != nil { if err != nil {
err = fmt.Errorf("%s servcie fail, ERR: %s", name, err) err = fmt.Errorf("%s servcie fail, ERR: %s", name, err)

View File

@ -3,17 +3,18 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "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" "io/ioutil"
"log" logger "log"
"net" "net"
"runtime/debug" "runtime/debug"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/aes"
"github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/socks"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@ -28,6 +29,7 @@ type Socks struct {
domainResolver utils.DomainResolver domainResolver utils.DomainResolver
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
func NewSocks() Service { func NewSocks() Service {
@ -108,9 +110,9 @@ func (s *Socks) CheckArgs() (err error) {
func (s *Socks) InitService() (err error) { func (s *Socks) InitService() (err error) {
s.InitBasicAuth() s.InitBasicAuth()
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
} }
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct) s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
e := s.ConnectSSH() e := s.ConnectSSH()
if e != nil { if e != nil {
@ -133,7 +135,7 @@ func (s *Socks) InitService() (err error) {
if s.sshClient != nil { if s.sshClient != nil {
s.sshClient.Close() s.sshClient.Close()
} }
log.Printf("ssh offline, retrying...") s.log.Printf("ssh offline, retrying...")
s.ConnectSSH() s.ConnectSSH()
} else { } else {
conn.Close() conn.Close()
@ -143,15 +145,15 @@ func (s *Socks) InitService() (err error) {
}() }()
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
log.Println("warn: socks udp not suppored for ssh") s.log.Printf("warn: socks udp not suppored for ssh")
} else { } else {
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal) s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal, s.log)
e := s.udpSC.ListenUDP(s.udpCallback) e := s.udpSC.ListenUDP(s.udpCallback)
if e != nil { if e != nil {
err = fmt.Errorf("init udp service fail, ERR: %s", e) err = fmt.Errorf("init udp service fail, ERR: %s", e)
return return
} }
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr()) s.log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
} }
return return
} }
@ -159,9 +161,9 @@ func (s *Socks) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop socks service crashed,%s", e) s.log.Printf("stop socks service crashed,%s", e)
} else { } else {
log.Printf("service socks stoped") s.log.Printf("service socks stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -179,7 +181,8 @@ func (s *Socks) StopService() {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
} }
func (s *Socks) Start(args interface{}) (err error) { func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
//start() //start()
s.cfg = args.(SocksArgs) s.cfg = args.(SocksArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
@ -189,24 +192,24 @@ func (s *Socks) Start(args interface{}) (err error) {
s.InitService() s.InitService()
} }
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
} }
if *s.cfg.UDPParent != "" { if *s.cfg.UDPParent != "" {
log.Printf("use socks udp parent %s", *s.cfg.UDPParent) s.log.Printf("use socks udp parent %s", *s.cfg.UDPParent)
} }
sc := utils.NewServerChannelHost(*s.cfg.Local) sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.socksConnCallback) err = sc.ListenTCP(s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback) err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback, s.log)
} }
if err != nil { if err != nil {
return return
} }
s.sc = &sc s.sc = &sc
log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr()) s.log.Printf("%s socks proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
return return
} }
func (s *Socks) Clean() { func (s *Socks) Clean() {
@ -222,29 +225,29 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
//decode b //decode b
rawB, err = goaes.Decrypt(s.UDPKey(), b) rawB, err = goaes.Decrypt(s.UDPKey(), b)
if err != nil { if err != nil {
log.Printf("decrypt udp packet fail from %s", srcAddr.String()) s.log.Printf("decrypt udp packet fail from %s", srcAddr.String())
return return
} }
} }
p, err := socks.ParseUDPPacket(rawB) p, err := socks.ParseUDPPacket(rawB)
log.Printf("udp revecived:%v", len(p.Data())) s.log.Printf("udp revecived:%v", len(p.Data()))
if err != nil { if err != nil {
log.Printf("parse udp packet fail, ERR:%s", err) s.log.Printf("parse udp packet fail, ERR:%s", err)
return return
} }
//防止死循环 //防止死循环
if s.IsDeadLoop((*localAddr).String(), p.Host()) { if s.IsDeadLoop((*localAddr).String(), p.Host()) {
log.Printf("dead loop detected , %s", p.Host()) s.log.Printf("dead loop detected , %s", p.Host())
return return
} }
//log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port()) //s.log.Printf("##########udp to -> %s:%s###########", p.Host(), p.Port())
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
//有上级代理,转发给上级 //有上级代理,转发给上级
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
//encode b //encode b
rawB, err = goaes.Encrypt(s.UDPKey(), rawB) rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
return return
} }
} }
@ -254,43 +257,43 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
} }
dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent)) dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent))
if err != nil { if err != nil {
log.Printf("can't resolve address: %s", err) s.log.Printf("can't resolve address: %s", err)
return return
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
_, err = conn.Write(rawB) _, err = conn.Write(rawB)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
log.Printf("udp request:%v", len(rawB)) s.log.Printf("udp request:%v", len(rawB))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024) buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
log.Printf("udp response:%v", len(respBody)) s.log.Printf("udp response:%v", len(respBody))
//log.Printf("revecived udp packet from %s", dstAddr.String()) //s.log.Printf("revecived udp packet from %s", dstAddr.String())
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
//decode b //decode b
respBody, err = goaes.Decrypt(s.UDPKey(), respBody) respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
conn.Close() conn.Close()
return return
} }
@ -298,81 +301,83 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" {
d, err := goaes.Encrypt(s.UDPKey(), respBody) d, err := goaes.Encrypt(s.UDPKey(), respBody)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail from %s", dstAddr.String()) s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close() conn.Close()
return return
} }
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{}) s.udpSC.UDPListener.SetDeadline(time.Time{})
log.Printf("udp reply:%v", len(d)) s.log.Printf("udp reply:%v", len(d))
d = nil
} else { } else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr) s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{}) s.udpSC.UDPListener.SetDeadline(time.Time{})
log.Printf("udp reply:%v", len(respBody)) s.log.Printf("udp reply:%v", len(respBody))
} }
} else { } else {
//本地代理 //本地代理
dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port())) dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port()))
if err != nil { if err != nil {
log.Printf("can't resolve address: %s", err) s.log.Printf("can't resolve address: %s", err)
return return
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
_, err = conn.Write(p.Data()) _, err = conn.Write(p.Data())
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
log.Printf("udp send:%v", len(p.Data())) s.log.Printf("udp send:%v", len(p.Data()))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 10*1024) buf := make([]byte, 10*1024)
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close() conn.Close()
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
//封装来自真实服务器的数据,返回给访问者 //封装来自真实服务器的数据,返回给访问者
respPacket := p.NewReply(respBody) respPacket := p.NewReply(respBody)
//log.Printf("revecived udp packet from %s", dstAddr.String()) //s.log.Printf("revecived udp packet from %s", dstAddr.String())
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" {
d, err := goaes.Encrypt(s.UDPKey(), respPacket) d, err := goaes.Encrypt(s.UDPKey(), respPacket)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail from %s", dstAddr.String()) s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close() conn.Close()
return return
} }
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{}) s.udpSC.UDPListener.SetDeadline(time.Time{})
d = nil
} else { } else {
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr) s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
s.udpSC.UDPListener.SetDeadline(time.Time{}) s.udpSC.UDPListener.SetDeadline(time.Time{})
} }
log.Printf("udp reply:%v", len(respPacket)) s.log.Printf("udp reply:%v", len(respPacket))
} }
} }
func (s *Socks) socksConnCallback(inConn net.Conn) { func (s *Socks) socksConnCallback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
inConn.Close() inConn.Close()
} }
}() }()
@ -393,7 +398,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
if err != nil { if err != nil {
methodReq.Reply(socks.Method_NONE_ACCEPTABLE) methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("new methods request fail,ERR: %s", err) s.log.Printf("new methods request fail,ERR: %s", err)
return return
} }
@ -401,29 +406,29 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
if !methodReq.Select(socks.Method_NO_AUTH) { if !methodReq.Select(socks.Method_NO_AUTH) {
methodReq.Reply(socks.Method_NONE_ACCEPTABLE) methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("none method found : Method_NO_AUTH") s.log.Printf("none method found : Method_NO_AUTH")
return return
} }
//method select reply //method select reply
err = methodReq.Reply(socks.Method_NO_AUTH) err = methodReq.Reply(socks.Method_NO_AUTH)
if err != nil { if err != nil {
log.Printf("reply answer data fail,ERR: %s", err) s.log.Printf("reply answer data fail,ERR: %s", err)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
return return
} }
// log.Printf("% x", methodReq.Bytes()) // s.log.Printf("% x", methodReq.Bytes())
} else { } else {
//auth //auth
if !methodReq.Select(socks.Method_USER_PASS) { if !methodReq.Select(socks.Method_USER_PASS) {
methodReq.Reply(socks.Method_NONE_ACCEPTABLE) methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("none method found : Method_USER_PASS") s.log.Printf("none method found : Method_USER_PASS")
return return
} }
//method reply need auth //method reply need auth
err = methodReq.Reply(socks.Method_USER_PASS) err = methodReq.Reply(socks.Method_USER_PASS)
if err != nil { if err != nil {
log.Printf("reply answer data fail,ERR: %s", err) s.log.Printf("reply answer data fail,ERR: %s", err)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
return return
} }
@ -439,7 +444,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
r := buf[:n] r := buf[:n]
user := string(r[2 : r[1]+2]) user := string(r[2 : r[1]+2])
pass := string(r[2+r[1]+1:]) pass := string(r[2+r[1]+1:])
//log.Printf("user:%s,pass:%s", user, pass) //s.log.Printf("user:%s,pass:%s", user, pass)
//auth //auth
_addr := strings.Split(inConn.RemoteAddr().String(), ":") _addr := strings.Split(inConn.RemoteAddr().String(), ":")
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") { if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
@ -460,7 +465,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
//request detail //request detail
request, err := socks.NewRequest(inConn) request, err := socks.NewRequest(inConn)
if err != nil { if err != nil {
log.Printf("read request data fail,ERR: %s", err) s.log.Printf("read request data fail,ERR: %s", err)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
return return
} }
@ -488,7 +493,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
} }
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String()) _, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
log.Printf("proxy udp on %s", net.JoinHostPort(host, port)) s.log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
} }
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
@ -500,7 +505,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
//防止死循环 //防止死循环
if s.IsDeadLoop((*inConn).LocalAddr().String(), request.Host()) { if s.IsDeadLoop((*inConn).LocalAddr().String(), request.Host()) {
utils.CloseConn(inConn) utils.CloseConn(inConn)
log.Printf("dead loop detected , %s", request.Host()) s.log.Printf("dead loop detected , %s", request.Host())
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
@ -514,7 +519,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
host, _, _ := net.SplitHostPort(request.Addr()) host, _, _ := net.SplitHostPort(request.Addr())
useProxy := false useProxy := false
if utils.IsIternalIP(host) { if utils.IsIternalIP(host, *s.cfg.Always) {
useProxy = false useProxy = false
} else { } else {
k := s.Resolve(request.Addr()) k := s.Resolve(request.Addr())
@ -535,26 +540,27 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
if err == nil || tryCount > maxTryCount || *s.cfg.Parent == "" { if err == nil || tryCount > maxTryCount || *s.cfg.Parent == "" {
break break
} else { } else {
log.Printf("get out conn fail,%s,retrying...", err) s.log.Printf("get out conn fail,%s,retrying...", err)
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
} }
} }
if err != nil { if err != nil {
log.Printf("get out conn fail,%s", err) s.log.Printf("get out conn fail,%s", err)
request.TCPReply(socks.REP_NETWOR_UNREACHABLE) request.TCPReply(socks.REP_NETWOR_UNREACHABLE)
return return
} }
log.Printf("use proxy %v : %s", useProxy, request.Addr()) s.log.Printf("use proxy %v : %s", useProxy, request.Addr())
request.TCPReply(socks.REP_SUCCESS) request.TCPReply(socks.REP_SUCCESS)
inAddr := (*inConn).RemoteAddr().String() inAddr := (*inConn).RemoteAddr().String()
//inLocalAddr := (*inConn).LocalAddr().String() //inLocalAddr := (*inConn).LocalAddr().String()
log.Printf("conn %s - %s connected", inAddr, request.Addr()) s.log.Printf("conn %s - %s connected", inAddr, request.Addr())
utils.IoBind(*inConn, outConn, func(err interface{}) { utils.IoBind(*inConn, outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, request.Addr()) s.log.Printf("conn %s - %s released", inAddr, request.Addr())
}) s.userConns.Remove(inAddr)
}, s.log)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
@ -606,7 +612,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
return return
} }
//resp := buf[:n] //resp := buf[:n]
//log.Printf("resp:%v", resp) //s.log.Printf("resp:%v", resp)
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(reqBytes) _, err = outConn.Write(reqBytes)
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
@ -622,7 +628,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
return return
} }
//result := buf[:n] //result := buf[:n]
//log.Printf("result:%v", result) //s.log.Printf("result:%v", result)
case "ssh": case "ssh":
maxTryCount := 1 maxTryCount := 1
@ -648,7 +654,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
s.sshClient.Close() s.sshClient.Close()
} }
if err != nil { if err != nil {
log.Printf("connect ssh fail, ERR: %s, retrying...", err) s.log.Printf("connect ssh fail, ERR: %s, retrying...", err)
e := s.ConnectSSH() e := s.ConnectSSH()
if e == nil { if e == nil {
tryCount++ tryCount++
@ -686,13 +692,13 @@ func (s *Socks) ConnectSSH() (err error) {
} }
func (s *Socks) InitBasicAuth() (err error) { func (s *Socks) InitBasicAuth() (err error) {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver) s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
} else { } else {
s.basicAuth = utils.NewBasicAuth(nil) s.basicAuth = utils.NewBasicAuth(nil, s.log)
} }
if *s.cfg.AuthURL != "" { if *s.cfg.AuthURL != "" {
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry) s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
log.Printf("auth from %s", *s.cfg.AuthURL) s.log.Printf("auth from %s", *s.cfg.AuthURL)
} }
if *s.cfg.AuthFile != "" { if *s.cfg.AuthFile != "" {
var n = 0 var n = 0
@ -701,11 +707,11 @@ func (s *Socks) InitBasicAuth() (err error) {
err = fmt.Errorf("auth-file ERR:%s", err) err = fmt.Errorf("auth-file ERR:%s", err)
return return
} }
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
} }
if len(*s.cfg.Auth) > 0 { if len(*s.cfg.Auth) > 0 {
n := s.basicAuth.Add(*s.cfg.Auth) n := s.basicAuth.Add(*s.cfg.Auth)
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
} }
return return
} }
@ -757,7 +763,7 @@ func (s *Socks) Resolve(address string) string {
} }
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
} }
return ip return ip
} }

View File

@ -5,16 +5,17 @@ import (
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/socks"
"github.com/snail007/goproxy/utils/conncrypt"
"io/ioutil" "io/ioutil"
"log" logger "log"
"net" "net"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/socks"
) )
type SPS struct { type SPS struct {
@ -24,6 +25,7 @@ type SPS struct {
basicAuth utils.BasicAuth basicAuth utils.BasicAuth
serverChannels []*utils.ServerChannel serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
func NewSPS() Service { func NewSPS() Service {
@ -60,10 +62,10 @@ func (s *SPS) CheckArgs() (err error) {
return return
} }
func (s *SPS) InitService() (err error) { func (s *SPS) InitService() (err error) {
s.InitOutConnPool()
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL) (*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
} }
s.InitOutConnPool()
err = s.InitBasicAuth() err = s.InitBasicAuth()
return return
} }
@ -86,9 +88,9 @@ func (s *SPS) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop sps service crashed,%s", e) s.log.Printf("stop sps service crashed,%s", e)
} else { } else {
log.Printf("service sps stoped") s.log.Printf("service sps stoped")
} }
}() }()
for _, sc := range s.serverChannels { for _, sc := range s.serverChannels {
@ -100,10 +102,16 @@ func (s *SPS) StopService() {
} }
} }
for _, c := range s.userConns.Items() { for _, c := range s.userConns.Items() {
if _, ok := c.(*net.Conn); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
if _, ok := c.(**net.Conn); ok {
(*(*c.(**net.Conn))).Close()
} }
func (s *SPS) Start(args interface{}) (err error) { }
}
func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(SPSArgs) s.cfg = args.(SPSArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -111,23 +119,23 @@ func (s *SPS) Start(args interface{}) (err error) {
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent) s.log.Printf("use %s %s parent %s", *s.cfg.ParentType, *s.cfg.ParentServiceType, *s.cfg.Parent)
for _, addr := range strings.Split(*s.cfg.Local, ",") { for _, addr := range strings.Split(*s.cfg.Local, ",") {
if addr != "" { if addr != "" {
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
} }
if err != nil { if err != nil {
return return
} }
log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr()) s.log.Printf("%s http(s)+socks proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.serverChannels = append(s.serverChannels, &sc) s.serverChannels = append(s.serverChannels, &sc)
} }
} }
@ -140,7 +148,7 @@ func (s *SPS) Clean() {
func (s *SPS) callback(inConn net.Conn) { func (s *SPS) callback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack())) s.log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
} }
}() }()
if *s.cfg.LocalCompress { if *s.cfg.LocalCompress {
@ -163,56 +171,78 @@ func (s *SPS) callback(inConn net.Conn) {
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType) err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
} }
if err != nil { if err != nil {
log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr()) s.log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
} }
} }
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) { func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
buf := make([]byte, 1024) bInConn := utils.NewBufferedConn(*inConn)
n, err := (*inConn).Read(buf) //important
header := buf[:n] //action read will regist read event to system,
//when data arrived , system call process
//so that we can get buffered bytes count
//otherwise Buffered() always return 0
bInConn.ReadByte()
bInConn.UnreadByte()
n := 8
if n > bInConn.Buffered() {
n = bInConn.Buffered()
}
h, err := bInConn.Peek(n)
if err != nil { if err != nil {
log.Printf("ERR:%s", err) s.log.Printf("peek error %s ", err)
utils.CloseConn(inConn) (*inConn).Close()
return return
} }
*inConn = bInConn
address := "" address := ""
var auth socks.Auth var auth socks.Auth
var forwardBytes []byte var forwardBytes []byte
//fmt.Printf("%v", header) //fmt.Printf("%v", header)
if header[0] == socks.VERSION_V5 { if utils.IsSocks5(h) {
if *s.cfg.DisableSocks5 {
(*inConn).Close()
return
}
//socks5 server //socks5 server
var serverConn *socks.ServerConn var serverConn *socks.ServerConn
if s.IsBasicAuth() { if s.IsBasicAuth() {
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", nil)
} else { } else {
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header) serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", nil)
} }
if err = serverConn.Handshake(); err != nil { if err = serverConn.Handshake(); err != nil {
return return
} }
address = serverConn.Target() address = serverConn.Target()
auth = serverConn.AuthData() auth = serverConn.AuthData()
} else if bytes.IndexByte(header, '\n') != -1 { } else if utils.IsHTTP(h) {
if *s.cfg.DisableHTTP {
(*inConn).Close()
return
}
//http //http
var request utils.HTTPRequest var request utils.HTTPRequest
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) (*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
if s.IsBasicAuth() { if s.IsBasicAuth() {
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header) request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, s.log)
} else { } else {
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header) request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, s.log)
} }
(*inConn).SetDeadline(time.Time{}) (*inConn).SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("new http request fail,ERR: %s", err) s.log.Printf("new http request fail,ERR: %s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
if len(header) >= 7 && strings.ToLower(string(header[:7])) == "connect" { if len(h) >= 7 && strings.ToLower(string(h[:7])) == "connect" {
//https //https
request.HTTPSReply() request.HTTPSReply()
//log.Printf("https reply: %s", request.Host) //s.log.Printf("https reply: %s", request.Host)
} else { } else {
//forwardBytes = bytes.TrimRight(request.HeadBuf,"\r\n")
forwardBytes = request.HeadBuf forwardBytes = request.HeadBuf
} }
address = request.Host address = request.Host
@ -227,8 +257,10 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]} auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
} }
} }
} else { }
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header)) if err != nil || address == "" {
s.log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(h))
(*inConn).Close()
utils.CloseConn(inConn) utils.CloseConn(inConn)
err = errors.New("unknown request") err = errors.New("unknown request")
return return
@ -237,7 +269,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn var outConn net.Conn
outConn, err = s.outPool.Get() outConn, err = s.outPool.Get()
if err != nil { if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
@ -249,12 +281,23 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
Password: *s.cfg.ParentKey, Password: *s.cfg.ParentKey,
}) })
} }
if *s.cfg.ParentAuth != "" || s.IsBasicAuth() {
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
}
//ask parent for connect to target address //ask parent for connect to target address
if *s.cfg.ParentServiceType == "http" { if *s.cfg.ParentServiceType == "http" {
//http parent //http parent
isHTTPS := false
pb := new(bytes.Buffer) pb := new(bytes.Buffer)
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address))) if len(forwardBytes) == 0 {
//Proxy-Authorization:\r\n isHTTPS = true
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", address)))
}
pb.WriteString("Proxy-Connection: Keep-Alive\r\n")
u := "" u := ""
if *s.cfg.ParentAuth != "" { if *s.cfg.ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":") a := strings.Split(*s.cfg.ParentAuth, ":")
@ -271,29 +314,41 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
if u != "" { if u != "" {
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u))))) pb.Write([]byte(fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
} }
if isHTTPS {
pb.Write([]byte("\r\n")) pb.Write([]byte("\r\n"))
} else {
forwardBytes = utils.InsertProxyHeaders(forwardBytes, string(pb.Bytes()))
pb.Reset()
pb.Write(forwardBytes)
forwardBytes = nil
}
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(pb.Bytes()) _, err = outConn.Write(pb.Bytes())
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
return return
} }
if isHTTPS {
reply := make([]byte, 1024) reply := make([]byte, 1024)
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Read(reply) _, err = outConn.Read(reply)
outConn.SetDeadline(time.Time{}) outConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err) s.log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
return return
} }
//log.Printf("reply: %s", string(reply[:n])) //s.log.Printf("reply: %s", string(reply[:n]))
} else { }
log.Printf("connect %s", address) } else if *s.cfg.ParentServiceType == "socks" {
s.log.Printf("connect %s", address)
//socks client //socks client
var clientConn *socks.ClientConn var clientConn *socks.ClientConn
if *s.cfg.ParentAuth != "" { if *s.cfg.ParentAuth != "" {
@ -302,45 +357,47 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
err = fmt.Errorf("parent auth data format error") err = fmt.Errorf("parent auth data format error")
return return
} }
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, header) clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, nil)
} else { } else {
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" { if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header) clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, nil)
} else { } else {
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header) clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, nil)
} }
} }
if err = clientConn.Handshake(); err != nil { if err = clientConn.Handshake(); err != nil {
return return
} }
} }
//forward client data to target,if necessary. //forward client data to target,if necessary.
if len(forwardBytes) > 0 { if len(forwardBytes) > 0 {
outConn.Write(forwardBytes) outConn.Write(forwardBytes)
} }
//bind //bind
inAddr := (*inConn).RemoteAddr().String() inAddr := (*inConn).RemoteAddr().String()
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr) s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, address)
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
}) }, s.log)
log.Printf("conn %s - %s connected", inAddr, outAddr) s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, address)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
s.userConns.Set(inAddr, &inConn) s.userConns.Set(inAddr, inConn)
return return
} }
func (s *SPS) InitBasicAuth() (err error) { func (s *SPS) InitBasicAuth() (err error) {
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver) s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
} else { } else {
s.basicAuth = utils.NewBasicAuth(nil) s.basicAuth = utils.NewBasicAuth(nil, s.log)
} }
if *s.cfg.AuthURL != "" { if *s.cfg.AuthURL != "" {
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry) s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
log.Printf("auth from %s", *s.cfg.AuthURL) s.log.Printf("auth from %s", *s.cfg.AuthURL)
} }
if *s.cfg.AuthFile != "" { if *s.cfg.AuthFile != "" {
var n = 0 var n = 0
@ -349,11 +406,11 @@ func (s *SPS) InitBasicAuth() (err error) {
err = fmt.Errorf("auth-file ERR:%s", err) err = fmt.Errorf("auth-file ERR:%s", err)
return return
} }
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
} }
if len(*s.cfg.Auth) > 0 { if len(*s.cfg.Auth) > 0 {
n := s.basicAuth.Add(*s.cfg.Auth) n := s.basicAuth.Add(*s.cfg.Auth)
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total()) s.log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
} }
return return
} }
@ -404,7 +461,7 @@ func (s *SPS) Resolve(address string) string {
} }
ip, err := s.domainResolver.Resolve(address) ip, err := s.domainResolver.Resolve(address)
if err != nil { if err != nil {
log.Printf("dns error %s , ERR:%s", address, err) s.log.Printf("dns error %s , ERR:%s", address, err)
} }
return ip return ip
} }

View File

@ -3,13 +3,14 @@ package services
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"net" "net"
"runtime/debug" "runtime/debug"
"time" "time"
"github.com/snail007/goproxy/utils"
"strconv" "strconv"
) )
@ -19,6 +20,7 @@ type TCP struct {
sc *utils.ServerChannel sc *utils.ServerChannel
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
func NewTCP() Service { func NewTCP() Service {
@ -54,9 +56,9 @@ func (s *TCP) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop tcp service crashed,%s", e) s.log.Printf("stop tcp service crashed,%s", e)
} else { } else {
log.Printf("service tcp stoped") s.log.Printf("service tcp stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -70,7 +72,8 @@ func (s *TCP) StopService() {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
} }
func (s *TCP) Start(args interface{}) (err error) { func (s *TCP) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(TCPArgs) s.cfg = args.(TCPArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -78,22 +81,22 @@ func (s *TCP) Start(args interface{}) (err error) {
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == TYPE_TCP { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_TLS { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(s.cfg.KCP, s.callback) err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
} }
if err != nil { if err != nil {
return return
} }
log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr()) s.log.Printf("%s proxy on %s", s.cfg.Protocol(), (*sc.Listener).Addr())
s.sc = &sc s.sc = &sc
return return
} }
@ -104,7 +107,7 @@ func (s *TCP) Clean() {
func (s *TCP) callback(inConn net.Conn) { func (s *TCP) callback(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack())) s.log.Printf("%s conn handler crashed with err : %s \nstack: %s", s.cfg.Protocol(), err, string(debug.Stack()))
} }
}() }()
var err error var err error
@ -121,7 +124,7 @@ func (s *TCP) callback(inConn net.Conn) {
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType) err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
} }
if err != nil { if err != nil {
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err) s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
} }
} }
@ -129,7 +132,7 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
var outConn net.Conn var outConn net.Conn
outConn, err = s.outPool.Get() outConn, err = s.outPool.Get()
if err != nil { if err != nil {
log.Printf("connect to %s , err:%s", *s.cfg.Parent, err) s.log.Printf("connect to %s , err:%s", *s.cfg.Parent, err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
@ -138,18 +141,18 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
outAddr := outConn.RemoteAddr().String() outAddr := outConn.RemoteAddr().String()
//outLocalAddr := outConn.LocalAddr().String() //outLocalAddr := outConn.LocalAddr().String()
utils.IoBind((*inConn), outConn, func(err interface{}) { utils.IoBind((*inConn), outConn, func(err interface{}) {
log.Printf("conn %s - %s released", inAddr, outAddr) s.log.Printf("conn %s - %s released", inAddr, outAddr)
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
}) }, s.log)
log.Printf("conn %s - %s connected", inAddr, outAddr) s.log.Printf("conn %s - %s connected", inAddr, outAddr)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
s.userConns.Set(inAddr, &inConn) s.userConns.Set(inAddr, inConn)
return return
} }
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) { func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr()) s.log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
for { for {
if s.isStop { if s.isStop {
(*inConn).Close() (*inConn).Close()
@ -157,45 +160,45 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
} }
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn)) srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %s released", srcAddr) //s.log.Printf("connection %s released", srcAddr)
utils.CloseConn(inConn) utils.CloseConn(inConn)
break break
} }
//log.Debugf("udp packet revecived:%s,%v", srcAddr, body) //log.Debugf("udp packet revecived:%s,%v", srcAddr, body)
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent) dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
if err != nil { if err != nil {
log.Printf("can't resolve address: %s", err) s.log.Printf("can't resolve address: %s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
break break
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
continue continue
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write(body) _, err = conn.Write(body)
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
continue continue
} }
//log.Debugf("send udp packet to %s success", dstAddr.String()) //log.Debugf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 512) buf := make([]byte, 512)
len, _, err := conn.ReadFromUDP(buf) len, _, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
continue continue
} }
respBody := buf[0:len] respBody := buf[0:len]
//log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody) //log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
_, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody)) _, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody))
if err != nil { if err != nil {
log.Printf("send udp response fail ,ERR:%s", err) s.log.Printf("send udp response fail ,ERR:%s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
break break
} }
//log.Printf("send udp response success ,from:%s", dstAddr.String()) //s.log.Printf("send udp response success ,from:%s", dstAddr.String())
} }
return return

View File

@ -3,13 +3,16 @@ package services
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/snail007/goproxy/utils" logger "log"
"log"
"net" "net"
"os"
"strconv" "strconv"
"time" "time"
"github.com/xtaci/smux" "github.com/snail007/goproxy/utils"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type ServerConn struct { type ServerConn struct {
@ -21,6 +24,7 @@ type TunnelBridge struct {
serverConns utils.ConcurrentMap serverConns utils.ConcurrentMap
clientControlConns utils.ConcurrentMap clientControlConns utils.ConcurrentMap
isStop bool isStop bool
log *logger.Logger
} }
func NewTunnelBridge() Service { func NewTunnelBridge() Service {
@ -47,9 +51,9 @@ func (s *TunnelBridge) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop tbridge service crashed,%s", e) s.log.Printf("stop tbridge service crashed,%s", e)
} else { } else {
log.Printf("service tbridge stoped") s.log.Printf("service tbridge stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -60,7 +64,8 @@ func (s *TunnelBridge) StopService() {
(*sess.(ServerConn).Conn).Close() (*sess.(ServerConn).Conn).Close()
} }
} }
func (s *TunnelBridge) Start(args interface{}) (err error) { func (s *TunnelBridge) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(TunnelBridgeArgs) s.cfg = args.(TunnelBridgeArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -70,13 +75,13 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
} }
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
if err != nil { if err != nil {
return return
} }
log.Printf("proxy on tunnel bridge mode %s", (*sc.Listener).Addr()) s.log.Printf("proxy on tunnel bridge mode %s", (*sc.Listener).Addr())
return return
} }
func (s *TunnelBridge) Clean() { func (s *TunnelBridge) Clean() {
@ -84,20 +89,22 @@ func (s *TunnelBridge) Clean() {
} }
func (s *TunnelBridge) callback(inConn net.Conn) { func (s *TunnelBridge) callback(inConn net.Conn) {
var err error var err error
//log.Printf("connection from %s ", inConn.RemoteAddr()) //s.log.Printf("connection from %s ", inConn.RemoteAddr())
sess, err := smux.Server(inConn, &smux.Config{ sess, err := smux.Server(inConn, &smux.Config{
KeepAliveInterval: 10 * time.Second, AcceptBacklog: 256,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second, EnableKeepAlive: true,
MaxFrameSize: 4096, KeepAliveInterval: 9 * time.Second,
MaxReceiveBuffer: 4194304, ConnectionWriteTimeout: 3 * time.Second,
MaxStreamWindowSize: 512 * 1024,
LogOutput: os.Stderr,
}) })
if err != nil { if err != nil {
log.Printf("new mux server conn error,ERR:%s", err) s.log.Printf("new mux server conn error,ERR:%s", err)
return return
} }
inConn, err = sess.AcceptStream() inConn, err = sess.AcceptStream()
if err != nil { if err != nil {
log.Printf("mux server conn accept error,ERR:%s", err) s.log.Printf("mux server conn accept error,ERR:%s", err)
return return
} }
@ -109,7 +116,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
var connType uint8 var connType uint8
err = utils.ReadPacket(reader, &connType) err = utils.ReadPacket(reader, &connType)
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
switch connType { switch connType {
@ -117,11 +124,11 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
var key, ID, clientLocalAddr, serverID string var key, ID, clientLocalAddr, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID) err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID) packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID) s.log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
//addr := clientLocalAddr + "@" + ID //addr := clientLocalAddr + "@" + ID
s.serverConns.Set(ID, ServerConn{ s.serverConns.Set(ID, ServerConn{
@ -133,7 +140,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
} }
item, ok := s.clientControlConns.Get(key) item, ok := s.clientControlConns.Get(key)
if !ok { if !ok {
log.Printf("client %s control conn not exists", key) s.log.Printf("client %s control conn not exists", key)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} }
@ -141,7 +148,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
_, err := (*item.(*net.Conn)).Write(packet) _, err := (*item.(*net.Conn)).Write(packet)
(*item.(*net.Conn)).SetWriteDeadline(time.Time{}) (*item.(*net.Conn)).SetWriteDeadline(time.Time{})
if err != nil { if err != nil {
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err) s.log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -153,15 +160,15 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
var key, ID, serverID string var key, ID, serverID string
err = utils.ReadPacketData(reader, &key, &ID, &serverID) err = utils.ReadPacketData(reader, &key, &ID, &serverID)
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID) s.log.Printf("client connection , key: %s , id: %s, server id:%s", key, ID, serverID)
serverConnItem, ok := s.serverConns.Get(ID) serverConnItem, ok := s.serverConns.Get(ID)
if !ok { if !ok {
inConn.Close() inConn.Close()
log.Printf("server conn %s exists", ID) s.log.Printf("server conn %s exists", ID)
return return
} }
serverConn := serverConnItem.(ServerConn).Conn serverConn := serverConnItem.(ServerConn).Conn
@ -169,24 +176,24 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
s.serverConns.Remove(ID) s.serverConns.Remove(ID)
// s.cmClient.RemoveOne(key, ID) // s.cmClient.RemoveOne(key, ID)
// s.cmServer.RemoveOne(serverID, ID) // s.cmServer.RemoveOne(serverID, ID)
log.Printf("conn %s released", ID) s.log.Printf("conn %s released", ID)
}) }, s.log)
// s.cmClient.Add(key, ID, &inConn) // s.cmClient.Add(key, ID, &inConn)
log.Printf("conn %s created", ID) s.log.Printf("conn %s created", ID)
case CONN_CLIENT_CONTROL: case CONN_CLIENT_CONTROL:
var key string var key string
err = utils.ReadPacketData(reader, &key) err = utils.ReadPacketData(reader, &key)
if err != nil { if err != nil {
log.Printf("read error,ERR:%s", err) s.log.Printf("read error,ERR:%s", err)
return return
} }
log.Printf("client control connection, key: %s", key) s.log.Printf("client control connection, key: %s", key)
if s.clientControlConns.Has(key) { if s.clientControlConns.Has(key) {
item, _ := s.clientControlConns.Get(key) item, _ := s.clientControlConns.Get(key)
(*item.(*net.Conn)).Close() (*item.(*net.Conn)).Close()
} }
s.clientControlConns.Set(key, &inConn) s.clientControlConns.Set(key, &inConn)
log.Printf("set client %s control conn", key) s.log.Printf("set client %s control conn", key)
} }
} }

View File

@ -3,13 +3,16 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"net" "net"
"os"
"time" "time"
"github.com/xtaci/smux" "github.com/snail007/goproxy/utils"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type TunnelClient struct { type TunnelClient struct {
@ -17,6 +20,7 @@ type TunnelClient struct {
ctrlConn net.Conn ctrlConn net.Conn
isStop bool isStop bool
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
func NewTunnelClient() Service { func NewTunnelClient() Service {
@ -33,7 +37,7 @@ func (s *TunnelClient) InitService() (err error) {
func (s *TunnelClient) CheckArgs() (err error) { func (s *TunnelClient) CheckArgs() (err error) {
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) s.log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } else {
err = fmt.Errorf("parent required") err = fmt.Errorf("parent required")
return return
@ -49,9 +53,9 @@ func (s *TunnelClient) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop tclient service crashed,%s", e) s.log.Printf("stop tclient service crashed,%s", e)
} else { } else {
log.Printf("service tclient stoped") s.log.Printf("service tclient stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -62,7 +66,8 @@ func (s *TunnelClient) StopService() {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
} }
func (s *TunnelClient) Start(args interface{}) (err error) { func (s *TunnelClient) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(TunnelClientArgs) s.cfg = args.(TunnelClientArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -70,7 +75,7 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
log.Printf("proxy on tunnel client mode") s.log.Printf("proxy on tunnel client mode")
for { for {
if s.isStop { if s.isStop {
@ -82,7 +87,7 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
s.ctrlConn, err = s.GetInConn(CONN_CLIENT_CONTROL, *s.cfg.Key) s.ctrlConn, err = s.GetInConn(CONN_CLIENT_CONTROL, *s.cfg.Key)
if err != nil { if err != nil {
log.Printf("control connection err: %s, retrying...", err) s.log.Printf("control connection err: %s, retrying...", err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
if s.ctrlConn != nil { if s.ctrlConn != nil {
s.ctrlConn.Close() s.ctrlConn.Close()
@ -99,10 +104,10 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
if s.ctrlConn != nil { if s.ctrlConn != nil {
s.ctrlConn.Close() s.ctrlConn.Close()
} }
log.Printf("read connection signal err: %s, retrying...", err) s.log.Printf("read connection signal err: %s, retrying...", err)
break break
} }
log.Printf("signal revecived:%s %s %s", serverID, ID, clientLocalAddr) s.log.Printf("signal revecived:%s %s %s", serverID, ID, clientLocalAddr)
protocol := clientLocalAddr[:3] protocol := clientLocalAddr[:3]
localAddr := clientLocalAddr[4:] localAddr := clientLocalAddr[4:]
if protocol == "udp" { if protocol == "udp" {
@ -136,19 +141,21 @@ func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
if err == nil { if err == nil {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
c, e := smux.Client(conn, &smux.Config{ c, e := smux.Client(conn, &smux.Config{
KeepAliveInterval: 10 * time.Second, AcceptBacklog: 256,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second, EnableKeepAlive: true,
MaxFrameSize: 4096, KeepAliveInterval: 9 * time.Second,
MaxReceiveBuffer: 4194304, ConnectionWriteTimeout: 3 * time.Second,
MaxStreamWindowSize: 512 * 1024,
LogOutput: os.Stderr,
}) })
if e != nil { if e != nil {
log.Printf("new mux client conn error,ERR:%s", e) s.log.Printf("new mux client conn error,ERR:%s", e)
err = e err = e
return return
} }
conn, e = c.OpenStream() conn, e = c.OpenStream()
if e != nil { if e != nil {
log.Printf("mux client conn open stream error,ERR:%s", e) s.log.Printf("mux client conn open stream error,ERR:%s", e)
err = e err = e
return return
} }
@ -170,7 +177,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID) inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("connection err: %s, retrying...", err) s.log.Printf("connection err: %s, retrying...", err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -178,7 +185,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
} }
} }
// s.cm.Add(*s.cfg.Key, ID, &inConn) // s.cm.Add(*s.cfg.Key, ID, &inConn)
log.Printf("conn %s created", ID) s.log.Printf("conn %s created", ID)
for { for {
if s.isStop { if s.isStop {
@ -186,13 +193,13 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
} }
srcAddr, body, err := utils.ReadUDPPacket(inConn) srcAddr, body, err := utils.ReadUDPPacket(inConn)
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("connection %s released", ID) s.log.Printf("connection %s released", ID)
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
break break
} else if err != nil { } else if err != nil {
log.Printf("udp packet revecived fail, err: %s", err) s.log.Printf("udp packet revecived fail, err: %s", err)
} else { } else {
//log.Printf("udp packet revecived:%s,%v", srcAddr, body) //s.log.Printf("udp packet revecived:%s,%v", srcAddr, body)
go s.processUDPPacket(&inConn, srcAddr, localAddr, body) go s.processUDPPacket(&inConn, srcAddr, localAddr, body)
} }
@ -202,39 +209,39 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr string, body []byte) { func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr string, body []byte) {
dstAddr, err := net.ResolveUDPAddr("udp", localAddr) dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
if err != nil { if err != nil {
log.Printf("can't resolve address: %s", err) s.log.Printf("can't resolve address: %s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write(body) _, err = conn.Write(body)
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 1024) buf := make([]byte, 1024)
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody) //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
bs := utils.UDPPacket(srcAddr, respBody) bs := utils.UDPPacket(srcAddr, respBody)
_, err = (*inConn).Write(bs) _, err = (*inConn).Write(bs)
if err != nil { if err != nil {
log.Printf("send udp response fail ,ERR:%s", err) s.log.Printf("send udp response fail ,ERR:%s", err)
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
//log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs) //s.log.Printf("send udp response success ,from:%s ,%d ,%v", dstAddr.String(), len(bs), bs)
} }
func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) { func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
var inConn, outConn net.Conn var inConn, outConn net.Conn
@ -246,7 +253,7 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID) inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
log.Printf("connection err: %s, retrying...", err) s.log.Printf("connection err: %s, retrying...", err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -265,7 +272,7 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
break break
} else { } else {
if i == 3 { if i == 3 {
log.Printf("connect to %s err: %s, retrying...", localAddr, err) s.log.Printf("connect to %s err: %s, retrying...", localAddr, err)
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
continue continue
} }
@ -274,17 +281,17 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
if err != nil { if err != nil {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("build connection error, err: %s", err) s.log.Printf("build connection error, err: %s", err)
return return
} }
inAddr := inConn.RemoteAddr().String() inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) { utils.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("conn %s released", ID) s.log.Printf("conn %s released", ID)
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
}) }, s.log)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
s.userConns.Set(inAddr, &inConn) s.userConns.Set(inAddr, &inConn)
log.Printf("conn %s created", ID) s.log.Printf("conn %s created", ID)
} }

View File

@ -3,16 +3,19 @@ package services
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/snail007/goproxy/utils"
"io" "io"
"log" logger "log"
"net" "net"
"os"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/xtaci/smux" "github.com/snail007/goproxy/utils"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
) )
type TunnelServer struct { type TunnelServer struct {
@ -22,6 +25,7 @@ type TunnelServer struct {
isStop bool isStop bool
udpConn *net.Conn udpConn *net.Conn
userConns utils.ConcurrentMap userConns utils.ConcurrentMap
log *logger.Logger
} }
type TunnelServerManager struct { type TunnelServerManager struct {
@ -29,6 +33,7 @@ type TunnelServerManager struct {
udpChn chan UDPItem udpChn chan UDPItem
serverID string serverID string
servers []*Service servers []*Service
log *logger.Logger
} }
func NewTunnelServerManager() Service { func NewTunnelServerManager() Service {
@ -39,13 +44,14 @@ func NewTunnelServerManager() Service {
servers: []*Service{}, servers: []*Service{},
} }
} }
func (s *TunnelServerManager) Start(args interface{}) (err error) { func (s *TunnelServerManager) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(TunnelServerArgs) s.cfg = args.(TunnelServerArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
} }
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
log.Printf("use tls parent %s", *s.cfg.Parent) s.log.Printf("use tls parent %s", *s.cfg.Parent)
} else { } else {
err = fmt.Errorf("parent required") err = fmt.Errorf("parent required")
return return
@ -55,8 +61,8 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
return return
} }
log.Printf("server id: %s", s.serverID) s.log.Printf("server id: %s", s.serverID)
//log.Printf("route:%v", *s.cfg.Route) //s.log.Printf("route:%v", *s.cfg.Route)
for _, _info := range *s.cfg.Route { for _, _info := range *s.cfg.Route {
IsUDP := *s.cfg.IsUDP IsUDP := *s.cfg.IsUDP
if strings.HasPrefix(_info, "udp://") { if strings.HasPrefix(_info, "udp://") {
@ -88,7 +94,7 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
Key: &KEY, Key: &KEY,
Timeout: s.cfg.Timeout, Timeout: s.cfg.Timeout,
Mgr: s, Mgr: s,
}) }, log)
if err != nil { if err != nil {
return return
@ -120,13 +126,13 @@ func (s *TunnelServerManager) InitService() (err error) {
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) { func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn() outConn, err = s.GetConn()
if err != nil { if err != nil {
log.Printf("connection err: %s", err) s.log.Printf("connection err: %s", err)
return return
} }
ID = s.serverID ID = s.serverID
_, err = outConn.Write(utils.BuildPacket(typ, s.serverID)) _, err = outConn.Write(utils.BuildPacket(typ, s.serverID))
if err != nil { if err != nil {
log.Printf("write connection data err: %s ,retrying...", err) s.log.Printf("write connection data err: %s ,retrying...", err)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
return return
} }
@ -159,9 +165,9 @@ func (s *TunnelServer) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
log.Printf("service server stoped") s.log.Printf("service server stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -191,7 +197,8 @@ func (s *TunnelServer) CheckArgs() (err error) {
return return
} }
func (s *TunnelServer) Start(args interface{}) (err error) { func (s *TunnelServer) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(TunnelServerArgs) s.cfg = args.(TunnelServerArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
@ -201,7 +208,7 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
} }
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p) s.sc = utils.NewServerChannel(host, p, s.log)
if *s.cfg.IsUDP { if *s.cfg.IsUDP {
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) { err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
s.udpChn <- UDPItem{ s.udpChn <- UDPItem{
@ -213,12 +220,12 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
if err != nil { if err != nil {
return return
} }
log.Printf("proxy on udp tunnel server mode %s", (*s.sc.UDPListener).LocalAddr()) s.log.Printf("proxy on udp tunnel server mode %s", (*s.sc.UDPListener).LocalAddr())
} else { } else {
err = s.sc.ListenTCP(func(inConn net.Conn) { err = s.sc.ListenTCP(func(inConn net.Conn) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("tserver conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("tserver conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
var outConn net.Conn var outConn net.Conn
@ -230,7 +237,7 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
outConn, ID, err = s.GetOutConn(CONN_SERVER) outConn, ID, err = s.GetOutConn(CONN_SERVER)
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err) s.log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -240,18 +247,18 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
inAddr := inConn.RemoteAddr().String() inAddr := inConn.RemoteAddr().String()
utils.IoBind(inConn, outConn, func(err interface{}) { utils.IoBind(inConn, outConn, func(err interface{}) {
s.userConns.Remove(inAddr) s.userConns.Remove(inAddr)
log.Printf("%s conn %s released", *s.cfg.Key, ID) s.log.Printf("%s conn %s released", *s.cfg.Key, ID)
}) }, s.log)
if c, ok := s.userConns.Get(inAddr); ok { if c, ok := s.userConns.Get(inAddr); ok {
(*c.(*net.Conn)).Close() (*c.(*net.Conn)).Close()
} }
s.userConns.Set(inAddr, &inConn) s.userConns.Set(inAddr, &inConn)
log.Printf("%s conn %s created", *s.cfg.Key, ID) s.log.Printf("%s conn %s created", *s.cfg.Key, ID)
}) })
if err != nil { if err != nil {
return return
} }
log.Printf("proxy on tunnel server mode %s", (*s.sc.Listener).Addr()) s.log.Printf("proxy on tunnel server mode %s", (*s.sc.Listener).Addr())
} }
return return
} }
@ -261,7 +268,7 @@ func (s *TunnelServer) Clean() {
func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) { func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
outConn, err = s.GetConn() outConn, err = s.GetConn()
if err != nil { if err != nil {
log.Printf("connection err: %s", err) s.log.Printf("connection err: %s", err)
return return
} }
remoteAddr := "tcp:" + *s.cfg.Remote remoteAddr := "tcp:" + *s.cfg.Remote
@ -271,7 +278,7 @@ func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err e
ID = utils.Uniqueid() ID = utils.Uniqueid()
_, err = outConn.Write(utils.BuildPacket(typ, *s.cfg.Key, ID, remoteAddr, s.cfg.Mgr.serverID)) _, err = outConn.Write(utils.BuildPacket(typ, *s.cfg.Key, ID, remoteAddr, s.cfg.Mgr.serverID))
if err != nil { if err != nil {
log.Printf("write connection data err: %s ,retrying...", err) s.log.Printf("write connection data err: %s ,retrying...", err)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
return return
} }
@ -283,19 +290,21 @@ func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
if err == nil { if err == nil {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
c, e := smux.Client(conn, &smux.Config{ c, e := smux.Client(conn, &smux.Config{
KeepAliveInterval: 10 * time.Second, AcceptBacklog: 256,
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second, EnableKeepAlive: true,
MaxFrameSize: 4096, KeepAliveInterval: 9 * time.Second,
MaxReceiveBuffer: 4194304, ConnectionWriteTimeout: 3 * time.Second,
MaxStreamWindowSize: 512 * 1024,
LogOutput: os.Stderr,
}) })
if e != nil { if e != nil {
log.Printf("new mux client conn error,ERR:%s", e) s.log.Printf("new mux client conn error,ERR:%s", e)
err = e err = e
return return
} }
conn, e = c.OpenStream() conn, e = c.OpenStream()
if e != nil { if e != nil {
log.Printf("mux client conn open stream error,ERR:%s", e) s.log.Printf("mux client conn open stream error,ERR:%s", e)
err = e err = e
return return
} }
@ -306,7 +315,7 @@ func (s *TunnelServer) UDPConnDeamon() {
go func() { go func() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("udp conn deamon crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
var outConn net.Conn var outConn net.Conn
@ -333,7 +342,7 @@ func (s *TunnelServer) UDPConnDeamon() {
// cmdChn <- true // cmdChn <- true
outConn = nil outConn = nil
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err) s.log.Printf("connect to %s fail, err: %s, retrying...", *s.cfg.Parent, err)
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
continue continue
} else { } else {
@ -348,27 +357,27 @@ func (s *TunnelServer) UDPConnDeamon() {
} }
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn) srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
log.Printf("UDP deamon connection %s exited", ID) s.log.Printf("UDP deamon connection %s exited", ID)
break break
} }
if err != nil { if err != nil {
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body) s.log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
continue continue
} }
//log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn) //s.log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
_srcAddr := strings.Split(srcAddrFromConn, ":") _srcAddr := strings.Split(srcAddrFromConn, ":")
if len(_srcAddr) != 2 { if len(_srcAddr) != 2 {
log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn) s.log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
continue continue
} }
port, _ := strconv.Atoi(_srcAddr[1]) port, _ := strconv.Atoi(_srcAddr[1])
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port} dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr) _, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
if err != nil { if err != nil {
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err) s.log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
continue continue
} }
//log.Printf("udp response to local %s success , %v", srcAddrFromConn, body) //s.log.Printf("udp response to local %s success , %v", srcAddrFromConn, body)
} }
}(outConn, ID) }(outConn, ID)
break break
@ -381,10 +390,10 @@ func (s *TunnelServer) UDPConnDeamon() {
if err != nil { if err != nil {
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
outConn = nil outConn = nil
log.Printf("write udp packet to %s fail ,flush err:%s ,retrying...", *s.cfg.Parent, err) s.log.Printf("write udp packet to %s fail ,flush err:%s ,retrying...", *s.cfg.Parent, err)
goto RETRY goto RETRY
} }
//log.Printf("write packet %v", *item.packet) //s.log.Printf("write packet %v", *item.packet)
} }
}() }()
} }

View File

@ -3,16 +3,17 @@ package services
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"hash/crc32" "hash/crc32"
"io" "io"
"log" logger "log"
"net" "net"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
) )
type UDP struct { type UDP struct {
@ -21,6 +22,7 @@ type UDP struct {
cfg UDPArgs cfg UDPArgs
sc *utils.ServerChannel sc *utils.ServerChannel
isStop bool isStop bool
log *logger.Logger
} }
func NewUDP() Service { func NewUDP() Service {
@ -57,9 +59,9 @@ func (s *UDP) StopService() {
defer func() { defer func() {
e := recover() e := recover()
if e != nil { if e != nil {
log.Printf("stop udp service crashed,%s", e) s.log.Printf("stop udp service crashed,%s", e)
} else { } else {
log.Printf("service udp stoped") s.log.Printf("service udp stoped")
} }
}() }()
s.isStop = true s.isStop = true
@ -70,24 +72,25 @@ func (s *UDP) StopService() {
(*s.sc.UDPListener).Close() (*s.sc.UDPListener).Close()
} }
} }
func (s *UDP) Start(args interface{}) (err error) { func (s *UDP) Start(args interface{}, log *logger.Logger) (err error) {
s.log = log
s.cfg = args.(UDPArgs) s.cfg = args.(UDPArgs)
if err = s.CheckArgs(); err != nil { if err = s.CheckArgs(); err != nil {
return return
} }
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent) s.log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
if err = s.InitService(); err != nil { if err = s.InitService(); err != nil {
return return
} }
host, port, _ := net.SplitHostPort(*s.cfg.Local) host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p) sc := utils.NewServerChannel(host, p, s.log)
s.sc = &sc s.sc = &sc
err = sc.ListenUDP(s.callback) err = sc.ListenUDP(s.callback)
if err != nil { if err != nil {
return return
} }
log.Printf("udp proxy on %s", (*sc.UDPListener).LocalAddr()) s.log.Printf("udp proxy on %s", (*sc.UDPListener).LocalAddr())
return return
} }
@ -97,7 +100,7 @@ func (s *UDP) Clean() {
func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) { func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
var err error var err error
@ -112,7 +115,7 @@ func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType) err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
} }
if err != nil { if err != nil {
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err) s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
} }
} }
func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) { func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
@ -140,17 +143,17 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
connKey := uint64((numLocal/10)*10 + numSrc%mod) connKey := uint64((numLocal/10)*10 + numSrc%mod)
conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey)) conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey))
if err != nil { if err != nil {
log.Printf("upd get conn to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err) s.log.Printf("upd get conn to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
return return
} }
if isNew { if isNew {
go func() { go func() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Printf("udp conn handler out to tcp crashed with err : %s \nstack: %s", err, string(debug.Stack())) s.log.Printf("udp conn handler out to tcp crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
log.Printf("conn %d created , local: %s", connKey, srcAddr.String()) s.log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
for { for {
if s.isStop { if s.isStop {
conn.Close() conn.Close()
@ -158,76 +161,76 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
} }
srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn)) srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn))
if err == io.EOF || err == io.ErrUnexpectedEOF { if err == io.EOF || err == io.ErrUnexpectedEOF {
//log.Printf("connection %d released", connKey) //s.log.Printf("connection %d released", connKey)
s.p.Remove(fmt.Sprintf("%d", connKey)) s.p.Remove(fmt.Sprintf("%d", connKey))
break break
} }
if err != nil { if err != nil {
log.Printf("parse revecived udp packet fail, err: %s", err) s.log.Printf("parse revecived udp packet fail, err: %s", err)
continue continue
} }
//log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn) //s.log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
_srcAddr := strings.Split(srcAddrFromConn, ":") _srcAddr := strings.Split(srcAddrFromConn, ":")
if len(_srcAddr) != 2 { if len(_srcAddr) != 2 {
log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn) s.log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
continue continue
} }
port, _ := strconv.Atoi(_srcAddr[1]) port, _ := strconv.Atoi(_srcAddr[1])
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port} dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr) _, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
if err != nil { if err != nil {
log.Printf("udp response to local %s fail,ERR:%s", srcAddr, err) s.log.Printf("udp response to local %s fail,ERR:%s", srcAddr, err)
continue continue
} }
//log.Printf("udp response to local %s success", srcAddr) //s.log.Printf("udp response to local %s success", srcAddr)
} }
}() }()
} }
//log.Printf("select conn %d , local: %s", connKey, srcAddr.String()) //s.log.Printf("select conn %d , local: %s", connKey, srcAddr.String())
writer := bufio.NewWriter(conn) writer := bufio.NewWriter(conn)
//fmt.Println(conn, writer) //fmt.Println(conn, writer)
writer.Write(utils.UDPPacket(srcAddr.String(), packet)) writer.Write(utils.UDPPacket(srcAddr.String(), packet))
err = writer.Flush() err = writer.Flush()
if err != nil { if err != nil {
log.Printf("write udp packet to %s fail ,flush err:%s", *s.cfg.Parent, err) s.log.Printf("write udp packet to %s fail ,flush err:%s", *s.cfg.Parent, err)
return return
} }
//log.Printf("write packet %v", packet) //s.log.Printf("write packet %v", packet)
return return
} }
func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) { func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
//log.Printf("udp packet revecived:%s,%v", srcAddr, packet) //s.log.Printf("udp packet revecived:%s,%v", srcAddr, packet)
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent) dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
if err != nil { if err != nil {
log.Printf("resolve udp addr %s fail fail,ERR:%s", dstAddr.String(), err) s.log.Printf("resolve udp addr %s fail fail,ERR:%s", dstAddr.String(), err)
return return
} }
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0} clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr) conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
if err != nil { if err != nil {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write(packet) _, err = conn.Write(packet)
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //s.log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 512) buf := make([]byte, 512)
len, _, err := conn.ReadFromUDP(buf) len, _, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
return return
} }
//log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody) //s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
_, err = s.sc.UDPListener.WriteToUDP(buf[0:len], srcAddr) _, err = s.sc.UDPListener.WriteToUDP(buf[0:len], srcAddr)
if err != nil { if err != nil {
log.Printf("send udp response to cluster fail ,ERR:%s", err) s.log.Printf("send udp response to cluster fail ,ERR:%s", err)
return return
} }
//log.Printf("send udp response to cluster success ,from:%s", dstAddr.String()) //s.log.Printf("send udp response to cluster success ,from:%s", dstAddr.String())
return return
} }
func (s *UDP) InitOutConnPool() { func (s *UDP) InitOutConnPool() {

View File

@ -10,27 +10,29 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"io" "io"
"io/ioutil" "io/ioutil"
"log" logger "log"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"github.com/snail007/goproxy/services/kcpcfg"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
"github.com/snail007/goproxy/utils/id"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/snail007/goproxy/utils/id"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
) )
func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{})) { func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interface{}), log *logger.Logger) {
go func() { go func() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
@ -68,11 +70,14 @@ func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interfac
} }
src.Close() src.Close()
dst.Close() dst.Close()
if fn != nil {
fn(err) fn(err)
}
}() }()
} }
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) { func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
buf := make([]byte, 32*1024) buf := LeakyBuffer.Get()
defer LeakyBuffer.Put(buf)
n := 0 n := 0
for { for {
n, err = src.Read(buf) n, err = src.Read(buf)
@ -171,33 +176,6 @@ func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.C
return NewCompStream(kcpconn), err return NewCompStream(kcpconn), err
} }
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()
caBytes := certBytes
if caCertBytes != nil {
caBytes = caCertBytes
}
ok := clientCertPool.AppendCertsFromPEM(caBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
config := &tls.Config{
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
}
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
if err == nil {
ln = &_ln
}
return
}
func PathExists(_path string) bool { func PathExists(_path string) bool {
_, err := os.Stat(_path) _, err := os.Stat(_path)
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
@ -245,7 +223,7 @@ func Keygen() (err error) {
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048") cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -254,7 +232,7 @@ func Keygen() (err error) {
cmd = exec.Command("sh", "-c", cmdStr) cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -273,7 +251,7 @@ func Keygen() (err error) {
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048") cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -283,7 +261,7 @@ func Keygen() (err error) {
cmd = exec.Command("sh", "-c", cmdStr) cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -293,7 +271,7 @@ func Keygen() (err error) {
cmd = exec.Command("sh", "-c", cmdStr) cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
@ -307,7 +285,7 @@ proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sig
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048") cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -316,7 +294,7 @@ proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sig
cmd = exec.Command("sh", "-c", cmdStr) cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput() out, err = cmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("err:%s", err) logger.Printf("err:%s", err)
return return
} }
fmt.Println(string(out)) fmt.Println(string(out))
@ -601,9 +579,23 @@ func HttpGet(URL string, timeout int, host ...string) (body []byte, code int, er
body, err = ioutil.ReadAll(resp.Body) body, err = ioutil.ReadAll(resp.Body)
return return
} }
func IsIternalIP(domainOrIP string) bool { func IsIternalIP(domainOrIP string, always bool) bool {
var outIPs []net.IP var outIPs []net.IP
outIPs, err := net.LookupIP(domainOrIP) var err error
var isDomain bool
if net.ParseIP(domainOrIP) == nil {
isDomain = true
}
if always && isDomain {
return false
}
if isDomain {
outIPs, err = net.LookupIP(domainOrIP)
} else {
outIPs = []net.IP{net.ParseIP(domainOrIP)}
}
if err != nil { if err != nil {
return false return false
} }
@ -624,6 +616,53 @@ func IsIternalIP(domainOrIP string) bool {
} }
return false return false
} }
func IsHTTP(head []byte) bool {
keys := []string{"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"}
for _, key := range keys {
if bytes.HasPrefix(head, []byte(key)) || bytes.HasPrefix(head, []byte(strings.ToLower(key))) {
return true
}
}
return false
}
func IsSocks5(head []byte) bool {
if len(head) < 3 {
return false
}
if head[0] == uint8(0x05) && 0 < int(head[1]) && int(head[1]) < 255 {
if len(head) == 2+int(head[1]) {
return true
}
}
return false
}
func RemoveProxyHeaders(head []byte) []byte {
newLines := [][]byte{}
var keys = map[string]bool{}
lines := bytes.Split(head, []byte("\r\n"))
IsBody := false
for _, line := range lines {
if len(line) == 0 || IsBody {
newLines = append(newLines, line)
IsBody = true
} else {
hline := bytes.SplitN(line, []byte(":"), 2)
if len(hline) != 2 {
continue
}
k := strings.ToUpper(string(hline[0]))
if _, ok := keys[k]; ok || strings.HasPrefix(k, "PROXY-") {
continue
}
keys[k] = true
newLines = append(newLines, line)
}
}
return bytes.Join(newLines, []byte("\r\n"))
}
func InsertProxyHeaders(head []byte, headers string) []byte {
return bytes.Replace(head, []byte("\r\n"), []byte("\r\n"+headers), 1)
}
// type sockaddr struct { // type sockaddr struct {
// family uint16 // family uint16

45
utils/leakybuf.go Normal file
View File

@ -0,0 +1,45 @@
// Provides leaky buffer, based on the example in Effective Go.
package utils
type LeakyBuf struct {
bufSize int // size of each buffer
freeList chan []byte
}
const LeakyBufSize = 2048 // data.len(2) + hmacsha1(10) + data(4096)
const maxNBuf = 2048
var LeakyBuffer = NewLeakyBuf(maxNBuf, LeakyBufSize)
// NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each
// with bufSize bytes.
func NewLeakyBuf(n, bufSize int) *LeakyBuf {
return &LeakyBuf{
bufSize: bufSize,
freeList: make(chan []byte, n),
}
}
// Get returns a buffer from the leaky buffer or create a new buffer.
func (lb *LeakyBuf) Get() (b []byte) {
select {
case b = <-lb.freeList:
default:
b = make([]byte, lb.bufSize)
}
return
}
// Put add the buffer into the free buffer pool for reuse. Panic if the buffer
// size is not the same with the leaky buffer's. This is intended to expose
// error usage of leaky buffer.
func (lb *LeakyBuf) Put(b []byte) {
if len(b) != lb.bufSize {
panic("invalid buffer size that's put into leaky buffer")
}
select {
case lb.freeList <- b:
default:
}
return
}

View File

@ -1,13 +1,17 @@
package utils package utils
import ( import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt" "fmt"
"github.com/snail007/goproxy/services/kcpcfg" logger "log"
"log"
"net" "net"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"github.com/snail007/goproxy/services/kcpcfg"
kcp "github.com/xtaci/kcp-go" kcp "github.com/xtaci/kcp-go"
) )
@ -17,23 +21,26 @@ type ServerChannel struct {
Listener *net.Listener Listener *net.Listener
UDPListener *net.UDPConn UDPListener *net.UDPConn
errAcceptHandler func(err error) errAcceptHandler func(err error)
log *logger.Logger
} }
func NewServerChannel(ip string, port int) ServerChannel { func NewServerChannel(ip string, port int, log *logger.Logger) ServerChannel {
return ServerChannel{ return ServerChannel{
ip: ip, ip: ip,
port: port, port: port,
log: log,
errAcceptHandler: func(err error) { errAcceptHandler: func(err error) {
log.Printf("accept error , ERR:%s", err) log.Printf("accept error , ERR:%s", err)
}, },
} }
} }
func NewServerChannelHost(host string) ServerChannel { func NewServerChannelHost(host string, log *logger.Logger) ServerChannel {
h, port, _ := net.SplitHostPort(host) h, port, _ := net.SplitHostPort(host)
p, _ := strconv.Atoi(port) p, _ := strconv.Atoi(port)
return ServerChannel{ return ServerChannel{
ip: h, ip: h,
port: p, port: p,
log: log,
errAcceptHandler: func(err error) { errAcceptHandler: func(err error) {
log.Printf("accept error , ERR:%s", err) log.Printf("accept error , ERR:%s", err)
}, },
@ -43,12 +50,12 @@ func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
sc.errAcceptHandler = fn sc.errAcceptHandler = fn
} }
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) { 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) sc.Listener, err = sc.listenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
if err == nil { if err == nil {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("ListenTls crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("ListenTls crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
for { for {
@ -58,7 +65,7 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn f
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("tls connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("tls connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
fn(conn) fn(conn)
@ -73,7 +80,33 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn f
} }
return return
} }
func (sc *ServerChannel) 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()
caBytes := certBytes
if caCertBytes != nil {
caBytes = caCertBytes
}
ok := clientCertPool.AppendCertsFromPEM(caBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
config := &tls.Config{
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
}
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
if err == nil {
ln = &_ln
}
return
}
func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) { func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
var l net.Listener var l net.Listener
l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port)) l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
@ -82,7 +115,7 @@ func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("ListenTCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("ListenTCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
for { for {
@ -92,7 +125,7 @@ func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("tcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("tcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
fn(conn) fn(conn)
@ -114,7 +147,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("ListenUDP crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("ListenUDP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
for { for {
@ -125,7 +158,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
fn(packet, addr, srcAddr) fn(packet, addr, srcAddr)
@ -139,7 +172,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
} }
return return
} }
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn)) (err error) { func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard) lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
if err == nil { if err == nil {
if err = lis.SetDSCP(*config.DSCP); err != nil { if err = lis.SetDSCP(*config.DSCP); err != nil {
@ -159,7 +192,7 @@ func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("ListenKCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("ListenKCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
for { for {
@ -169,7 +202,7 @@ func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack())) sc.log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
} }
}() }()
conn.SetStreamMode(true) conn.SetStreamMode(true)

View File

@ -1,22 +1,24 @@
package utils package utils
import ( import (
"bufio"
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils/sni"
"io" "io"
"io/ioutil" "io/ioutil"
"log" logger "log"
"net" "net"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils/sni"
"github.com/golang/snappy" "github.com/golang/snappy"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -28,6 +30,7 @@ type Checker struct {
interval int64 interval int64
timeout int timeout int
isStop bool isStop bool
log *logger.Logger
} }
type CheckerItem struct { type CheckerItem struct {
IsHTTPS bool IsHTTPS bool
@ -43,12 +46,13 @@ type CheckerItem struct {
//NewChecker args: //NewChecker args:
//timeout : tcp timeout milliseconds ,connect to host //timeout : tcp timeout milliseconds ,connect to host
//interval: recheck domain interval seconds //interval: recheck domain interval seconds
func NewChecker(timeout int, interval int64, blockedFile, directFile string) Checker { func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger) Checker {
ch := Checker{ ch := Checker{
data: NewConcurrentMap(), data: NewConcurrentMap(),
interval: interval, interval: interval,
timeout: timeout, timeout: timeout,
isStop: false, isStop: false,
log: log,
} }
ch.blockedMap = ch.loadMap(blockedFile) ch.blockedMap = ch.loadMap(blockedFile)
ch.directMap = ch.loadMap(directFile) ch.directMap = ch.loadMap(directFile)
@ -70,7 +74,7 @@ func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
if PathExists(f) { if PathExists(f) {
_contents, err := ioutil.ReadFile(f) _contents, err := ioutil.ReadFile(f)
if err != nil { if err != nil {
log.Printf("load file err:%s", err) c.log.Printf("load file err:%s", err)
return return
} }
for _, line := range strings.Split(string(_contents), "\n") { for _, line := range strings.Split(string(_contents), "\n") {
@ -149,7 +153,7 @@ func (c *Checker) IsBlocked(address string) (blocked bool, failN, successN uint)
func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
u, err := url.Parse("http://" + address) u, err := url.Parse("http://" + address)
if err != nil { if err != nil {
log.Printf("blocked check , url parse err:%s", err) c.log.Printf("blocked check , url parse err:%s", err)
return true return true
} }
domainSlice := strings.Split(u.Hostname(), ".") domainSlice := strings.Split(u.Hostname(), ".")
@ -187,12 +191,14 @@ type BasicAuth struct {
authTimeout int authTimeout int
authRetry int authRetry int
dns *DomainResolver dns *DomainResolver
log *logger.Logger
} }
func NewBasicAuth(dns *DomainResolver) BasicAuth { func NewBasicAuth(dns *DomainResolver, log *logger.Logger) BasicAuth {
return BasicAuth{ return BasicAuth{
data: NewConcurrentMap(), data: NewConcurrentMap(),
dns: dns, dns: dns,
log: log,
} }
} }
func (ba *BasicAuth) SetAuthURL(URL string, code, timeout, retry int) { func (ba *BasicAuth) SetAuthURL(URL string, code, timeout, retry int) {
@ -245,7 +251,7 @@ func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
if err == nil { if err == nil {
return true return true
} }
log.Printf("%s", err) ba.log.Printf("%s", err)
} }
return false return false
} }
@ -294,7 +300,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b) 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 { if err != nil && tryCount < ba.authRetry {
log.Print(err) ba.log.Print(err)
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
} }
tryCount++ tryCount++
@ -320,13 +326,15 @@ type HTTPRequest struct {
hostOrURL string hostOrURL string
isBasicAuth bool isBasicAuth bool
basicAuth *BasicAuth basicAuth *BasicAuth
log *logger.Logger
} }
func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, header ...[]byte) (req HTTPRequest, err error) { func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth, log *logger.Logger, header ...[]byte) (req HTTPRequest, err error) {
buf := make([]byte, bufSize) buf := make([]byte, bufSize)
n := 0 n := 0
req = HTTPRequest{ req = HTTPRequest{
conn: inConn, conn: inConn,
log: log,
} }
if header != nil && len(header) == 1 && len(header[0]) > 1 { if header != nil && len(header) == 1 && len(header[0]) > 1 {
buf = header[0] buf = header[0]
@ -419,7 +427,7 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
authorization = strings.Trim(authorization, " \r\n\t") authorization = strings.Trim(authorization, " \r\n\t")
if authorization == "" { if authorization == "" {
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "407") fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"\"\r\n\r\nProxy Authentication Required", "407")
CloseConn(req.conn) CloseConn(req.conn)
err = errors.New("require auth header data") err = errors.New("require auth header data")
return return
@ -455,7 +463,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
authOk := (*req.basicAuth).Check(string(user), addr[0], URL) authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
//log.Printf("auth %s,%v", string(user), authOk) //log.Printf("auth %s,%v", string(user), authOk)
if !authOk { if !authOk {
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407") fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407")
CloseConn(req.conn) CloseConn(req.conn)
err = fmt.Errorf("basic auth fail") err = fmt.Errorf("basic auth fail")
return return
@ -478,10 +486,10 @@ func (req *HTTPRequest) getHeader(key string) (val string) {
lines := strings.Split(string(req.HeadBuf), "\r\n") lines := strings.Split(string(req.HeadBuf), "\r\n")
//log.Println(lines) //log.Println(lines)
for _, line := range lines { for _, line := range lines {
line := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2) hline := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2)
if len(line) == 2 { if len(hline) == 2 {
k := strings.ToUpper(strings.Trim(line[0], " ")) k := strings.ToUpper(strings.Trim(hline[0], " "))
v := strings.Trim(line[1], " ") v := strings.Trim(hline[1], " ")
if key == k { if key == k {
val = v val = v
return return
@ -546,12 +554,14 @@ func (op *OutConn) Get() (conn net.Conn, err error) {
type ConnManager struct { type ConnManager struct {
pool ConcurrentMap pool ConcurrentMap
l *sync.Mutex l *sync.Mutex
log *logger.Logger
} }
func NewConnManager() ConnManager { func NewConnManager(log *logger.Logger) ConnManager {
cm := ConnManager{ cm := ConnManager{
pool: NewConcurrentMap(), pool: NewConcurrentMap(),
l: &sync.Mutex{}, l: &sync.Mutex{},
log: log,
} }
return cm return cm
} }
@ -568,7 +578,7 @@ func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
(*v.(*net.Conn)).Close() (*v.(*net.Conn)).Close()
} }
conns.Set(ID, conn) conns.Set(ID, conn)
log.Printf("%s conn added", key) cm.log.Printf("%s conn added", key)
return conns return conns
}) })
} }
@ -579,7 +589,7 @@ func (cm *ConnManager) Remove(key string) {
conns.IterCb(func(key string, v interface{}) { conns.IterCb(func(key string, v interface{}) {
CloseConn(v.(*net.Conn)) CloseConn(v.(*net.Conn))
}) })
log.Printf("%s conns closed", key) cm.log.Printf("%s conns closed", key)
} }
cm.pool.Remove(key) cm.pool.Remove(key)
} }
@ -594,7 +604,7 @@ func (cm *ConnManager) RemoveOne(key string, ID string) {
(*v.(*net.Conn)).Close() (*v.(*net.Conn)).Close()
conns.Remove(ID) conns.Remove(ID)
cm.pool.Set(key, conns) cm.pool.Set(key, conns)
log.Printf("%s %s conn closed", key, ID) cm.log.Printf("%s %s conn closed", key, ID)
} }
} }
} }
@ -650,6 +660,7 @@ type DomainResolver struct {
ttl int ttl int
dnsAddrress string dnsAddrress string
data ConcurrentMap data ConcurrentMap
log *logger.Logger
} }
type DomainResolverItem struct { type DomainResolverItem struct {
ip string ip string
@ -657,12 +668,12 @@ type DomainResolverItem struct {
expiredAt int64 expiredAt int64
} }
func NewDomainResolver(dnsAddrress string, ttl int) DomainResolver { func NewDomainResolver(dnsAddrress string, ttl int, log *logger.Logger) DomainResolver {
return DomainResolver{ return DomainResolver{
ttl: ttl, ttl: ttl,
dnsAddrress: dnsAddrress, dnsAddrress: dnsAddrress,
data: NewConcurrentMap(), data: NewConcurrentMap(),
log: log,
} }
} }
func (a *DomainResolver) MustResolve(address string) (ip string) { func (a *DomainResolver) MustResolve(address string) (ip string) {
@ -677,7 +688,7 @@ func (a *DomainResolver) Resolve(address string) (ip string, err error) {
if port != "" { if port != "" {
ip = net.JoinHostPort(ip, port) ip = net.JoinHostPort(ip, port)
} }
log.Printf("dns:%s->%s,cache:%s", address, ip, fromCache) a.log.Printf("dns:%s->%s,cache:%s", address, ip, fromCache)
//a.PrintData() //a.PrintData()
}() }()
if strings.Contains(domain, ":") { if strings.Contains(domain, ":") {
@ -739,7 +750,7 @@ func (a *DomainResolver) Resolve(address string) (ip string, err error) {
func (a *DomainResolver) PrintData() { func (a *DomainResolver) PrintData() {
for k, item := range a.data.Items() { for k, item := range a.data.Items() {
d := item.(*DomainResolverItem) d := item.(*DomainResolverItem)
fmt.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt) a.log.Printf("%s:ip[%s],domain[%s],expired at[%d]\n", k, (*d).ip, (*d).domain, (*d).expiredAt)
} }
} }
func NewCompStream(conn net.Conn) *CompStream { func NewCompStream(conn net.Conn) *CompStream {
@ -792,3 +803,33 @@ func (c *CompStream) SetReadDeadline(t time.Time) error {
func (c *CompStream) SetWriteDeadline(t time.Time) error { func (c *CompStream) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t) return c.conn.SetWriteDeadline(t)
} }
type BufferedConn struct {
r *bufio.Reader
net.Conn // So that most methods are embedded
}
func NewBufferedConn(c net.Conn) BufferedConn {
return BufferedConn{bufio.NewReader(c), c}
}
func NewBufferedConnSize(c net.Conn, n int) BufferedConn {
return BufferedConn{bufio.NewReaderSize(c, n), c}
}
func (b BufferedConn) Peek(n int) ([]byte, error) {
return b.r.Peek(n)
}
func (b BufferedConn) Read(p []byte) (int, error) {
return b.r.Read(p)
}
func (b BufferedConn) ReadByte() (byte, error) {
return b.r.ReadByte()
}
func (b BufferedConn) UnreadByte() error {
return b.r.UnreadByte()
}
func (b BufferedConn) Buffered() int {
return b.r.Buffered()
}

122
vendor/github.com/Yawning/chacha20/LICENSE generated vendored Normal file
View File

@ -0,0 +1,122 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

14
vendor/github.com/Yawning/chacha20/README.md generated vendored Normal file
View File

@ -0,0 +1,14 @@
### chacha20 - ChaCha20
#### Yawning Angel (yawning at schwanenlied dot me)
Yet another Go ChaCha20 implementation. Everything else I found was slow,
didn't support all the variants I need to use, or relied on cgo to go fast.
Features:
* 20 round, 256 bit key only. Everything else is pointless and stupid.
* IETF 96 bit nonce variant.
* XChaCha 24 byte nonce variant.
* SSE2 and AVX2 support on amd64 targets.
* Incremental encrypt/decrypt support, unlike golang.org/x/crypto/salsa20.

273
vendor/github.com/Yawning/chacha20/chacha20.go generated vendored Normal file
View File

@ -0,0 +1,273 @@
// chacha20.go - A ChaCha stream cipher implementation.
//
// To the extent possible under law, Yawning Angel has waived all copyright
// and related or neighboring rights to chacha20, using the Creative
// Commons "CC0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
package chacha20
import (
"crypto/cipher"
"encoding/binary"
"errors"
"math"
"runtime"
)
const (
// KeySize is the ChaCha20 key size in bytes.
KeySize = 32
// NonceSize is the ChaCha20 nonce size in bytes.
NonceSize = 8
// INonceSize is the IETF ChaCha20 nonce size in bytes.
INonceSize = 12
// XNonceSize is the XChaCha20 nonce size in bytes.
XNonceSize = 24
// HNonceSize is the HChaCha20 nonce size in bytes.
HNonceSize = 16
// BlockSize is the ChaCha20 block size in bytes.
BlockSize = 64
stateSize = 16
chachaRounds = 20
// The constant "expand 32-byte k" as little endian uint32s.
sigma0 = uint32(0x61707865)
sigma1 = uint32(0x3320646e)
sigma2 = uint32(0x79622d32)
sigma3 = uint32(0x6b206574)
)
var (
// ErrInvalidKey is the error returned when the key is invalid.
ErrInvalidKey = errors.New("key length must be KeySize bytes")
// ErrInvalidNonce is the error returned when the nonce is invalid.
ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes")
// ErrInvalidCounter is the error returned when the counter is invalid.
ErrInvalidCounter = errors.New("block counter is invalid (out of range)")
useUnsafe = false
usingVectors = false
blocksFn = blocksRef
)
// A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and
// nonce.
type Cipher struct {
state [stateSize]uint32
buf [BlockSize]byte
off int
ietf bool
}
// Reset zeros the key data so that it will no longer appear in the process's
// memory.
func (c *Cipher) Reset() {
for i := range c.state {
c.state[i] = 0
}
for i := range c.buf {
c.buf[i] = 0
}
}
// XORKeyStream sets dst to the result of XORing src with the key stream. Dst
// and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
if len(dst) < len(src) {
src = src[:len(dst)]
}
for remaining := len(src); remaining > 0; {
// Process multiple blocks at once.
if c.off == BlockSize {
nrBlocks := remaining / BlockSize
directBytes := nrBlocks * BlockSize
if nrBlocks > 0 {
blocksFn(&c.state, src, dst, nrBlocks, c.ietf)
remaining -= directBytes
if remaining == 0 {
return
}
dst = dst[directBytes:]
src = src[directBytes:]
}
// If there's a partial block, generate 1 block of keystream into
// the internal buffer.
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
c.off = 0
}
// Process partial blocks from the buffered keystream.
toXor := BlockSize - c.off
if remaining < toXor {
toXor = remaining
}
if toXor > 0 {
for i, v := range src[:toXor] {
dst[i] = v ^ c.buf[c.off+i]
}
dst = dst[toXor:]
src = src[toXor:]
remaining -= toXor
c.off += toXor
}
}
}
// KeyStream sets dst to the raw keystream.
func (c *Cipher) KeyStream(dst []byte) {
for remaining := len(dst); remaining > 0; {
// Process multiple blocks at once.
if c.off == BlockSize {
nrBlocks := remaining / BlockSize
directBytes := nrBlocks * BlockSize
if nrBlocks > 0 {
blocksFn(&c.state, nil, dst, nrBlocks, c.ietf)
remaining -= directBytes
if remaining == 0 {
return
}
dst = dst[directBytes:]
}
// If there's a partial block, generate 1 block of keystream into
// the internal buffer.
blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
c.off = 0
}
// Process partial blocks from the buffered keystream.
toCopy := BlockSize - c.off
if remaining < toCopy {
toCopy = remaining
}
if toCopy > 0 {
copy(dst[:toCopy], c.buf[c.off:c.off+toCopy])
dst = dst[toCopy:]
remaining -= toCopy
c.off += toCopy
}
}
}
// ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key
// and nonce.
func (c *Cipher) ReKey(key, nonce []byte) error {
if len(key) != KeySize {
return ErrInvalidKey
}
switch len(nonce) {
case NonceSize:
case INonceSize:
case XNonceSize:
var subkey [KeySize]byte
var subnonce [HNonceSize]byte
copy(subnonce[:], nonce[0:16])
HChaCha(key, &subnonce, &subkey)
key = subkey[:]
nonce = nonce[16:24]
defer func() {
for i := range subkey {
subkey[i] = 0
}
}()
default:
return ErrInvalidNonce
}
c.Reset()
c.state[0] = sigma0
c.state[1] = sigma1
c.state[2] = sigma2
c.state[3] = sigma3
c.state[4] = binary.LittleEndian.Uint32(key[0:4])
c.state[5] = binary.LittleEndian.Uint32(key[4:8])
c.state[6] = binary.LittleEndian.Uint32(key[8:12])
c.state[7] = binary.LittleEndian.Uint32(key[12:16])
c.state[8] = binary.LittleEndian.Uint32(key[16:20])
c.state[9] = binary.LittleEndian.Uint32(key[20:24])
c.state[10] = binary.LittleEndian.Uint32(key[24:28])
c.state[11] = binary.LittleEndian.Uint32(key[28:32])
c.state[12] = 0
if len(nonce) == INonceSize {
c.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
c.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
c.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
c.ietf = true
} else {
c.state[13] = 0
c.state[14] = binary.LittleEndian.Uint32(nonce[0:4])
c.state[15] = binary.LittleEndian.Uint32(nonce[4:8])
c.ietf = false
}
c.off = BlockSize
return nil
}
// Seek sets the block counter to a given offset.
func (c *Cipher) Seek(blockCounter uint64) error {
if c.ietf {
if blockCounter > math.MaxUint32 {
return ErrInvalidCounter
}
c.state[12] = uint32(blockCounter)
} else {
c.state[12] = uint32(blockCounter)
c.state[13] = uint32(blockCounter >> 32)
}
c.off = BlockSize
return nil
}
// NewCipher returns a new ChaCha20/XChaCha20 instance.
func NewCipher(key, nonce []byte) (*Cipher, error) {
c := new(Cipher)
if err := c.ReKey(key, nonce); err != nil {
return nil, err
}
return c, nil
}
// HChaCha is the HChaCha20 hash function used to make XChaCha.
func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) {
var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded.
x[0] = binary.LittleEndian.Uint32(key[0:4])
x[1] = binary.LittleEndian.Uint32(key[4:8])
x[2] = binary.LittleEndian.Uint32(key[8:12])
x[3] = binary.LittleEndian.Uint32(key[12:16])
x[4] = binary.LittleEndian.Uint32(key[16:20])
x[5] = binary.LittleEndian.Uint32(key[20:24])
x[6] = binary.LittleEndian.Uint32(key[24:28])
x[7] = binary.LittleEndian.Uint32(key[28:32])
x[8] = binary.LittleEndian.Uint32(nonce[0:4])
x[9] = binary.LittleEndian.Uint32(nonce[4:8])
x[10] = binary.LittleEndian.Uint32(nonce[8:12])
x[11] = binary.LittleEndian.Uint32(nonce[12:16])
hChaChaRef(&x, out)
}
func init() {
switch runtime.GOARCH {
case "386", "amd64":
// Abuse unsafe to skip calling binary.LittleEndian.PutUint32
// in the critical path. This is a big boost on systems that are
// little endian and not overly picky about alignment.
useUnsafe = true
}
}
var _ cipher.Stream = (*Cipher)(nil)

95
vendor/github.com/Yawning/chacha20/chacha20_amd64.go generated vendored Normal file
View File

@ -0,0 +1,95 @@
// chacha20_amd64.go - AMD64 optimized chacha20.
//
// To the extent possible under law, Yawning Angel has waived all copyright
// and related or neighboring rights to chacha20, using the Creative
// Commons "CC0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
// +build amd64,!gccgo,!appengine
package chacha20
import (
"math"
)
var usingAVX2 = false
func blocksAmd64SSE2(x *uint32, inp, outp *byte, nrBlocks uint)
func blocksAmd64AVX2(x *uint32, inp, outp *byte, nrBlocks uint)
func cpuidAmd64(cpuidParams *uint32)
func xgetbv0Amd64(xcrVec *uint32)
func blocksAmd64(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
// Probably unneeded, but stating this explicitly simplifies the assembly.
if nrBlocks == 0 {
return
}
if isIetf {
var totalBlocks uint64
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
if totalBlocks > math.MaxUint32 {
panic("chacha20: Exceeded keystream per nonce limit")
}
}
if in == nil {
for i := range out {
out[i] = 0
}
in = out
}
// Pointless to call the AVX2 code for just a single block, since half of
// the output gets discarded...
if usingAVX2 && nrBlocks > 1 {
blocksAmd64AVX2(&x[0], &in[0], &out[0], uint(nrBlocks))
} else {
blocksAmd64SSE2(&x[0], &in[0], &out[0], uint(nrBlocks))
}
}
func supportsAVX2() bool {
// https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
const (
osXsaveBit = 1 << 27
avx2Bit = 1 << 5
)
// Check to see if CPUID actually supports the leaf that indicates AVX2.
// CPUID.(EAX=0H, ECX=0H) >= 7
regs := [4]uint32{0x00}
cpuidAmd64(&regs[0])
if regs[0] < 7 {
return false
}
// Check to see if the OS knows how to save/restore XMM/YMM state.
// CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1
regs = [4]uint32{0x01}
cpuidAmd64(&regs[0])
if regs[2]&osXsaveBit == 0 {
return false
}
xcrRegs := [2]uint32{}
xgetbv0Amd64(&xcrRegs[0])
if xcrRegs[0]&6 != 6 {
return false
}
// Check for AVX2 support.
// CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
regs = [4]uint32{0x07}
cpuidAmd64(&regs[0])
return regs[1]&avx2Bit != 0
}
func init() {
blocksFn = blocksAmd64
usingVectors = true
usingAVX2 = supportsAVX2()
}

1295
vendor/github.com/Yawning/chacha20/chacha20_amd64.py generated vendored Normal file

File diff suppressed because it is too large Load Diff

1180
vendor/github.com/Yawning/chacha20/chacha20_amd64.s generated vendored Normal file

File diff suppressed because it is too large Load Diff

394
vendor/github.com/Yawning/chacha20/chacha20_ref.go generated vendored Normal file
View File

@ -0,0 +1,394 @@
// chacha20_ref.go - Reference ChaCha20.
//
// To the extent possible under law, Yawning Angel has waived all copyright
// and related or neighboring rights to chacha20, using the Creative
// Commons "CC0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
// +build !go1.9
package chacha20
import (
"encoding/binary"
"math"
"unsafe"
)
func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
if isIetf {
var totalBlocks uint64
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
if totalBlocks > math.MaxUint32 {
panic("chacha20: Exceeded keystream per nonce limit")
}
}
// This routine ignores x[0]...x[4] in favor the const values since it's
// ever so slightly faster.
for n := 0; n < nrBlocks; n++ {
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
for i := chachaRounds; i > 0; i -= 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ^= x0
x12 = (x12 << 16) | (x12 >> 16)
x8 += x12
x4 ^= x8
x4 = (x4 << 12) | (x4 >> 20)
x0 += x4
x12 ^= x0
x12 = (x12 << 8) | (x12 >> 24)
x8 += x12
x4 ^= x8
x4 = (x4 << 7) | (x4 >> 25)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ^= x1
x13 = (x13 << 16) | (x13 >> 16)
x9 += x13
x5 ^= x9
x5 = (x5 << 12) | (x5 >> 20)
x1 += x5
x13 ^= x1
x13 = (x13 << 8) | (x13 >> 24)
x9 += x13
x5 ^= x9
x5 = (x5 << 7) | (x5 >> 25)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ^= x2
x14 = (x14 << 16) | (x14 >> 16)
x10 += x14
x6 ^= x10
x6 = (x6 << 12) | (x6 >> 20)
x2 += x6
x14 ^= x2
x14 = (x14 << 8) | (x14 >> 24)
x10 += x14
x6 ^= x10
x6 = (x6 << 7) | (x6 >> 25)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ^= x3
x15 = (x15 << 16) | (x15 >> 16)
x11 += x15
x7 ^= x11
x7 = (x7 << 12) | (x7 >> 20)
x3 += x7
x15 ^= x3
x15 = (x15 << 8) | (x15 >> 24)
x11 += x15
x7 ^= x11
x7 = (x7 << 7) | (x7 >> 25)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ^= x0
x15 = (x15 << 16) | (x15 >> 16)
x10 += x15
x5 ^= x10
x5 = (x5 << 12) | (x5 >> 20)
x0 += x5
x15 ^= x0
x15 = (x15 << 8) | (x15 >> 24)
x10 += x15
x5 ^= x10
x5 = (x5 << 7) | (x5 >> 25)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ^= x1
x12 = (x12 << 16) | (x12 >> 16)
x11 += x12
x6 ^= x11
x6 = (x6 << 12) | (x6 >> 20)
x1 += x6
x12 ^= x1
x12 = (x12 << 8) | (x12 >> 24)
x11 += x12
x6 ^= x11
x6 = (x6 << 7) | (x6 >> 25)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ^= x2
x13 = (x13 << 16) | (x13 >> 16)
x8 += x13
x7 ^= x8
x7 = (x7 << 12) | (x7 >> 20)
x2 += x7
x13 ^= x2
x13 = (x13 << 8) | (x13 >> 24)
x8 += x13
x7 ^= x8
x7 = (x7 << 7) | (x7 >> 25)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ^= x3
x14 = (x14 << 16) | (x14 >> 16)
x9 += x14
x4 ^= x9
x4 = (x4 << 12) | (x4 >> 20)
x3 += x4
x14 ^= x3
x14 = (x14 << 8) | (x14 >> 24)
x9 += x14
x4 ^= x9
x4 = (x4 << 7) | (x4 >> 25)
}
// On amd64 at least, this is a rather big boost.
if useUnsafe {
if in != nil {
inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize]))
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
outArr[0] = inArr[0] ^ (x0 + sigma0)
outArr[1] = inArr[1] ^ (x1 + sigma1)
outArr[2] = inArr[2] ^ (x2 + sigma2)
outArr[3] = inArr[3] ^ (x3 + sigma3)
outArr[4] = inArr[4] ^ (x4 + x[4])
outArr[5] = inArr[5] ^ (x5 + x[5])
outArr[6] = inArr[6] ^ (x6 + x[6])
outArr[7] = inArr[7] ^ (x7 + x[7])
outArr[8] = inArr[8] ^ (x8 + x[8])
outArr[9] = inArr[9] ^ (x9 + x[9])
outArr[10] = inArr[10] ^ (x10 + x[10])
outArr[11] = inArr[11] ^ (x11 + x[11])
outArr[12] = inArr[12] ^ (x12 + x[12])
outArr[13] = inArr[13] ^ (x13 + x[13])
outArr[14] = inArr[14] ^ (x14 + x[14])
outArr[15] = inArr[15] ^ (x15 + x[15])
} else {
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
outArr[0] = x0 + sigma0
outArr[1] = x1 + sigma1
outArr[2] = x2 + sigma2
outArr[3] = x3 + sigma3
outArr[4] = x4 + x[4]
outArr[5] = x5 + x[5]
outArr[6] = x6 + x[6]
outArr[7] = x7 + x[7]
outArr[8] = x8 + x[8]
outArr[9] = x9 + x[9]
outArr[10] = x10 + x[10]
outArr[11] = x11 + x[11]
outArr[12] = x12 + x[12]
outArr[13] = x13 + x[13]
outArr[14] = x14 + x[14]
outArr[15] = x15 + x[15]
}
} else {
// Slow path, either the architecture cares about alignment, or is not little endian.
x0 += sigma0
x1 += sigma1
x2 += sigma2
x3 += sigma3
x4 += x[4]
x5 += x[5]
x6 += x[6]
x7 += x[7]
x8 += x[8]
x9 += x[9]
x10 += x[10]
x11 += x[11]
x12 += x[12]
x13 += x[13]
x14 += x[14]
x15 += x[15]
if in != nil {
binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0)
binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1)
binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2)
binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3)
binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4)
binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5)
binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6)
binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7)
binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8)
binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9)
binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10)
binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11)
binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12)
binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13)
binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14)
binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15)
in = in[BlockSize:]
} else {
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x4)
binary.LittleEndian.PutUint32(out[20:24], x5)
binary.LittleEndian.PutUint32(out[24:28], x6)
binary.LittleEndian.PutUint32(out[28:32], x7)
binary.LittleEndian.PutUint32(out[32:36], x8)
binary.LittleEndian.PutUint32(out[36:40], x9)
binary.LittleEndian.PutUint32(out[40:44], x10)
binary.LittleEndian.PutUint32(out[44:48], x11)
binary.LittleEndian.PutUint32(out[48:52], x12)
binary.LittleEndian.PutUint32(out[52:56], x13)
binary.LittleEndian.PutUint32(out[56:60], x14)
binary.LittleEndian.PutUint32(out[60:64], x15)
}
out = out[BlockSize:]
}
// Stoping at 2^70 bytes per nonce is the user's responsibility.
ctr := uint64(x[13])<<32 | uint64(x[12])
ctr++
x[12] = uint32(ctr)
x[13] = uint32(ctr >> 32)
}
}
func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
for i := chachaRounds; i > 0; i -= 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ^= x0
x12 = (x12 << 16) | (x12 >> 16)
x8 += x12
x4 ^= x8
x4 = (x4 << 12) | (x4 >> 20)
x0 += x4
x12 ^= x0
x12 = (x12 << 8) | (x12 >> 24)
x8 += x12
x4 ^= x8
x4 = (x4 << 7) | (x4 >> 25)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ^= x1
x13 = (x13 << 16) | (x13 >> 16)
x9 += x13
x5 ^= x9
x5 = (x5 << 12) | (x5 >> 20)
x1 += x5
x13 ^= x1
x13 = (x13 << 8) | (x13 >> 24)
x9 += x13
x5 ^= x9
x5 = (x5 << 7) | (x5 >> 25)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ^= x2
x14 = (x14 << 16) | (x14 >> 16)
x10 += x14
x6 ^= x10
x6 = (x6 << 12) | (x6 >> 20)
x2 += x6
x14 ^= x2
x14 = (x14 << 8) | (x14 >> 24)
x10 += x14
x6 ^= x10
x6 = (x6 << 7) | (x6 >> 25)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ^= x3
x15 = (x15 << 16) | (x15 >> 16)
x11 += x15
x7 ^= x11
x7 = (x7 << 12) | (x7 >> 20)
x3 += x7
x15 ^= x3
x15 = (x15 << 8) | (x15 >> 24)
x11 += x15
x7 ^= x11
x7 = (x7 << 7) | (x7 >> 25)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ^= x0
x15 = (x15 << 16) | (x15 >> 16)
x10 += x15
x5 ^= x10
x5 = (x5 << 12) | (x5 >> 20)
x0 += x5
x15 ^= x0
x15 = (x15 << 8) | (x15 >> 24)
x10 += x15
x5 ^= x10
x5 = (x5 << 7) | (x5 >> 25)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ^= x1
x12 = (x12 << 16) | (x12 >> 16)
x11 += x12
x6 ^= x11
x6 = (x6 << 12) | (x6 >> 20)
x1 += x6
x12 ^= x1
x12 = (x12 << 8) | (x12 >> 24)
x11 += x12
x6 ^= x11
x6 = (x6 << 7) | (x6 >> 25)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ^= x2
x13 = (x13 << 16) | (x13 >> 16)
x8 += x13
x7 ^= x8
x7 = (x7 << 12) | (x7 >> 20)
x2 += x7
x13 ^= x2
x13 = (x13 << 8) | (x13 >> 24)
x8 += x13
x7 ^= x8
x7 = (x7 << 7) | (x7 >> 25)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ^= x3
x14 = (x14 << 16) | (x14 >> 16)
x9 += x14
x4 ^= x9
x4 = (x4 << 12) | (x4 >> 20)
x3 += x4
x14 ^= x3
x14 = (x14 << 8) | (x14 >> 24)
x9 += x14
x4 ^= x9
x4 = (x4 << 7) | (x4 >> 25)
}
// HChaCha returns x0...x3 | x12...x15, which corresponds to the
// indexes of the ChaCha constant and the indexes of the IV.
if useUnsafe {
outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
outArr[0] = x0
outArr[1] = x1
outArr[2] = x2
outArr[3] = x3
outArr[4] = x12
outArr[5] = x13
outArr[6] = x14
outArr[7] = x15
} else {
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x12)
binary.LittleEndian.PutUint32(out[20:24], x13)
binary.LittleEndian.PutUint32(out[24:28], x14)
binary.LittleEndian.PutUint32(out[28:32], x15)
}
return
}

395
vendor/github.com/Yawning/chacha20/chacha20_ref_go19.go generated vendored Normal file
View File

@ -0,0 +1,395 @@
// chacha20_ref.go - Reference ChaCha20.
//
// To the extent possible under law, Yawning Angel has waived all copyright
// and related or neighboring rights to chacha20, using the Creative
// Commons "CC0" public domain dedication. See LICENSE or
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
// +build go1.9
package chacha20
import (
"encoding/binary"
"math"
"math/bits"
"unsafe"
)
func blocksRef(x *[stateSize]uint32, in []byte, out []byte, nrBlocks int, isIetf bool) {
if isIetf {
var totalBlocks uint64
totalBlocks = uint64(x[12]) + uint64(nrBlocks)
if totalBlocks > math.MaxUint32 {
panic("chacha20: Exceeded keystream per nonce limit")
}
}
// This routine ignores x[0]...x[4] in favor the const values since it's
// ever so slightly faster.
for n := 0; n < nrBlocks; n++ {
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
for i := chachaRounds; i > 0; i -= 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ^= x0
x12 = bits.RotateLeft32(x12, 16)
x8 += x12
x4 ^= x8
x4 = bits.RotateLeft32(x4, 12)
x0 += x4
x12 ^= x0
x12 = bits.RotateLeft32(x12, 8)
x8 += x12
x4 ^= x8
x4 = bits.RotateLeft32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ^= x1
x13 = bits.RotateLeft32(x13, 16)
x9 += x13
x5 ^= x9
x5 = bits.RotateLeft32(x5, 12)
x1 += x5
x13 ^= x1
x13 = bits.RotateLeft32(x13, 8)
x9 += x13
x5 ^= x9
x5 = bits.RotateLeft32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ^= x2
x14 = bits.RotateLeft32(x14, 16)
x10 += x14
x6 ^= x10
x6 = bits.RotateLeft32(x6, 12)
x2 += x6
x14 ^= x2
x14 = bits.RotateLeft32(x14, 8)
x10 += x14
x6 ^= x10
x6 = bits.RotateLeft32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ^= x3
x15 = bits.RotateLeft32(x15, 16)
x11 += x15
x7 ^= x11
x7 = bits.RotateLeft32(x7, 12)
x3 += x7
x15 ^= x3
x15 = bits.RotateLeft32(x15, 8)
x11 += x15
x7 ^= x11
x7 = bits.RotateLeft32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ^= x0
x15 = bits.RotateLeft32(x15, 16)
x10 += x15
x5 ^= x10
x5 = bits.RotateLeft32(x5, 12)
x0 += x5
x15 ^= x0
x15 = bits.RotateLeft32(x15, 8)
x10 += x15
x5 ^= x10
x5 = bits.RotateLeft32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ^= x1
x12 = bits.RotateLeft32(x12, 16)
x11 += x12
x6 ^= x11
x6 = bits.RotateLeft32(x6, 12)
x1 += x6
x12 ^= x1
x12 = bits.RotateLeft32(x12, 8)
x11 += x12
x6 ^= x11
x6 = bits.RotateLeft32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ^= x2
x13 = bits.RotateLeft32(x13, 16)
x8 += x13
x7 ^= x8
x7 = bits.RotateLeft32(x7, 12)
x2 += x7
x13 ^= x2
x13 = bits.RotateLeft32(x13, 8)
x8 += x13
x7 ^= x8
x7 = bits.RotateLeft32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ^= x3
x14 = bits.RotateLeft32(x14, 16)
x9 += x14
x4 ^= x9
x4 = bits.RotateLeft32(x4, 12)
x3 += x4
x14 ^= x3
x14 = bits.RotateLeft32(x14, 8)
x9 += x14
x4 ^= x9
x4 = bits.RotateLeft32(x4, 7)
}
// On amd64 at least, this is a rather big boost.
if useUnsafe {
if in != nil {
inArr := (*[16]uint32)(unsafe.Pointer(&in[n*BlockSize]))
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
outArr[0] = inArr[0] ^ (x0 + sigma0)
outArr[1] = inArr[1] ^ (x1 + sigma1)
outArr[2] = inArr[2] ^ (x2 + sigma2)
outArr[3] = inArr[3] ^ (x3 + sigma3)
outArr[4] = inArr[4] ^ (x4 + x[4])
outArr[5] = inArr[5] ^ (x5 + x[5])
outArr[6] = inArr[6] ^ (x6 + x[6])
outArr[7] = inArr[7] ^ (x7 + x[7])
outArr[8] = inArr[8] ^ (x8 + x[8])
outArr[9] = inArr[9] ^ (x9 + x[9])
outArr[10] = inArr[10] ^ (x10 + x[10])
outArr[11] = inArr[11] ^ (x11 + x[11])
outArr[12] = inArr[12] ^ (x12 + x[12])
outArr[13] = inArr[13] ^ (x13 + x[13])
outArr[14] = inArr[14] ^ (x14 + x[14])
outArr[15] = inArr[15] ^ (x15 + x[15])
} else {
outArr := (*[16]uint32)(unsafe.Pointer(&out[n*BlockSize]))
outArr[0] = x0 + sigma0
outArr[1] = x1 + sigma1
outArr[2] = x2 + sigma2
outArr[3] = x3 + sigma3
outArr[4] = x4 + x[4]
outArr[5] = x5 + x[5]
outArr[6] = x6 + x[6]
outArr[7] = x7 + x[7]
outArr[8] = x8 + x[8]
outArr[9] = x9 + x[9]
outArr[10] = x10 + x[10]
outArr[11] = x11 + x[11]
outArr[12] = x12 + x[12]
outArr[13] = x13 + x[13]
outArr[14] = x14 + x[14]
outArr[15] = x15 + x[15]
}
} else {
// Slow path, either the architecture cares about alignment, or is not little endian.
x0 += sigma0
x1 += sigma1
x2 += sigma2
x3 += sigma3
x4 += x[4]
x5 += x[5]
x6 += x[6]
x7 += x[7]
x8 += x[8]
x9 += x[9]
x10 += x[10]
x11 += x[11]
x12 += x[12]
x13 += x[13]
x14 += x[14]
x15 += x[15]
if in != nil {
binary.LittleEndian.PutUint32(out[0:4], binary.LittleEndian.Uint32(in[0:4])^x0)
binary.LittleEndian.PutUint32(out[4:8], binary.LittleEndian.Uint32(in[4:8])^x1)
binary.LittleEndian.PutUint32(out[8:12], binary.LittleEndian.Uint32(in[8:12])^x2)
binary.LittleEndian.PutUint32(out[12:16], binary.LittleEndian.Uint32(in[12:16])^x3)
binary.LittleEndian.PutUint32(out[16:20], binary.LittleEndian.Uint32(in[16:20])^x4)
binary.LittleEndian.PutUint32(out[20:24], binary.LittleEndian.Uint32(in[20:24])^x5)
binary.LittleEndian.PutUint32(out[24:28], binary.LittleEndian.Uint32(in[24:28])^x6)
binary.LittleEndian.PutUint32(out[28:32], binary.LittleEndian.Uint32(in[28:32])^x7)
binary.LittleEndian.PutUint32(out[32:36], binary.LittleEndian.Uint32(in[32:36])^x8)
binary.LittleEndian.PutUint32(out[36:40], binary.LittleEndian.Uint32(in[36:40])^x9)
binary.LittleEndian.PutUint32(out[40:44], binary.LittleEndian.Uint32(in[40:44])^x10)
binary.LittleEndian.PutUint32(out[44:48], binary.LittleEndian.Uint32(in[44:48])^x11)
binary.LittleEndian.PutUint32(out[48:52], binary.LittleEndian.Uint32(in[48:52])^x12)
binary.LittleEndian.PutUint32(out[52:56], binary.LittleEndian.Uint32(in[52:56])^x13)
binary.LittleEndian.PutUint32(out[56:60], binary.LittleEndian.Uint32(in[56:60])^x14)
binary.LittleEndian.PutUint32(out[60:64], binary.LittleEndian.Uint32(in[60:64])^x15)
in = in[BlockSize:]
} else {
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x4)
binary.LittleEndian.PutUint32(out[20:24], x5)
binary.LittleEndian.PutUint32(out[24:28], x6)
binary.LittleEndian.PutUint32(out[28:32], x7)
binary.LittleEndian.PutUint32(out[32:36], x8)
binary.LittleEndian.PutUint32(out[36:40], x9)
binary.LittleEndian.PutUint32(out[40:44], x10)
binary.LittleEndian.PutUint32(out[44:48], x11)
binary.LittleEndian.PutUint32(out[48:52], x12)
binary.LittleEndian.PutUint32(out[52:56], x13)
binary.LittleEndian.PutUint32(out[56:60], x14)
binary.LittleEndian.PutUint32(out[60:64], x15)
}
out = out[BlockSize:]
}
// Stoping at 2^70 bytes per nonce is the user's responsibility.
ctr := uint64(x[13])<<32 | uint64(x[12])
ctr++
x[12] = uint32(ctr)
x[13] = uint32(ctr >> 32)
}
}
func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
for i := chachaRounds; i > 0; i -= 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ^= x0
x12 = bits.RotateLeft32(x12, 16)
x8 += x12
x4 ^= x8
x4 = bits.RotateLeft32(x4, 12)
x0 += x4
x12 ^= x0
x12 = bits.RotateLeft32(x12, 8)
x8 += x12
x4 ^= x8
x4 = bits.RotateLeft32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ^= x1
x13 = bits.RotateLeft32(x13, 16)
x9 += x13
x5 ^= x9
x5 = bits.RotateLeft32(x5, 12)
x1 += x5
x13 ^= x1
x13 = bits.RotateLeft32(x13, 8)
x9 += x13
x5 ^= x9
x5 = bits.RotateLeft32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ^= x2
x14 = bits.RotateLeft32(x14, 16)
x10 += x14
x6 ^= x10
x6 = bits.RotateLeft32(x6, 12)
x2 += x6
x14 ^= x2
x14 = bits.RotateLeft32(x14, 8)
x10 += x14
x6 ^= x10
x6 = bits.RotateLeft32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ^= x3
x15 = bits.RotateLeft32(x15, 16)
x11 += x15
x7 ^= x11
x7 = bits.RotateLeft32(x7, 12)
x3 += x7
x15 ^= x3
x15 = bits.RotateLeft32(x15, 8)
x11 += x15
x7 ^= x11
x7 = bits.RotateLeft32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ^= x0
x15 = bits.RotateLeft32(x15, 16)
x10 += x15
x5 ^= x10
x5 = bits.RotateLeft32(x5, 12)
x0 += x5
x15 ^= x0
x15 = bits.RotateLeft32(x15, 8)
x10 += x15
x5 ^= x10
x5 = bits.RotateLeft32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ^= x1
x12 = bits.RotateLeft32(x12, 16)
x11 += x12
x6 ^= x11
x6 = bits.RotateLeft32(x6, 12)
x1 += x6
x12 ^= x1
x12 = bits.RotateLeft32(x12, 8)
x11 += x12
x6 ^= x11
x6 = bits.RotateLeft32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ^= x2
x13 = bits.RotateLeft32(x13, 16)
x8 += x13
x7 ^= x8
x7 = bits.RotateLeft32(x7, 12)
x2 += x7
x13 ^= x2
x13 = bits.RotateLeft32(x13, 8)
x8 += x13
x7 ^= x8
x7 = bits.RotateLeft32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ^= x3
x14 = bits.RotateLeft32(x14, 16)
x9 += x14
x4 ^= x9
x4 = bits.RotateLeft32(x4, 12)
x3 += x4
x14 ^= x3
x14 = bits.RotateLeft32(x14, 8)
x9 += x14
x4 ^= x9
x4 = bits.RotateLeft32(x4, 7)
}
// HChaCha returns x0...x3 | x12...x15, which corresponds to the
// indexes of the ChaCha constant and the indexes of the IV.
if useUnsafe {
outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
outArr[0] = x0
outArr[1] = x1
outArr[2] = x2
outArr[3] = x3
outArr[4] = x12
outArr[5] = x13
outArr[6] = x14
outArr[7] = x15
} else {
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x12)
binary.LittleEndian.PutUint32(out[20:24], x13)
binary.LittleEndian.PutUint32(out[24:28], x14)
binary.LittleEndian.PutUint32(out[28:32], x15)
}
return
}