Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4214ec4239 | ||
|
|
504de47999 | ||
|
|
e185d734d0 | ||
|
|
9b1ef52649 | ||
|
|
5c9fc850d8 | ||
|
|
ff96e52a33 | ||
|
|
78004bcd39 | ||
|
|
b16decf976 | ||
|
|
828636553d | ||
|
|
bfcc27e70f | ||
|
|
7cb7d34d42 | ||
|
|
5276154401 | ||
|
|
dad091441e | ||
|
|
81ff3dadd5 | ||
|
|
f559fb1cae | ||
|
|
8649bbc191 | ||
|
|
d775339948 | ||
|
|
69a5b906e0 | ||
|
|
2d66cc6215 | ||
|
|
8d74baf48c | ||
|
|
d7641c4483 | ||
|
|
ffe54c3af7 | ||
|
|
53df3b5578 | ||
|
|
54c22f1410 | ||
|
|
366b7e04f3 | ||
|
|
a33a4d2bd3 | ||
|
|
eb00d570a8 | ||
|
|
500142f4c8 | ||
|
|
bffd5891cc | ||
|
|
cf2e6f9ff0 | ||
|
|
ed4b8d11e3 | ||
|
|
905c1eac63 | ||
|
|
61872133b1 | ||
|
|
e18f53a5bb | ||
|
|
947fb51963 | ||
|
|
7aeef3f8ba | ||
|
|
b42f6a6364 | ||
|
|
92f4d31dfc | ||
|
|
4f11593f26 | ||
|
|
795d63879f | ||
|
|
1c46eeaf43 | ||
|
|
6f47d12498 | ||
|
|
e6c56675ca | ||
|
|
ff92c96d8d | ||
|
|
fed2afb964 | ||
|
|
b3feff7843 | ||
|
|
edb2fb3458 | ||
|
|
dc51a0bd9d | ||
|
|
34b30ac8c9 | ||
|
|
8122af9096 | ||
|
|
2b267fe4bb | ||
|
|
90bf483976 | ||
|
|
b109f273a5 | ||
|
|
482977a4ac |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ goproxy
|
||||
*.exe
|
||||
*.exe~
|
||||
.*
|
||||
*.prof
|
||||
!.gitignore
|
||||
release-*
|
||||
proxy.crt
|
||||
|
||||
20
CHANGELOG
20
CHANGELOG
@ -1,4 +1,24 @@
|
||||
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
|
||||
1.增加了基于gomobile的sdk,对android/ios/windows/linux/mac提供SDK支持.
|
||||
2.优化了bridge的日志,增加了client和server的掉线日志.
|
||||
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal 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
140
Godeps/Godeps.json
generated
@ -1,11 +1,27 @@
|
||||
{
|
||||
"ImportPath": "github.com/snail007/goproxy",
|
||||
"GoVersion": "go1.9",
|
||||
"GoVersion": "go1.8",
|
||||
"GodepVersion": "v80",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"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",
|
||||
"Rev": "553a641470496b2327abcac10b36396bd98e45c9"
|
||||
@ -15,66 +31,15 @@
|
||||
"Comment": "v1.0.4-1-g40b5202",
|
||||
"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",
|
||||
"Comment": "v0.8.0-6-g602255c",
|
||||
"Rev": "602255cdb6deaf1523ea53ac30eae5554ba7bee9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/templexxx/cpufeat",
|
||||
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/templexxx/reedsolomon",
|
||||
"Comment": "0.1.1-4-g7092926",
|
||||
@ -90,6 +55,16 @@
|
||||
"Comment": "v1.0.1-3-g9d99fac",
|
||||
"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",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
@ -98,10 +73,34 @@
|
||||
"ImportPath": "golang.org/x/crypto/cast5",
|
||||
"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",
|
||||
"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",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
@ -115,28 +114,33 @@
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/templexxx/cpufeat",
|
||||
"Rev": "3794dfbfb04749f896b521032f69383f24c3687e"
|
||||
"ImportPath": "golang.org/x/net/bpf",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
"ImportPath": "golang.org/x/net/internal/iana",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "0fcca4842a8d74bfddc2c96a073bd2a4d2a7a2e8"
|
||||
"ImportPath": "golang.org/x/net/internal/socket",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/template",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
"ImportPath": "golang.org/x/net/ipv4",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/units",
|
||||
"Rev": "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
|
||||
"ImportPath": "golang.org/x/net/ipv6",
|
||||
"Rev": "5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/alecthomas/template/parse",
|
||||
"Rev": "a0175ee3bccc567396460bf5acd36800cb10c49c"
|
||||
"ImportPath": "golang.org/x/time/rate",
|
||||
"Rev": "6dc17368e09b0e8634d71cac8168d853e869a0c7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
||||
"Comment": "v2.2.5",
|
||||
"Rev": "1087e65c9441605df944fb12c33f0fe7072d18ca"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
50
README.md
50
README.md
@ -6,7 +6,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
|
||||
|
||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
||||
|
||||
[中文手册](/README_ZH.md)
|
||||
[中文手册](/README_ZH.md) **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
|
||||
|
||||
### 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.
|
||||
@ -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.5 manual](https://github.com/snail007/goproxy/tree/v4.5)
|
||||
- [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
|
||||
- [Quick installation](#quick-installation)
|
||||
- [Manual installation](#manual-installation)
|
||||
- [Docker installation](#docker-installation)
|
||||
|
||||
### First use must read
|
||||
- [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
|
||||
```shell
|
||||
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**
|
||||
```shell
|
||||
@ -169,6 +172,36 @@ wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
|
||||
chmod +x 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**
|
||||
|
||||
@ -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`
|
||||
|
||||
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.
|
||||
for example:
|
||||
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
@ -963,7 +996,14 @@ If you want to get a more detailed configuration and explanation of the KCP para
|
||||
```
|
||||
|
||||
### TODO
|
||||
- Welcome joining group feedback...
|
||||
- HTTP, socks proxy which has multi parents proxy load balancing?
|
||||
- HTTP (s) proxy support PAC?
|
||||
- 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?
|
||||
Recommend go1.8.5, which does not guarantee that version >=1.9 can be used.
|
||||
|
||||
67
README_ZH.md
67
README_ZH.md
@ -7,7 +7,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
|
||||
[](https://github.com/snail007/goproxy/) []() [](https://github.com/snail007/goproxy/releases) [](https://github.com/snail007/goproxy/releases)
|
||||
|
||||
[English Manual](/README.md)
|
||||
**[English Manual](/README.md)** **[全平台GUI版本](/gui/README.md)** **[全平台SDK](/sdk/README.md)**
|
||||
|
||||
### Features
|
||||
- 链式代理,程序本身可以作为一级代理,如果设置了上级代理那么可以作为二级代理,乃至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.5手册](https://github.com/snail007/goproxy/tree/v4.5)
|
||||
- [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. [Docker安装](#docker安装)
|
||||
|
||||
### 首次使用必看
|
||||
- [环境](#首次使用必看-1)
|
||||
@ -137,7 +140,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
||||
- [6.6 认证功能](#66-认证功能)
|
||||
- [6.7 自定义加密](#67-自定义加密)
|
||||
- [6.8 压缩传输](#68-压缩传输)
|
||||
- [6.9 查看帮助](#69-查看帮助)
|
||||
- [6.9 禁用协议](#69-禁用协议)
|
||||
- [6.10 查看帮助](#610-查看帮助)
|
||||
- [7. KCP配置](#7kcp配置)
|
||||
- [7.1 配置介绍](#71-配置介绍)
|
||||
- [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
|
||||
```shell
|
||||
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.下载自动安装脚本**
|
||||
```shell
|
||||
@ -167,7 +171,36 @@ wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
|
||||
chmod +x 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秒后
|
||||

|
||||
使用本地端口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" `
|
||||
我们还可以指定网站域名的黑白名单文件,一行一个域名,匹配规则是最右匹配,比如: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`
|
||||
|
||||
#### **1.3.HTTP二级代理(加密)**
|
||||
> 注意: 后面二级代理使用的`proxy.crt`和`proxy.key`应与一级代理一致
|
||||
|
||||

|
||||
一级HTTP代理(VPS,IP:22.22.22.22)
|
||||
`./proxy http -t tls -p ":38080" -C proxy.crt -K proxy.key`
|
||||
@ -303,7 +338,7 @@ KCP协议需要--kcp-key参数设置一个密码用于加密解密数据
|
||||
|
||||
二级HTTP代理(本地Linux)
|
||||
`./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)反向代理**
|
||||

|
||||
@ -720,7 +755,7 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
|
||||
`./proxy socks -t tcp -p ":33080" -F auth-file.txt`
|
||||
|
||||
另外,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"`
|
||||
@ -956,7 +991,16 @@ proxy的sps代理在tcp之上可以通过自定义加密和tls标准加密以及
|
||||
这样通过本地代理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`
|
||||
|
||||
### **7.KCP配置**
|
||||
@ -1002,6 +1046,11 @@ fast3:`--nodelay=1 --interval=10 --resend=2 --nc=1`
|
||||
- http(s)代理增加pac支持?
|
||||
- 欢迎加群反馈...
|
||||
|
||||
### 如何贡献代码(Pull Request)?
|
||||
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
|
||||
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
|
||||
pr的时候需要说明做了什么变更,原因是什么.
|
||||
|
||||
### 如何使用源码?
|
||||
建议go1.8.5,不保证>=1.9能用.
|
||||
`go get github.com/snail007/goproxy`
|
||||
|
||||
94
config.go
94
config.go
@ -4,13 +4,15 @@ import (
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
logger "log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime/pprof"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/services"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
@ -18,9 +20,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
app *kingpin.Application
|
||||
service *services.ServiceItem
|
||||
cmd *exec.Cmd
|
||||
app *kingpin.Application
|
||||
service *services.ServiceItem
|
||||
cmd *exec.Cmd
|
||||
cpuProfilingFile, memProfilingFile, blockProfilingFile, goroutineProfilingFile, threadcreateProfilingFile *os.File
|
||||
isDebug bool
|
||||
)
|
||||
|
||||
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.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
|
||||
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
|
||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||
spsArgs.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.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()
|
||||
@ -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.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.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
|
||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
|
||||
isDebug = *debug
|
||||
|
||||
//set kcp config
|
||||
|
||||
switch *kcpArgs.Mode {
|
||||
@ -297,11 +305,19 @@ func initConfig() (err error) {
|
||||
muxServerArgs.KCP = kcpArgs
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
|
||||
flags := log.Ldate
|
||||
log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime)
|
||||
|
||||
flags := logger.Ldate
|
||||
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 {
|
||||
flags |= log.Ltime
|
||||
flags |= logger.Ltime
|
||||
}
|
||||
log.SetFlags(flags)
|
||||
|
||||
@ -381,20 +397,41 @@ func initConfig() (err error) {
|
||||
}
|
||||
if *logfile == "" {
|
||||
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
|
||||
services.Regist("http", services.NewHTTP(), httpArgs)
|
||||
services.Regist("tcp", services.NewTCP(), tcpArgs)
|
||||
services.Regist("udp", services.NewUDP(), udpArgs)
|
||||
services.Regist("tserver", services.NewTunnelServerManager(), tunnelServerArgs)
|
||||
services.Regist("tclient", services.NewTunnelClient(), tunnelClientArgs)
|
||||
services.Regist("tbridge", services.NewTunnelBridge(), tunnelBridgeArgs)
|
||||
services.Regist("server", services.NewMuxServerManager(), muxServerArgs)
|
||||
services.Regist("client", services.NewMuxClient(), muxClientArgs)
|
||||
services.Regist("bridge", services.NewMuxBridge(), muxBridgeArgs)
|
||||
services.Regist("socks", services.NewSocks(), socksArgs)
|
||||
services.Regist("sps", services.NewSPS(), spsArgs)
|
||||
service, err = services.Run(serviceName)
|
||||
//regist services and run service
|
||||
switch serviceName {
|
||||
case "http":
|
||||
services.Regist(serviceName, services.NewHTTP(), httpArgs, log)
|
||||
case "tcp":
|
||||
services.Regist(serviceName, services.NewTCP(), tcpArgs, log)
|
||||
case "udp":
|
||||
services.Regist(serviceName, services.NewUDP(), udpArgs, log)
|
||||
case "tserver":
|
||||
services.Regist(serviceName, services.NewTunnelServerManager(), tunnelServerArgs, log)
|
||||
case "tclient":
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
|
||||
fi
|
||||
mkdir /tmp/proxy
|
||||
cd /tmp/proxy
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.7/proxy-linux-amd64.tar.gz
|
||||
wget https://github.com/snail007/goproxy/releases/download/v4.9/proxy-linux-amd64.tar.gz
|
||||
|
||||
# #install proxy
|
||||
tar zxvf proxy-linux-amd64.tar.gz
|
||||
|
||||
8
main.go
8
main.go
@ -1,14 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/snail007/goproxy/services"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/snail007/goproxy/services"
|
||||
)
|
||||
|
||||
const APP_VERSION = "4.7"
|
||||
const APP_VERSION = "4.9"
|
||||
|
||||
func main() {
|
||||
err := initConfig()
|
||||
@ -40,6 +41,9 @@ func Clean(s *services.Service) {
|
||||
log.Printf("clean process %d", cmd.Process.Pid)
|
||||
cmd.Process.Kill()
|
||||
}
|
||||
if isDebug {
|
||||
saveProfiling()
|
||||
}
|
||||
cleanupDone <- true
|
||||
}
|
||||
}()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="4.7"
|
||||
VER="4.9"
|
||||
RELEASE="release-${VER}"
|
||||
rm -rf .cert
|
||||
mkdir .cert
|
||||
|
||||
3
sdk/CHANGELOG
Normal file
3
sdk/CHANGELOG
Normal file
@ -0,0 +1,3 @@
|
||||
v4.8
|
||||
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
|
||||
2.增加了获取sdk版本的Version()方法.
|
||||
@ -9,7 +9,7 @@
|
||||
- MacOS,`.dylib`库
|
||||
|
||||
proxy使用gombile实现了一份go代码编译为android和ios平台下面可以直接调用的sdk类库,
|
||||
另外还为linux和windows提供sdk支持,基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。
|
||||
另外还为linux和windows,MacOS提供sdk支持,基于这些类库,APP开发者可以轻松的开发出各种形式的代理工具。
|
||||
|
||||
# 下面分平台介绍SDK的用法
|
||||
|
||||
|
||||
@ -1,10 +1,19 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
VER="v4.8"
|
||||
rm -rf sdk-android-*.tar.gz
|
||||
rm -rf 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"
|
||||
mv proxy.aar android/snail007.goproxy.sdk.aar
|
||||
mv proxy-sources.jar android/snail007.goproxy.sdk-sources.jar
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
VER="v4.8"
|
||||
rm -rf sdk-ios-*.tar.gz
|
||||
rm -rf ios
|
||||
mkdir ios
|
||||
|
||||
@ -3,17 +3,20 @@ package proxy
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/services"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"log"
|
||||
logger "log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/snail007/goproxy/services"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
const SDK_VERSION = "4.8"
|
||||
|
||||
var (
|
||||
app *kingpin.Application
|
||||
)
|
||||
@ -43,7 +46,7 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
|
||||
kcpArgs := kcpcfg.KCPConfigArgs{}
|
||||
//build srvice args
|
||||
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()
|
||||
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()
|
||||
@ -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.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.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
|
||||
_args := strings.Fields(strings.Trim(serviceArgsStr, " "))
|
||||
@ -298,11 +303,12 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
|
||||
muxServerArgs.KCP = kcpArgs
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
|
||||
flags := log.Ldate
|
||||
log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime)
|
||||
flags := logger.Ldate
|
||||
if *debug {
|
||||
flags |= log.Lshortfile | log.Lmicroseconds
|
||||
flags |= logger.Lshortfile | logger.Lmicroseconds
|
||||
} else {
|
||||
flags |= log.Ltime
|
||||
flags |= logger.Ltime
|
||||
}
|
||||
log.SetFlags(flags)
|
||||
|
||||
@ -317,29 +323,29 @@ func Start(serviceID, serviceArgsStr string) (errStr string) {
|
||||
//regist services and run service
|
||||
switch serviceName {
|
||||
case "http":
|
||||
services.Regist(serviceID, services.NewHTTP(), httpArgs)
|
||||
services.Regist(serviceID, services.NewHTTP(), httpArgs, log)
|
||||
case "tcp":
|
||||
services.Regist(serviceID, services.NewTCP(), tcpArgs)
|
||||
services.Regist(serviceID, services.NewTCP(), tcpArgs, log)
|
||||
case "udp":
|
||||
services.Regist(serviceID, services.NewUDP(), udpArgs)
|
||||
services.Regist(serviceID, services.NewUDP(), udpArgs, log)
|
||||
case "tserver":
|
||||
services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs)
|
||||
services.Regist(serviceID, services.NewTunnelServerManager(), tunnelServerArgs, log)
|
||||
case "tclient":
|
||||
services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs)
|
||||
services.Regist(serviceID, services.NewTunnelClient(), tunnelClientArgs, log)
|
||||
case "tbridge":
|
||||
services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs)
|
||||
services.Regist(serviceID, services.NewTunnelBridge(), tunnelBridgeArgs, log)
|
||||
case "server":
|
||||
services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs)
|
||||
services.Regist(serviceID, services.NewMuxServerManager(), muxServerArgs, log)
|
||||
case "client":
|
||||
services.Regist(serviceID, services.NewMuxClient(), muxClientArgs)
|
||||
services.Regist(serviceID, services.NewMuxClient(), muxClientArgs, log)
|
||||
case "bridge":
|
||||
services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs)
|
||||
services.Regist(serviceID, services.NewMuxBridge(), muxBridgeArgs, log)
|
||||
case "socks":
|
||||
services.Regist(serviceID, services.NewSocks(), socksArgs)
|
||||
services.Regist(serviceID, services.NewSocks(), socksArgs, log)
|
||||
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 {
|
||||
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) {
|
||||
services.Stop(serviceID)
|
||||
}
|
||||
|
||||
func Version() string {
|
||||
return SDK_VERSION
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
VER="v4.8"
|
||||
|
||||
rm -rf sdk-linux-*.tar.gz
|
||||
rm -rf README.md libproxy-sdk.so libproxy-sdk.h libproxy-sdk.a
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
VER="v4.8"
|
||||
|
||||
rm -rf *.tar.gz
|
||||
rm -rf README.md libproxy-sdk.dylib libproxy-sdk.h
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
VER="v4.7"
|
||||
VER="v4.8"
|
||||
|
||||
sudo rm /usr/local/go
|
||||
sudo ln -s /usr/local/go1.10.1 /usr/local/go
|
||||
|
||||
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"C"
|
||||
|
||||
sdk "github.com/snail007/goproxy/sdk/android-ios"
|
||||
)
|
||||
|
||||
@ -15,5 +16,10 @@ func Stop(serviceID *C.char) {
|
||||
sdk.Stop(C.GoString(serviceID))
|
||||
}
|
||||
|
||||
//export Version
|
||||
func Version() (ver *C.char) {
|
||||
return C.CString(sdk.Version())
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
@ -232,6 +232,8 @@ type SPSArgs struct {
|
||||
ParentKey *string
|
||||
LocalCompress *bool
|
||||
ParentCompress *bool
|
||||
DisableHTTP *bool
|
||||
DisableSocks5 *bool
|
||||
}
|
||||
|
||||
func (a *SPSArgs) Protocol() string {
|
||||
|
||||
@ -2,17 +2,18 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@ -27,6 +28,7 @@ type HTTP struct {
|
||||
isStop bool
|
||||
serverChannels []*utils.ServerChannel
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewHTTP() Service {
|
||||
@ -95,10 +97,10 @@ func (s *HTTP) CheckArgs() (err error) {
|
||||
func (s *HTTP) InitService() (err error) {
|
||||
s.InitBasicAuth()
|
||||
if *s.cfg.Parent != "" {
|
||||
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct)
|
||||
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log)
|
||||
}
|
||||
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" {
|
||||
err = s.ConnectSSH()
|
||||
@ -125,7 +127,7 @@ func (s *HTTP) InitService() (err error) {
|
||||
s.sshClient.Conn.Close()
|
||||
}
|
||||
}
|
||||
log.Printf("ssh offline, retrying...")
|
||||
s.log.Printf("ssh offline, retrying...")
|
||||
s.ConnectSSH()
|
||||
} else {
|
||||
conn.Close()
|
||||
@ -140,9 +142,9 @@ func (s *HTTP) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop http(s) service crashed,%s", e)
|
||||
s.log.Printf("stop http(s) service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service http(s) stoped")
|
||||
s.log.Printf("service http(s) stoped")
|
||||
}
|
||||
}()
|
||||
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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use %s parent %s", *s.cfg.ParentType, *s.cfg.Parent)
|
||||
s.InitOutConnPool()
|
||||
}
|
||||
|
||||
if err = s.InitService(); err != nil {
|
||||
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, ",") {
|
||||
if addr != "" {
|
||||
host, port, _ := net.SplitHostPort(addr)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
sc := utils.NewServerChannel(host, p, s.log)
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||
} 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -199,7 +205,7 @@ func (s *HTTP) Clean() {
|
||||
func (s *HTTP) callback(inConn net.Conn) {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -212,10 +218,10 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
}
|
||||
var err interface{}
|
||||
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 != 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)
|
||||
return
|
||||
@ -223,7 +229,7 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
address := req.Host
|
||||
host, _, _ := net.SplitHostPort(address)
|
||||
useProxy := false
|
||||
if !utils.IsIternalIP(host) {
|
||||
if !utils.IsIternalIP(host, *s.cfg.Always) {
|
||||
useProxy = true
|
||||
if *s.cfg.Parent == "" {
|
||||
useProxy = false
|
||||
@ -234,18 +240,18 @@ func (s *HTTP) callback(inConn net.Conn) {
|
||||
s.checker.Add(k)
|
||||
//var n, m uint
|
||||
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)
|
||||
if err != nil {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
@ -270,7 +276,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
outConn, err = s.getSSHConn(address)
|
||||
} else {
|
||||
// log.Printf("%v", s.outPool)
|
||||
// s.log.Printf("%v", s.outPool)
|
||||
outConn, err = s.outPool.Get()
|
||||
}
|
||||
} else {
|
||||
@ -280,12 +286,12 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
if err == nil || tryCount > maxTryCount {
|
||||
break
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -306,20 +312,25 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
} else {
|
||||
//https或者http,上级是代理,proxy需要转发
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Write(req.HeadBuf)
|
||||
//直连目标或上级非代理,清理HTTP头部的代理头信息
|
||||
if !useProxy || *s.cfg.ParentType == "ssh" {
|
||||
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
|
||||
} else {
|
||||
_, err = outConn.Write(req.HeadBuf)
|
||||
}
|
||||
outConn.SetDeadline(time.Time{})
|
||||
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)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
|
||||
}, s.log)
|
||||
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
@ -350,7 +361,7 @@ RETRY:
|
||||
err = fmt.Errorf("ssh dial %s timeout", host)
|
||||
}
|
||||
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()
|
||||
if e == nil {
|
||||
tryCount++
|
||||
@ -400,13 +411,13 @@ func (s *HTTP) InitOutConnPool() {
|
||||
}
|
||||
func (s *HTTP) InitBasicAuth() (err error) {
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
|
||||
} else {
|
||||
s.basicAuth = utils.NewBasicAuth(nil)
|
||||
s.basicAuth = utils.NewBasicAuth(nil, s.log)
|
||||
}
|
||||
if *s.cfg.AuthURL != "" {
|
||||
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
s.log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
}
|
||||
if *s.cfg.AuthFile != "" {
|
||||
var n = 0
|
||||
@ -415,11 +426,11 @@ func (s *HTTP) InitBasicAuth() (err error) {
|
||||
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
@ -471,7 +482,7 @@ func (s *HTTP) Resolve(address string) string {
|
||||
}
|
||||
ip, err := s.domainResolver.Resolve(address)
|
||||
if err != nil {
|
||||
log.Printf("dns error %s , ERR:%s", address, err)
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@ -3,9 +3,8 @@ package services
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
@ -13,7 +12,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type MuxBridge struct {
|
||||
@ -24,6 +26,7 @@ type MuxBridge struct {
|
||||
l *sync.Mutex
|
||||
isStop bool
|
||||
sc *utils.ServerChannel
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewMuxBridge() Service {
|
||||
@ -58,9 +61,9 @@ func (s *MuxBridge) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop bridge service crashed,%s", e)
|
||||
s.log.Printf("stop bridge service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service bridge stoped")
|
||||
s.log.Printf("service bridge stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -76,7 +79,8 @@ func (s *MuxBridge) StopService() {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -87,19 +91,19 @@ func (s *MuxBridge) Start(args interface{}) (err error) {
|
||||
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
sc := utils.NewServerChannel(host, p, s.log)
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.handler)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.handler, s.log)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
func (s *MuxBridge) Clean() {
|
||||
@ -115,7 +119,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
err = utils.ReadPacket(reader, &connType, &key)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
@ -126,10 +130,10 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
err = utils.ReadPacketData(reader, &serverID)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
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 {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
@ -137,7 +141,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
session, err := smux.Server(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("server session error,ERR:%s", err)
|
||||
s.log.Printf("server session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
@ -149,30 +153,30 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
session.Close()
|
||||
utils.CloseConn(&inConn)
|
||||
s.serverConns.Remove(inAddr)
|
||||
log.Printf("server connection %s %s released", serverID, key)
|
||||
s.log.Printf("server connection %s %s released", serverID, key)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
log.Printf("bridge callback crashed,err: %s", e)
|
||||
s.log.Printf("bridge callback crashed,err: %s", e)
|
||||
}
|
||||
}()
|
||||
s.callback(stream, serverID, key)
|
||||
}()
|
||||
}
|
||||
case CONN_CLIENT:
|
||||
log.Printf("client connection %s connected", key)
|
||||
s.log.Printf("client connection %s connected", key)
|
||||
session, err := smux.Client(inConn, nil)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client session error,ERR:%s", err)
|
||||
s.log.Printf("client session error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
keyInfo := strings.Split(key, "-")
|
||||
if len(keyInfo) != 2 {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("client key format error,key:%s", key)
|
||||
s.log.Printf("client key format error,key:%s", key)
|
||||
return
|
||||
}
|
||||
groupKey := keyInfo[0]
|
||||
@ -200,7 +204,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
defer s.l.Unlock()
|
||||
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
|
||||
group.Remove(index)
|
||||
log.Printf("client connection %s released", key)
|
||||
s.log.Printf("client connection %s released", key)
|
||||
}
|
||||
if group.IsEmpty() {
|
||||
s.clientControlConns.Remove(groupKey)
|
||||
@ -210,7 +214,7 @@ func (s *MuxBridge) handler(inConn net.Conn) {
|
||||
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)
|
||||
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)
|
||||
continue
|
||||
}
|
||||
@ -240,22 +244,22 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
if keysLen > 0 {
|
||||
i = rand.Intn(keysLen)
|
||||
} 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)
|
||||
continue
|
||||
}
|
||||
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.(*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()
|
||||
session.(*smux.Session).SetDeadline(time.Time{})
|
||||
//session.(*smux.Session).SetDeadline(time.Time{})
|
||||
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)
|
||||
continue
|
||||
} else {
|
||||
log.Printf("stream %s -> %s created", serverID, key)
|
||||
s.log.Printf("stream %s -> %s created", serverID, key)
|
||||
die1 := make(chan bool, 1)
|
||||
die2 := make(chan bool, 1)
|
||||
go func() {
|
||||
@ -272,7 +276,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
|
||||
}
|
||||
stream.Close()
|
||||
inConn.Close()
|
||||
log.Printf("%s server %s stream released", key, serverID)
|
||||
s.log.Printf("%s server %s stream released", key, serverID)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,20 +3,23 @@ package services
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/xtaci/smux"
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type MuxClient struct {
|
||||
cfg MuxClientArgs
|
||||
isStop bool
|
||||
sessions utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewMuxClient() Service {
|
||||
@ -33,7 +36,7 @@ func (s *MuxClient) InitService() (err error) {
|
||||
|
||||
func (s *MuxClient) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
s.log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
@ -54,9 +57,9 @@ func (s *MuxClient) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop client service crashed,%s", e)
|
||||
s.log.Printf("stop client service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service client stoped")
|
||||
s.log.Printf("service client stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -64,7 +67,8 @@ func (s *MuxClient) StopService() {
|
||||
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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -72,19 +76,19 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("client started")
|
||||
s.log.Printf("client started")
|
||||
count := 1
|
||||
if *s.cfg.SessionCount > 0 {
|
||||
count = *s.cfg.SessionCount
|
||||
}
|
||||
for i := 1; i <= count; i++ {
|
||||
key := fmt.Sprintf("worker[%d]", i)
|
||||
log.Printf("session %s started", key)
|
||||
s.log.Printf("session %s started", key)
|
||||
go func(i int) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("session worker crashed: %s", e)
|
||||
s.log.Printf("session worker crashed: %s", e)
|
||||
}
|
||||
}()
|
||||
for {
|
||||
@ -93,7 +97,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
}
|
||||
conn, err := s.getParentConn()
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
s.log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
@ -102,13 +106,13 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
s.log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
}
|
||||
session, err := smux.Server(conn, nil)
|
||||
if err != nil {
|
||||
log.Printf("session err: %s, retrying...", err)
|
||||
s.log.Printf("session err: %s, retrying...", err)
|
||||
conn.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
@ -123,7 +127,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
}
|
||||
stream, err := session.AcceptStream()
|
||||
if err != nil {
|
||||
log.Printf("accept stream err: %s, retrying...", err)
|
||||
s.log.Printf("accept stream err: %s, retrying...", err)
|
||||
session.Close()
|
||||
time.Sleep(time.Second * 3)
|
||||
break
|
||||
@ -132,7 +136,7 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stream handler crashed: %s", e)
|
||||
s.log.Printf("stream handler crashed: %s", e)
|
||||
}
|
||||
}()
|
||||
var ID, clientLocalAddr, serverID string
|
||||
@ -140,11 +144,11 @@ func (s *MuxClient) Start(args interface{}) (err error) {
|
||||
err = utils.ReadPacketData(stream, &ID, &clientLocalAddr, &serverID)
|
||||
stream.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read stream signal err: %s", err)
|
||||
s.log.Printf("read stream signal err: %s", err)
|
||||
stream.Close()
|
||||
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]
|
||||
localAddr := clientLocalAddr[4:]
|
||||
if protocol == "udp" {
|
||||
@ -186,16 +190,16 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
|
||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||
inConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp packet revecived fail, err: %s", err)
|
||||
log.Printf("connection %s released", ID)
|
||||
s.log.Printf("udp packet revecived fail, err: %s", err)
|
||||
s.log.Printf("connection %s released", ID)
|
||||
inConn.Close()
|
||||
break
|
||||
} else {
|
||||
//log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
||||
//s.log.Printf("udp packet revecived:%s,%v", srcAddr, body)
|
||||
go func() {
|
||||
defer func() {
|
||||
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)
|
||||
@ -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) {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
|
||||
if err != nil {
|
||||
log.Printf("can't resolve address: %s", err)
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
inConn.Close()
|
||||
return
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
conn.SetDeadline(time.Time{})
|
||||
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
|
||||
}
|
||||
//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)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*inConn).Write(bs)
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("send udp response fail ,ERR:%s", err)
|
||||
s.log.Printf("send udp response fail ,ERR:%s", err)
|
||||
inConn.Close()
|
||||
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) {
|
||||
var err error
|
||||
@ -262,7 +266,7 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
|
||||
break
|
||||
} else {
|
||||
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)
|
||||
continue
|
||||
}
|
||||
@ -271,11 +275,11 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
|
||||
if err != nil {
|
||||
inConn.Close()
|
||||
utils.CloseConn(&outConn)
|
||||
log.Printf("build connection error, err: %s", err)
|
||||
s.log.Printf("build connection error, err: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("stream %s created", ID)
|
||||
s.log.Printf("stream %s created", ID)
|
||||
if *s.cfg.IsCompress {
|
||||
die1 := 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()
|
||||
inConn.Close()
|
||||
log.Printf("%s stream %s released", *s.cfg.Key, ID)
|
||||
s.log.Printf("%s stream %s released", *s.cfg.Key, ID)
|
||||
} else {
|
||||
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||
log.Printf("stream %s released", ID)
|
||||
})
|
||||
s.log.Printf("stream %s released", ID)
|
||||
}, s.log)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,8 @@ package services
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
@ -13,8 +12,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/xtaci/smux"
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type MuxServer struct {
|
||||
@ -25,6 +27,7 @@ type MuxServer struct {
|
||||
lockChn chan bool
|
||||
isStop bool
|
||||
udpConn *net.Conn
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
type MuxServerManager struct {
|
||||
@ -32,6 +35,7 @@ type MuxServerManager struct {
|
||||
udpChn chan MuxUDPItem
|
||||
serverID string
|
||||
servers []*Service
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
@ -59,8 +64,8 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("server id: %s", s.serverID)
|
||||
//log.Printf("route:%v", *s.cfg.Route)
|
||||
s.log.Printf("server id: %s", s.serverID)
|
||||
//s.log.Printf("route:%v", *s.cfg.Route)
|
||||
for _, _info := range *s.cfg.Route {
|
||||
if _info == "" {
|
||||
continue
|
||||
@ -73,6 +78,7 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
info = strings.TrimPrefix(info, "tcp://")
|
||||
_routeInfo := strings.Split(info, "@")
|
||||
server := NewMuxServer()
|
||||
|
||||
local := _routeInfo[0]
|
||||
remote := _routeInfo[1]
|
||||
KEY := *s.cfg.Key
|
||||
@ -99,7 +105,7 @@ func (s *MuxServerManager) Start(args interface{}) (err error) {
|
||||
SessionCount: s.cfg.SessionCount,
|
||||
KCP: s.cfg.KCP,
|
||||
ParentType: s.cfg.ParentType,
|
||||
})
|
||||
}, log)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
@ -153,9 +159,9 @@ func (s *MuxServer) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop server service crashed,%s", e)
|
||||
s.log.Printf("stop server service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service server stoped")
|
||||
s.log.Printf("service server stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -184,7 +190,8 @@ func (s *MuxServer) CheckArgs() (err error) {
|
||||
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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -194,7 +201,7 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
s.sc = utils.NewServerChannel(host, p)
|
||||
s.sc = utils.NewServerChannel(host, p, s.log)
|
||||
if *s.cfg.IsUDP {
|
||||
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
s.udpChn <- MuxUDPItem{
|
||||
@ -206,12 +213,12 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
|
||||
s.log.Printf("server on %s", (*s.sc.UDPListener).LocalAddr())
|
||||
} else {
|
||||
err = s.sc.ListenTCP(func(inConn net.Conn) {
|
||||
defer func() {
|
||||
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
|
||||
@ -223,14 +230,14 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
outConn, ID, err = s.GetOutConn()
|
||||
if err != nil {
|
||||
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)
|
||||
continue
|
||||
} else {
|
||||
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 {
|
||||
die1 := make(chan bool, 1)
|
||||
die2 := make(chan bool, 1)
|
||||
@ -248,17 +255,17 @@ func (s *MuxServer) Start(args interface{}) (err error) {
|
||||
}
|
||||
outConn.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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
log.Printf("server on %s", (*s.sc.Listener).Addr())
|
||||
s.log.Printf("server on %s", (*s.sc.Listener).Addr())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -272,7 +279,7 @@ func (s *MuxServer) GetOutConn() (outConn net.Conn, ID string, err error) {
|
||||
}
|
||||
outConn, err = s.GetConn(fmt.Sprintf("%d", i))
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s", err)
|
||||
s.log.Printf("connection err: %s", err)
|
||||
return
|
||||
}
|
||||
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))
|
||||
outConn.SetDeadline(time.Time{})
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -325,7 +332,7 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
|
||||
_sess.(*smux.Session).Close()
|
||||
}
|
||||
s.sessions.Set(index, session)
|
||||
log.Printf("session[%s] created", index)
|
||||
s.log.Printf("session[%s] created", index)
|
||||
go func() {
|
||||
for {
|
||||
if s.isStop {
|
||||
@ -366,7 +373,7 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
go func() {
|
||||
defer func() {
|
||||
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
|
||||
@ -390,7 +397,7 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
if err != nil {
|
||||
outConn = nil
|
||||
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)
|
||||
continue
|
||||
} else {
|
||||
@ -407,14 +414,14 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||
log.Printf("UDP deamon connection %s exited", ID)
|
||||
s.log.Printf("parse revecived udp packet fail, err: %s ,%v", err, body)
|
||||
s.log.Printf("UDP deamon connection %s exited", ID)
|
||||
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, ":")
|
||||
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
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
@ -423,10 +430,10 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
s.sc.UDPListener.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||
s.log.Printf("udp response to local %s fail,ERR:%s", srcAddrFromConn, err)
|
||||
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)
|
||||
break
|
||||
@ -439,10 +446,10 @@ func (s *MuxServer) UDPConnDeamon() {
|
||||
if err != nil {
|
||||
utils.CloseConn(&outConn)
|
||||
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
|
||||
}
|
||||
//log.Printf("write packet %v", *item.packet)
|
||||
//s.log.Printf("write packet %v", *item.packet)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -2,27 +2,30 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
logger "log"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Start(args interface{}) (err error)
|
||||
Start(args interface{}, log *logger.Logger) (err error)
|
||||
Clean()
|
||||
}
|
||||
type ServiceItem struct {
|
||||
S Service
|
||||
Args interface{}
|
||||
Name string
|
||||
Log *logger.Logger
|
||||
}
|
||||
|
||||
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)
|
||||
servicesMap[name] = &ServiceItem{
|
||||
S: s,
|
||||
Args: args,
|
||||
Name: name,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
func GetService(name string) *ServiceItem {
|
||||
@ -37,7 +40,7 @@ func Stop(name string) {
|
||||
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]
|
||||
if ok {
|
||||
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()))
|
||||
}
|
||||
}()
|
||||
if len(args) == 1 {
|
||||
err = service.S.Start(args[0])
|
||||
if args != nil {
|
||||
err = service.S.Start(args, service.Log)
|
||||
} else {
|
||||
err = service.S.Start(service.Args)
|
||||
err = service.S.Start(service.Args, service.Log)
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s servcie fail, ERR: %s", name, err)
|
||||
|
||||
@ -3,17 +3,18 @@ package services
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/aes"
|
||||
"github.com/snail007/goproxy/utils/socks"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -28,6 +29,7 @@ type Socks struct {
|
||||
domainResolver utils.DomainResolver
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewSocks() Service {
|
||||
@ -108,9 +110,9 @@ func (s *Socks) CheckArgs() (err error) {
|
||||
func (s *Socks) InitService() (err error) {
|
||||
s.InitBasicAuth()
|
||||
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" {
|
||||
e := s.ConnectSSH()
|
||||
if e != nil {
|
||||
@ -133,7 +135,7 @@ func (s *Socks) InitService() (err error) {
|
||||
if s.sshClient != nil {
|
||||
s.sshClient.Close()
|
||||
}
|
||||
log.Printf("ssh offline, retrying...")
|
||||
s.log.Printf("ssh offline, retrying...")
|
||||
s.ConnectSSH()
|
||||
} else {
|
||||
conn.Close()
|
||||
@ -143,15 +145,15 @@ func (s *Socks) InitService() (err error) {
|
||||
}()
|
||||
}
|
||||
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 {
|
||||
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal)
|
||||
s.udpSC = utils.NewServerChannelHost(*s.cfg.UDPLocal, s.log)
|
||||
e := s.udpSC.ListenUDP(s.udpCallback)
|
||||
if e != nil {
|
||||
err = fmt.Errorf("init udp service fail, ERR: %s", e)
|
||||
return
|
||||
}
|
||||
log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
|
||||
s.log.Printf("udp socks proxy on %s", s.udpSC.UDPListener.LocalAddr())
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -159,9 +161,9 @@ func (s *Socks) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop socks service crashed,%s", e)
|
||||
s.log.Printf("stop socks service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service socks stoped")
|
||||
s.log.Printf("service socks stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -179,7 +181,8 @@ func (s *Socks) StopService() {
|
||||
(*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()
|
||||
s.cfg = args.(SocksArgs)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
@ -189,24 +192,24 @@ func (s *Socks) Start(args interface{}) (err error) {
|
||||
s.InitService()
|
||||
}
|
||||
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 != "" {
|
||||
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 {
|
||||
err = sc.ListenTCP(s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.socksConnCallback)
|
||||
} else if *s.cfg.LocalType == TYPE_KCP {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback)
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback, s.log)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
func (s *Socks) Clean() {
|
||||
@ -222,29 +225,29 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
//decode b
|
||||
rawB, err = goaes.Decrypt(s.UDPKey(), b)
|
||||
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
|
||||
}
|
||||
}
|
||||
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 {
|
||||
log.Printf("parse udp packet fail, ERR:%s", err)
|
||||
s.log.Printf("parse udp packet fail, ERR:%s", err)
|
||||
return
|
||||
}
|
||||
//防止死循环
|
||||
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
|
||||
}
|
||||
//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.ParentType == "tls" {
|
||||
//encode b
|
||||
rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
|
||||
if err != nil {
|
||||
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -254,43 +257,43 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
}
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", s.Resolve(parent))
|
||||
if err != nil {
|
||||
log.Printf("can't resolve address: %s", err)
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
return
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*5)))
|
||||
_, err = conn.Write(rawB)
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp request:%v", len(rawB))
|
||||
s.log.Printf("udp request:%v", len(rawB))
|
||||
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()
|
||||
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)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
respBody := buf[0:length]
|
||||
log.Printf("udp response:%v", len(respBody))
|
||||
//log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||
s.log.Printf("udp response:%v", len(respBody))
|
||||
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
//decode b
|
||||
respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
|
||||
if err != nil {
|
||||
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||
s.log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
@ -298,81 +301,83 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
if *s.cfg.LocalType == "tls" {
|
||||
d, err := goaes.Encrypt(s.UDPKey(), respBody)
|
||||
if err != nil {
|
||||
log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(d))
|
||||
s.log.Printf("udp reply:%v", len(d))
|
||||
d = nil
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
log.Printf("udp reply:%v", len(respBody))
|
||||
s.log.Printf("udp reply:%v", len(respBody))
|
||||
}
|
||||
|
||||
} else {
|
||||
//本地代理
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(s.Resolve(p.Host()), p.Port()))
|
||||
if err != nil {
|
||||
log.Printf("can't resolve address: %s", err)
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
return
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
|
||||
_, err = conn.Write(p.Data())
|
||||
conn.SetDeadline(time.Time{})
|
||||
log.Printf("udp send:%v", len(p.Data()))
|
||||
s.log.Printf("udp send:%v", len(p.Data()))
|
||||
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()
|
||||
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)
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
respBody := buf[0:length]
|
||||
//封装来自真实服务器的数据,返回给访问者
|
||||
respPacket := p.NewReply(respBody)
|
||||
//log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||
//s.log.Printf("revecived udp packet from %s", dstAddr.String())
|
||||
if *s.cfg.LocalType == "tls" {
|
||||
d, err := goaes.Encrypt(s.UDPKey(), respPacket)
|
||||
if err != nil {
|
||||
log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||
s.log.Printf("encrypt udp data fail from %s", dstAddr.String())
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
d = nil
|
||||
} else {
|
||||
s.udpSC.UDPListener.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
|
||||
s.udpSC.UDPListener.SetDeadline(time.Time{})
|
||||
}
|
||||
log.Printf("udp reply:%v", len(respPacket))
|
||||
s.log.Printf("udp reply:%v", len(respPacket))
|
||||
}
|
||||
|
||||
}
|
||||
func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
s.log.Printf("socks conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
inConn.Close()
|
||||
}
|
||||
}()
|
||||
@ -393,7 +398,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
if err != nil {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("new methods request fail,ERR: %s", err)
|
||||
s.log.Printf("new methods request fail,ERR: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -401,29 +406,29 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
if !methodReq.Select(socks.Method_NO_AUTH) {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("none method found : Method_NO_AUTH")
|
||||
s.log.Printf("none method found : Method_NO_AUTH")
|
||||
return
|
||||
}
|
||||
//method select reply
|
||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
||||
if err != nil {
|
||||
log.Printf("reply answer data fail,ERR: %s", err)
|
||||
s.log.Printf("reply answer data fail,ERR: %s", err)
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
// log.Printf("% x", methodReq.Bytes())
|
||||
// s.log.Printf("% x", methodReq.Bytes())
|
||||
} else {
|
||||
//auth
|
||||
if !methodReq.Select(socks.Method_USER_PASS) {
|
||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("none method found : Method_USER_PASS")
|
||||
s.log.Printf("none method found : Method_USER_PASS")
|
||||
return
|
||||
}
|
||||
//method reply need auth
|
||||
err = methodReq.Reply(socks.Method_USER_PASS)
|
||||
if err != nil {
|
||||
log.Printf("reply answer data fail,ERR: %s", err)
|
||||
s.log.Printf("reply answer data fail,ERR: %s", err)
|
||||
utils.CloseConn(&inConn)
|
||||
return
|
||||
}
|
||||
@ -439,7 +444,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
r := buf[:n]
|
||||
user := string(r[2 : r[1]+2])
|
||||
pass := string(r[2+r[1]+1:])
|
||||
//log.Printf("user:%s,pass:%s", user, pass)
|
||||
//s.log.Printf("user:%s,pass:%s", user, pass)
|
||||
//auth
|
||||
_addr := strings.Split(inConn.RemoteAddr().String(), ":")
|
||||
if s.basicAuth.CheckUserPass(user, pass, _addr[0], "") {
|
||||
@ -460,7 +465,7 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
|
||||
//request detail
|
||||
request, err := socks.NewRequest(inConn)
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -488,7 +493,7 @@ func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
}
|
||||
host, _, _ := net.SplitHostPort((*inConn).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))
|
||||
}
|
||||
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()) {
|
||||
utils.CloseConn(inConn)
|
||||
log.Printf("dead loop detected , %s", request.Host())
|
||||
s.log.Printf("dead loop detected , %s", request.Host())
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
@ -514,7 +519,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
|
||||
if *s.cfg.Parent != "" {
|
||||
host, _, _ := net.SplitHostPort(request.Addr())
|
||||
useProxy := false
|
||||
if utils.IsIternalIP(host) {
|
||||
if utils.IsIternalIP(host, *s.cfg.Always) {
|
||||
useProxy = false
|
||||
} else {
|
||||
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 == "" {
|
||||
break
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
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)
|
||||
inAddr := (*inConn).RemoteAddr().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{}) {
|
||||
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 {
|
||||
(*c.(*net.Conn)).Close()
|
||||
s.userConns.Remove(inAddr)
|
||||
@ -606,7 +612,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
return
|
||||
}
|
||||
//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)))
|
||||
_, err = outConn.Write(reqBytes)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
@ -622,7 +628,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
return
|
||||
}
|
||||
//result := buf[:n]
|
||||
//log.Printf("result:%v", result)
|
||||
//s.log.Printf("result:%v", result)
|
||||
|
||||
case "ssh":
|
||||
maxTryCount := 1
|
||||
@ -648,7 +654,7 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
|
||||
s.sshClient.Close()
|
||||
}
|
||||
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()
|
||||
if e == nil {
|
||||
tryCount++
|
||||
@ -686,13 +692,13 @@ func (s *Socks) ConnectSSH() (err error) {
|
||||
}
|
||||
func (s *Socks) InitBasicAuth() (err error) {
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
|
||||
} else {
|
||||
s.basicAuth = utils.NewBasicAuth(nil)
|
||||
s.basicAuth = utils.NewBasicAuth(nil, s.log)
|
||||
}
|
||||
if *s.cfg.AuthURL != "" {
|
||||
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
s.log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
}
|
||||
if *s.cfg.AuthFile != "" {
|
||||
var n = 0
|
||||
@ -701,11 +707,11 @@ func (s *Socks) InitBasicAuth() (err error) {
|
||||
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
@ -757,7 +763,7 @@ func (s *Socks) Resolve(address string) string {
|
||||
}
|
||||
ip, err := s.domainResolver.Resolve(address)
|
||||
if err != nil {
|
||||
log.Printf("dns error %s , ERR:%s", address, err)
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
183
services/sps.go
183
services/sps.go
@ -5,16 +5,17 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/socks"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
"github.com/snail007/goproxy/utils/socks"
|
||||
)
|
||||
|
||||
type SPS struct {
|
||||
@ -24,6 +25,7 @@ type SPS struct {
|
||||
basicAuth utils.BasicAuth
|
||||
serverChannels []*utils.ServerChannel
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewSPS() Service {
|
||||
@ -60,10 +62,10 @@ func (s *SPS) CheckArgs() (err error) {
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitService() (err error) {
|
||||
s.InitOutConnPool()
|
||||
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()
|
||||
return
|
||||
}
|
||||
@ -86,9 +88,9 @@ func (s *SPS) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop sps service crashed,%s", e)
|
||||
s.log.Printf("stop sps service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service sps stoped")
|
||||
s.log.Printf("service sps stoped")
|
||||
}
|
||||
}()
|
||||
for _, sc := range s.serverChannels {
|
||||
@ -100,10 +102,16 @@ func (s *SPS) StopService() {
|
||||
}
|
||||
}
|
||||
for _, c := range s.userConns.Items() {
|
||||
(*c.(*net.Conn)).Close()
|
||||
if _, ok := c.(*net.Conn); ok {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -111,23 +119,23 @@ func (s *SPS) Start(args interface{}) (err error) {
|
||||
if err = s.InitService(); err != nil {
|
||||
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, ",") {
|
||||
if addr != "" {
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
sc := utils.NewServerChannel(host, p, s.log)
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
|
||||
} 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -140,7 +148,7 @@ func (s *SPS) Clean() {
|
||||
func (s *SPS) callback(inConn net.Conn) {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -163,56 +171,78 @@ func (s *SPS) callback(inConn net.Conn) {
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s 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)
|
||||
}
|
||||
}
|
||||
func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
buf := make([]byte, 1024)
|
||||
n, err := (*inConn).Read(buf)
|
||||
header := buf[:n]
|
||||
bInConn := utils.NewBufferedConn(*inConn)
|
||||
//important
|
||||
//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 {
|
||||
log.Printf("ERR:%s", err)
|
||||
utils.CloseConn(inConn)
|
||||
s.log.Printf("peek error %s ", err)
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
|
||||
*inConn = bInConn
|
||||
address := ""
|
||||
var auth socks.Auth
|
||||
var forwardBytes []byte
|
||||
//fmt.Printf("%v", header)
|
||||
if header[0] == socks.VERSION_V5 {
|
||||
if utils.IsSocks5(h) {
|
||||
if *s.cfg.DisableSocks5 {
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
//socks5 server
|
||||
var serverConn *socks.ServerConn
|
||||
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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
address = serverConn.Target()
|
||||
auth = serverConn.AuthData()
|
||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
||||
} else if utils.IsHTTP(h) {
|
||||
if *s.cfg.DisableHTTP {
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
//http
|
||||
var request utils.HTTPRequest
|
||||
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
if s.IsBasicAuth() {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, s.log)
|
||||
} else {
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, s.log)
|
||||
}
|
||||
(*inConn).SetDeadline(time.Time{})
|
||||
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)
|
||||
return
|
||||
}
|
||||
if len(header) >= 7 && strings.ToLower(string(header[:7])) == "connect" {
|
||||
if len(h) >= 7 && strings.ToLower(string(h[:7])) == "connect" {
|
||||
//https
|
||||
request.HTTPSReply()
|
||||
//log.Printf("https reply: %s", request.Host)
|
||||
//s.log.Printf("https reply: %s", request.Host)
|
||||
} else {
|
||||
//forwardBytes = bytes.TrimRight(request.HeadBuf,"\r\n")
|
||||
forwardBytes = request.HeadBuf
|
||||
}
|
||||
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]}
|
||||
}
|
||||
}
|
||||
} 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)
|
||||
err = errors.New("unknown request")
|
||||
return
|
||||
@ -237,7 +269,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
var outConn net.Conn
|
||||
outConn, err = s.outPool.Get()
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -249,12 +281,23 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
}
|
||||
|
||||
if *s.cfg.ParentAuth != "" || s.IsBasicAuth() {
|
||||
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
|
||||
}
|
||||
|
||||
//ask parent for connect to target address
|
||||
if *s.cfg.ParentServiceType == "http" {
|
||||
//http parent
|
||||
isHTTPS := false
|
||||
|
||||
pb := new(bytes.Buffer)
|
||||
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
||||
//Proxy-Authorization:\r\n
|
||||
if len(forwardBytes) == 0 {
|
||||
isHTTPS = true
|
||||
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", address)))
|
||||
}
|
||||
pb.WriteString("Proxy-Connection: Keep-Alive\r\n")
|
||||
|
||||
u := ""
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
@ -269,31 +312,43 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
||||
}
|
||||
}
|
||||
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)))))
|
||||
}
|
||||
pb.Write([]byte("\r\n"))
|
||||
|
||||
if isHTTPS {
|
||||
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)))
|
||||
_, err = outConn.Write(pb.Bytes())
|
||||
outConn.SetDeadline(time.Time{})
|
||||
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(&outConn)
|
||||
return
|
||||
}
|
||||
reply := make([]byte, 1024)
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(reply)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
|
||||
if isHTTPS {
|
||||
reply := make([]byte, 1024)
|
||||
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = outConn.Read(reply)
|
||||
outConn.SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
s.log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||
utils.CloseConn(inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
//s.log.Printf("reply: %s", string(reply[:n]))
|
||||
}
|
||||
//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
|
||||
var clientConn *socks.ClientConn
|
||||
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")
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//forward client data to target,if necessary.
|
||||
if len(forwardBytes) > 0 {
|
||||
outConn.Write(forwardBytes)
|
||||
}
|
||||
|
||||
//bind
|
||||
inAddr := (*inConn).RemoteAddr().String()
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
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)
|
||||
})
|
||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
}, s.log)
|
||||
s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, address)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
s.userConns.Set(inAddr, inConn)
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitBasicAuth() (err error) {
|
||||
if *s.cfg.DNSAddress != "" {
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
|
||||
} else {
|
||||
s.basicAuth = utils.NewBasicAuth(nil)
|
||||
s.basicAuth = utils.NewBasicAuth(nil, s.log)
|
||||
}
|
||||
if *s.cfg.AuthURL != "" {
|
||||
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
s.log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||
}
|
||||
if *s.cfg.AuthFile != "" {
|
||||
var n = 0
|
||||
@ -349,11 +406,11 @@ func (s *SPS) InitBasicAuth() (err error) {
|
||||
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
@ -404,7 +461,7 @@ func (s *SPS) Resolve(address string) string {
|
||||
}
|
||||
ip, err := s.domainResolver.Resolve(address)
|
||||
if err != nil {
|
||||
log.Printf("dns error %s , ERR:%s", address, err)
|
||||
s.log.Printf("dns error %s , ERR:%s", address, err)
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
@ -3,13 +3,14 @@ package services
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@ -19,6 +20,7 @@ type TCP struct {
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewTCP() Service {
|
||||
@ -54,9 +56,9 @@ func (s *TCP) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tcp service crashed,%s", e)
|
||||
s.log.Printf("stop tcp service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tcp stoped")
|
||||
s.log.Printf("service tcp stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -70,7 +72,8 @@ func (s *TCP) StopService() {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -78,22 +81,22 @@ func (s *TCP) Start(args interface{}) (err error) {
|
||||
if err = s.InitService(); err != nil {
|
||||
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)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
sc := utils.NewServerChannel(host, p, s.log)
|
||||
|
||||
if *s.cfg.LocalType == TYPE_TCP {
|
||||
err = sc.ListenTCP(s.callback)
|
||||
} else if *s.cfg.LocalType == TYPE_TLS {
|
||||
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
|
||||
} 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 {
|
||||
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
|
||||
return
|
||||
}
|
||||
@ -104,7 +107,7 @@ func (s *TCP) Clean() {
|
||||
func (s *TCP) callback(inConn net.Conn) {
|
||||
defer func() {
|
||||
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
|
||||
@ -121,7 +124,7 @@ func (s *TCP) callback(inConn net.Conn) {
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
utils.CloseConn(&inConn)
|
||||
}
|
||||
}
|
||||
@ -129,7 +132,7 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||
var outConn net.Conn
|
||||
outConn, err = s.outPool.Get()
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -138,18 +141,18 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||
outAddr := outConn.RemoteAddr().String()
|
||||
//outLocalAddr := outConn.LocalAddr().String()
|
||||
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)
|
||||
})
|
||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
}, s.log)
|
||||
s.log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
s.userConns.Set(inAddr, inConn)
|
||||
return
|
||||
}
|
||||
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 {
|
||||
if s.isStop {
|
||||
(*inConn).Close()
|
||||
@ -157,45 +160,45 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
|
||||
}
|
||||
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
//log.Printf("connection %s released", srcAddr)
|
||||
//s.log.Printf("connection %s released", srcAddr)
|
||||
utils.CloseConn(inConn)
|
||||
break
|
||||
}
|
||||
//log.Debugf("udp packet revecived:%s,%v", srcAddr, body)
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
|
||||
if err != nil {
|
||||
log.Printf("can't resolve address: %s", err)
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
break
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
continue
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
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
|
||||
}
|
||||
//log.Debugf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 512)
|
||||
len, _, err := conn.ReadFromUDP(buf)
|
||||
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
|
||||
}
|
||||
respBody := buf[0:len]
|
||||
//log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||
_, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody))
|
||||
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)
|
||||
break
|
||||
}
|
||||
//log.Printf("send udp response success ,from:%s", dstAddr.String())
|
||||
//s.log.Printf("send udp response success ,from:%s", dstAddr.String())
|
||||
}
|
||||
return
|
||||
|
||||
|
||||
@ -3,13 +3,16 @@ package services
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type ServerConn struct {
|
||||
@ -21,6 +24,7 @@ type TunnelBridge struct {
|
||||
serverConns utils.ConcurrentMap
|
||||
clientControlConns utils.ConcurrentMap
|
||||
isStop bool
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewTunnelBridge() Service {
|
||||
@ -47,9 +51,9 @@ func (s *TunnelBridge) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tbridge service crashed,%s", e)
|
||||
s.log.Printf("stop tbridge service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tbridge stoped")
|
||||
s.log.Printf("service tbridge stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -60,7 +64,8 @@ func (s *TunnelBridge) StopService() {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -70,13 +75,13 @@ func (s *TunnelBridge) Start(args interface{}) (err error) {
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
func (s *TunnelBridge) Clean() {
|
||||
@ -84,20 +89,22 @@ func (s *TunnelBridge) Clean() {
|
||||
}
|
||||
func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
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{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
AcceptBacklog: 256,
|
||||
EnableKeepAlive: true,
|
||||
KeepAliveInterval: 9 * time.Second,
|
||||
ConnectionWriteTimeout: 3 * time.Second,
|
||||
MaxStreamWindowSize: 512 * 1024,
|
||||
LogOutput: os.Stderr,
|
||||
})
|
||||
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
|
||||
}
|
||||
inConn, err = sess.AcceptStream()
|
||||
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
|
||||
}
|
||||
|
||||
@ -109,7 +116,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
var connType uint8
|
||||
err = utils.ReadPacket(reader, &connType)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
switch connType {
|
||||
@ -117,11 +124,11 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
var key, ID, clientLocalAddr, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &clientLocalAddr, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
packet := utils.BuildPacketData(ID, clientLocalAddr, serverID)
|
||||
log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
|
||||
s.log.Printf("server connection, key: %s , id: %s %s %s", key, ID, clientLocalAddr, serverID)
|
||||
|
||||
//addr := clientLocalAddr + "@" + ID
|
||||
s.serverConns.Set(ID, ServerConn{
|
||||
@ -133,7 +140,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
}
|
||||
item, ok := s.clientControlConns.Get(key)
|
||||
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)
|
||||
continue
|
||||
}
|
||||
@ -141,7 +148,7 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
_, err := (*item.(*net.Conn)).Write(packet)
|
||||
(*item.(*net.Conn)).SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
||||
s.log.Printf("%s client control conn write signal fail, err: %s, retrying...", key, err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
@ -153,15 +160,15 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
var key, ID, serverID string
|
||||
err = utils.ReadPacketData(reader, &key, &ID, &serverID)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
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)
|
||||
if !ok {
|
||||
inConn.Close()
|
||||
log.Printf("server conn %s exists", ID)
|
||||
s.log.Printf("server conn %s exists", ID)
|
||||
return
|
||||
}
|
||||
serverConn := serverConnItem.(ServerConn).Conn
|
||||
@ -169,24 +176,24 @@ func (s *TunnelBridge) callback(inConn net.Conn) {
|
||||
s.serverConns.Remove(ID)
|
||||
// s.cmClient.RemoveOne(key, 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)
|
||||
log.Printf("conn %s created", ID)
|
||||
s.log.Printf("conn %s created", ID)
|
||||
|
||||
case CONN_CLIENT_CONTROL:
|
||||
var key string
|
||||
err = utils.ReadPacketData(reader, &key)
|
||||
if err != nil {
|
||||
log.Printf("read error,ERR:%s", err)
|
||||
s.log.Printf("read error,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
log.Printf("client control connection, key: %s", key)
|
||||
s.log.Printf("client control connection, key: %s", key)
|
||||
if s.clientControlConns.Has(key) {
|
||||
item, _ := s.clientControlConns.Get(key)
|
||||
(*item.(*net.Conn)).Close()
|
||||
}
|
||||
s.clientControlConns.Set(key, &inConn)
|
||||
log.Printf("set client %s control conn", key)
|
||||
s.log.Printf("set client %s control conn", key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,13 +3,16 @@ package services
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type TunnelClient struct {
|
||||
@ -17,6 +20,7 @@ type TunnelClient struct {
|
||||
ctrlConn net.Conn
|
||||
isStop bool
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewTunnelClient() Service {
|
||||
@ -33,7 +37,7 @@ func (s *TunnelClient) InitService() (err error) {
|
||||
|
||||
func (s *TunnelClient) CheckArgs() (err error) {
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
s.log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
@ -49,9 +53,9 @@ func (s *TunnelClient) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop tclient service crashed,%s", e)
|
||||
s.log.Printf("stop tclient service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service tclient stoped")
|
||||
s.log.Printf("service tclient stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -62,7 +66,8 @@ func (s *TunnelClient) StopService() {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -70,7 +75,7 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
|
||||
if err = s.InitService(); err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("proxy on tunnel client mode")
|
||||
s.log.Printf("proxy on tunnel client mode")
|
||||
|
||||
for {
|
||||
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)
|
||||
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)
|
||||
if s.ctrlConn != nil {
|
||||
s.ctrlConn.Close()
|
||||
@ -99,10 +104,10 @@ func (s *TunnelClient) Start(args interface{}) (err error) {
|
||||
if s.ctrlConn != nil {
|
||||
s.ctrlConn.Close()
|
||||
}
|
||||
log.Printf("read connection signal err: %s, retrying...", err)
|
||||
s.log.Printf("read connection signal err: %s, retrying...", err)
|
||||
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]
|
||||
localAddr := clientLocalAddr[4:]
|
||||
if protocol == "udp" {
|
||||
@ -136,19 +141,21 @@ func (s *TunnelClient) GetConn() (conn net.Conn, err error) {
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
c, e := smux.Client(conn, &smux.Config{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
AcceptBacklog: 256,
|
||||
EnableKeepAlive: true,
|
||||
KeepAliveInterval: 9 * time.Second,
|
||||
ConnectionWriteTimeout: 3 * time.Second,
|
||||
MaxStreamWindowSize: 512 * 1024,
|
||||
LogOutput: os.Stderr,
|
||||
})
|
||||
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
|
||||
return
|
||||
}
|
||||
conn, e = c.OpenStream()
|
||||
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
|
||||
return
|
||||
}
|
||||
@ -170,7 +177,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
inConn, err = s.GetInConn(CONN_CLIENT, *s.cfg.Key, ID, serverID)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
s.log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
@ -178,7 +185,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
}
|
||||
}
|
||||
// s.cm.Add(*s.cfg.Key, ID, &inConn)
|
||||
log.Printf("conn %s created", ID)
|
||||
s.log.Printf("conn %s created", ID)
|
||||
|
||||
for {
|
||||
if s.isStop {
|
||||
@ -186,13 +193,13 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
}
|
||||
srcAddr, body, err := utils.ReadUDPPacket(inConn)
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
log.Printf("connection %s released", ID)
|
||||
s.log.Printf("connection %s released", ID)
|
||||
utils.CloseConn(&inConn)
|
||||
break
|
||||
} else if err != nil {
|
||||
log.Printf("udp packet revecived fail, err: %s", err)
|
||||
s.log.Printf("udp packet revecived fail, err: %s", err)
|
||||
} 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)
|
||||
}
|
||||
|
||||
@ -202,39 +209,39 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
|
||||
func (s *TunnelClient) processUDPPacket(inConn *net.Conn, srcAddr, localAddr string, body []byte) {
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", localAddr)
|
||||
if err != nil {
|
||||
log.Printf("can't resolve address: %s", err)
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
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
|
||||
}
|
||||
//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)
|
||||
length, _, err := conn.ReadFromUDP(buf)
|
||||
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
|
||||
}
|
||||
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)
|
||||
_, err = (*inConn).Write(bs)
|
||||
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)
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
log.Printf("connection err: %s, retrying...", err)
|
||||
s.log.Printf("connection err: %s, retrying...", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
continue
|
||||
} else {
|
||||
@ -265,7 +272,7 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||
break
|
||||
} else {
|
||||
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)
|
||||
continue
|
||||
}
|
||||
@ -274,17 +281,17 @@ func (s *TunnelClient) ServeConn(localAddr, ID, serverID string) {
|
||||
if err != nil {
|
||||
utils.CloseConn(&inConn)
|
||||
utils.CloseConn(&outConn)
|
||||
log.Printf("build connection error, err: %s", err)
|
||||
s.log.Printf("build connection error, err: %s", err)
|
||||
return
|
||||
}
|
||||
inAddr := inConn.RemoteAddr().String()
|
||||
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||
log.Printf("conn %s released", ID)
|
||||
s.log.Printf("conn %s released", ID)
|
||||
s.userConns.Remove(inAddr)
|
||||
})
|
||||
}, s.log)
|
||||
if c, ok := s.userConns.Get(inAddr); ok {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
s.userConns.Set(inAddr, &inConn)
|
||||
log.Printf("conn %s created", ID)
|
||||
s.log.Printf("conn %s created", ID)
|
||||
}
|
||||
|
||||
@ -3,16 +3,19 @@ package services
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xtaci/smux"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
|
||||
//"github.com/xtaci/smux"
|
||||
smux "github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
type TunnelServer struct {
|
||||
@ -22,6 +25,7 @@ type TunnelServer struct {
|
||||
isStop bool
|
||||
udpConn *net.Conn
|
||||
userConns utils.ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
type TunnelServerManager struct {
|
||||
@ -29,6 +33,7 @@ type TunnelServerManager struct {
|
||||
udpChn chan UDPItem
|
||||
serverID string
|
||||
servers []*Service
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewTunnelServerManager() Service {
|
||||
@ -39,13 +44,14 @@ func NewTunnelServerManager() 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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.Parent != "" {
|
||||
log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
s.log.Printf("use tls parent %s", *s.cfg.Parent)
|
||||
} else {
|
||||
err = fmt.Errorf("parent required")
|
||||
return
|
||||
@ -55,8 +61,8 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("server id: %s", s.serverID)
|
||||
//log.Printf("route:%v", *s.cfg.Route)
|
||||
s.log.Printf("server id: %s", s.serverID)
|
||||
//s.log.Printf("route:%v", *s.cfg.Route)
|
||||
for _, _info := range *s.cfg.Route {
|
||||
IsUDP := *s.cfg.IsUDP
|
||||
if strings.HasPrefix(_info, "udp://") {
|
||||
@ -88,7 +94,7 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
|
||||
Key: &KEY,
|
||||
Timeout: s.cfg.Timeout,
|
||||
Mgr: s,
|
||||
})
|
||||
}, log)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
@ -120,13 +126,13 @@ func (s *TunnelServerManager) InitService() (err error) {
|
||||
func (s *TunnelServerManager) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
|
||||
outConn, err = s.GetConn()
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s", err)
|
||||
s.log.Printf("connection err: %s", err)
|
||||
return
|
||||
}
|
||||
ID = s.serverID
|
||||
_, err = outConn.Write(utils.BuildPacket(typ, s.serverID))
|
||||
if err != nil {
|
||||
log.Printf("write connection data err: %s ,retrying...", err)
|
||||
s.log.Printf("write connection data err: %s ,retrying...", err)
|
||||
utils.CloseConn(&outConn)
|
||||
return
|
||||
}
|
||||
@ -159,9 +165,9 @@ func (s *TunnelServer) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop server service crashed,%s", e)
|
||||
s.log.Printf("stop server service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service server stoped")
|
||||
s.log.Printf("service server stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -191,7 +197,8 @@ func (s *TunnelServer) CheckArgs() (err error) {
|
||||
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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
return
|
||||
@ -201,7 +208,7 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
s.sc = utils.NewServerChannel(host, p)
|
||||
s.sc = utils.NewServerChannel(host, p, s.log)
|
||||
if *s.cfg.IsUDP {
|
||||
err = s.sc.ListenUDP(func(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
s.udpChn <- UDPItem{
|
||||
@ -213,12 +220,12 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
if err != nil {
|
||||
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 {
|
||||
err = s.sc.ListenTCP(func(inConn net.Conn) {
|
||||
defer func() {
|
||||
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
|
||||
@ -230,7 +237,7 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
outConn, ID, err = s.GetOutConn(CONN_SERVER)
|
||||
if err != nil {
|
||||
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)
|
||||
continue
|
||||
} else {
|
||||
@ -240,18 +247,18 @@ func (s *TunnelServer) Start(args interface{}) (err error) {
|
||||
inAddr := inConn.RemoteAddr().String()
|
||||
utils.IoBind(inConn, outConn, func(err interface{}) {
|
||||
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 {
|
||||
(*c.(*net.Conn)).Close()
|
||||
}
|
||||
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 {
|
||||
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
|
||||
}
|
||||
@ -261,7 +268,7 @@ func (s *TunnelServer) Clean() {
|
||||
func (s *TunnelServer) GetOutConn(typ uint8) (outConn net.Conn, ID string, err error) {
|
||||
outConn, err = s.GetConn()
|
||||
if err != nil {
|
||||
log.Printf("connection err: %s", err)
|
||||
s.log.Printf("connection err: %s", err)
|
||||
return
|
||||
}
|
||||
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()
|
||||
_, err = outConn.Write(utils.BuildPacket(typ, *s.cfg.Key, ID, remoteAddr, s.cfg.Mgr.serverID))
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -283,19 +290,21 @@ func (s *TunnelServer) GetConn() (conn net.Conn, err error) {
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
c, e := smux.Client(conn, &smux.Config{
|
||||
KeepAliveInterval: 10 * time.Second,
|
||||
KeepAliveTimeout: time.Duration(*s.cfg.Timeout) * time.Second,
|
||||
MaxFrameSize: 4096,
|
||||
MaxReceiveBuffer: 4194304,
|
||||
AcceptBacklog: 256,
|
||||
EnableKeepAlive: true,
|
||||
KeepAliveInterval: 9 * time.Second,
|
||||
ConnectionWriteTimeout: 3 * time.Second,
|
||||
MaxStreamWindowSize: 512 * 1024,
|
||||
LogOutput: os.Stderr,
|
||||
})
|
||||
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
|
||||
return
|
||||
}
|
||||
conn, e = c.OpenStream()
|
||||
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
|
||||
return
|
||||
}
|
||||
@ -306,7 +315,7 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
go func() {
|
||||
defer func() {
|
||||
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
|
||||
@ -333,7 +342,7 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
// cmdChn <- true
|
||||
outConn = nil
|
||||
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)
|
||||
continue
|
||||
} else {
|
||||
@ -348,27 +357,27 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
}
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(outConn)
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
//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, ":")
|
||||
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
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
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
|
||||
}
|
||||
//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)
|
||||
break
|
||||
@ -381,10 +390,10 @@ func (s *TunnelServer) UDPConnDeamon() {
|
||||
if err != nil {
|
||||
utils.CloseConn(&outConn)
|
||||
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
|
||||
}
|
||||
//log.Printf("write packet %v", *item.packet)
|
||||
//s.log.Printf("write packet %v", *item.packet)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -3,16 +3,17 @@ package services
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
)
|
||||
|
||||
type UDP struct {
|
||||
@ -21,6 +22,7 @@ type UDP struct {
|
||||
cfg UDPArgs
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewUDP() Service {
|
||||
@ -57,9 +59,9 @@ func (s *UDP) StopService() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
log.Printf("stop udp service crashed,%s", e)
|
||||
s.log.Printf("stop udp service crashed,%s", e)
|
||||
} else {
|
||||
log.Printf("service udp stoped")
|
||||
s.log.Printf("service udp stoped")
|
||||
}
|
||||
}()
|
||||
s.isStop = true
|
||||
@ -70,24 +72,25 @@ func (s *UDP) StopService() {
|
||||
(*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)
|
||||
if err = s.CheckArgs(); err != nil {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
host, port, _ := net.SplitHostPort(*s.cfg.Local)
|
||||
p, _ := strconv.Atoi(port)
|
||||
sc := utils.NewServerChannel(host, p)
|
||||
sc := utils.NewServerChannel(host, p, s.log)
|
||||
s.sc = &sc
|
||||
err = sc.ListenUDP(s.callback)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("udp proxy on %s", (*sc.UDPListener).LocalAddr())
|
||||
s.log.Printf("udp proxy on %s", (*sc.UDPListener).LocalAddr())
|
||||
return
|
||||
}
|
||||
|
||||
@ -97,7 +100,7 @@ func (s *UDP) Clean() {
|
||||
func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
defer func() {
|
||||
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
|
||||
@ -112,7 +115,7 @@ func (s *UDP) callback(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
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) {
|
||||
@ -140,17 +143,17 @@ func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err erro
|
||||
connKey := uint64((numLocal/10)*10 + numSrc%mod)
|
||||
conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey))
|
||||
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
|
||||
}
|
||||
if isNew {
|
||||
go func() {
|
||||
defer func() {
|
||||
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 {
|
||||
if s.isStop {
|
||||
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))
|
||||
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))
|
||||
break
|
||||
}
|
||||
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
|
||||
}
|
||||
//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, ":")
|
||||
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
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
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
|
||||
}
|
||||
//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)
|
||||
//fmt.Println(conn, writer)
|
||||
writer.Write(utils.UDPPacket(srcAddr.String(), packet))
|
||||
err = writer.Flush()
|
||||
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
|
||||
}
|
||||
//log.Printf("write packet %v", packet)
|
||||
//s.log.Printf("write packet %v", packet)
|
||||
return
|
||||
}
|
||||
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)
|
||||
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
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(packet)
|
||||
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
|
||||
}
|
||||
//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)
|
||||
len, _, err := conn.ReadFromUDP(buf)
|
||||
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
|
||||
}
|
||||
//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)
|
||||
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
|
||||
}
|
||||
//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
|
||||
}
|
||||
func (s *UDP) InitOutConnPool() {
|
||||
|
||||
@ -10,27 +10,29 @@ import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
logger "log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"github.com/snail007/goproxy/utils/id"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/utils/id"
|
||||
|
||||
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() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -68,11 +70,14 @@ func IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, fn func(err interfac
|
||||
}
|
||||
src.Close()
|
||||
dst.Close()
|
||||
fn(err)
|
||||
if fn != nil {
|
||||
fn(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
|
||||
buf := make([]byte, 32*1024)
|
||||
buf := LeakyBuffer.Get()
|
||||
defer LeakyBuffer.Put(buf)
|
||||
n := 0
|
||||
for {
|
||||
n, err = src.Read(buf)
|
||||
@ -171,33 +176,6 @@ func ConnectKCPHost(hostAndPort string, config kcpcfg.KCPConfigArgs) (conn net.C
|
||||
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 {
|
||||
_, err := os.Stat(_path)
|
||||
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")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
@ -254,7 +232,7 @@ func Keygen() (err error) {
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
@ -273,7 +251,7 @@ func Keygen() (err error) {
|
||||
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
@ -283,7 +261,7 @@ func Keygen() (err error) {
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
@ -293,7 +271,7 @@ func Keygen() (err error) {
|
||||
cmd = exec.Command("sh", "-c", cmdStr)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
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")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("err:%s", err)
|
||||
logger.Printf("err:%s", err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
func IsIternalIP(domainOrIP string) bool {
|
||||
func IsIternalIP(domainOrIP string, always bool) bool {
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
@ -624,6 +616,53 @@ func IsIternalIP(domainOrIP string) bool {
|
||||
}
|
||||
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 {
|
||||
// family uint16
|
||||
|
||||
45
utils/leakybuf.go
Normal file
45
utils/leakybuf.go
Normal 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
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
|
||||
kcp "github.com/xtaci/kcp-go"
|
||||
)
|
||||
|
||||
@ -17,23 +21,26 @@ type ServerChannel struct {
|
||||
Listener *net.Listener
|
||||
UDPListener *net.UDPConn
|
||||
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{
|
||||
ip: ip,
|
||||
port: port,
|
||||
log: log,
|
||||
errAcceptHandler: func(err error) {
|
||||
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)
|
||||
p, _ := strconv.Atoi(port)
|
||||
return ServerChannel{
|
||||
ip: h,
|
||||
port: p,
|
||||
log: log,
|
||||
errAcceptHandler: func(err error) {
|
||||
log.Printf("accept error , ERR:%s", err)
|
||||
},
|
||||
@ -43,12 +50,12 @@ func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||
sc.errAcceptHandler = fn
|
||||
}
|
||||
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 {
|
||||
go func() {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -58,7 +65,7 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn f
|
||||
go func() {
|
||||
defer func() {
|
||||
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)
|
||||
@ -73,7 +80,33 @@ func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn f
|
||||
}
|
||||
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) {
|
||||
var l net.Listener
|
||||
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() {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -92,7 +125,7 @@ func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
|
||||
go func() {
|
||||
defer func() {
|
||||
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)
|
||||
@ -114,7 +147,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
||||
go func() {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -125,7 +158,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
||||
go func() {
|
||||
defer func() {
|
||||
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)
|
||||
@ -139,7 +172,7 @@ func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *ne
|
||||
}
|
||||
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)
|
||||
if 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() {
|
||||
defer func() {
|
||||
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 {
|
||||
@ -169,7 +202,7 @@ func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net
|
||||
go func() {
|
||||
defer func() {
|
||||
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)
|
||||
|
||||
@ -1,22 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils/sni"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
logger "log"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/services/kcpcfg"
|
||||
"github.com/snail007/goproxy/utils/sni"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@ -28,6 +30,7 @@ type Checker struct {
|
||||
interval int64
|
||||
timeout int
|
||||
isStop bool
|
||||
log *logger.Logger
|
||||
}
|
||||
type CheckerItem struct {
|
||||
IsHTTPS bool
|
||||
@ -43,12 +46,13 @@ type CheckerItem struct {
|
||||
//NewChecker args:
|
||||
//timeout : tcp timeout milliseconds ,connect to host
|
||||
//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{
|
||||
data: NewConcurrentMap(),
|
||||
interval: interval,
|
||||
timeout: timeout,
|
||||
isStop: false,
|
||||
log: log,
|
||||
}
|
||||
ch.blockedMap = ch.loadMap(blockedFile)
|
||||
ch.directMap = ch.loadMap(directFile)
|
||||
@ -70,7 +74,7 @@ func (c *Checker) loadMap(f string) (dataMap ConcurrentMap) {
|
||||
if PathExists(f) {
|
||||
_contents, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
log.Printf("load file err:%s", err)
|
||||
c.log.Printf("load file err:%s", err)
|
||||
return
|
||||
}
|
||||
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 {
|
||||
u, err := url.Parse("http://" + address)
|
||||
if err != nil {
|
||||
log.Printf("blocked check , url parse err:%s", err)
|
||||
c.log.Printf("blocked check , url parse err:%s", err)
|
||||
return true
|
||||
}
|
||||
domainSlice := strings.Split(u.Hostname(), ".")
|
||||
@ -187,12 +191,14 @@ type BasicAuth struct {
|
||||
authTimeout int
|
||||
authRetry int
|
||||
dns *DomainResolver
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewBasicAuth(dns *DomainResolver) BasicAuth {
|
||||
func NewBasicAuth(dns *DomainResolver, log *logger.Logger) BasicAuth {
|
||||
return BasicAuth{
|
||||
data: NewConcurrentMap(),
|
||||
dns: dns,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
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 {
|
||||
return true
|
||||
}
|
||||
log.Printf("%s", err)
|
||||
ba.log.Printf("%s", err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
if err != nil && tryCount < ba.authRetry {
|
||||
log.Print(err)
|
||||
ba.log.Print(err)
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
tryCount++
|
||||
@ -320,13 +326,15 @@ type HTTPRequest struct {
|
||||
hostOrURL string
|
||||
isBasicAuth bool
|
||||
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)
|
||||
n := 0
|
||||
req = HTTPRequest{
|
||||
conn: inConn,
|
||||
log: log,
|
||||
}
|
||||
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||
buf = header[0]
|
||||
@ -419,7 +427,7 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||
|
||||
authorization = strings.Trim(authorization, " \r\n\t")
|
||||
if authorization == "" {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "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)
|
||||
err = errors.New("require auth header data")
|
||||
return
|
||||
@ -455,7 +463,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
||||
//log.Printf("auth %s,%v", string(user), authOk)
|
||||
if !authOk {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407")
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407")
|
||||
CloseConn(req.conn)
|
||||
err = fmt.Errorf("basic auth fail")
|
||||
return
|
||||
@ -478,10 +486,10 @@ func (req *HTTPRequest) getHeader(key string) (val string) {
|
||||
lines := strings.Split(string(req.HeadBuf), "\r\n")
|
||||
//log.Println(lines)
|
||||
for _, line := range lines {
|
||||
line := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2)
|
||||
if len(line) == 2 {
|
||||
k := strings.ToUpper(strings.Trim(line[0], " "))
|
||||
v := strings.Trim(line[1], " ")
|
||||
hline := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2)
|
||||
if len(hline) == 2 {
|
||||
k := strings.ToUpper(strings.Trim(hline[0], " "))
|
||||
v := strings.Trim(hline[1], " ")
|
||||
if key == k {
|
||||
val = v
|
||||
return
|
||||
@ -546,12 +554,14 @@ func (op *OutConn) Get() (conn net.Conn, err error) {
|
||||
type ConnManager struct {
|
||||
pool ConcurrentMap
|
||||
l *sync.Mutex
|
||||
log *logger.Logger
|
||||
}
|
||||
|
||||
func NewConnManager() ConnManager {
|
||||
func NewConnManager(log *logger.Logger) ConnManager {
|
||||
cm := ConnManager{
|
||||
pool: NewConcurrentMap(),
|
||||
l: &sync.Mutex{},
|
||||
log: log,
|
||||
}
|
||||
return cm
|
||||
}
|
||||
@ -568,7 +578,7 @@ func (cm *ConnManager) Add(key, ID string, conn *net.Conn) {
|
||||
(*v.(*net.Conn)).Close()
|
||||
}
|
||||
conns.Set(ID, conn)
|
||||
log.Printf("%s conn added", key)
|
||||
cm.log.Printf("%s conn added", key)
|
||||
return conns
|
||||
})
|
||||
}
|
||||
@ -579,7 +589,7 @@ func (cm *ConnManager) Remove(key string) {
|
||||
conns.IterCb(func(key string, v interface{}) {
|
||||
CloseConn(v.(*net.Conn))
|
||||
})
|
||||
log.Printf("%s conns closed", key)
|
||||
cm.log.Printf("%s conns closed", key)
|
||||
}
|
||||
cm.pool.Remove(key)
|
||||
}
|
||||
@ -594,7 +604,7 @@ func (cm *ConnManager) RemoveOne(key string, ID string) {
|
||||
(*v.(*net.Conn)).Close()
|
||||
conns.Remove(ID)
|
||||
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
|
||||
dnsAddrress string
|
||||
data ConcurrentMap
|
||||
log *logger.Logger
|
||||
}
|
||||
type DomainResolverItem struct {
|
||||
ip string
|
||||
@ -657,12 +668,12 @@ type DomainResolverItem struct {
|
||||
expiredAt int64
|
||||
}
|
||||
|
||||
func NewDomainResolver(dnsAddrress string, ttl int) DomainResolver {
|
||||
|
||||
func NewDomainResolver(dnsAddrress string, ttl int, log *logger.Logger) DomainResolver {
|
||||
return DomainResolver{
|
||||
ttl: ttl,
|
||||
dnsAddrress: dnsAddrress,
|
||||
data: NewConcurrentMap(),
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
func (a *DomainResolver) MustResolve(address string) (ip string) {
|
||||
@ -677,7 +688,7 @@ func (a *DomainResolver) Resolve(address string) (ip string, err error) {
|
||||
if 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()
|
||||
}()
|
||||
if strings.Contains(domain, ":") {
|
||||
@ -739,7 +750,7 @@ func (a *DomainResolver) Resolve(address string) (ip string, err error) {
|
||||
func (a *DomainResolver) PrintData() {
|
||||
for k, item := range a.data.Items() {
|
||||
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 {
|
||||
@ -792,3 +803,33 @@ func (c *CompStream) SetReadDeadline(t time.Time) error {
|
||||
func (c *CompStream) SetWriteDeadline(t time.Time) error {
|
||||
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
122
vendor/github.com/Yawning/chacha20/LICENSE
generated
vendored
Normal 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
14
vendor/github.com/Yawning/chacha20/README.md
generated
vendored
Normal 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
273
vendor/github.com/Yawning/chacha20/chacha20.go
generated
vendored
Normal 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
95
vendor/github.com/Yawning/chacha20/chacha20_amd64.go
generated
vendored
Normal 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(®s[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(®s[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(®s[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
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
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
394
vendor/github.com/Yawning/chacha20/chacha20_ref.go
generated
vendored
Normal 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
395
vendor/github.com/Yawning/chacha20/chacha20_ref_go19.go
generated
vendored
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user