87 Commits
v6.1 ... imgbot

Author SHA1 Message Date
ImgBotApp
bee025e6f0 [ImgBot] Optimize images
*Total -- 815.67kb -> 652.94kb (19.95%)

/vendor/github.com/xtaci/kcp-go/donate.png -- 4.32kb -> 2.43kb (43.67%)
/docs/images/5.2.png -- 12.26kb -> 8.70kb (29.02%)
/docs/images/tcp-3.png -- 21.86kb -> 16.34kb (25.25%)
/docs/images/udp-3.png -- 22.86kb -> 17.12kb (25.09%)
/docs/images/fxdl.png -- 33.46kb -> 25.09kb (25.01%)
/vendor/github.com/xtaci/kcp-go/frame.png -- 35.16kb -> 26.43kb (24.82%)
/docs/images/http-tls-2.png -- 24.64kb -> 18.54kb (24.78%)
/docs/images/http-tls-3.png -- 29.66kb -> 22.31kb (24.76%)
/docs/images/http-ssh-1.png -- 29.06kb -> 21.89kb (24.68%)
/docs/images/tcp-tls-3.png -- 24.60kb -> 18.56kb (24.55%)
/docs/images/http-kcp.png -- 25.42kb -> 19.19kb (24.51%)
/docs/images/udp-tls-3.png -- 25.61kb -> 19.34kb (24.46%)
/docs/images/socks-ssh.png -- 24.47kb -> 18.56kb (24.12%)
/docs/images/http-2.png -- 21.60kb -> 16.50kb (23.61%)
/docs/images/http-1.png -- 18.26kb -> 14.06kb (23.02%)
/docs/images/socks-tls-3.png -- 24.67kb -> 19.02kb (22.88%)
/docs/images/tcp-tls-2.png -- 19.21kb -> 15.10kb (21.37%)
/docs/images/tcp-2.png -- 17.44kb -> 13.83kb (20.7%)
/docs/images/sps-tls.png -- 23.78kb -> 18.91kb (20.47%)
/docs/images/udp-tls-2.png -- 22.06kb -> 17.67kb (19.92%)
/docs/images/udp-2.png -- 20.14kb -> 16.16kb (19.79%)
/docs/images/socks-tls-2.png -- 19.06kb -> 15.39kb (19.24%)
/docs/images/socks-2.png -- 17.54kb -> 14.29kb (18.57%)
/docs/images/logo.jpg -- 118.72kb -> 96.96kb (18.32%)
/docs/images/udp-1.png -- 12.81kb -> 10.67kb (16.7%)
/docs/images/tcp-1.png -- 13.98kb -> 11.66kb (16.61%)
/docs/images/1.1.jpg -- 94.13kb -> 83.31kb (11.49%)
/docs/images/2.1.png -- 26.48kb -> 24.44kb (7.71%)
/docs/images/2.2.png -- 32.43kb -> 30.46kb (6.09%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2020-02-03 08:06:25 +00:00
arraykeys@gmail.com
198281b5eb Merge branch 'dev' 2019-01-24 16:35:04 +08:00
arraykeys@gmail.com
426d711d0b a 2019-01-24 16:34:49 +08:00
arraykeys@gmail.com
73d3b60a2f Merge branch 'dev' 2019-01-23 12:36:16 +08:00
arraykeys@gmail.com
b336b9ce03 a 2019-01-23 12:36:06 +08:00
arraykeys@gmail.com
9654efb952 Merge branch 'dev' 2019-01-22 16:04:50 +08:00
snail007
c3262fc0cb Merge pull request #211 from yincongcyincong/dev
Dev
2019-01-22 16:04:21 +08:00
yincongcyincong
2fef2c0eaa Update README.md 2019-01-22 15:52:26 +08:00
yincongcyincong
3d33cdc9f1 Update README.md 2019-01-22 15:47:20 +08:00
arraykeys@gmail.com
509ad47a71 a 2019-01-22 15:03:53 +08:00
arraykeys@gmail.com
c14a3b2773 a 2019-01-22 14:50:03 +08:00
arraykeys@gmail.com
e6e61b3cdb v6.9 2019-01-22 14:30:45 +08:00
arraykeys@gmail.com
303587f91b fix #210 2019-01-22 14:24:38 +08:00
arraykeys@gmail.com
5c3fd53fab 修复了socks5代理错误处理超时的问题. 2019-01-21 16:58:21 +08:00
arraykeys@gmail.com
0c675e6ff6 sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
现在上级格式: YTpi#2.2.2.2:33080@1
  说明:
  YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
     如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
  # 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
  2.2.2.2:33080 是上级地址
  @1 是设置权重,可以参考手册权重部分.
2019-01-21 16:21:46 +08:00
arraykeys@gmail.com
942b026a05 sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
现在上级格式: YTpi#2.2.2.2:33080@1
  说明:
  YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
     如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
  # 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
  2.2.2.2:33080 是上级地址
  @1 是设置权重,可以参考手册权重部分.
2019-01-21 13:33:51 +08:00
arraykeys@gmail.com
0b347b7f8d sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
现在上级格式: YTpi#2.2.2.2:33080@1
  说明:
  YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
     如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
  # 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
  2.2.2.2:33080 是上级地址
  @1 是设置权重,可以参考手册权重部分.
2019-01-21 12:15:54 +08:00
arraykeys
87322c335e a 2019-01-19 18:54:42 +08:00
arraykeys@gmail.com
1bf4b38268 fix sps start crash 2019-01-07 12:43:44 +08:00
snail007
60b1742088 Merge pull request #205 from snail007/master
fix qq group no.
2018-12-30 17:08:03 +08:00
snail007
266fa6f6fa Update README.md 2018-12-30 17:06:28 +08:00
snail007
02c3c9b374 Update README_ZH.md 2018-12-30 17:05:46 +08:00
arraykeys@gmail.com
8f7da3ed94 sdk log->os.Stdout 2018-12-29 18:28:45 +08:00
arraykeys@gmail.com
a5a6e8645a A 2018-12-29 17:06:07 +08:00
arraykeys@gmail.com
83022d3efc v6.8 2018-12-29 13:29:45 +08:00
arraykeys@gmail.com
78143ce638 Merge branch 'master' into dev 2018-12-27 17:18:48 +08:00
snail007
cee38766c5 Update README.md 2018-12-27 17:17:26 +08:00
snail007
c66147c686 Merge pull request #201 from snail007/master
add more en markdown
2018-12-25 13:13:04 +08:00
snail007
08e149b180 Merge pull request #200 from denji/master
Dockerfile refresh
2018-12-25 13:08:31 +08:00
Denis Denisov
e3f8b652f4 README en-US markdown 2018-12-25 05:03:48 +02:00
Denis Denisov
6a4a45c96b Dockerfile refresh 2018-12-25 04:37:25 +02:00
arraykeys@gmail.com
e5bf95bdc8 a 2018-12-21 17:54:37 +08:00
arraykeys@gmail.com
ed1e7253f3 fix #194
fix #134
2018-12-19 17:28:24 +08:00
arraykeys@gmail.com
db43daea0b Merge branch 'master' into dev 2018-12-14 13:12:14 +08:00
snail007
0359ef40e1 Merge pull request #196 from pkptzx/master
修正Dockerfile无法构建
2018-12-14 13:11:47 +08:00
arraykeys@gmail.com
89b5744e27 Merge branch 'a' into dev 2018-12-14 13:08:52 +08:00
arraykeys@gmail.com
18f293a7aa a 2018-12-14 13:08:34 +08:00
码魂
acf70602ff 1.修正go-src下载地址错误.地址应该为:https://dl.google.com/go/goxxxxx.src.tar.gz
参考:https://blog.csdn.net/warrially/article/details/79879119

2.修正Dockerfile构建失败.
原因: 不知道作者为什么写的时候丢失了镜像名称,不知道为什么多了个build.更搞不清楚为什么这个Dockerfile写的如此复杂,我也懒得简化它了,只修正问题吧...
2018-12-13 19:48:37 +08:00
arraykeys@gmail.com
ebba94b9d1 add profiling support for sdk 2018-12-06 13:01:39 +08:00
arraykeys@gmail.com
23c379faf9 add profiling support for sdk 2018-12-06 10:12:04 +08:00
arraykeys@gmail.com
124852b3a2 add profiling support for sdk 2018-12-05 17:08:05 +08:00
arraykeys@gmail.com
e6d557f61e add profiling support for sdk 2018-12-05 16:27:58 +08:00
arraykeys@gmail.com
0a2ed2e498 add profiling support for sdk 2018-12-05 14:52:59 +08:00
arraykeys@gmail.com
4ce5fd463d add profiling support for sdk 2018-12-05 14:52:00 +08:00
arraykeys@gmail.com
367cfb36dd add profiling support for sdk 2018-12-05 14:09:32 +08:00
arraykeys@gmail.com
57555ffc1e a 2018-12-03 18:06:38 +08:00
arraykeys@gmail.com
8a86a53bd2 add local_ip for auth url 2018-12-03 15:40:52 +08:00
snail007
4a7b1af383 Merge pull request #189 from yincongcyincong/dev
Dev
2018-12-03 11:32:33 +08:00
arraykeys@gmail.com
78e631f551 fix #188 2018-12-03 11:30:55 +08:00
yincongcyincong
0af83540d3 Update README.md 2018-12-03 09:59:26 +08:00
arraykeys@gmail.com
9004913483 a 2018-11-30 13:12:35 +08:00
arraykeys@gmail.com
44909ea6c6 v6.6 2018-11-30 10:56:35 +08:00
arraykeys@gmail.com
a0cd66e319 增加智能模式参数 2018-11-30 10:47:31 +08:00
arraykeys@gmail.com
8c4e5025ed v6.6 2018-11-30 10:16:11 +08:00
arraykeys@gmail.com
442e7b7c01 a 2018-11-30 10:10:39 +08:00
arraykeys@gmail.com
05dfbe6f8a a 2018-11-29 11:23:24 +08:00
arraykeys@gmail.com
c64324227b sdk adding CloseIntelligent 2018-11-21 14:16:21 +08:00
snail007
1388f2e008 Merge pull request #179 from x22x22/x22x22
add close intelligent HTTP, SOCKS5 proxy
2018-11-20 19:51:42 +08:00
x22x22
2752d79248 add close intelligent HTTP, SOCKS5 proxy
为了方便用于代理上网行为管理, 有时候不需要智能判断代理是否可用而进行跳转, 所以增加一个关闭智能跳转代理的参数.
2018-11-20 12:45:24 +08:00
arraykeys@gmail.com
7aa24afcf2 Merge remote-tracking branch 'origin/dev' into dev 2018-11-19 18:39:34 +08:00
arraykeys@gmail.com
b3622e709c a 2018-11-19 18:39:04 +08:00
snail007
02a58189ad Merge pull request #173 from RickieL/RickieL-patch-1
typo fix
2018-11-08 13:57:43 +08:00
yongfu
f42184daaf Update README.md
typo fix
2018-11-08 09:41:29 +08:00
arraykeys@gmail.com
7754fcc13e v6.5 2018-11-01 13:40:02 +08:00
arraykeys@gmail.com
d421b79071 v6.6 2018-11-01 13:39:17 +08:00
arraykeys@gmail.com
80146fbe0d 修复合并企业版遗留的一些bug. 2018-11-01 12:59:56 +08:00
arraykeys@gmail.com
e95a1f8ad5 Merge branch 'master' into dev
# Conflicts:
#	CHANGELOG
2018-10-31 14:54:18 +08:00
arraykeys@gmail.com
9e496f246c a 2018-10-31 14:49:37 +08:00
arraykeys@gmail.com
f0389cdd5b fix #164 2018-10-26 14:25:45 +08:00
arraykeys@gmail.com
bcca92affc 优化了socks5的UDP功能可能存在的内存占用过多问题. 2018-10-23 14:08:29 +08:00
arraykeys@gmail.com
421e72188b a 2018-10-19 16:35:45 +08:00
arraykeys@gmail.com
cc8416e6bf a 2018-10-16 13:00:07 +08:00
arraykeys@gmail.com
fb09a100e1 Merge branch 'dev' 2018-10-16 11:27:38 +08:00
arraykeys@gmail.com
1b1091d75f a 2018-10-16 11:27:18 +08:00
arraykeys@gmail.com
ea30beb79b v6.3 2018-10-15 13:05:37 +08:00
arraykeys@gmail.com
99881e2c70 fix #156 2018-10-09 14:23:22 +08:00
arraykeys@gmail.com
325acb2942 fix #156 2018-10-09 14:21:00 +08:00
arraykeys@gmail.com
6babe1ea10 update vendor 2018-09-28 14:59:03 +08:00
arraykeys@gmail.com
6c586e2b78 Merge branch 'dev' 2018-09-26 12:08:30 +08:00
arraykeys@gmail.com
6917ff3347 a 2018-09-21 18:01:58 +08:00
arraykeys@gmail.com
284bb83d64 1.修复encrypt.Conn释放内存,导致的潜在panic问题.
2.修复了basic认证,处理认证文件没有正确处理注释的bug.
3.修正了ssh中转手册参数-A调整为-D.
2018-09-21 13:57:46 +08:00
arraykeys@gmail.com
1b29112a2c 修复encrypt.Conn释放内存,导致的潜在panic问题. 2018-09-21 12:02:54 +08:00
arraykeys@gmail.com
b9afc98230 修复encrypt.Conn释放内存,导致的潜在panic问题. 2018-09-21 12:01:46 +08:00
arraykeys@gmail.com
20761d2183 修复encrypt.Conn释放内存,导致的潜在panic问题. 2018-09-21 12:01:13 +08:00
arraykeys@gmail.com
1ab07c81ab a 2018-09-19 15:45:15 +08:00
arraykeys@gmail.com
07efc2c8de Merge branch 'dev' 2018-09-19 12:15:15 +08:00
yincongcyincong
69f20e1d7a Update README.md 2018-09-07 09:19:26 +08:00
344 changed files with 186319 additions and 654 deletions

View File

@ -1,13 +1,13 @@
# GoProxy特殊授权 # GoProxy special authorization
1.goproxy采用GPLv3源代码开放协议,未经许可,基于本项目开发的软件,衍生软件,相关软件,必须严格遵守GPLv3,否则一经发现, 1. gproxy uses GPLv3 source code open agreement, without permission, based on the project development software, derivative software, related software, must strictly abide by GPLv3, otherwise once found,
将严厉追责. Will be harshly punished.
2.如果公司或个人使用本项目代码开发相关软件,衍生软件,又不想遵守GPLv3协议,需要取得作者的"GoProxy特殊授权"书面授权. 2. If the company or individual uses the project code to develop related software, derivative software, and does not want to comply with the GPLv3 agreement, need to obtain the author's "GoProxy special authorization" written authorization.
3.如果本页面查询不到"GoProxy特殊授权"书面授权信息,则"GoProxy特殊授权"书面授权无效. 3. If "GoPro special authorization"is not available on this page,the" GoPro special authorization"is invalid.
4.下面列出了有效的授权编号和有效期. 4. A valid authorization number and expiration date are listed below.
授权编号 | 授权有效期 Authorization number | Authorization validity period
:--- | :--- :--- | :---

13
AUTHORIZATION_ZH.md Normal file
View File

@ -0,0 +1,13 @@
# GoProxy特殊授权
1.goproxy采用GPLv3源代码开放协议,未经许可,基于本项目开发的软件,衍生软件,相关软件,必须严格遵守GPLv3,否则一经发现,
将严厉追责.
2.如果公司或个人使用本项目代码开发相关软件,衍生软件,又不想遵守GPLv3协议,需要取得作者的"GoProxy特殊授权"书面授权.
3.如果本页面查询不到"GoProxy特殊授权"书面授权信息,则"GoProxy特殊授权"书面授权无效.
4.下面列出了有效的授权编号和有效期.
授权编号 | 授权有效期
:--- | :---

View File

@ -1,5 +1,53 @@
proxy更新日志 proxy更新日志
v6.9
1.修复了sps的start潜在的crash问题.
2.sps代理增加了--parent-tls-single参数用来支持单向tls上级。
3.sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
现在上级格式: -P YTpi#2.2.2.2:33080@1
说明:
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
2.2.2.2:33080 是上级地址
@1 是设置权重,可以参考手册权重部分.
4.修复了socks5代理错误处理超时的问题.
5.修复了http(s)代理错误处理-Z的问题.
v6.8
1.HTTP(S)\SOCKS5代理,API认证功能,发送给认证接口的参数增加了本地IP,local_ip字段,
代表用户访问的是本地服务器的哪个IP.
2.fix #194 , fix #134 , 代理更稳定.
3.增加了一波英文文档.
v6.6
1.优化了limitconn的关闭逻辑,释放更多资源.
2.http(s)\socks代理增加了--intelligent,智能模式设置,可以是intelligent|direct|parent三者之一,
默认是:intelligent.每个值的含义如下.
--intelligent=direct,不在blocked里面的目标都直连.
--intelligent=parent,不在direct里面的目标都走上级.
--intelligent=intelligent,blocked和direct里面都没有的目标,智能判断是否使用上级访问目标.
v6.5
1.修复了合并企业版遗留的一些bug.
v6.4
1.http(s)代理增加了--jumper参数,可以穿透外部代理连接上级.
2.优化了socks5代理UDP功能可能存在的内存占用过多问题.
3.优化了jumper,避免某些情况下不能正确返回错误的问题.
4.sps代理增加了--jumper参数,可以穿透外部代理连接上级.
5.修复了--debug不能正常工作的问题.
v6.3
1.fixed #156
2.修复DNS代理,没有定时保存缓存结果到文件.重启会降低查询速度.
v6.2
1.修复encrypt.Conn释放内存,导致的潜在panic问题.
2.修复了basic认证,处理认证文件没有正确处理注释的bug.
3.修正了ssh中转手册参数-A调整为-D.
v6.1 v6.1
1.黑白名单支持设置顶级域了,比如:com,匹配所有的.com域名 1.黑白名单支持设置顶级域了,比如:com,匹配所有的.com域名
2.优化TCPS内存释放. 2.优化TCPS内存释放.

View File

@ -1,82 +0,0 @@
FROM alpine:3.7 AS builder
RUN apk add --no-cache \
ca-certificates
# set up nsswitch.conf for Go's "netgo" implementation
# - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275
# - docker run --rm debian:stretch grep '^hosts:' /etc/nsswitch.conf
RUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf
ENV GOLANG_VERSION 1.10.3
# make-sure-R0-is-zero-before-main-on-ppc64le.patch: https://github.com/golang/go/commit/9aea0e89b6df032c29d0add8d69ba2c95f1106d9 (Go 1.9)
#COPY *.patch /go-alpine-patches/
RUN set -eux; \
apk add --no-cache --virtual .build-deps \
bash \
gcc \
musl-dev \
openssl \
go \
; \
export \
# set GOROOT_BOOTSTRAP such that we can actually build Go
GOROOT_BOOTSTRAP="$(go env GOROOT)" \
# ... and set "cross-building" related vars to the installed system's values so that we create a build targeting the proper arch
# (for example, if our build host is GOARCH=amd64, but our build env/image is GOARCH=386, our build needs GOARCH=386)
GOOS="$(go env GOOS)" \
GOARCH="$(go env GOARCH)" \
GOHOSTOS="$(go env GOHOSTOS)" \
GOHOSTARCH="$(go env GOHOSTARCH)" \
; \
# also explicitly set GO386 and GOARM if appropriate
# https://github.com/docker-library/golang/issues/184
apkArch="$(apk --print-arch)"; \
case "$apkArch" in \
armhf) export GOARM='6' ;; \
x86) export GO386='387' ;; \
esac; \
\
wget -O go.tgz "https://golang.org/dl/go$GOLANG_VERSION.src.tar.gz"; \
echo '567b1cc66c9704d1c019c50bef946272e911ec6baf244310f87f4e678be155f2 *go.tgz' | sha256sum -c -; \
tar -C /usr/local -xzf go.tgz; \
rm go.tgz; \
\
cd /usr/local/go/src; \
for p in /go-alpine-patches/*.patch; do \
[ -f "$p" ] || continue; \
patch -p2 -i "$p"; \
done; \
./make.bash; \
\
rm -rf /go-alpine-patches; \
apk del .build-deps; \
\
export PATH="/usr/local/go/bin:$PATH"; \
go version
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
ARG GOPROXY_VERSION=master
RUN apk update; apk upgrade; \
apk add --no-cache git; \
cd /go/src/; \
mkdir github.com; \
mkdir github.com/snail007; \
cd github.com/snail007; \
git clone https://github.com/snail007/goproxy.git; \
cd goproxy; \
git checkout ${GOPROXY_VERSION}; \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -a -installsuffix cgo -o proxy; \
chmod 0777 proxy
FROM 1.10.3-stretch
RUN mkdir /proxy && chmod 0777 /proxy
COPY --from=builder builder /go/src/github.com/snail007/goproxy/proxy /proxy/
CMD cd /proxy && /proxy ${OPTS}

20
Gopkg.lock generated
View File

@ -1,6 +1,12 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/Yawning/chacha20"
packages = ["."]
revision = "e3b1f968fc6397b51d963fee8ec8711a47bc0ce8"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "github.com/alecthomas/template" name = "github.com/alecthomas/template"
@ -28,6 +34,12 @@
packages = ["."] packages = ["."]
revision = "3520598351bb3500a49ae9563f5539666ae0a27c" revision = "3520598351bb3500a49ae9563f5539666ae0a27c"
[[projects]]
name = "github.com/juju/ratelimit"
packages = ["."]
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
version = "1.0.1"
[[projects]] [[projects]]
name = "github.com/klauspost/cpuid" name = "github.com/klauspost/cpuid"
packages = ["."] packages = ["."]
@ -119,6 +131,12 @@
] ]
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196" revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "dad3d9fb7b6e83d0f9ac8f54670f6334c3a287b4"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "golang.org/x/time" name = "golang.org/x/time"
@ -134,6 +152,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "eab0ef29432489696d8bfd524757dcb03a83f91c329f2d05c36da70df850360d" inputs-digest = "15e4e23c0695db1458b3dc5514c8765be091a420c923b24bb9e186f43400995f"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -1,6 +1,7 @@
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss proxy server implemented by golang. It supports parent proxy,nat forward,TCP/UDP port forwarding, SSH transfer, TLS encrypted transmission, protocol conversion. you can expose a local server behind a NAT or firewall to the internet, secure DNS proxy.   Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss proxy server implemented by golang. It supports parent proxy,nat forward,TCP/UDP port forwarding, SSH transfer, TLS encrypted transmission, protocol conversion. you can expose a local server behind a NAT or firewall to the internet, secure DNS proxy.  
[Download](https://github.com/snail007/goproxy/releases)
--- ---
@ -8,11 +9,11 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss
**[中文手册](/README_ZH.md)** **[中文手册](/README_ZH.md)**
**[全平台图形界面版本](/gui/README.md)** **[Full-platform graphical interface version](/gui/README.md)**
**[全平台SDK](/sdk/README.md)** **[Full platform SDK](https://github.com/snail007/goproxy-sdk/blob/master/README.md)**
**[GoProxy特殊授权](/AUTHORIZATION.md)** **[GoProxy special authorization](/AUTHORIZATION.md)**
### How to contribute to the code (Pull Request)? ### How to contribute to the code (Pull Request)?
@ -100,7 +101,8 @@ This page is the v6.0 manual, and the other version of the manual can be checked
- [1.15 speed limit](#115-speed-limit) - [1.15 speed limit](#115-speed-limit)
- [1.16 Designated exporting IP](#116-designated-export-ip) - [1.16 Designated exporting IP](#116-designated-export-ip)
- [1.17 Certificate parameters using Base64 data](#117-certificate-parameters-using-Base64-data) - [1.17 Certificate parameters using Base64 data](#117-certificate-parameters-using-Base64-data)
- [1.18 View help](#118view-help) - [1.18 Intelligent mode](#118-intelligent-mode)
- [1.19 View help](#119view-help)
- [2.TCP proxy](#2tcp-proxy) - [2.TCP proxy](#2tcp-proxy)
- [2.1 Common TCP first level proxy](#21common-tcp-first-level-proxy) - [2.1 Common TCP first level proxy](#21common-tcp-first-level-proxy)
- [2.2 Common TCP second level proxy](#22common-tcp-second-level-proxy) - [2.2 Common TCP second level proxy](#22common-tcp-second-level-proxy)
@ -145,7 +147,8 @@ This page is the v6.0 manual, and the other version of the manual can be checked
- [5.14 Designated exporting IP](#514-designated-exporting-ip) - [5.14 Designated exporting IP](#514-designated-exporting-ip)
- [5.15 Cascade authentication](#515-cascade-authentication) - [5.15 Cascade authentication](#515-cascade-authentication)
- [5.16 Certificate parameters using Base64 data](#516-certificate-parameters-using-base64-data) - [5.16 Certificate parameters using Base64 data](#516-certificate-parameters-using-base64-data)
- [5.17 View help](#517view-help) - [5.17 Intelligent mode](#517-intelligent-mode)
- [5.18 View help](#518view-help)
- [6.Proxy protocol conversion](#6proxy-protocol-conversion) - [6.Proxy protocol conversion](#6proxy-protocol-conversion)
- [6.1 Functional introduction](#61functional-introduction) - [6.1 Functional introduction](#61functional-introduction)
- [6.2 HTTP(S) to HTTP(S) + SOCKS5](#62http-to-http-socks5) - [6.2 HTTP(S) to HTTP(S) + SOCKS5](#62http-to-http-socks5)
@ -199,6 +202,8 @@ chmod +x install.sh
#### Docker installation #### Docker installation
[docker](https://hub.docker.com/r/snail007/goproxy)
Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version. Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version.
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 6.0: 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 6.0:
@ -323,7 +328,7 @@ accessing the local 8080 port is accessing the proxy port 38080 above VPS.  
HTTP second level proxy(local windows) HTTP second level proxy(local windows)
`./proxy.exe http -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key` `./proxy.exe http -t tcp -p ":8080" -T tls -P "22.22.22.22:38080" -C proxy.crt -K proxy.key`
In your windos system, the mode of the program that needs to surf the Internet by proxy is setted up as HTTP mode, the address is 127.0.0.1, the port is: 8080, the program can go through the encrypted channel through VPS to surf on the internet. In your windows system, the mode of the program that needs to surf the Internet by proxy is setted up as HTTP mode, the address is 127.0.0.1, the port is: 8080, the program can go through the encrypted channel through VPS to surf on the internet.
#### **1.4.HTTP third level encrypted proxy** #### **1.4.HTTP third level encrypted proxy**
![1.4](/docs/images/http-tls-3.png) ![1.4](/docs/images/http-tls-3.png)
@ -513,14 +518,22 @@ The speed limit is 100K, which can be specified through the `-l` parameter, for
`proxy http -t tcp -p 2.2.2.2:33080 -l 100K` `proxy http -t tcp -p 2.2.2.2:33080 -l 100K`
### **1.16 Designated exporting IP** ### **1.16 Designated exporting IP**
The `- bind-listen` parameter opens the client's ability to access the target site with an entry IP connection, using the entry IP as the exporting IP. If the entry IP is the intranet IP, the exporting IP will not use the entry IP.. The `--bind-listen` parameter open the client's ability to access the target site with an entry IP connection, using the entry IP as the exporting IP. If the entry IP is the intranet IP, the exporting IP will not use the entry IP..
`proxy http -t tcp -p 2.2.2.2:33080 --bind-listen` `proxy http -t tcp -p 2.2.2.2:33080 --bind-listen`
### **1.17 Certificate parameters using Base64 data** ### **1.17 Certificate parameters using Base64 data**
By default, the -C and -K parameters are the paths of CRT certificates and key files, By default, the -C and -K parameters are the paths of CRT certificates and key files,
If it is the beginning of base64://, then it is considered that the data behind is Base64 encoded and will be used after decoding. If it is the beginning of base64://, then it is considered that the data behind is Base64 encoded and will be used after decoding.
#### **1.18.view help** #### **1.18 Intelligent mode**
Intelligent mode setting which can be one of intelligent|direct|parent.
default:intelligent.
The meaning of each value is as follows:
`--intelligent=direct`, Targets that are not in blocked directly connected.
`--intelligent=parent`, Targets that are not in direct connect to parent proxy.
`--intelligent=intelligent`, Targets that are not in direct and blocked Neither can intelligently judge on whether to connetc parent proxy.
#### **1.19.view help**
`./proxy help http` `./proxy help http`
### **2.TCP proxy** ### **2.TCP proxy**
@ -959,9 +972,17 @@ localhost:
#### **5.16 Certificate parameters using Base64 data** #### **5.16 Certificate parameters using Base64 data**
By default, the -C and -K parameters are the paths of CRT certificates and key files, By default, the -C and -K parameters are the paths of CRT certificates and key files,
If it is the beginning of base64://, then it is considered that the data behind is Base64 encoded and will be used after decoding.. If it is the beginning of base64://, then it is considered that the data behind is Base64 encoded and will be used after decoding.
#### **5.17.view help** #### **5.17 Intelligent mode**
Intelligent mode setting which can be one of intelligent|direct|parent.
default:intelligent.
The meaning of each value is as follows:
`--intelligent=direct`, Targets that are not in blocked directly connected.
`--intelligent=parent`, Targets that are not in direct connect to parent proxy.
`--intelligent=intelligent`, Targets that are not in direct and blocked Neither can intelligently judge on whether to connetc parent proxy.
#### **5.18.view help**
`./proxy help socks` `./proxy help socks`
### **6.Proxy protocol conversion** ### **6.Proxy protocol conversion**
@ -1068,6 +1089,19 @@ target: if the client is the HTTP (s) proxy request, this represents the complet
If there is no -a or -F or --auth-url parameters, local authentication is closed. If there is no -a or -F or --auth-url parameters, local authentication is closed.
If there is no -A parameter, the connection to the father proxy does not use authentication. If there is no -A parameter, the connection to the father proxy does not use authentication.
**Setting up separate authentication information**
If there are many different parent proxys and their passwords are the same or different, then authentication information can be set for each parent proxy.
At the same time, a global authentication information can be set with the - A parameter. If a parent proxy does not set the authentication information separately, the global authentication information can be used.
Authentication information is written together with parent proxy.
format: YTpi#2.2.2.2:33080@1
Explain:
YTpi is the Authentication information encoded by Base64, For example, http (s)/socks original authentication information, a:b,the user is a and the password is b, which is YTpi after Base64 encoding.
if it is ss, A is the encryption method and B is the password, for example, aes-192-cfb:your_pass, which is YWVzLTE5Mi1jZmI6eW91cl9wYXNz after Base64 encoding.
\# is an interval symbol. If there is authentication information, there must be #. No authentication information can be omitted #
2.2.2.2:33080 is parent proxy's address
@1 is weights, Nothing can be omitted. Detailed instructions can be referred to in the manual.***weights***
#### **6.8 Custom encryption** #### **6.8 Custom encryption**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted. HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples: Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
@ -1104,7 +1138,7 @@ through this way, When you visits the website by local proxy 8080, it visits the
**three level example** **three level example**
First level VPS (ip:2.2.2.2) execution: First level VPS (ip:2.2.2.2) execution:
`proxy sps -t tcp -m -p :7777` `proxy sps -t tcp -m -p :7777`
Second level VPS (ip:3.3.3.3) execution:: Second level VPS (ip:3.3.3.3) execution:
`proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888` `proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
Local third level execution: Local third level execution:
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080` `proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
@ -1123,7 +1157,7 @@ Suppose there has a SOCKS5 parent proxy:
`proxy socks -p 2.2.2.2:33080 -z password -t tcp` `proxy socks -p 2.2.2.2:33080 -z password -t tcp`
SPS lower speed limit 100K SPS lower speed limit 100K
`proxy sps -S socks -P 2.2.2.2:33080 -T tcp -Z password -l 100K -t tcp -p :33080` `proxy sps -S socks -P 2.2.2.2:33080 -T tcp -Z password -l 100K -t tcp -p :33080`
It can be specified through the `-l` parameter, for example: 100K 1.5M. 0 means unlimited.. It can be specified through the `-l` parameter, for example: 100K 1.5M. 0 means unlimited.
#### **6.12 Designated exporting IP** #### **6.12 Designated exporting IP**
The `- bind-listen` parameter opens the client's ability to access the target site with an entry IP connection, using the entry IP as the exporting IP. If the entry IP is the intranet IP, the exporting IP will not use the entry IP. The `- bind-listen` parameter opens the client's ability to access the target site with an entry IP connection, using the entry IP as the exporting IP. If the entry IP is the intranet IP, the exporting IP will not use the entry IP.
@ -1251,16 +1285,15 @@ execution: `go run *.go`
### License ### License
Proxy is licensed under GPLv3 license. Proxy is licensed under GPLv3 license.
### Contact ### Contact
proxy QQ group:189618940 proxy QQ group: 793015219 , 189618940 (full)
### Donation ### Donation
if proxy help you a lot,you can support us by: if proxy help you a lot,you can support us by:
### AliPay ### AliPay
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/>
### Wechat Pay ### Wechat Pay
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/wxpay.jpg?raw=true" width="200"/>

View File

@ -1,7 +1,7 @@
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。 Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群:189618940 [点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群: 793015219 (2群), 189618940 (1群满)
--- ---
@ -9,11 +9,11 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
**[English Manual](/README.md)** **[English Manual](/README.md)**
**[全平台图形界面版本](/gui/README.md)** **[全平台图形界面版本](/gui/README_ZH.md)**
**[全平台SDK](/sdk/README.md)** **[全平台SDK](https://github.com/snail007/goproxy-sdk/blob/master/README_ZH.md)**
**[GoProxy特殊授权](/AUTHORIZATION.md)** **[GoProxy特殊授权](/AUTHORIZATION_ZH.md)**
### 如何贡献代码(Pull Request)? ### 如何贡献代码(Pull Request)?
@ -56,7 +56,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
- ... - ...
本页是v5.4手册,其他版本手册请点击[这里](docs/old-release.md)查看. 本页是v5.4手册,其他版本手册请点击[这里](docs/old-release-zh.md)查看.
### 怎么找到组织? ### 怎么找到组织?
@ -99,7 +99,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
- [1.15 限速](#115-限速) - [1.15 限速](#115-限速)
- [1.16 指定出口IP](#116-指定出口ip) - [1.16 指定出口IP](#116-指定出口ip)
- [1.17 证书参数使用base64数据](#117-证书参数使用base64数据) - [1.17 证书参数使用base64数据](#117-证书参数使用base64数据)
- [1.18 查看帮助](#118-查看帮助) - [1.18 智能模式](#118-智能模式)
- [1.19 查看帮助](#119-查看帮助)
- [2. TCP代理(端口映射)](#2tcp代理) - [2. TCP代理(端口映射)](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理) - [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理) - [2.2 普通二级TCP代理](#22普通二级tcp代理)
@ -144,7 +145,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
- [5.14 指定出口IP](#514-指定出口ip) - [5.14 指定出口IP](#514-指定出口ip)
- [5.15 级联认证](#515-级联认证) - [5.15 级联认证](#515-级联认证)
- [5.16 证书参数使用base64数据](#516-证书参数使用base64数据) - [5.16 证书参数使用base64数据](#516-证书参数使用base64数据)
- [5.17 查看帮助](#517查看帮助) - [5.17 智能模式](#517-智能模式)
- [5.18 查看帮助](#518-查看帮助)
- [6. 代理协议转换](#6代理协议转换) - [6. 代理协议转换](#6代理协议转换)
- [6.1 功能介绍](#61-功能介绍) - [6.1 功能介绍](#61-功能介绍)
- [6.2 HTTP(S)转HTTP(S)+SOCKS5+SS](#62-https转httpssocks5ss) - [6.2 HTTP(S)转HTTP(S)+SOCKS5+SS](#62-https转httpssocks5ss)
@ -171,21 +173,27 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
提示:所有操作需要root权限. 提示:所有操作需要root权限.
#### 自动安装 #### 自动安装
#### **0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.** #### **0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
```shell ```shell
curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
``` ```
安装完成,配置目录是/etc/proxy,更详细的使用方法请参考上面的手册目录,进一步了解你想要使用的功能. 安装完成,配置目录是/etc/proxy,更详细的使用方法请参考上面的手册目录,进一步了解你想要使用的功能.
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装: 如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
#### 手动安装 #### 手动安装
#### **1.下载proxy** #### **1.下载proxy**
下载地址:https://github.com/snail007/goproxy/releases 下载地址:https://github.com/snail007/goproxy/releases/latest
下面以v6.2为例,如果有最新版,请使用最新版链接.
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v6.1/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v6.2/proxy-linux-amd64.tar.gz
``` ```
#### **2.下载自动安装脚本** #### **2.下载自动安装脚本**
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
@ -194,6 +202,9 @@ chmod +x install.sh
``` ```
#### Docker安装 #### Docker安装
[docker](https://hub.docker.com/r/snail007/goproxy)
项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本, 项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile 全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
或者使用参数GOPROXY_VERSION指定构建的goproxy版本. 或者使用参数GOPROXY_VERSION指定构建的goproxy版本.
@ -358,11 +369,12 @@ weight 根据每个上级的权重和连接数情况,选择出一个上级
比如: 比如:
`./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"), 用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,target四个参数: 带上user,pass,ip,local_ip,target五个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET} http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}&target={TARGET}
user:用户名 user:用户名
pass:密码 pass:密码
ip:用户的IP,比如:192.168.1.200 ip:用户的IP,比如:192.168.1.200
local_ip:用户访问的服务器的IP,比如:3.3.3.3
target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80 target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80
如果没有-a或-F或--auth-url参数,就是关闭Basic认证. 如果没有-a或-F或--auth-url参数,就是关闭Basic认证.
@ -380,7 +392,7 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
##### ***1.7.1 ssh用户名和密码的方式*** ##### ***1.7.1 ssh用户名和密码的方式***
本地HTTP(S)代理28080端口,执行: 本地HTTP(S)代理28080端口,执行:
`./proxy http -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"` `./proxy http -T ssh -P "2.2.2.2:22" -u user -D demo -t tcp -p ":28080"`
##### ***1.7.2 ssh用户名和密钥的方式*** ##### ***1.7.2 ssh用户名和密钥的方式***
本地HTTP(S)代理28080端口,执行: 本地HTTP(S)代理28080端口,执行:
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"` `./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
@ -545,7 +557,15 @@ HTTP(S)代理支持上级负载均衡,多个上级重复-P参数即可.
如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用. 如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
#### **1.18 查看帮助** #### **1.18 智能模式**
智能模式设置,可以是intelligent|direct|parent三者之一.
默认是:intelligent.
每个值的含义如下:
`--intelligent=direct`,不在blocked里面的目标都直连.
`--intelligent=parent`,不在direct里面的目标都走上级.
`--intelligent=intelligent`,blocked和direct里面都没有的目标,智能判断是否使用上级访问目标.
#### **1.19 查看帮助**
`./proxy help http` `./proxy help http`
### **2.TCP代理** ### **2.TCP代理**
@ -879,7 +899,7 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
##### ***5.6.1 ssh用户名和密码的方式*** ##### ***5.6.1 ssh用户名和密码的方式***
本地SOCKS5代理28080端口,执行: 本地SOCKS5代理28080端口,执行:
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -A demo -t tcp -p ":28080"` `./proxy socks -T ssh -P "2.2.2.2:22" -u user -D demo -t tcp -p ":28080"`
##### ***5.6.2 ssh用户名和密钥的方式*** ##### ***5.6.2 ssh用户名和密钥的方式***
本地SOCKS5代理28080端口,执行: 本地SOCKS5代理28080端口,执行:
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"` `./proxy socks -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
@ -899,11 +919,12 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
比如: 比如:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"), 用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,个参数: 带上user,pass,ip,local_ip四个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP} http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}
user:用户名 user:用户名
pass:密码 pass:密码
ip:用户的IP,比如:192.168.1.200 ip:用户的IP,比如:192.168.1.200
local_ip:用户访问的服务器的IP,比如:3.3.3.3
如果没有-a或-F或--auth-url参数,就是关闭认证. 如果没有-a或-F或--auth-url参数,就是关闭认证.
@ -1024,7 +1045,15 @@ SOCKS5支持级联认证,-A可以设置上级认证信息.
如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用. 如果是base64://开头,那么就认为后面的数据是base64编码的,会解码后使用.
#### **5.17.查看帮助** #### **5.17 智能模式**
智能模式设置,可以是intelligent|direct|parent三者之一.
默认是:intelligent.
每个值的含义如下:
`--intelligent=direct`,不在blocked里面的目标都直连.
`--intelligent=parent`,不在direct里面的目标都走上级.
`--intelligent=intelligent`,blocked和direct里面都没有的目标,智能判断是否使用上级访问目标.
#### **5.18.查看帮助**
`./proxy help socks` `./proxy help socks`
### **6.代理协议转换** ### **6.代理协议转换**
@ -1131,6 +1160,18 @@ target:如果客户端是http(s)代理请求,这里代表的是请求的完整ur
如果没有-a或-F或--auth-url参数,就是关闭本地认证. 如果没有-a或-F或--auth-url参数,就是关闭本地认证.
如果没有-A参数,连接上级不使用认证. 如果没有-A参数,连接上级不使用认证.
**设置单独认证信息**
如果存在多个不同上级,而且他们的密码有的一样有的不一样,那么可以针对每个上级设置认证信息,
同时还可以用-A参数设置一个全局认证信息,如果某个上级没有单独设置认证信息就使用全局设置的认证信息.
认证信息和上级写在一起.
格式是: YTpi#2.2.2.2:33080@1
说明:
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#
2.2.2.2:33080 是上级地址
@1 是设置权重,没有可以省略,详细说明可以参考手册***权重部分***
#### **6.8 自定义加密** #### **6.8 自定义加密**
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行 proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
@ -1344,7 +1385,7 @@ utils是工具包,service是具体的每个服务类.
### License ### License
Proxy is licensed under GPLv3 license. Proxy is licensed under GPLv3 license.
### Contact ### Contact
QQ交流群:189618940 官方QQ交流群: 793015219 (2群), 189618940 (1群满)
### Donation ### Donation

View File

@ -1 +1 @@
6.1 6.9

View File

@ -34,11 +34,12 @@ import (
) )
var ( var (
app *kingpin.Application app *kingpin.Application
service *services.ServiceItem service *services.ServiceItem
cmd *exec.Cmd cmd *exec.Cmd
cpuProfilingFile, memProfilingFile, blockProfilingFile, goroutineProfilingFile, threadcreateProfilingFile *os.File cpuProfilingFile, memProfilingFile, blockProfilingFile,
isDebug bool goroutineProfilingFile, threadcreateProfilingFile *os.File
isDebug *bool
) )
func initConfig() (err error) { func initConfig() (err error) {
@ -60,7 +61,7 @@ func initConfig() (err error) {
//build srvice args //build srvice args
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version(APP_VERSION) app.Author("snail").Version(APP_VERSION)
isDebug := app.Flag("debug", "debug log output").Default("false").Bool() isDebug = app.Flag("debug", "debug log output").Default("false").Bool()
daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool() daemon := app.Flag("daemon", "run proxy in background").Default("false").Bool()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool() forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String() logfile := app.Flag("log", "log file path").Default("").String()
@ -116,13 +117,15 @@ func initConfig() (err error) {
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
httpArgs.LoadBalanceMethod = http.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash") httpArgs.Intelligent = http.Flag("intelligent", "settting intelligent HTTP, SOCKS5 proxy mode, can be <intelligent|direct|parent>").Default("intelligent").Enum("intelligent", "direct", "parent")
httpArgs.LoadBalanceMethod = http.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("roundrobin").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
httpArgs.LoadBalanceTimeout = http.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int() httpArgs.LoadBalanceTimeout = http.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
httpArgs.LoadBalanceRetryTime = http.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int() httpArgs.LoadBalanceRetryTime = http.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
httpArgs.LoadBalanceHashTarget = http.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() httpArgs.LoadBalanceHashTarget = http.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
httpArgs.LoadBalanceOnlyHA = http.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() httpArgs.LoadBalanceOnlyHA = http.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
httpArgs.RateLimit = http.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() httpArgs.RateLimit = http.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
httpArgs.BindListen = http.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool() httpArgs.BindListen = http.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool()
httpArgs.Jumper = http.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
httpArgs.Debug = isDebug httpArgs.Debug = isDebug
//########tcp######### //########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode") tcp := app.Command("tcp", "proxy on tcp mode")
@ -219,7 +222,7 @@ func initConfig() (err error) {
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int() tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########ssh######### //########socks#########
socks := app.Command("socks", "proxy on ssh mode") socks := app.Command("socks", "proxy on ssh mode")
socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').Strings() socksArgs.Parent = socks.Flag("parent", "parent ssh address, such as: \"23.32.32.19:22\"").Default("").Short('P').Strings()
socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh") socksArgs.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
@ -251,7 +254,8 @@ func initConfig() (err error) {
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
socksArgs.LoadBalanceMethod = socks.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash") socksArgs.Intelligent = socks.Flag("intelligent", "settting intelligent HTTP, SOCKS5 proxy mode, can be <intelligent|direct|parent>").Default("intelligent").Enum("intelligent", "direct", "parent")
socksArgs.LoadBalanceMethod = socks.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("roundrobin").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
socksArgs.LoadBalanceTimeout = socks.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int() socksArgs.LoadBalanceTimeout = socks.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
socksArgs.LoadBalanceRetryTime = socks.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int() socksArgs.LoadBalanceRetryTime = socks.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
socksArgs.LoadBalanceHashTarget = socks.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() socksArgs.LoadBalanceHashTarget = socks.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
@ -260,7 +264,7 @@ func initConfig() (err error) {
socksArgs.BindListen = socks.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool() socksArgs.BindListen = socks.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool()
socksArgs.Debug = isDebug socksArgs.Debug = isDebug
//########socks+http(s)######### //########sps#########
sps := app.Command("sps", "proxy on socks+http(s) mode") sps := app.Command("sps", "proxy on socks+http(s) mode")
spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').Strings() spsArgs.Parent = sps.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').Strings()
spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String() spsArgs.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
@ -292,12 +296,14 @@ func initConfig() (err error) {
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool() spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool() spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
spsArgs.DisableSS = sps.Flag("disable-ss", "disable ss proxy").Default("false").Bool() spsArgs.DisableSS = sps.Flag("disable-ss", "disable ss proxy").Default("false").Bool()
spsArgs.LoadBalanceMethod = sps.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash") spsArgs.LoadBalanceMethod = sps.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("roundrobin").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
spsArgs.LoadBalanceTimeout = sps.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int() spsArgs.LoadBalanceTimeout = sps.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
spsArgs.LoadBalanceRetryTime = sps.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int() spsArgs.LoadBalanceRetryTime = sps.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
spsArgs.LoadBalanceHashTarget = sps.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceHashTarget = sps.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
spsArgs.Debug = isDebug spsArgs.Debug = isDebug
//########dns######### //########dns#########

View File

@ -137,7 +137,7 @@ func (c *Conn) start() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
c.reader() c.reader()

View File

@ -155,7 +155,7 @@ func (m ConcurrentMap) Iter() <-chan Tuple {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
fanIn(chans, ch) fanIn(chans, ch)
@ -174,7 +174,7 @@ func (m ConcurrentMap) IterBuffered() <-chan Tuple {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
fanIn(chans, ch) fanIn(chans, ch)
@ -195,7 +195,7 @@ func snapshot(m ConcurrentMap) (chans []chan Tuple) {
go func(index int, shard *ConcurrentMapShared) { go func(index int, shard *ConcurrentMapShared) {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
// Foreach key, value pair. // Foreach key, value pair.
@ -221,7 +221,7 @@ func fanIn(chans []chan Tuple, out chan Tuple) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
func(ch chan Tuple) { func(ch chan Tuple) {
@ -274,7 +274,7 @@ func (m ConcurrentMap) Keys() []string {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
// Foreach shard. // Foreach shard.
@ -284,7 +284,7 @@ func (m ConcurrentMap) Keys() []string {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
func(shard *ConcurrentMapShared) { func(shard *ConcurrentMapShared) {

View File

@ -2,6 +2,7 @@ package encrypt
import ( import (
"crypto/cipher" "crypto/cipher"
"fmt"
"io" "io"
"net" "net"
@ -33,15 +34,23 @@ func NewConn(c net.Conn, method, password string) (conn net.Conn, err error) {
return return
} }
func (s *Conn) Read(b []byte) (n int, err error) { func (s *Conn) Read(b []byte) (n int, err error) {
if s.r == nil {
return 0, fmt.Errorf("use of closed network connection")
}
return s.r.Read(b) return s.r.Read(b)
} }
func (s *Conn) Write(b []byte) (n int, err error) { func (s *Conn) Write(b []byte) (n int, err error) {
if s.w == nil {
return 0, fmt.Errorf("use of closed network connection")
}
return s.w.Write(b) return s.w.Write(b)
} }
func (s *Conn) Close() (err error) { func (s *Conn) Close() (err error) {
err = s.Conn.Close() if s.Cipher != nil {
s.Cipher = nil err = s.Conn.Close()
s.r = nil s.Cipher = nil
s.w = nil s.r = nil
return err s.w = nil
}
return
} }

View File

@ -62,7 +62,7 @@ func (s *IOBinder) AliveWithServeConn(srcAddr string, inTCPConn *net.Conn) *IOBi
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
buf := make([]byte, 1) buf := make([]byte, 1)
@ -75,7 +75,7 @@ func (s *IOBinder) AliveWithServeConn(srcAddr string, inTCPConn *net.Conn) *IOBi
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
for { for {
@ -96,7 +96,7 @@ func (s *IOBinder) AliveWithClientConn(srcAddr string, outTCPConn *net.Conn) *IO
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
buf := make([]byte, 1) buf := make([]byte, 1)
@ -156,7 +156,7 @@ func (s *IOBinder) Run() (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
defer func() { defer func() {

View File

@ -14,7 +14,7 @@ import (
) )
type BasicAuther interface { type BasicAuther interface {
CheckUserPass(username, password, fromIP, ToTarget string) bool CheckUserPass(username, password, userIP, localIP, toTarget string) bool
} }
type Request struct { type Request struct {
ver uint8 ver uint8
@ -239,15 +239,16 @@ func (s *ServerConn) Target() string {
} }
func (s *ServerConn) Handshake() (err error) { func (s *ServerConn) Handshake() (err error) {
remoteAddr := (*s.conn).RemoteAddr() remoteAddr := (*s.conn).RemoteAddr()
localAddr := (*s.conn).LocalAddr()
//协商开始 //协商开始
//method select request //method select request
var methodReq MethodsRequest var methodReq MethodsRequest
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq, e := NewMethodsRequest((*s.conn), s.header) methodReq, e := NewMethodsRequest((*s.conn), s.header)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if e != nil { if e != nil {
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE) methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
err = fmt.Errorf("new methods request fail,ERR: %s", e) err = fmt.Errorf("new methods request fail,ERR: %s", e)
@ -264,7 +265,7 @@ func (s *ServerConn) Handshake() (err error) {
// } // }
s.method = socks5c.Method_NO_AUTH s.method = socks5c.Method_NO_AUTH
//method select reply //method select reply
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
err = methodReq.Reply(socks5c.Method_NO_AUTH) err = methodReq.Reply(socks5c.Method_NO_AUTH)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -275,7 +276,7 @@ func (s *ServerConn) Handshake() (err error) {
} else { } else {
//auth //auth
if !methodReq.Select(socks5c.Method_USER_PASS) { if !methodReq.Select(socks5c.Method_USER_PASS) {
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE) methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
err = fmt.Errorf("none method found : Method_USER_PASS") err = fmt.Errorf("none method found : Method_USER_PASS")
@ -283,7 +284,7 @@ func (s *ServerConn) Handshake() (err error) {
} }
s.method = socks5c.Method_USER_PASS s.method = socks5c.Method_USER_PASS
//method reply need auth //method reply need auth
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
err = methodReq.Reply(socks5c.Method_USER_PASS) err = methodReq.Reply(socks5c.Method_USER_PASS)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -293,7 +294,7 @@ func (s *ServerConn) Handshake() (err error) {
//read auth //read auth
buf := make([]byte, 500) buf := make([]byte, 500)
var n int var n int
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
n, err = (*s.conn).Read(buf) n, err = (*s.conn).Read(buf)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -305,9 +306,10 @@ func (s *ServerConn) Handshake() (err error) {
s.password = string(r[2+r[1]+1:]) s.password = string(r[2+r[1]+1:])
//err = fmt.Errorf("user:%s,pass:%s", user, pass) //err = fmt.Errorf("user:%s,pass:%s", user, pass)
//auth //auth
_addr := strings.Split(remoteAddr.String(), ":") _userAddr := strings.Split(remoteAddr.String(), ":")
if s.auth == nil || (*s.auth).CheckUserPass(s.user, s.password, _addr[0], "") { _localAddr := strings.Split(localAddr.String(), ":")
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) if s.auth == nil || (*s.auth).CheckUserPass(s.user, s.password, _userAddr[0], _localAddr[0], "") {
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
_, err = (*s.conn).Write([]byte{0x01, 0x00}) _, err = (*s.conn).Write([]byte{0x01, 0x00})
(*s.conn).SetDeadline(time.Time{}) (*s.conn).SetDeadline(time.Time{})
if err != nil { if err != nil {
@ -315,7 +317,7 @@ func (s *ServerConn) Handshake() (err error) {
return return
} }
} else { } else {
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) (*s.conn).SetDeadline(time.Now().Add(s.timeout))
_, err = (*s.conn).Write([]byte{0x01, 0x01}) _, err = (*s.conn).Write([]byte{0x01, 0x01})
(*s.conn).SetDeadline(time.Time{}) (*s.conn).SetDeadline(time.Time{})
if err != nil { if err != nil {
@ -327,7 +329,7 @@ func (s *ServerConn) Handshake() (err error) {
} }
} }
//request detail //request detail
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
request, e := NewRequest(*s.conn) request, e := NewRequest(*s.conn)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if e != nil { if e != nil {

View File

@ -1,35 +1,35 @@
# 透传用户IP手册 # Pass-through user IP manual
说明: ## Description:
通过Linux的TPROXY功能,可以实现源站服务程序可以看见客户端真实IP,实现该功能需要linux操作系统和程序都要满足一定的条件. By Linux TPROXY function,you can achieve the source Station service program can see the client's real IP, to achieve this feature requires linux operating systems and programs must meet certain conditions.
环境要求: ## Environmental requirements:
源站必须是运行在Linux上面的服务程序,同时Linux需要满足下面条件: The source station must be a service program running on Linux, and Linux needs to meet the following conditions:
1.Linux内核版本 >= 2.6.28 1. Linux kernel version >= 2.6.28
2.判断系统是否支持TPROXY,执行: 2. Determine whether the system supports TPROXY, execute:
grep TPROXY /boot/config-`uname -r` grep TPROXY /boot/config-`uname -r`
如果输出有下面的结果说明支持. If the output has the following result description is supported.
CONFIG_NETFILTER_XT_TARGET_TPROXY=m CONFIG_NETFILTER_XT_TARGET_TPROXY=m
部署步骤: ## Deployment steps:
1.在源站的linux系统里面每次开机启动都要用root权限执行tproxy环境设置脚本:tproxy_setup.sh 1. The tproxy environment setup script should be executed with root privileges every time the boot from the source Linux system: tproxy_setup.sh
2.在源站的linux系统里面使用root权限执行代理proxy 2. Execute proxy proxy with root access on the source Linux system
参数 -tproxy 是开启代理的tproxy功能. ## Parameter-tproxy is the tproxy function that turns on the proxy.
./proxy -tproxy ./proxy -tproxy
2.源站的程序监听的地址IP需要使用:127.0.1.1 2. The IP address of the source station to listen to the program requires the use of: `127.0.1.1`
比如源站以前监听的地址是: 0.0.0.0:8800 , 现在需要修改为:127.0.1.1:8800 For example, the address of the source station before listening is: `0.0.0.0:8800`, now need to be modified to: `127.0.1.1:8800`
3.转发规则里面源站地址必须是对应的,比如上面的:127.0.1.1:8800 3. Forwarding rules inside the source address must be the corresponding, such as the above: `127.0.1.1:8800`

35
core/tproxy/README_ZH.md Normal file
View File

@ -0,0 +1,35 @@
# 透传用户IP手册
## 说明:
通过Linux的TPROXY功能,可以实现源站服务程序可以看见客户端真实IP,实现该功能需要linux操作系统和程序都要满足一定的条件.
## 环境要求:
源站必须是运行在Linux上面的服务程序,同时Linux需要满足下面条件:
1. Linux内核版本 >= 2.6.28
2. 判断系统是否支持TPROXY,执行:
grep TPROXY /boot/config-`uname -r`
如果输出有下面的结果说明支持.
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
## 部署步骤:
1. 在源站的linux系统里面每次开机启动都要用root权限执行tproxy环境设置脚本:tproxy_setup.sh
2. 在源站的linux系统里面使用root权限执行代理proxy
## 参数 -tproxy 是开启代理的tproxy功能.
./proxy -tproxy
2. 源站的程序监听的地址IP需要使用:127.0.1.1
比如源站以前监听的地址是: 0.0.0.0:8800 , 现在需要修改为:127.0.1.1:8800
3. 转发规则里面源站地址必须是对应的,比如上面的:127.0.1.1:8800

19
docker/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM golang:alpine AS builder
WORKDIR $GOPATH
ARG GOPROXY_VERSION=master
RUN apk update; apk upgrade; \
apk add --no-cache ca-certificates git; \
cd /go/src/; \
mkdir -p github.com/snail007; \
cd github.com/snail007; \
git clone --depth=1 https://github.com/snail007/goproxy.git; \
cd goproxy; \
git checkout ${GOPROXY_VERSION}; \
CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -a -installsuffix cgo -o proxy; \
chmod 0777 proxy
FROM debian:stable-slim
COPY --from=builder /go/src/github.com/snail007/goproxy/proxy /usr/local/bin/
# RUN chmod 0777 /usr/local/bin/proxy
EXPOSE 80 443
CMD /usr/local/bin/proxy http -t tcp -p :80,:443

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 19 KiB

25
docs/old-release-zh.md Normal file
View File

@ -0,0 +1,25 @@
# Old Versions of Proxy
- [v5.3手册](https://github.com/snail007/goproxy/tree/v5.3)
- [v5.2手册](https://github.com/snail007/goproxy/tree/v5.2)
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1)
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0)
- [v4.9手册](https://github.com/snail007/goproxy/tree/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)
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3)
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2)
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1)
- [v3.9手册](https://github.com/snail007/goproxy/tree/v3.9)
- [v3.8手册](https://github.com/snail007/goproxy/tree/v3.8)
- [v3.6-v3.7手册](https://github.com/snail007/goproxy/tree/v3.6)
- [v3.5手册](https://github.com/snail007/goproxy/tree/v3.5)
- [v3.4手册](https://github.com/snail007/goproxy/tree/v3.4)
- [v3.3手册](https://github.com/snail007/goproxy/tree/v3.3)
- [v3.2手册](https://github.com/snail007/goproxy/tree/v3.2)
- [v3.1手册](https://github.com/snail007/goproxy/tree/v3.1)
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0)
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2)

View File

@ -1,25 +1,25 @@
# Old Versions of Proxy # Old Versions of Proxy
- [v5.3手册](https://github.com/snail007/goproxy/tree/v5.3) - [v5.3 Manual](https://github.com/snail007/goproxy/tree/v5.3)
- [v5.2手册](https://github.com/snail007/goproxy/tree/v5.2) - [v5.2 Manual](https://github.com/snail007/goproxy/tree/v5.2)
- [v5.1手册](https://github.com/snail007/goproxy/tree/v5.1) - [v5.1 Manual](https://github.com/snail007/goproxy/tree/v5.1)
- [v5.0手册](https://github.com/snail007/goproxy/tree/v5.0) - [v5.0 Manual](https://github.com/snail007/goproxy/tree/v5.0)
- [v4.9手册](https://github.com/snail007/goproxy/tree/v4.9) - [v4.9 Manual](https://github.com/snail007/goproxy/tree/v4.9)
- [v4.8手册](https://github.com/snail007/goproxy/tree/v4.8) - [v4.8 Manual](https://github.com/snail007/goproxy/tree/v4.8)
- [v4.7手册](https://github.com/snail007/goproxy/tree/v4.7) - [v4.7 Manual](https://github.com/snail007/goproxy/tree/v4.7)
- [v4.6手册](https://github.com/snail007/goproxy/tree/v4.6) - [v4.6 Manual](https://github.com/snail007/goproxy/tree/v4.6)
- [v4.5手册](https://github.com/snail007/goproxy/tree/v4.5) - [v4.5 Manual](https://github.com/snail007/goproxy/tree/v4.5)
- [v4.4手册](https://github.com/snail007/goproxy/tree/v4.4) - [v4.4 Manual](https://github.com/snail007/goproxy/tree/v4.4)
- [v4.3手册](https://github.com/snail007/goproxy/tree/v4.3) - [v4.3 Manual](https://github.com/snail007/goproxy/tree/v4.3)
- [v4.2手册](https://github.com/snail007/goproxy/tree/v4.2) - [v4.2 Manual](https://github.com/snail007/goproxy/tree/v4.2)
- [v4.0-v4.1手册](https://github.com/snail007/goproxy/tree/v4.1) - [v4.0-v4.1 Manual](https://github.com/snail007/goproxy/tree/v4.1)
- [v3.9手册](https://github.com/snail007/goproxy/tree/v3.9) - [v3.9 Manual](https://github.com/snail007/goproxy/tree/v3.9)
- [v3.8手册](https://github.com/snail007/goproxy/tree/v3.8) - [v3.8 Manual](https://github.com/snail007/goproxy/tree/v3.8)
- [v3.6-v3.7手册](https://github.com/snail007/goproxy/tree/v3.6) - [v3.6-v3.7 Manual](https://github.com/snail007/goproxy/tree/v3.6)
- [v3.5手册](https://github.com/snail007/goproxy/tree/v3.5) - [v3.5 Manual](https://github.com/snail007/goproxy/tree/v3.5)
- [v3.4手册](https://github.com/snail007/goproxy/tree/v3.4) - [v3.4 Manual](https://github.com/snail007/goproxy/tree/v3.4)
- [v3.3手册](https://github.com/snail007/goproxy/tree/v3.3) - [v3.3 Manual](https://github.com/snail007/goproxy/tree/v3.3)
- [v3.2手册](https://github.com/snail007/goproxy/tree/v3.2) - [v3.2 Manual](https://github.com/snail007/goproxy/tree/v3.2)
- [v3.1手册](https://github.com/snail007/goproxy/tree/v3.1) - [v3.1 Manual](https://github.com/snail007/goproxy/tree/v3.1)
- [v3.0手册](https://github.com/snail007/goproxy/tree/v3.0) - [v3.0 Manual](https://github.com/snail007/goproxy/tree/v3.0)
- [v2.x手册](https://github.com/snail007/goproxy/tree/v2.2) - [v2.x Manual](https://github.com/snail007/goproxy/tree/v2.2)

View File

@ -1,13 +1,13 @@
# Proxy-GUI # Proxy-GUI
基于proxy的各平台SDK,作者和众多热心人士开发了各平台的GUI版本的proxy,下面分平台介绍. Based on the proxy platform SDK, the author and many enthusiasts have developed the GUI version of the proxy for each platform.
## Windows ## Windows
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui) - Official java version, Project Homepage:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## Linux ## Linux
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui) - Official java version, Project Homepage:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## MacOS ## MacOS
@ -15,13 +15,13 @@
## Android ## Android
- proxy-go,一个非官方实现版本,界面比较简陋,但是够用.下载地址:[proxy-go](https://github.com/snail007/goproxy-gui-stuff/releases/tag/proxy-go-release) - proxy-go,An unofficial implementation version, the interface is relatively simple, but enough.Download address:[proxy-go](https://github.com/snail007/goproxy-gui-stuff/releases/tag/proxy-go-release)
## IOS ## IOS
- Coming Soon ... - Coming Soon ...
## 跨平台 ## Cross-platform
- proxy-web,一个跨平台的web UI版本,项目主页:[proxy-web](https://github.com/yincongcyincong/proxy-web) - proxy-web,A cross-platform web UI version,project home page:[proxy-web](https://github.com/yincongcyincong/proxy-web)

27
gui/README_ZH.md Normal file
View File

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

View File

@ -5,7 +5,10 @@ if [ -e /tmp/proxy ]; then
fi fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /tmp/proxy cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v6.1/proxy-linux-amd64.tar.gz
LAST_VERSION=$(curl --silent "https://api.github.com/repos/snail007/goproxy/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')
wget "https://github.com/snail007/goproxy/releases/download/${LAST_VERSION}/proxy-linux-amd64.tar.gz"
# #install proxy # #install proxy
tar zxvf proxy-linux-amd64.tar.gz tar zxvf proxy-linux-amd64.tar.gz

View File

@ -36,10 +36,10 @@ func Clean(s *services.Service) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
for _ = range signalChan { for range signalChan {
log.Println("Received an interrupt, stopping services...") log.Println("Received an interrupt, stopping services...")
if s != nil && *s != nil { if s != nil && *s != nil {
(*s).Clean() (*s).Clean()
@ -48,11 +48,12 @@ func Clean(s *services.Service) {
log.Printf("clean process %d", cmd.Process.Pid) log.Printf("clean process %d", cmd.Process.Pid)
cmd.Process.Kill() cmd.Process.Kill()
} }
if isDebug { if *isDebug {
saveProfiling() saveProfiling()
} }
cleanupDone <- true cleanupDone <- true
} }
}() }()
<-cleanupDone <-cleanupDone
os.Exit(0)
} }

View File

@ -82,6 +82,3 @@ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build $OPTS -ldflags "$X" -o proxy.e
rm -rf proxy proxy.exe proxy-noconsole.exe .cert rm -rf proxy proxy.exe proxy-noconsole.exe .cert
#todo
#1.install_auto.sh goproxy/releases/download/vxxx
#2.README goproxy/releases/download/vxxx

View File

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

View File

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

View File

@ -57,6 +57,17 @@ func (s *DNS) CheckArgs() (err error) {
func (s *DNS) InitService() (err error) { func (s *DNS) InitService() (err error) {
s.cache = gocache.New(time.Second*time.Duration(*s.cfg.DNSTTL), time.Second*60) s.cache = gocache.New(time.Second*time.Duration(*s.cfg.DNSTTL), time.Second*60)
s.cache.LoadFile(*s.cfg.CacheFile) s.cache.LoadFile(*s.cfg.CacheFile)
go func() {
for {
select {
case <-s.exitSig:
return
case <-time.After(time.Second * 300):
s.cache.DeleteExpired()
s.cache.SaveFile(*s.cfg.CacheFile)
}
}
}()
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
@ -81,7 +92,7 @@ func (s *DNS) InitService() (err error) {
nil, nil,
&net.Dialer{ &net.Dialer{
Timeout: 5 * time.Second, Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second, KeepAlive: 2 * time.Second,
}, },
) )
if err != nil { if err != nil {
@ -122,7 +133,7 @@ func (s *DNS) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop dns service crashed,%s", e) s.log.Printf("stop dns service crashed,%s", e)
} else { } else {
s.log.Printf("service dns stoped") s.log.Printf("service dns stopped")
} }
}() }()
Stop(s.serviceKey) Stop(s.serviceKey)

View File

@ -8,7 +8,9 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"runtime/pprof"
"strings" "strings"
"sync"
"github.com/snail007/goproxy/core/lib/kcpcfg" "github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt" encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
@ -31,6 +33,10 @@ var SDK_VERSION = "No Version Provided"
var ( var (
app *kingpin.Application app *kingpin.Application
cpuProfilingFile, memProfilingFile, blockProfilingFile,
goroutineProfilingFile, threadcreateProfilingFile *os.File
isProfiling bool
profilingLock = &sync.Mutex{}
) )
type LogCallback interface { type LogCallback interface {
@ -85,8 +91,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
nolog := app.Flag("nolog", "turn off logging").Default("false").Bool() nolog := app.Flag("nolog", "turn off logging").Default("false").Bool()
kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String() kcpArgs.Key = app.Flag("kcp-key", "pre-shared secret between client and server").Default("secrect").String()
kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none") kcpArgs.Crypt = app.Flag("kcp-method", "encrypt/decrypt method, can be: aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none").Default("aes").Enum("aes", "aes-128", "aes-192", "salsa20", "blowfish", "twofish", "cast5", "3des", "tea", "xtea", "xor", "sm4", "none")
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast").Enum("fast3", "fast2", "fast", "normal", "manual") kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("450").Int() kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int() kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int() kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int() kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
@ -134,13 +140,15 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() httpArgs.ParentKey = http.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() httpArgs.LocalCompress = http.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() httpArgs.ParentCompress = http.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
httpArgs.LoadBalanceMethod = http.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash") httpArgs.Intelligent = http.Flag("intelligent", "settting intelligent HTTP, SOCKS5 proxy mode, can be <intelligent|direct|parent>").Default("intelligent").Enum("intelligent", "direct", "parent")
httpArgs.LoadBalanceMethod = http.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("roundrobin").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
httpArgs.LoadBalanceTimeout = http.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int() httpArgs.LoadBalanceTimeout = http.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
httpArgs.LoadBalanceRetryTime = http.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int() httpArgs.LoadBalanceRetryTime = http.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
httpArgs.LoadBalanceHashTarget = http.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() httpArgs.LoadBalanceHashTarget = http.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
httpArgs.LoadBalanceOnlyHA = http.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() httpArgs.LoadBalanceOnlyHA = http.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
httpArgs.RateLimit = http.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() httpArgs.RateLimit = http.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
httpArgs.BindListen = http.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool() httpArgs.BindListen = http.Flag("bind-listen", "using listener binding IP when connect to target").Short('B').Default("false").Bool()
httpArgs.Jumper = http.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Short('J').Default("").String()
httpArgs.Debug = debug httpArgs.Debug = debug
//########tcp######### //########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode") tcp := app.Command("tcp", "proxy on tcp mode")
@ -269,7 +277,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String() socksArgs.ParentKey = socks.Flag("parent-key", "the password for auto encrypt/decrypt parent connection data").Short('Z').Default("").String()
socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool() socksArgs.LocalCompress = socks.Flag("local-compress", "auto compress/decompress data on local connection").Short('m').Default("false").Bool()
socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool() socksArgs.ParentCompress = socks.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
socksArgs.LoadBalanceMethod = socks.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("hash").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash") socksArgs.Intelligent = socks.Flag("intelligent", "settting intelligent HTTP, SOCKS5 proxy mode, can be <intelligent|direct|parent>").Default("intelligent").Enum("intelligent", "direct", "parent")
socksArgs.LoadBalanceMethod = socks.Flag("lb-method", "load balance method when use multiple parent,can be <roundrobin|leastconn|leasttime|hash|weight>").Default("roundrobin").Enum("roundrobin", "weight", "leastconn", "leasttime", "hash")
socksArgs.LoadBalanceTimeout = socks.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int() socksArgs.LoadBalanceTimeout = socks.Flag("lb-timeout", "tcp milliseconds timeout of connecting to parent").Default("500").Int()
socksArgs.LoadBalanceRetryTime = socks.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int() socksArgs.LoadBalanceRetryTime = socks.Flag("lb-retrytime", "sleep time milliseconds after checking").Default("1000").Int()
socksArgs.LoadBalanceHashTarget = socks.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() socksArgs.LoadBalanceHashTarget = socks.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
@ -316,6 +325,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
spsArgs.LoadBalanceHashTarget = sps.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceHashTarget = sps.Flag("lb-hashtarget", "use target address to choose parent for LB").Default("false").Bool()
spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
spsArgs.Debug = debug spsArgs.Debug = debug
//########dns######### //########dns#########
@ -407,7 +418,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxClientArgs.KCP = kcpArgs muxClientArgs.KCP = kcpArgs
dnsArgs.KCP = kcpArgs dnsArgs.KCP = kcpArgs
log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime) log := logger.New(os.Stdout, "", logger.Ldate|logger.Ltime)
flags := logger.Ldate flags := logger.Ldate
if *debug { if *debug {
flags |= logger.Lshortfile | logger.Lmicroseconds flags |= logger.Lshortfile | logger.Lmicroseconds
@ -473,3 +484,41 @@ func Stop(serviceID string) {
func Version() string { func Version() string {
return SDK_VERSION return SDK_VERSION
} }
func StartProfiling(storePath string) {
profilingLock.Lock()
defer profilingLock.Unlock()
if !isProfiling {
isProfiling = true
if storePath == "" {
storePath = "."
}
cpuProfilingFile, _ = os.Create(filepath.Join(storePath, "cpu.prof"))
memProfilingFile, _ = os.Create(filepath.Join(storePath, "memory.prof"))
blockProfilingFile, _ = os.Create(filepath.Join(storePath, "block.prof"))
goroutineProfilingFile, _ = os.Create(filepath.Join(storePath, "goroutine.prof"))
threadcreateProfilingFile, _ = os.Create(filepath.Join(storePath, "threadcreate.prof"))
pprof.StartCPUProfile(cpuProfilingFile)
}
}
func StopProfiling() {
profilingLock.Lock()
defer profilingLock.Unlock()
if isProfiling {
isProfiling = false
pprof.StopCPUProfile()
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)
//close
goroutineProfilingFile.Close()
memProfilingFile.Close()
blockProfilingFile.Close()
threadcreateProfilingFile.Close()
}
}

View File

@ -21,5 +21,15 @@ func Version() (ver *C.char) {
return C.CString(sdk.Version()) return C.CString(sdk.Version())
} }
//export StartProfiling
func StartProfiling(storePath *C.char) {
sdk.StartProfiling(C.GoString(storePath))
}
//export StopProfiling
func StopProfiling() {
sdk.StopProfiling()
}
func main() { func main() {
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/snail007/goproxy/utils/datasize" "github.com/snail007/goproxy/utils/datasize"
"github.com/snail007/goproxy/utils/dnsx" "github.com/snail007/goproxy/utils/dnsx"
"github.com/snail007/goproxy/utils/iolimiter" "github.com/snail007/goproxy/utils/iolimiter"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/lb" "github.com/snail007/goproxy/utils/lb"
"github.com/snail007/goproxy/utils/mapx" "github.com/snail007/goproxy/utils/mapx"
@ -65,6 +66,7 @@ type HTTPArgs struct {
ParentKey *string ParentKey *string
LocalCompress *bool LocalCompress *bool
ParentCompress *bool ParentCompress *bool
Intelligent *string
LoadBalanceMethod *string LoadBalanceMethod *string
LoadBalanceTimeout *int LoadBalanceTimeout *int
LoadBalanceRetryTime *int LoadBalanceRetryTime *int
@ -75,6 +77,7 @@ type HTTPArgs struct {
RateLimitBytes float64 RateLimitBytes float64
BindListen *bool BindListen *bool
Debug *bool Debug *bool
Jumper *string
} }
type HTTP struct { type HTTP struct {
cfg HTTPArgs cfg HTTPArgs
@ -88,6 +91,7 @@ type HTTP struct {
userConns mapx.ConcurrentMap userConns mapx.ConcurrentMap
log *logger.Logger log *logger.Logger
lb *lb.Group lb *lb.Group
jumper *jumper.Jumper
} }
func NewHTTP() services.Service { func NewHTTP() services.Service {
@ -163,13 +167,26 @@ func (s *HTTP) CheckArgs() (err error) {
} }
s.cfg.RateLimitBytes = float64(size) s.cfg.RateLimitBytes = float64(size)
} }
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
func (s *HTTP) InitService() (err error) { func (s *HTTP) InitService() (err error) {
s.InitBasicAuth() s.InitBasicAuth()
//init lb //init lb
if len(*s.cfg.Parent) > 0 { if len(*s.cfg.Parent) > 0 {
s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log) s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log, *s.cfg.Intelligent)
s.InitLB() s.InitLB()
} }
if *s.cfg.DNSAddress != "" { if *s.cfg.DNSAddress != "" {
@ -193,7 +210,7 @@ func (s *HTTP) InitService() (err error) {
return return
} }
conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2) conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
if err == nil { if err == nil && conn != nil {
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write([]byte{0}) _, err = conn.Write([]byte{0})
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
@ -222,7 +239,7 @@ func (s *HTTP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop http(s) service crashed,%s", e) s.log.Printf("stop http(s) service crashed,%s", e)
} else { } else {
s.log.Printf("service http(s) stoped") s.log.Printf("service http(s) stopped")
} }
s.basicAuth = utils.BasicAuth{} s.basicAuth = utils.BasicAuth{}
s.cfg = HTTPArgs{} s.cfg = HTTPArgs{}
@ -231,6 +248,7 @@ func (s *HTTP) StopService() {
s.lb = nil s.lb = nil
s.lockChn = nil s.lockChn = nil
s.log = nil s.log = nil
s.jumper = nil
s.serverChannels = nil s.serverChannels = nil
s.sshClient = nil s.sshClient = nil
s.userConns = nil s.userConns = nil
@ -368,12 +386,17 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} }
if useProxy { if useProxy {
// s.log.Printf("%v", s.outPool) // s.log.Printf("%v", s.outPool)
selectAddr := (*inConn).RemoteAddr().String() if *s.cfg.ParentType == "ssh" {
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget { outConn, err = s.getSSHConn(address)
selectAddr = address } else {
selectAddr := (*inConn).RemoteAddr().String()
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
selectAddr = address
}
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
outConn, err = s.GetParentConn(lbAddr)
} }
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
outConn, err = s.GetParentConn(lbAddr)
} else { } else {
outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr) outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr)
} }
@ -393,7 +416,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if *s.cfg.ParentCompress { if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn) outConn = utils.NewCompConn(outConn)
} }
if *s.cfg.ParentKey != "" { if useProxy && *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{ outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey, Password: *s.cfg.ParentKey,
}) })
@ -408,7 +431,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
//https或者http,上级是代理,proxy需要转发 //https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
//直连目标或上级非代理或非SNI,,清理HTTP头部的代理头信息 //直连目标或上级非代理或非SNI,,清理HTTP头部的代理头信息
if !useProxy || *s.cfg.ParentType == "ssh" && !req.IsSNI { if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf)) _, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
} else { } else {
_, err = outConn.Write(req.HeadBuf) _, err = outConn.Write(req.HeadBuf)
@ -497,6 +520,9 @@ func (s *HTTP) ConnectSSH() (err error) {
s.sshClient.Close() s.sshClient.Close()
} }
s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config) s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config)
if err != nil {
s.log.Printf("connect to ssh %s fail", s.cfg.Parent)
}
<-s.lockChn <-s.lockChn
return return
} }
@ -602,11 +628,24 @@ func (s *HTTP) Resolve(address string) string {
} }
func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) { func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
var _conn tls.Conn if s.jumper == nil {
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes) var _conn tls.Conn
if err == nil { _conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
conn = net.Conn(&_conn) if err == nil {
conn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
} }
} else if *s.cfg.ParentType == "kcp" { } else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP) conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
} else if *s.cfg.ParentType == "ssh" { } else if *s.cfg.ParentType == "ssh" {
@ -616,7 +655,11 @@ func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
err = fmt.Errorf("%s", e) err = fmt.Errorf("%s", e)
} }
} else { } else {
conn, err = utils.ConnectHost(address, *s.cfg.Timeout) if s.jumper == nil {
conn, err = utils.ConnectHost(address, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
} }
return return
} }

View File

@ -81,7 +81,7 @@ func (s *MuxBridge) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop bridge service crashed,%s", e) s.log.Printf("stop bridge service crashed,%s", e)
} else { } else {
s.log.Printf("service bridge stoped") s.log.Printf("service bridge stopped")
} }
s.cfg = MuxBridgeArgs{} s.cfg = MuxBridgeArgs{}
s.clientControlConns = nil s.clientControlConns = nil

View File

@ -111,7 +111,7 @@ func (s *MuxClient) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop client service crashed,%s", e) s.log.Printf("stop client service crashed,%s", e)
} else { } else {
s.log.Printf("service client stoped") s.log.Printf("service client stopped")
} }
s.cfg = MuxClientArgs{} s.cfg = MuxClientArgs{}
s.jumper = nil s.jumper = nil
@ -242,9 +242,9 @@ func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
} }
} else { } else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil) conf, e := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil { if e != nil {
return nil, err return nil, e
} }
var _c net.Conn var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout)) _c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))

View File

@ -207,7 +207,7 @@ func (s *MuxServer) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
s.log.Printf("service server stoped") s.log.Printf("service server stopped")
} }
s.cfg = MuxServerArgs{} s.cfg = MuxServerArgs{}
s.jumper = nil s.jumper = nil

View File

@ -39,6 +39,9 @@ func GetService(name string) *ServiceItem {
func Stop(name string) { func Stop(name string) {
if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil { if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
s.(*ServiceItem).S.Clean() s.(*ServiceItem).S.Clean()
*s.(*ServiceItem) = ServiceItem{}
s = nil
servicesMap.Store(name, nil)
servicesMap.Delete(name) servicesMap.Delete(name)
} }
} }

View File

@ -64,6 +64,7 @@ type SocksArgs struct {
ParentKey *string ParentKey *string
LocalCompress *bool LocalCompress *bool
ParentCompress *bool ParentCompress *bool
Intelligent *string
LoadBalanceMethod *string LoadBalanceMethod *string
LoadBalanceTimeout *int LoadBalanceTimeout *int
LoadBalanceRetryTime *int LoadBalanceRetryTime *int
@ -180,7 +181,7 @@ func (s *Socks) InitService() (err error) {
(*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log) (*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
} }
if len(*s.cfg.Parent) > 0 { if len(*s.cfg.Parent) > 0 {
s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log) s.checker = utils.NewChecker(*s.cfg.Timeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log, *s.cfg.Intelligent)
s.InitLB() s.InitLB()
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
@ -192,7 +193,7 @@ func (s *Socks) InitService() (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
//循环检查ssh网络连通性 //循环检查ssh网络连通性
@ -230,7 +231,7 @@ func (s *Socks) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop socks service crashed,%s", e) s.log.Printf("stop socks service crashed,%s", e)
} else { } else {
s.log.Printf("service socks stoped") s.log.Printf("service socks stopped")
} }
s.basicAuth = utils.BasicAuth{} s.basicAuth = utils.BasicAuth{}
s.cfg = SocksArgs{} s.cfg = SocksArgs{}

View File

@ -174,9 +174,9 @@ func (s *Socks) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
} }
s.log.Printf("use proxy %v : udp %s", useProxy, serverConn.Target()) s.log.Printf("use proxy %v : udp %s", useProxy, serverConn.Target())
//relay //relay
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for { for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
n, srcAddr, err := udpListener.ReadFromUDP(buf) n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil { if err != nil {
s.log.Printf("udp listener read fail, %s", err.Error()) s.log.Printf("udp listener read fail, %s", err.Error())

View File

@ -101,7 +101,7 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
s.log.Printf("connect %s for udp", serverConn.Target()) s.log.Printf("connect %s for udp", serverConn.Target())
//socks client //socks client
client, err := s.HandshakeSocksParent(&outconn, "udp", serverConn.Target(), serverConn.AuthData(), false) client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
if err != nil { if err != nil {
clean("handshake fail", fmt.Sprintf("%s", err)) clean("handshake fail", fmt.Sprintf("%s", err))
return return
@ -126,9 +126,9 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
//s.log.Printf("parent udp address %s", client.UDPAddr) //s.log.Printf("parent udp address %s", client.UDPAddr)
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr) destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
//relay //relay
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for { for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
n, srcAddr, err := udpListener.ReadFromUDP(buf) n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil { if err != nil {
s.log.Printf("udp listener read fail, %s", err.Error()) s.log.Printf("udp listener read fail, %s", err.Error())

View File

@ -13,6 +13,7 @@ import (
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/snail007/goproxy/core/cs/server" "github.com/snail007/goproxy/core/cs/server"
@ -20,9 +21,11 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/conncrypt"
cryptool "github.com/snail007/goproxy/utils/crypt"
"github.com/snail007/goproxy/utils/datasize" "github.com/snail007/goproxy/utils/datasize"
"github.com/snail007/goproxy/utils/dnsx" "github.com/snail007/goproxy/utils/dnsx"
"github.com/snail007/goproxy/utils/iolimiter" "github.com/snail007/goproxy/utils/iolimiter"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/lb" "github.com/snail007/goproxy/utils/lb"
"github.com/snail007/goproxy/utils/mapx" "github.com/snail007/goproxy/utils/mapx"
"github.com/snail007/goproxy/utils/sni" "github.com/snail007/goproxy/utils/sni"
@ -70,10 +73,12 @@ type SPSArgs struct {
LoadBalanceRetryTime *int LoadBalanceRetryTime *int
LoadBalanceHashTarget *bool LoadBalanceHashTarget *bool
LoadBalanceOnlyHA *bool LoadBalanceOnlyHA *bool
ParentTLSSingle *bool
RateLimit *string RateLimit *string
RateLimitBytes float64 RateLimitBytes float64
Debug *bool Debug *bool
Jumper *string
} }
type SPS struct { type SPS struct {
cfg SPSArgs cfg SPSArgs
@ -88,6 +93,9 @@ type SPS struct {
lb *lb.Group lb *lb.Group
udpLocalKey []byte udpLocalKey []byte
udpParentKey []byte udpParentKey []byte
jumper *jumper.Jumper
parentAuthData *sync.Map
parentCipherData *sync.Map
} }
func NewSPS() services.Service { func NewSPS() services.Service {
@ -97,6 +105,8 @@ func NewSPS() services.Service {
serverChannels: []*server.ServerChannel{}, serverChannels: []*server.ServerChannel{},
userConns: mapx.NewConcurrentMap(), userConns: mapx.NewConcurrentMap(),
udpRelatedPacketConns: mapx.NewConcurrentMap(), udpRelatedPacketConns: mapx.NewConcurrentMap(),
parentAuthData: &sync.Map{},
parentCipherData: &sync.Map{},
} }
} }
func (s *SPS) CheckArgs() (err error) { func (s *SPS) CheckArgs() (err error) {
@ -118,9 +128,11 @@ func (s *SPS) CheckArgs() (err error) {
return return
} }
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" { if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) if !*s.cfg.ParentTLSSingle {
if err != nil { s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
return if err != nil {
return
}
} }
if *s.cfg.CaCertFile != "" { if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
@ -141,6 +153,19 @@ func (s *SPS) CheckArgs() (err error) {
} }
s.udpLocalKey = s.LocalUDPKey() s.udpLocalKey = s.LocalUDPKey()
s.udpParentKey = s.ParentUDPKey() s.udpParentKey = s.ParentUDPKey()
if *s.cfg.Jumper != "" {
if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
err = fmt.Errorf("jumper only worked of -T is tls or tcp")
return
}
var j jumper.Jumper
j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err != nil {
err = fmt.Errorf("parse jumper fail, err %s", err)
return
}
s.jumper = &j
}
return return
} }
func (s *SPS) InitService() (err error) { func (s *SPS) InitService() (err error) {
@ -150,7 +175,10 @@ func (s *SPS) InitService() (err error) {
} }
if len(*s.cfg.Parent) > 0 { if len(*s.cfg.Parent) > 0 {
s.InitLB() err = s.InitLB()
if err != nil {
return
}
} }
err = s.InitBasicAuth() err = s.InitBasicAuth()
@ -177,13 +205,14 @@ func (s *SPS) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop sps service crashed,%s", e) s.log.Printf("stop sps service crashed,%s", e)
} else { } else {
s.log.Printf("service sps stoped") s.log.Printf("service sps stopped")
} }
s.basicAuth = utils.BasicAuth{} s.basicAuth = utils.BasicAuth{}
s.cfg = SPSArgs{} s.cfg = SPSArgs{}
s.domainResolver = dnsx.DomainResolver{} s.domainResolver = dnsx.DomainResolver{}
s.lb = nil s.lb = nil
s.localCipher = nil s.localCipher = nil
s.jumper = nil
s.log = nil s.log = nil
s.parentCipher = nil s.parentCipher = nil
s.serverChannels = nil s.serverChannels = nil
@ -191,6 +220,8 @@ func (s *SPS) StopService() {
s.udpParentKey = nil s.udpParentKey = nil
s.udpRelatedPacketConns = nil s.udpRelatedPacketConns = nil
s.userConns = nil s.userConns = nil
s.parentAuthData = nil
s.parentCipherData = nil
s = nil s = nil
}() }()
for _, sc := range s.serverChannels { for _, sc := range s.serverChannels {
@ -237,9 +268,12 @@ func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
err = sc.ListenTCP(s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == "tls" { } else if *s.cfg.LocalType == "tls" {
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback) err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == "tcp" { } else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log) err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
} }
if err != nil {
return
}
if *s.cfg.ParentServiceType == "socks" { if *s.cfg.ParentServiceType == "socks" {
err = s.RunSSUDP(addr) err = s.RunSSUDP(addr)
} else { } else {
@ -414,8 +448,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
ParentAuth := s.getParentAuth(lbAddr)
if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() { if ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
forwardBytes = utils.RemoveProxyHeaders(forwardBytes) forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
} }
@ -435,8 +469,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
pb.WriteString("Connection: Keep-Alive\r\n") pb.WriteString("Connection: Keep-Alive\r\n")
u := "" u := ""
if *s.cfg.ParentAuth != "" { if ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":") a := strings.Split(ParentAuth, ":")
if len(a) != 2 { if len(a) != 2 {
err = fmt.Errorf("parent auth data format error") err = fmt.Errorf("parent auth data format error")
return return
@ -487,7 +521,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
s.log.Printf("connect %s", address) s.log.Printf("connect %s", address)
//socks client //socks client
_, err = s.HandshakeSocksParent(&outConn, "tcp", address, auth, false) _, err = s.HandshakeSocksParent(ParentAuth, &outConn, "tcp", address, auth, false)
if err != nil { if err != nil {
s.log.Printf("handshake fail, %s", err) s.log.Printf("handshake fail, %s", err)
return return
@ -500,7 +534,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
return return
} }
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy()) outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.getParentCipher(lbAddr))
if err != nil { if err != nil {
err = fmt.Errorf("dial ss parent fail, err : %s", err) err = fmt.Errorf("dial ss parent fail, err : %s", err)
return return
@ -560,10 +594,41 @@ func (s *SPS) InitBasicAuth() (err error) {
} }
return return
} }
func (s *SPS) InitLB() { func (s *SPS) InitLB() (err error) {
configs := lb.BackendsConfig{} configs := lb.BackendsConfig{}
for _, addr := range *s.cfg.Parent { for _, addr := range *s.cfg.Parent {
_addrInfo := strings.Split(addr, "@") var _addrInfo []string
if strings.Contains(addr, "#") {
_s := addr[:strings.Index(addr, "#")]
_auth, err := cryptool.CryptTools.Base64Decode(_s)
if err != nil {
s.log.Printf("decoding parent auth data [ %s ] fail , error : %s", _s, err)
return err
}
_addrInfo = strings.Split(addr[strings.Index(addr, "#")+1:], "@")
if *s.cfg.ParentServiceType == "ss" {
_s := strings.Split(_auth, ":")
m := _s[0]
k := _s[1]
if m == "" {
m = *s.cfg.ParentSSMethod
}
if k == "" {
k = *s.cfg.ParentSSKey
}
cipher, err := ss.NewCipher(m, k)
if err != nil {
s.log.Printf("error generating cipher, ssMethod: %s, ssKey: %s, error : %s", m, k, err)
return err
}
s.parentCipherData.Store(_addrInfo[0], cipher)
} else {
s.parentAuthData.Store(_addrInfo[0], _auth)
}
} else {
_addrInfo = strings.Split(addr, "@")
}
_addr := _addrInfo[0] _addr := _addrInfo[0]
weight := 1 weight := 1
if len(_addrInfo) == 2 { if len(_addrInfo) == 2 {
@ -580,6 +645,19 @@ func (s *SPS) InitLB() {
} }
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug) LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
s.lb = &LB s.lb = &LB
return
}
func (s *SPS) getParentAuth(lbAddr string) string {
if v, ok := s.parentAuthData.Load(lbAddr); ok {
return v.(string)
}
return *s.cfg.ParentAuth
}
func (s *SPS) getParentCipher(lbAddr string) *ss.Cipher {
if v, ok := s.parentCipherData.Load(lbAddr); ok {
return v.(*ss.Cipher).Copy()
}
return s.parentCipher.Copy()
} }
func (s *SPS) IsBasicAuth() bool { func (s *SPS) IsBasicAuth() bool {
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != "" return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
@ -635,15 +713,41 @@ func (s *SPS) Resolve(address string) string {
} }
func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) { func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
var _conn tls.Conn if s.jumper == nil {
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes) var _conn tls.Conn
if err == nil { if *s.cfg.ParentTLSSingle {
conn = net.Conn(&_conn) _conn, err = utils.SingleTlsConnectHost(address, *s.cfg.Timeout, s.cfg.CaCertBytes)
} else {
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
}
if err == nil {
conn = net.Conn(&_conn)
}
} else {
var conf *tls.Config
if *s.cfg.ParentTLSSingle {
conf, err = utils.SingleTlsConfig(s.cfg.CaCertBytes)
} else {
conf, err = utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
}
if err != nil {
return nil, err
}
var _c net.Conn
_c, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn = net.Conn(tls.Client(_c, conf))
}
} }
} else if *s.cfg.ParentType == "kcp" { } else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP) conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
} else { } else {
conn, err = utils.ConnectHost(address, *s.cfg.Timeout) if s.jumper == nil {
conn, err = utils.ConnectHost(address, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
} }
if err == nil { if err == nil {
if *s.cfg.ParentCompress { if *s.cfg.ParentCompress {
@ -657,9 +761,9 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
} }
return return
} }
func (s *SPS) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) { func (s *SPS) HandshakeSocksParent(parentAuth string, outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
if *s.cfg.ParentAuth != "" { if parentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":") a := strings.Split(parentAuth, ":")
if len(a) != 2 { if len(a) != 2 {
err = fmt.Errorf("parent auth data format error") err = fmt.Errorf("parent auth data format error")
return return
@ -683,7 +787,9 @@ func (s *SPS) ParentUDPKey() (key []byte) {
return []byte(v)[:24] return []byte(v)[:24]
} }
case "tls": case "tls":
return s.cfg.KeyBytes[:24] if s.cfg.KeyBytes != nil {
return s.cfg.KeyBytes[:24]
}
case "kcp": case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24] return []byte(v)[:24]

View File

@ -27,9 +27,9 @@ func (s *SPS) RunSSUDP(addr string) (err error) {
s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack())) s.log.Printf("udp local->out io copy crashed:\n%s\n%s", e, string(debug.Stack()))
} }
}() }()
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for { for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
n, srcAddr, err := listener.ReadFrom(buf) n, srcAddr, err := listener.ReadFrom(buf)
if err != nil { if err != nil {
s.log.Printf("read from client error %s", err) s.log.Printf("read from client error %s", err)
@ -88,7 +88,7 @@ func (s *SPS) RunSSUDP(addr string) (err error) {
return return
} }
client, err := s.HandshakeSocksParent(&outconn, "udp", socksPacket.Addr(), socks.Auth{}, true) client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", socksPacket.Addr(), socks.Auth{}, true)
if err != nil { if err != nil {
clean("handshake fail", fmt.Sprintf("%s", err)) clean("handshake fail", fmt.Sprintf("%s", err))
return return

View File

@ -100,7 +100,7 @@ func (s *TCP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tcp service crashed,%s", e) s.log.Printf("stop tcp service crashed,%s", e)
} else { } else {
s.log.Printf("service tcp stoped") s.log.Printf("service tcp stopped")
} }
s.cfg = TCPArgs{} s.cfg = TCPArgs{}
s.jumper = nil s.jumper = nil

View File

@ -72,7 +72,7 @@ func (s *TunnelBridge) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tbridge service crashed,%s", e) s.log.Printf("stop tbridge service crashed,%s", e)
} else { } else {
s.log.Printf("service tbridge stoped") s.log.Printf("service tbridge stopped")
} }
s.cfg = TunnelBridgeArgs{} s.cfg = TunnelBridgeArgs{}
s.clientControlConns = nil s.clientControlConns = nil

View File

@ -95,7 +95,7 @@ func (s *TunnelClient) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop tclient service crashed,%s", e) s.log.Printf("stop tclient service crashed,%s", e)
} else { } else {
s.log.Printf("service tclient stoped") s.log.Printf("service tclient stopped")
} }
s.cfg = TunnelClientArgs{} s.cfg = TunnelClientArgs{}
s.ctrlConn = nil s.ctrlConn = nil
@ -159,7 +159,7 @@ func (s *TunnelClient) Start(args interface{}, log *logger.Logger) (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
s.ServeUDP(localAddr, ID, serverID) s.ServeUDP(localAddr, ID, serverID)
@ -168,7 +168,7 @@ func (s *TunnelClient) Start(args interface{}, log *logger.Logger) (err error) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
s.ServeConn(localAddr, ID, serverID) s.ServeConn(localAddr, ID, serverID)
@ -324,7 +324,7 @@ func (s *TunnelClient) ServeUDP(localAddr, ID, serverID string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
(*item).udpConn.Write(body) (*item).udpConn.Write(body)
@ -335,7 +335,7 @@ func (s *TunnelClient) UDPRevecive(key, ID string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
s.log.Printf("udp conn %s connected", ID) s.log.Printf("udp conn %s connected", ID)
@ -365,7 +365,7 @@ func (s *TunnelClient) UDPRevecive(key, ID string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
(*cui.conn).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) (*cui.conn).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
@ -384,7 +384,7 @@ func (s *TunnelClient) UDPGCDeamon() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
if s.isStop { if s.isStop {

View File

@ -176,7 +176,7 @@ func (s *TunnelServer) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop server service crashed,%s", e) s.log.Printf("stop server service crashed,%s", e)
} else { } else {
s.log.Printf("service server stoped") s.log.Printf("service server stopped")
} }
s.cfg = TunnelServerArgs{} s.cfg = TunnelServerArgs{}
s.jumper = nil s.jumper = nil
@ -369,7 +369,7 @@ func (s *TunnelServer) UDPGCDeamon() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
if s.isStop { if s.isStop {
@ -440,7 +440,7 @@ func (s *TunnelServer) UDPRevecive(key, ID string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
s.log.Printf("udp conn %s connected", ID) s.log.Printf("udp conn %s connected", ID)
@ -473,7 +473,7 @@ func (s *TunnelServer) UDPRevecive(key, ID string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
s.sc.UDPListener.WriteToUDP(body, uc.srcAddr) s.sc.UDPListener.WriteToUDP(body, uc.srcAddr)

View File

@ -94,7 +94,7 @@ func (s *UDP) StopService() {
if e != nil { if e != nil {
s.log.Printf("stop udp service crashed,%s", e) s.log.Printf("stop udp service crashed,%s", e)
} else { } else {
s.log.Printf("service udp stoped") s.log.Printf("service udp stopped")
} }
s.cfg = UDPArgs{} s.cfg = UDPArgs{}
s.log = nil s.log = nil
@ -174,7 +174,7 @@ func (s *UDP) OutToUDPGCDeamon() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
if s.isStop { if s.isStop {
@ -216,7 +216,7 @@ func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
s.log.Printf("udp conn %s <--> %s connected", srcAddr.String(), localAddr.String()) s.log.Printf("udp conn %s <--> %s connected", srcAddr.String(), localAddr.String())
@ -238,7 +238,7 @@ func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
(*(s.sc).UDPListener).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) (*(s.sc).UDPListener).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
@ -275,7 +275,7 @@ func (s *UDP) UDPGCDeamon() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
if s.isStop { if s.isStop {
@ -352,7 +352,7 @@ func (s *UDP) UDPRevecive(key string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
s.log.Printf("udp conn %s connected", key) s.log.Printf("udp conn %s connected", key)
@ -366,7 +366,7 @@ func (s *UDP) UDPRevecive(key string) {
}() }()
v, ok := s.udpConns.Get(key) v, ok := s.udpConns.Get(key)
if !ok { if !ok {
s.log.Printf("[warn] udp conn not exists for %s, connid : %s", key) s.log.Printf("[warn] udp conn not exists for %s", key)
return return
} }
uc = v.(*UDPConnItem) uc = v.(*UDPConnItem)
@ -385,7 +385,7 @@ func (s *UDP) UDPRevecive(key string) {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:", e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
} }
}() }()
s.sc.UDPListener.WriteToUDP(body, uc.srcAddr) s.sc.UDPListener.WriteToUDP(body, uc.srcAddr)

38
utils/crypt/misc.go Normal file
View File

@ -0,0 +1,38 @@
package utils
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
)
type CryptTool struct{}
var CryptTools = NewCryptTool()
func NewCryptTool() *CryptTool {
return &CryptTool{}
}
func (encrypt *CryptTool) Base64Encode(str string) string {
return string([]byte(base64.StdEncoding.EncodeToString([]byte(str))))
}
func (encrypt *CryptTool) Base64EncodeBytes(bytes []byte) []byte {
return []byte(base64.StdEncoding.EncodeToString(bytes))
}
func (encrypt *CryptTool) Base64Decode(str string) (string, error) {
by, err := base64.StdEncoding.DecodeString(str)
return string(by), err
}
func (encrypt *CryptTool) Base64DecodeBytes(str string) ([]byte, error) {
return base64.StdEncoding.DecodeString(str)
}
func (encrypt *CryptTool) MD5(str string) string {
hash := md5.New()
hash.Write([]byte(str))
return hex.EncodeToString(hash.Sum(nil))
}

View File

@ -122,12 +122,55 @@ func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
} }
} }
} }
func SingleTlsConnectHost(host string, timeout int, caCertBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1])
return SingleTlsConnect(h[0], port, timeout, caCertBytes)
}
func SingleTlsConnect(host string, port, timeout int, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestSingleTlsConfig(caCertBytes)
if err != nil {
return
}
_conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Duration(timeout)*time.Millisecond)
if err != nil {
return
}
return *tls.Client(_conn, conf), err
}
func SingleTlsConfig(caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestSingleTlsConfig(caCertBytes)
}
func getRequestSingleTlsConfig(caCertBytes []byte) (conf *tls.Config, err error) {
conf = &tls.Config{InsecureSkipVerify: true}
serverCertPool := x509.NewCertPool()
if caCertBytes != nil {
ok := serverCertPool.AppendCertsFromPEM(caCertBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
conf.RootCAs = serverCertPool
conf.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
opts := x509.VerifyOptions{
Roots: serverCertPool,
}
for _, rawCert := range rawCerts {
cert, _ := x509.ParseCertificate(rawCert)
_, err := cert.Verify(opts)
if err != nil {
return err
}
}
return nil
}
}
return
}
func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) { func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":") h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1]) port, _ := strconv.Atoi(h[1])
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes) return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
} }
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) { func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes) conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
if err != nil { if err != nil {
@ -371,11 +414,20 @@ func RandInt(strLen int) int64 {
return i return i
} }
func ReadBytes(r io.Reader) (data []byte, err error) { func ReadBytes(r io.Reader) (data []byte, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("read bytes fail ,err : %s", e)
}
}()
var len uint64 var len uint64
err = binary.Read(r, binary.LittleEndian, &len) err = binary.Read(r, binary.LittleEndian, &len)
if err != nil { if err != nil {
return return
} }
if len == 0 || len > ^uint64(0) {
err = fmt.Errorf("data len out of range, %d", len)
return
}
var n int var n int
data = make([]byte, len) data = make([]byte, len)
n, err = r.Read(data) n, err = r.Read(data)

View File

@ -102,6 +102,19 @@ func (s *conn) Write(p []byte) (int, error) {
} }
return n, err return n, err
} }
func (s *conn) Close() error {
if s.Conn != nil {
e := s.Conn.Close()
s.Conn = nil
s.r = nil
s.w = nil
s.readLimiter = nil
s.writeLimiter = nil
s.ctx = nil
return e
}
return nil
}
// NewReader returns a reader that implements io.Reader with rate limiting. // NewReader returns a reader that implements io.Reader with rate limiting.
func NewReader(r io.Reader) *Reader { func NewReader(r io.Reader) *Reader {

View File

@ -24,8 +24,9 @@ func (s socks5Dialer) Dial(network, addr string) (net.Conn, error) {
} }
func New(proxyURL string, timeout time.Duration) (j Jumper, err error) { func New(proxyURL string, timeout time.Duration) (j Jumper, err error) {
u, err := url.Parse(proxyURL) u, e := url.Parse(proxyURL)
if err != nil { if e != nil {
err = e
return return
} }
j = Jumper{ j = Jumper{
@ -34,7 +35,7 @@ func New(proxyURL string, timeout time.Duration) (j Jumper, err error) {
} }
return return
} }
func (j *Jumper) Dial(address string, timeout time.Duration) (conn net.Conn, err error) { func (j *Jumper) Dial(address string, timeout time.Duration) (net.Conn, error) {
switch j.proxyURL.Scheme { switch j.proxyURL.Scheme {
case "https": case "https":
return j.dialHTTPS(address, timeout) return j.dialHTTPS(address, timeout)
@ -70,10 +71,10 @@ func (j *Jumper) dialHTTPS(address string, timeout time.Duration) (conn net.Conn
} }
reply := make([]byte, 1024) reply := make([]byte, 1024)
conn.SetDeadline(time.Now().Add(timeout)) conn.SetDeadline(time.Now().Add(timeout))
n, err := conn.Read(reply) n, e := conn.Read(reply)
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
if err != nil { if e != nil {
err = fmt.Errorf("error read reply from proxy: %s", err) err = fmt.Errorf("error read reply from proxy: %s", e)
conn.Close() conn.Close()
conn = nil conn = nil
return return
@ -94,9 +95,9 @@ func (j *Jumper) dialSOCKS5(address string, timeout time.Duration) (conn net.Con
} else { } else {
auth = nil auth = nil
} }
dialSocksProxy, err := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout}) dialSocksProxy, e := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout})
if err != nil { if e != nil {
err = fmt.Errorf("error connecting to proxy: %s", err) err = fmt.Errorf("error connecting to proxy: %s", e)
return return
} }
return dialSocksProxy.Dial("tcp", address) return dialSocksProxy.Dial("tcp", address)

View File

@ -116,7 +116,7 @@ func (b *Backend) startMuxHeartCheck() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
for { for {
@ -151,7 +151,7 @@ func (b *Backend) startTCPHeartCheck() {
go func() { go func() {
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:",e, string(debug.Stack())) fmt.Printf("crashed, err: %s\nstack:\n%s",e, string(debug.Stack()))
} }
}() }()
for { for {

View File

@ -72,9 +72,15 @@ func NewGroup(selectType int, configs BackendsConfig, dr *dnsx.DomainResolver, l
bks: bks, bks: bks,
} }
} }
func (g *Group) Select(srcAddr string, onlyHa bool) (addr string) { func (g *Group) Select(srcAddr string, onlyHa bool) (addr string) {
_, addr = g.Select2(srcAddr, onlyHa)
return
}
func (g *Group) Select2(srcAddr string, onlyHa bool) (isEmpty bool, addr string) {
addr = ""
if len(g.bks) == 1 { if len(g.bks) == 1 {
return g.bks[0].Address return false, g.bks[0].Address
} }
if onlyHa { if onlyHa {
g.lock.Lock() g.lock.Lock()
@ -84,16 +90,20 @@ func (g *Group) Select(srcAddr string, onlyHa bool) (addr string) {
g.log.Printf("############ choosed %s from lastest ############", g.last.Address) g.log.Printf("############ choosed %s from lastest ############", g.last.Address)
printDebug(true, g.log, nil, srcAddr, (*g.selector).Backends()) printDebug(true, g.log, nil, srcAddr, (*g.selector).Backends())
} }
return g.last.Address return false, g.last.Address
} }
g.last = (*g.selector).SelectBackend(srcAddr) g.last = (*g.selector).SelectBackend(srcAddr)
if !g.last.Active && g.last.ConnectUsedMillisecond > 0 { if !g.last.Active && g.last.ConnectUsedMillisecond > 0 {
g.log.Printf("###warn### lb selected empty , return default , for : %s", srcAddr) g.log.Printf("###warn### lb selected empty , return default , for : %s", srcAddr)
} }
return g.last.Address return true, g.last.Address
} }
b := (*g.selector).SelectBackend(srcAddr) b := (*g.selector).SelectBackend(srcAddr)
return b.Address if !b.Active && b.ConnectUsedMillisecond > 0 {
g.log.Printf("###warn### lb selected empty , return default , for : %s", srcAddr)
return true, b.Address
}
return false, b.Address
} }
func (g *Group) IncreasConns(addr string) { func (g *Group) IncreasConns(addr string) {

View File

@ -106,15 +106,16 @@ func (s *ServerConn) Port() string {
} }
func (s *ServerConn) Handshake() (err error) { func (s *ServerConn) Handshake() (err error) {
remoteAddr := (*s.conn).RemoteAddr() remoteAddr := (*s.conn).RemoteAddr()
localAddr := (*s.conn).LocalAddr()
//协商开始 //协商开始
//method select request //method select request
var methodReq MethodsRequest var methodReq MethodsRequest
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq, e := NewMethodsRequest((*s.conn), s.header) methodReq, e := NewMethodsRequest((*s.conn), s.header)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if e != nil { if e != nil {
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq.Reply(Method_NONE_ACCEPTABLE) methodReq.Reply(Method_NONE_ACCEPTABLE)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
err = fmt.Errorf("new methods request fail,ERR: %s", e) err = fmt.Errorf("new methods request fail,ERR: %s", e)
@ -123,7 +124,7 @@ func (s *ServerConn) Handshake() (err error) {
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH)) //log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) { if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
// if !methodReq.Select(Method_NO_AUTH) { // if !methodReq.Select(Method_NO_AUTH) {
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) // (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
// methodReq.Reply(Method_NONE_ACCEPTABLE) // methodReq.Reply(Method_NONE_ACCEPTABLE)
// (*s.conn).SetReadDeadline(time.Time{}) // (*s.conn).SetReadDeadline(time.Time{})
// err = fmt.Errorf("none method found : Method_NO_AUTH") // err = fmt.Errorf("none method found : Method_NO_AUTH")
@ -131,7 +132,7 @@ func (s *ServerConn) Handshake() (err error) {
// } // }
s.method = Method_NO_AUTH s.method = Method_NO_AUTH
//method select reply //method select reply
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
err = methodReq.Reply(Method_NO_AUTH) err = methodReq.Reply(Method_NO_AUTH)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -142,7 +143,7 @@ func (s *ServerConn) Handshake() (err error) {
} else { } else {
//auth //auth
if !methodReq.Select(Method_USER_PASS) { if !methodReq.Select(Method_USER_PASS) {
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
methodReq.Reply(Method_NONE_ACCEPTABLE) methodReq.Reply(Method_NONE_ACCEPTABLE)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
err = fmt.Errorf("none method found : Method_USER_PASS") err = fmt.Errorf("none method found : Method_USER_PASS")
@ -150,7 +151,7 @@ func (s *ServerConn) Handshake() (err error) {
} }
s.method = Method_USER_PASS s.method = Method_USER_PASS
//method reply need auth //method reply need auth
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
err = methodReq.Reply(Method_USER_PASS) err = methodReq.Reply(Method_USER_PASS)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -160,7 +161,7 @@ func (s *ServerConn) Handshake() (err error) {
//read auth //read auth
buf := make([]byte, 500) buf := make([]byte, 500)
var n int var n int
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
n, err = (*s.conn).Read(buf) n, err = (*s.conn).Read(buf)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if err != nil { if err != nil {
@ -172,9 +173,10 @@ func (s *ServerConn) Handshake() (err error) {
s.password = string(r[2+r[1]+1:]) s.password = string(r[2+r[1]+1:])
//err = fmt.Errorf("user:%s,pass:%s", user, pass) //err = fmt.Errorf("user:%s,pass:%s", user, pass)
//auth //auth
_addr := strings.Split(remoteAddr.String(), ":") _userAddr := strings.Split(remoteAddr.String(), ":")
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") { _localAddr := strings.Split(localAddr.String(), ":")
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _userAddr[0], _localAddr[0], "") {
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
_, err = (*s.conn).Write([]byte{0x01, 0x00}) _, err = (*s.conn).Write([]byte{0x01, 0x00})
(*s.conn).SetDeadline(time.Time{}) (*s.conn).SetDeadline(time.Time{})
if err != nil { if err != nil {
@ -182,7 +184,7 @@ func (s *ServerConn) Handshake() (err error) {
return return
} }
} else { } else {
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout))) (*s.conn).SetDeadline(time.Now().Add(s.timeout))
_, err = (*s.conn).Write([]byte{0x01, 0x01}) _, err = (*s.conn).Write([]byte{0x01, 0x01})
(*s.conn).SetDeadline(time.Time{}) (*s.conn).SetDeadline(time.Time{})
if err != nil { if err != nil {
@ -194,7 +196,7 @@ func (s *ServerConn) Handshake() (err error) {
} }
} }
//request detail //request detail
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout)) (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
request, e := NewRequest(*s.conn) request, e := NewRequest(*s.conn)
(*s.conn).SetReadDeadline(time.Time{}) (*s.conn).SetReadDeadline(time.Time{})
if e != nil { if e != nil {

View File

@ -24,13 +24,14 @@ import (
) )
type Checker struct { type Checker struct {
data mapx.ConcurrentMap data mapx.ConcurrentMap
blockedMap mapx.ConcurrentMap blockedMap mapx.ConcurrentMap
directMap mapx.ConcurrentMap directMap mapx.ConcurrentMap
interval int64 interval int64
timeout int timeout int
isStop bool isStop bool
log *logger.Logger intelligent string
log *logger.Logger
} }
type CheckerItem struct { type CheckerItem struct {
Domain string Domain string
@ -43,13 +44,14 @@ type CheckerItem struct {
//NewChecker args: //NewChecker args:
//timeout : tcp timeout milliseconds ,connect to host //timeout : tcp timeout milliseconds ,connect to host
//interval: recheck domain interval seconds //interval: recheck domain interval seconds
func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger) Checker { func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger, intelligent string) Checker {
ch := Checker{ ch := Checker{
data: mapx.NewConcurrentMap(), data: mapx.NewConcurrentMap(),
interval: interval, interval: interval,
timeout: timeout, timeout: timeout,
isStop: false, isStop: false,
log: log, intelligent: intelligent,
log: log,
} }
ch.blockedMap = ch.loadMap(blockedFile) ch.blockedMap = ch.loadMap(blockedFile)
ch.directMap = ch.loadMap(directFile) ch.directMap = ch.loadMap(directFile)
@ -164,10 +166,19 @@ func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, succes
//log.Printf("%s not in map, blocked true", address) //log.Printf("%s not in map, blocked true", address)
return true, false, 0, 0 return true, false, 0, 0
} }
item := _item.(CheckerItem) switch c.intelligent {
case "direct":
return (item.FailCount >= item.SuccessCount) && (time.Now().Unix()-item.Lasttime < 1800), true, item.FailCount, item.SuccessCount return false, true, 0, 0
case "parent":
return true, true, 0, 0
case "intelligent":
fallthrough
default:
item := _item.(CheckerItem)
return (item.FailCount >= item.SuccessCount) && (time.Now().Unix()-item.Lasttime < 1800), true, item.FailCount, item.SuccessCount
}
} }
func (c *Checker) domainIsInMap(address string, blockedMap bool) bool { func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
u, err := url.Parse("http://" + address) u, err := url.Parse("http://" + address)
if err != nil { if err != nil {
@ -235,7 +246,7 @@ func (ba *BasicAuth) AddFromFile(file string) (n int, err error) {
} }
userpassArr := strings.Split(strings.Replace(string(_content), "\r", "", -1), "\n") userpassArr := strings.Split(strings.Replace(string(_content), "\r", "", -1), "\n")
for _, userpass := range userpassArr { for _, userpass := range userpassArr {
if strings.HasPrefix("#", userpass) { if strings.HasPrefix(userpass, "#") {
continue continue
} }
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
@ -257,18 +268,23 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
} }
return return
} }
func (ba *BasicAuth) CheckUserPass(user, pass, ip, target string) (ok bool) { func (ba *BasicAuth) Delete(userArr []string) {
for _, u := range userArr {
return ba.Check(user+":"+pass, ip, target) ba.data.Remove(u)
}
} }
func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) { func (ba *BasicAuth) CheckUserPass(user, pass, userIP, localIP, target string) (ok bool) {
return ba.Check(user+":"+pass, userIP, localIP, target)
}
func (ba *BasicAuth) Check(userpass string, userIP, localIP, target string) (ok bool) {
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) == 2 { if len(u) == 2 {
if p, _ok := ba.data.Get(u[0]); _ok { if p, _ok := ba.data.Get(u[0]); _ok {
return p.(string) == u[1] return p.(string) == u[1]
} }
if ba.authURL != "" { if ba.authURL != "" {
err := ba.checkFromURL(userpass, ip, target) err := ba.checkFromURL(userpass, userIP, localIP, target)
if err == nil { if err == nil {
return true return true
} }
@ -278,7 +294,7 @@ func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
} }
return return
} }
func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) { func (ba *BasicAuth) checkFromURL(userpass, userIP, localIP, target string) (err error) {
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) != 2 { if len(u) != 2 {
return return
@ -290,7 +306,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
} else { } else {
URL += "?" URL += "?"
} }
URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&target=%s", u[0], u[1], ip, url.QueryEscape(target)) URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&local_ip=%s&target=%s", u[0], u[1], userIP, localIP, url.QueryEscape(target))
getURL := URL getURL := URL
var domain string var domain string
if ba.dns != nil { if ba.dns != nil {
@ -307,7 +323,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if err == nil && code == ba.authOkCode { if err == nil && code == ba.authOkCode {
break break
} else if err != nil { } else if err != nil {
err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s", URL, err, ip) err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s -> %s", URL, err, userIP, localIP)
} else { } else {
if len(body) > 0 { if len(body) > 0 {
err = fmt.Errorf(string(body[0:100])) err = fmt.Errorf(string(body[0:100]))
@ -318,7 +334,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if len(b) > 50 { if len(b) > 50 {
b = b[:50] b = b[:50]
} }
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b) err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s -> %s, %s", URL, code, ba.authOkCode, userIP, localIP, b)
} }
if err != nil && tryCount < ba.authRetry { if err != nil && tryCount < ba.authRetry {
ba.log.Print(err) ba.log.Print(err)
@ -472,7 +488,8 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
return return
} }
func (req *HTTPRequest) BasicAuth() (err error) { func (req *HTTPRequest) BasicAuth() (err error) {
addr := strings.Split((*req.conn).RemoteAddr().String(), ":") userIP := strings.Split((*req.conn).RemoteAddr().String(), ":")
localIP := strings.Split((*req.conn).LocalAddr().String(), ":")
URL := "" URL := ""
if req.IsHTTPS() { if req.IsHTTPS() {
URL = "https://" + req.Host URL = "https://" + req.Host
@ -483,7 +500,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
if err != nil { if err != nil {
return return
} }
authOk := (*req.basicAuth).Check(string(user), addr[0], URL) authOk := (*req.basicAuth).Check(string(user), userIP[0], localIP[0], URL)
//log.Printf("auth %s,%v", string(user), authOk) //log.Printf("auth %s,%v", string(user), authOk)
if !authOk { if !authOk {
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407") fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407")

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

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

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

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

191
vendor/github.com/juju/ratelimit/LICENSE generated vendored Normal file
View File

@ -0,0 +1,191 @@
All files in this repository are licensed as follows. If you contribute
to this repository, it is assumed that you license your contribution
under the same license unless you state otherwise.
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

117
vendor/github.com/juju/ratelimit/README.md generated vendored Normal file
View File

@ -0,0 +1,117 @@
# ratelimit
--
import "github.com/juju/ratelimit"
The ratelimit package provides an efficient token bucket implementation. See
http://en.wikipedia.org/wiki/Token_bucket.
## Usage
#### func Reader
```go
func Reader(r io.Reader, bucket *Bucket) io.Reader
```
Reader returns a reader that is rate limited by the given token bucket. Each
token in the bucket represents one byte.
#### func Writer
```go
func Writer(w io.Writer, bucket *Bucket) io.Writer
```
Writer returns a writer that is rate limited by the given token bucket. Each
token in the bucket represents one byte.
#### type Bucket
```go
type Bucket struct {
}
```
Bucket represents a token bucket that fills at a predetermined rate. Methods on
Bucket may be called concurrently.
#### func NewBucket
```go
func NewBucket(fillInterval time.Duration, capacity int64) *Bucket
```
NewBucket returns a new token bucket that fills at the rate of one token every
fillInterval, up to the given maximum capacity. Both arguments must be positive.
The bucket is initially full.
#### func NewBucketWithQuantum
```go
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket
```
NewBucketWithQuantum is similar to NewBucket, but allows the specification of
the quantum size - quantum tokens are added every fillInterval.
#### func NewBucketWithRate
```go
func NewBucketWithRate(rate float64, capacity int64) *Bucket
```
NewBucketWithRate returns a token bucket that fills the bucket at the rate of
rate tokens per second up to the given maximum capacity. Because of limited
clock resolution, at high rates, the actual rate may be up to 1% different from
the specified rate.
#### func (*Bucket) Rate
```go
func (tb *Bucket) Rate() float64
```
Rate returns the fill rate of the bucket, in tokens per second.
#### func (*Bucket) Take
```go
func (tb *Bucket) Take(count int64) time.Duration
```
Take takes count tokens from the bucket without blocking. It returns the time
that the caller should wait until the tokens are actually available.
Note that if the request is irrevocable - there is no way to return tokens to
the bucket once this method commits us to taking them.
#### func (*Bucket) TakeAvailable
```go
func (tb *Bucket) TakeAvailable(count int64) int64
```
TakeAvailable takes up to count immediately available tokens from the bucket. It
returns the number of tokens removed, or zero if there are no available tokens.
It does not block.
#### func (*Bucket) TakeMaxDuration
```go
func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool)
```
TakeMaxDuration is like Take, except that it will only take tokens from the
bucket if the wait time for the tokens is no greater than maxWait.
If it would take longer than maxWait for the tokens to become available, it does
nothing and reports false, otherwise it returns the time that the caller should
wait until the tokens are actually available, and reports true.
#### func (*Bucket) Wait
```go
func (tb *Bucket) Wait(count int64)
```
Wait takes count tokens from the bucket, waiting until they are available.
#### func (*Bucket) WaitMaxDuration
```go
func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool
```
WaitMaxDuration is like Wait except that it will only take tokens from the
bucket if it needs to wait for no greater than maxWait. It reports whether any
tokens have been removed from the bucket If no tokens have been removed, it
returns immediately.

344
vendor/github.com/juju/ratelimit/ratelimit.go generated vendored Normal file
View File

@ -0,0 +1,344 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
// Package ratelimit provides an efficient token bucket implementation
// that can be used to limit the rate of arbitrary things.
// See http://en.wikipedia.org/wiki/Token_bucket.
package ratelimit
import (
"math"
"strconv"
"sync"
"time"
)
// The algorithm that this implementation uses does computational work
// only when tokens are removed from the bucket, and that work completes
// in short, bounded-constant time (Bucket.Wait benchmarks at 175ns on
// my laptop).
//
// Time is measured in equal measured ticks, a given interval
// (fillInterval) apart. On each tick a number of tokens (quantum) are
// added to the bucket.
//
// When any of the methods are called the bucket updates the number of
// tokens that are in the bucket, and it records the current tick
// number too. Note that it doesn't record the current time - by
// keeping things in units of whole ticks, it's easy to dish out tokens
// at exactly the right intervals as measured from the start time.
//
// This allows us to calculate the number of tokens that will be
// available at some time in the future with a few simple arithmetic
// operations.
//
// The main reason for being able to transfer multiple tokens on each tick
// is so that we can represent rates greater than 1e9 (the resolution of the Go
// time package) tokens per second, but it's also useful because
// it means we can easily represent situations like "a person gets
// five tokens an hour, replenished on the hour".
// Bucket represents a token bucket that fills at a predetermined rate.
// Methods on Bucket may be called concurrently.
type Bucket struct {
clock Clock
// startTime holds the moment when the bucket was
// first created and ticks began.
startTime time.Time
// capacity holds the overall capacity of the bucket.
capacity int64
// quantum holds how many tokens are added on
// each tick.
quantum int64
// fillInterval holds the interval between each tick.
fillInterval time.Duration
// mu guards the fields below it.
mu sync.Mutex
// availableTokens holds the number of available
// tokens as of the associated latestTick.
// It will be negative when there are consumers
// waiting for tokens.
availableTokens int64
// latestTick holds the latest tick for which
// we know the number of tokens in the bucket.
latestTick int64
}
// NewBucket returns a new token bucket that fills at the
// rate of one token every fillInterval, up to the given
// maximum capacity. Both arguments must be
// positive. The bucket is initially full.
func NewBucket(fillInterval time.Duration, capacity int64) *Bucket {
return NewBucketWithClock(fillInterval, capacity, nil)
}
// NewBucketWithClock is identical to NewBucket but injects a testable clock
// interface.
func NewBucketWithClock(fillInterval time.Duration, capacity int64, clock Clock) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, 1, clock)
}
// rateMargin specifes the allowed variance of actual
// rate from specified rate. 1% seems reasonable.
const rateMargin = 0.01
// NewBucketWithRate returns a token bucket that fills the bucket
// at the rate of rate tokens per second up to the given
// maximum capacity. Because of limited clock resolution,
// at high rates, the actual rate may be up to 1% different from the
// specified rate.
func NewBucketWithRate(rate float64, capacity int64) *Bucket {
return NewBucketWithRateAndClock(rate, capacity, nil)
}
// NewBucketWithRateAndClock is identical to NewBucketWithRate but injects a
// testable clock interface.
func NewBucketWithRateAndClock(rate float64, capacity int64, clock Clock) *Bucket {
// Use the same bucket each time through the loop
// to save allocations.
tb := NewBucketWithQuantumAndClock(1, capacity, 1, clock)
for quantum := int64(1); quantum < 1<<50; quantum = nextQuantum(quantum) {
fillInterval := time.Duration(1e9 * float64(quantum) / rate)
if fillInterval <= 0 {
continue
}
tb.fillInterval = fillInterval
tb.quantum = quantum
if diff := math.Abs(tb.Rate() - rate); diff/rate <= rateMargin {
return tb
}
}
panic("cannot find suitable quantum for " + strconv.FormatFloat(rate, 'g', -1, 64))
}
// nextQuantum returns the next quantum to try after q.
// We grow the quantum exponentially, but slowly, so we
// get a good fit in the lower numbers.
func nextQuantum(q int64) int64 {
q1 := q * 11 / 10
if q1 == q {
q1++
}
return q1
}
// NewBucketWithQuantum is similar to NewBucket, but allows
// the specification of the quantum size - quantum tokens
// are added every fillInterval.
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, quantum, nil)
}
// NewBucketWithQuantumAndClock is like NewBucketWithQuantum, but
// also has a clock argument that allows clients to fake the passing
// of time. If clock is nil, the system clock will be used.
func NewBucketWithQuantumAndClock(fillInterval time.Duration, capacity, quantum int64, clock Clock) *Bucket {
if clock == nil {
clock = realClock{}
}
if fillInterval <= 0 {
panic("token bucket fill interval is not > 0")
}
if capacity <= 0 {
panic("token bucket capacity is not > 0")
}
if quantum <= 0 {
panic("token bucket quantum is not > 0")
}
return &Bucket{
clock: clock,
startTime: clock.Now(),
latestTick: 0,
fillInterval: fillInterval,
capacity: capacity,
quantum: quantum,
availableTokens: capacity,
}
}
// Wait takes count tokens from the bucket, waiting until they are
// available.
func (tb *Bucket) Wait(count int64) {
if d := tb.Take(count); d > 0 {
tb.clock.Sleep(d)
}
}
// WaitMaxDuration is like Wait except that it will
// only take tokens from the bucket if it needs to wait
// for no greater than maxWait. It reports whether
// any tokens have been removed from the bucket
// If no tokens have been removed, it returns immediately.
func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool {
d, ok := tb.TakeMaxDuration(count, maxWait)
if d > 0 {
tb.clock.Sleep(d)
}
return ok
}
const infinityDuration time.Duration = 0x7fffffffffffffff
// Take takes count tokens from the bucket without blocking. It returns
// the time that the caller should wait until the tokens are actually
// available.
//
// Note that if the request is irrevocable - there is no way to return
// tokens to the bucket once this method commits us to taking them.
func (tb *Bucket) Take(count int64) time.Duration {
tb.mu.Lock()
defer tb.mu.Unlock()
d, _ := tb.take(tb.clock.Now(), count, infinityDuration)
return d
}
// TakeMaxDuration is like Take, except that
// it will only take tokens from the bucket if the wait
// time for the tokens is no greater than maxWait.
//
// If it would take longer than maxWait for the tokens
// to become available, it does nothing and reports false,
// otherwise it returns the time that the caller should
// wait until the tokens are actually available, and reports
// true.
func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool) {
tb.mu.Lock()
defer tb.mu.Unlock()
return tb.take(tb.clock.Now(), count, maxWait)
}
// TakeAvailable takes up to count immediately available tokens from the
// bucket. It returns the number of tokens removed, or zero if there are
// no available tokens. It does not block.
func (tb *Bucket) TakeAvailable(count int64) int64 {
tb.mu.Lock()
defer tb.mu.Unlock()
return tb.takeAvailable(tb.clock.Now(), count)
}
// takeAvailable is the internal version of TakeAvailable - it takes the
// current time as an argument to enable easy testing.
func (tb *Bucket) takeAvailable(now time.Time, count int64) int64 {
if count <= 0 {
return 0
}
tb.adjustavailableTokens(tb.currentTick(now))
if tb.availableTokens <= 0 {
return 0
}
if count > tb.availableTokens {
count = tb.availableTokens
}
tb.availableTokens -= count
return count
}
// Available returns the number of available tokens. It will be negative
// when there are consumers waiting for tokens. Note that if this
// returns greater than zero, it does not guarantee that calls that take
// tokens from the buffer will succeed, as the number of available
// tokens could have changed in the meantime. This method is intended
// primarily for metrics reporting and debugging.
func (tb *Bucket) Available() int64 {
return tb.available(tb.clock.Now())
}
// available is the internal version of available - it takes the current time as
// an argument to enable easy testing.
func (tb *Bucket) available(now time.Time) int64 {
tb.mu.Lock()
defer tb.mu.Unlock()
tb.adjustavailableTokens(tb.currentTick(now))
return tb.availableTokens
}
// Capacity returns the capacity that the bucket was created with.
func (tb *Bucket) Capacity() int64 {
return tb.capacity
}
// Rate returns the fill rate of the bucket, in tokens per second.
func (tb *Bucket) Rate() float64 {
return 1e9 * float64(tb.quantum) / float64(tb.fillInterval)
}
// take is the internal version of Take - it takes the current time as
// an argument to enable easy testing.
func (tb *Bucket) take(now time.Time, count int64, maxWait time.Duration) (time.Duration, bool) {
if count <= 0 {
return 0, true
}
tick := tb.currentTick(now)
tb.adjustavailableTokens(tick)
avail := tb.availableTokens - count
if avail >= 0 {
tb.availableTokens = avail
return 0, true
}
// Round up the missing tokens to the nearest multiple
// of quantum - the tokens won't be available until
// that tick.
// endTick holds the tick when all the requested tokens will
// become available.
endTick := tick + (-avail+tb.quantum-1)/tb.quantum
endTime := tb.startTime.Add(time.Duration(endTick) * tb.fillInterval)
waitTime := endTime.Sub(now)
if waitTime > maxWait {
return 0, false
}
tb.availableTokens = avail
return waitTime, true
}
// currentTick returns the current time tick, measured
// from tb.startTime.
func (tb *Bucket) currentTick(now time.Time) int64 {
return int64(now.Sub(tb.startTime) / tb.fillInterval)
}
// adjustavailableTokens adjusts the current number of tokens
// available in the bucket at the given time, which must
// be in the future (positive) with respect to tb.latestTick.
func (tb *Bucket) adjustavailableTokens(tick int64) {
if tb.availableTokens >= tb.capacity {
return
}
tb.availableTokens += (tick - tb.latestTick) * tb.quantum
if tb.availableTokens > tb.capacity {
tb.availableTokens = tb.capacity
}
tb.latestTick = tick
return
}
// Clock represents the passage of time in a way that
// can be faked out for tests.
type Clock interface {
// Now returns the current time.
Now() time.Time
// Sleep sleeps for at least the given duration.
Sleep(d time.Duration)
}
// realClock implements Clock in terms of standard time functions.
type realClock struct{}
// Now implements Clock.Now by calling time.Now.
func (realClock) Now() time.Time {
return time.Now()
}
// Now implements Clock.Sleep by calling time.Sleep.
func (realClock) Sleep(d time.Duration) {
time.Sleep(d)
}

51
vendor/github.com/juju/ratelimit/reader.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2014 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package ratelimit
import "io"
type reader struct {
r io.Reader
bucket *Bucket
}
// Reader returns a reader that is rate limited by
// the given token bucket. Each token in the bucket
// represents one byte.
func Reader(r io.Reader, bucket *Bucket) io.Reader {
return &reader{
r: r,
bucket: bucket,
}
}
func (r *reader) Read(buf []byte) (int, error) {
n, err := r.r.Read(buf)
if n <= 0 {
return n, err
}
r.bucket.Wait(int64(n))
return n, err
}
type writer struct {
w io.Writer
bucket *Bucket
}
// Writer returns a reader that is rate limited by
// the given token bucket. Each token in the bucket
// represents one byte.
func Writer(w io.Writer, bucket *Bucket) io.Writer {
return &writer{
w: w,
bucket: bucket,
}
}
func (w *writer) Write(buf []byte) (int, error) {
w.bucket.Wait(int64(len(buf)))
return w.w.Write(buf)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 26 KiB

3
vendor/golang.org/x/sys/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/golang.org/x/sys/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

27
vendor/golang.org/x/sys/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/sys/PATENTS generated vendored Normal file
View File

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

2
vendor/golang.org/x/sys/unix/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
_obj/
unix.test

173
vendor/golang.org/x/sys/unix/README.md generated vendored Normal file
View File

@ -0,0 +1,173 @@
# Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
## Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
### Old Build System (currently for `GOOS != "Linux" || GOARCH == "sparc64"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, perl, go
### New Build System (currently for `GOOS == "Linux" && GOARCH != "sparc64"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, perl, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts cannot be called normally.
They must be called from within the docker container.
### asm files
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to an new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
### mksysnum
Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl`
for the old system). This script takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the
parsing in mksysnum.
### mksyscall.pl
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, an then write a custom wrapper in
`syscall_${GOOS}.go`.
### types files
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.
### mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
an a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include <errno.h>`, and the
signal numbers and strings are generated from `#include <signal.h>`. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
## Generated files
### `zerror_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.pl` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
### `ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).

124
vendor/golang.org/x/sys/unix/affinity_linux.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// CPU affinity functions
package unix
import (
"unsafe"
)
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
// CPUSet represents a CPU affinity mask.
type CPUSet [cpuSetSize]cpuMask
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
if e != 0 {
return errnoErr(e)
}
return nil
}
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedGetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
}
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
}
// Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() {
for i := range s {
s[i] = 0
}
}
func cpuBitsIndex(cpu int) int {
return cpu / _NCPUBITS
}
func cpuBitsMask(cpu int) cpuMask {
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
}
// Set adds cpu to the set s.
func (s *CPUSet) Set(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] |= cpuBitsMask(cpu)
}
}
// Clear removes cpu from the set s.
func (s *CPUSet) Clear(cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] &^= cpuBitsMask(cpu)
}
}
// IsSet reports whether cpu is in the set s.
func (s *CPUSet) IsSet(cpu int) bool {
i := cpuBitsIndex(cpu)
if i < len(s) {
return s[i]&cpuBitsMask(cpu) != 0
}
return false
}
// Count returns the number of CPUs in the set s.
func (s *CPUSet) Count() int {
c := 0
for _, b := range s {
c += onesCount64(uint64(b))
}
return c
}
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
// Once this package can require Go 1.9, we can delete this
// and update the caller to use bits.OnesCount64.
func onesCount64(x uint64) int {
const m0 = 0x5555555555555555 // 01010101 ...
const m1 = 0x3333333333333333 // 00110011 ...
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
const m3 = 0x00ff00ff00ff00ff // etc.
const m4 = 0x0000ffff0000ffff
// Implementation: Parallel summing of adjacent bits.
// See "Hacker's Delight", Chap. 5: Counting Bits.
// The following pattern shows the general approach:
//
// x = x>>1&(m0&m) + x&(m0&m)
// x = x>>2&(m1&m) + x&(m1&m)
// x = x>>4&(m2&m) + x&(m2&m)
// x = x>>8&(m3&m) + x&(m3&m)
// x = x>>16&(m4&m) + x&(m4&m)
// x = x>>32&(m5&m) + x&(m5&m)
// return int(x)
//
// Masking (& operations) can be left away when there's no
// danger that a field's sum will carry over into the next
// field: Since the result cannot be > 64, 8 bits is enough
// and we can ignore the masks for the shifts by 8 and up.
// Per "Hacker's Delight", the first line can be simplified
// more, but it saves at best one instruction, so we leave
// it alone for clarity.
const m = 1<<64 - 1
x = x>>1&(m0&m) + x&(m0&m)
x = x>>2&(m1&m) + x&(m1&m)
x = (x>>4 + x) & (m2 & m)
x += x >> 8
x += x >> 16
x += x >> 32
return int(x) & (1<<7 - 1)
}

Some files were not shown because too many files have changed in this diff Show More