129 Commits
v6.0 ... 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
arraykeys@gmail.com
ef8737063b v6.1 2018-09-19 12:14:16 +08:00
arraykeys@gmail.com
b5e0fa4895 v6.1 2018-09-19 11:51:01 +08:00
arraykeys@gmail.com
02513a9449 fix #146
server channel统一使用core
2018-09-19 11:34:34 +08:00
arraykeys@gmail.com
0859452475 优化负载均衡,当只有一个节点的时候,不再启动健康检查. 2018-09-18 16:14:06 +08:00
arraykeys@gmail.com
42d18ca1d3 优化负载均衡,当只有一个节点的时候,不再启动健康检查. 2018-09-18 16:08:59 +08:00
arraykeys@gmail.com
08b3715bda a 2018-09-18 15:36:10 +08:00
arraykeys@gmail.com
253783573a a 2018-09-18 15:34:38 +08:00
arraykeys@gmail.com
56dc3fdc07 a 2018-09-18 11:34:25 +08:00
arraykeys@gmail.com
af20893551 a 2018-09-18 11:30:48 +08:00
arraykeys@gmail.com
85178223e0 5.优化了DST,防止意外crash.
6.修复了mapx的Keys()方法的bug导致内网穿透bridge不稳定的问题.
2018-09-14 18:20:45 +08:00
arraykeys@gmail.com
e116bf8897 update kcpcfg import path 2018-09-14 16:12:56 +08:00
arraykeys@gmail.com
0fffedebd7 优化域名检测 2018-09-14 11:56:11 +08:00
arraykeys@gmail.com
1e259b5c6f 优化crashed日志 2018-09-14 11:48:51 +08:00
arraykeys@gmail.com
7bb5bb86dc 优化crashed日志 2018-09-14 11:47:50 +08:00
snail007
18716cb3a2 Merge pull request #143 from Quasilyte/quasilyte/docStub
core/tproxy: replace doc-comment stubs
2018-09-14 11:43:36 +08:00
snail007
1aca777c6d Merge pull request #142 from Quasilyte/quasilyte/underef
simplify (*x).f to x.f where it does not change the semantics
2018-09-14 11:42:34 +08:00
snail007
3a5b47b84a Merge pull request #141 from Quasilyte/quasilyte/commentedOutCode
remove some commented-out (dead) code
2018-09-14 11:40:51 +08:00
snail007
8bda30c4cf Merge pull request #140 from Quasilyte/quasilyte/emptyFallthrough
services: simplify switch statements with case clause lists
2018-09-14 11:37:25 +08:00
snail007
03ef384c48 Update install_auto.sh 2018-09-14 11:37:06 +08:00
Iskander Sharipov
5ace1eef1d core/tproxy: replace doc-comment stubs
Found using https://go-critic.github.io/overview#docStub-ref
2018-09-13 21:31:05 +03:00
Iskander Sharipov
d270b4a468 simplify (*x).f to x.f where it does not change the semantics
Found using https://go-critic.github.io/overview#underef-ref
2018-09-13 21:16:50 +03:00
Iskander Sharipov
6154d4173a remove some commented-out (dead) code
There are much more places, removed only few of them
to make review simpler (we can remove more later).

Found using https://go-critic.github.io/overview#commentedOutCode-ref
2018-09-13 21:04:07 +03:00
Iskander Sharipov
70067d67b9 services: simplify switch statements with case clause lists
Case clause lists are simpler and more compact than
multiple cases with fallthrough.

Found using https://go-critic.github.io/overview#emptyFallthrough-ref
2018-09-13 20:46:16 +03:00
arraykeys@gmail.com
8befdbc89c 黑白名单支持设置顶级域了,比如:com,匹配所有的.com域名 2018-09-12 11:20:03 +08:00
snail007
900b975c6a Update install_auto.sh 2018-09-11 19:30:47 +08:00
snail007
2ddb03a6c7 Merge pull request #139 from snail007/master
6.1
2018-09-11 19:29:16 +08:00
arraykeys@gmail.com
4145a31e5b 黑白名单支持设置顶级域了,比如:com,匹配所有的.com域名 2018-09-11 18:37:09 +08:00
arraykeys@gmail.com
96717f0c33 减少buf大小,降低高并发情况下内存占用量. 2018-09-10 14:42:04 +08:00
arraykeys@gmail.com
09348211b6 优化TCPS内存释放 2018-09-10 13:56:59 +08:00
arraykeys@gmail.com
179f9d63ab Merge remote-tracking branch 'origin/master' 2018-09-10 13:40:42 +08:00
arraykeys@gmail.com
7692446fd8 优化TCPS内存释放 2018-09-10 13:40:15 +08:00
yincongcyincong
69f20e1d7a Update README.md 2018-09-07 09:19:26 +08:00
snail007
0bebee1537 Merge pull request #133 from snail007/dev
update readme
2018-09-07 09:09:35 +08:00
snail007
61569c3a92 Merge pull request #132 from yincongcyincong/dev
Dev
2018-09-07 09:07:16 +08:00
yincongcyincong
0d6e10ad33 Update README.md 2018-09-07 08:53:17 +08:00
yincongcyincong
77a6300dae Update README.md 2018-09-06 18:48:07 +08:00
yincongcyincong
8f268b8b56 Update README.md 2018-09-06 18:04:10 +08:00
arraykeys@gmail.com
efb5710727 v6.0 2018-09-06 16:16:10 +08:00
arraykeys@gmail.com
7fc0b21764 Merge branch 'dev' 2018-09-06 16:10:00 +08:00
snail007
2f524010a1 Merge pull request #131 from smlrepo/master
fix build breakage
2018-09-06 16:09:18 +08:00
Lonnie Liu
c537240d3d fix build breakage 2018-09-06 00:31:02 -07:00
yincongcyincong
d3640f7519 Update README.md 2018-09-06 14:06:23 +08:00
yincongcyincong
575326bed1 Update README.md 2018-09-05 17:32:53 +08:00
352 changed files with 186763 additions and 1174 deletions

13
AUTHORIZATION.md Normal file
View File

@ -0,0 +1,13 @@
# GoProxy special authorization
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. 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. If "GoPro special authorization"is not available on this page,the" GoPro special authorization"is invalid.
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,64 @@
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
1.黑白名单支持设置顶级域了,比如:com,匹配所有的.com域名
2.优化TCPS内存释放.
3.优化了域名检查.
4.内网穿透增加了TCPS和TOU协议,
TCPS提供了多种自定义加密TCP方式传输.
TOU提供了TCP over UDP,多种自定义加密UDP方式传输TCP数据.
5.优化了DST,防止意外crash.
6.修复了mapx的Keys()方法的bug导致内网穿透bridge不稳定的问题.
7.修复了部分服务不能绑定IPv6地址的bug.
v6.0 企业版开源啦
本次更新主要是把企业版开源,把企业版代码合并到现在的开源goproxy当中,继续遵循GPLv3,免费开源,
之所以直接跳过5.x,用6.0版本号是为了与现有开源版本做一个明显的区分,下面功能主要来自企业版.

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'.
[[projects]]
branch = "master"
name = "github.com/Yawning/chacha20"
packages = ["."]
revision = "e3b1f968fc6397b51d963fee8ec8711a47bc0ce8"
[[projects]]
branch = "master"
name = "github.com/alecthomas/template"
@ -28,6 +34,12 @@
packages = ["."]
revision = "3520598351bb3500a49ae9563f5539666ae0a27c"
[[projects]]
name = "github.com/juju/ratelimit"
packages = ["."]
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
version = "1.0.1"
[[projects]]
name = "github.com/klauspost/cpuid"
packages = ["."]
@ -119,6 +131,12 @@
]
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "dad3d9fb7b6e83d0f9ac8f54670f6334c3a287b4"
[[projects]]
branch = "master"
name = "golang.org/x/time"
@ -134,6 +152,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "eab0ef29432489696d8bfd524757dcb03a83f91c329f2d05c36da70df850360d"
inputs-digest = "15e4e23c0695db1458b3dc5514c8765be091a420c923b24bb9e186f43400995f"
solver-name = "gps-cdcl"
solver-version = 1

244
README.md
View File

@ -1,6 +1,7 @@
<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 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,9 +9,11 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5 prox
**[中文手册](/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 special authorization](/AUTHORIZATION.md)**
### How to contribute to the code (Pull Request)?
@ -33,10 +36,15 @@ PR needs to explain what changes have been made and why you change them.
- The integrated external API, HTTP (S): SOCKS5 proxy authentication can be integrated with the external HTTP API, which can easily control the user's access through the external system.
- Reverse proxy: goproxy supports directly parsing the domain to proxy monitor IP, and then proxy will help you to access the HTTP (S) site that you need to access.
- Transparent proxy: with the iptables, goproxy can directly forward the 80 and 443 port's traffic to proxy in the gateway, and can realize the unaware intelligent router proxy.
- Protocol conversion: The existing HTTP (S) or SOCKS5 proxy can be converted to a proxy which support both HTTP (S) and SOCKS5 by one port, but the converted SOCKS5 proxy does not support the UDP function.Also support powerful cascading authentication.  
- Protocol conversion: The existing HTTP (S) or SOCKS5 or ss proxy can be converted to a proxy which support HTTP (S), SOCKS5 and ss by one port, if the converted SOCKS5 and ss proxy's parent proxy is SOCKS5, which can support the UDP function.Also support powerful cascading authentication.  
- Custom underlying encrypted transmission, HTTP(s)\sps\socks proxy can encrypt TCP data through TLS standard encryption and KCP protocol encryption. In addition, it also supports custom encryption after TLS and KCP. That is to say, custom encryption and tls|kcp can be used together. The internal uses AES256 encryption, and it only needs to define one password by yourself when is used.
- Low level compression and efficient transmissionThe HTTP(s)\sps\socks proxy can encrypt TCP data through a custom encryption and TLS standard encryption and KCP protocol encryption, and can also compress the data after encryption. That is to say, the compression and custom encryption and tls|kcp can be used together.
- The secure DNS proxy, Through the DNS proxy provided by the local proxy, you can encrypted communicate with the father proxy to realize the DNS query of security and pollution prevention.
- Load balance,High availability,HTTP(S)\SOCKS5\SPS proxy support Superior load balance and high availability. Multiple superiors repeat -P parameters.
- Designated exporting IP,HTTP(S)\SOCKS5\SPS proxy supports the client to connect with the entry IP,Using the entry IP as the exporting IP to visit the target website。If the entry IP is the intranet IPExporting IP will not use entry IP
- Support speed limit. HTTP (S) \SOCKS5\SPS proxy supports speed limit.
- SOCKS5 proxy supports cascade authentication.
- Certificate parameters use base64 data. By default, the - C, - K parameters are the path of the CRT certificate and key file. If “base64://” begins, the subsequent data is thought to be Base64 encoded which will be decoded and used.
### Why need these?
- Because for some reason, we cannot access our services elsewhere. We can build a secure tunnel to access our services through multiple connected proxy nodes.  
@ -48,7 +56,7 @@ PR needs to explain what changes have been made and why you change them.
- ...  
This page is the v5.4 manual, and the other version of the manual can be checked by the following [link](docs/old-release.md).
This page is the v6.0 manual, and the other version of the manual can be checked by the following [link](docs/old-release.md).
### How to find the organization?
@ -72,6 +80,7 @@ This page is the v5.4 manual, and the other version of the manual can be checked
- [Safety advice](#safety-advice)
### Manual catalogues
- [Load balance and high available](#load-balance-and-high-available)
- [1.HTTP proxy](#1http-proxy)
- [1.1 Common HTTP proxy](#11common-http-proxy)
- [1.2 Common HTTP second level proxy](#12common-http-second-level-proxy)
@ -88,7 +97,12 @@ This page is the v5.4 manual, and the other version of the manual can be checked
- [1.11 Custom DNS](#111custom-dns)
- [1.12 Custom encryption](#112-custom-encryption)
- [1.13 Compressed transmission](#113-compressed-transmission)
- [1.14 View help](#114view-help)
- [1.14 load balance](#114-load-balance)
- [1.15 speed limit](#115-speed-limit)
- [1.16 Designated exporting IP](#116-designated-export-ip)
- [1.17 Certificate parameters using Base64 data](#117-certificate-parameters-using-Base64-data)
- [1.18 Intelligent mode](#118-intelligent-mode)
- [1.19 View help](#119view-help)
- [2.TCP proxy](#2tcp-proxy)
- [2.1 Common TCP first level proxy](#21common-tcp-first-level-proxy)
- [2.2 Common TCP second level proxy](#22common-tcp-second-level-proxy)
@ -128,17 +142,28 @@ This page is the v5.4 manual, and the other version of the manual can be checked
- [5.9 Custom DNS](#59custom-dns)
- [5.10 Custom encryption](#510custom-encryption)
- [5.11 Compressed transmission](#511compressed-transmission)
- [5.12 View help](#512view-help)
- [5.12 load balance](#512-load-balance)
- [5.13 speed limit](#513-speed-limit)
- [5.14 Designated exporting IP](#514-designated-exporting-ip)
- [5.15 Cascade authentication](#515-cascade-authentication)
- [5.16 Certificate parameters using Base64 data](#516-certificate-parameters-using-base64-data)
- [5.17 Intelligent mode](#517-intelligent-mode)
- [5.18 View help](#518view-help)
- [6.Proxy protocol conversion](#6proxy-protocol-conversion)
- [6.1 Functional introduction](#61functional-introduction)
- [6.2 HTTP(S) to HTTP(S) + SOCKS5](#62http-to-http-socks5)
- [6.3 SOCKS5 to HTTP(S) + SOCKS5](#63socks5-to-http-socks5)
- [6.4 Chain style connection](#64chain-style-connection)
- [6.5 Listening on multiple ports](#65listening-on-multiple-ports)
- [6.6 Authentication](#66authentication)
- [6.7 Custom encryption](#67-custom-encryption)
- [6.8 Compressed transmission](#68-compressed-transmission)
- [6.9 View Help](#69view-help)
- [6.4 SS to HTTP(S)+SOCKS5+SS](#64-ss-to-httpssocks5ss)
- [6.5 Chain style connection](#65chain-style-connection)
- [6.6 Listening on multiple ports](#66listening-on-multiple-ports)
- [6.7 Authentication](#67authentication)
- [6.8 Custom encryption](#68-custom-encryption)
- [6.9 Compressed transmission](#69-compressed-transmission)
- [6.10 Disable-protocol](#610-disable-protocol)
- [6.11 speed limit](#611-speed-limit)
- [6.12 Designated exporting IP](#612-designated-exporting-ip)
- [6.13 Certificate parameters using Base64 data](#613-certificate-parameters-using-base64-data)
- [6.14 View Help](#614view-help)
- [7.KCP Configuration](#7kcp-configuration)
- [7.1 Configuration introduction](#71configuration-introduction)
- [7.2 Configuration details](#72configuration-details)
@ -155,7 +180,7 @@ tips:all operations require root permissions.
```shell
curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
```
The installation is completed, the configuration directory is /etc/proxy, more detailed use of the method referred to the following manual for further understanding.
The installation is completed, the configuration directory is /etc/proxy, For more detailed usage, please refer to the manual above to further understand the functions you want to use.
If the installation fails or your VPS is not a linux64 system, please follow the semi-automatic step below:
#### Manual installation
@ -164,7 +189,7 @@ If the installation fails or your VPS is not a linux64 system, please follow the
Download address: https://github.com/snail007/goproxy/releases
```shell
cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v5.4/proxy-linux-amd64.tar.gz
wget https://github.com/snail007/goproxy/releases/download/v6.0/proxy-linux-amd64.tar.gz
```
#### **2.Download the automatic installation script**
@ -177,12 +202,14 @@ chmod +x install.sh
#### 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.
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 5.4:
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:
```
ARG GOPROXY_VERSION=v5.4
ARG GOPROXY_VERSION=v6.0
```
To Run:
@ -261,6 +288,20 @@ When vps is behind the NAT, the network card IP on VPS is an internal network IP
Assuming that your VPS outer external network IP is 23.23.23.23, the following command sets the 23.23.23.23 through the -g parameter.
`./proxy http -g "23.23.23.23"`
### **Load balance and high available**
HTTP(S)\SOCKS5\SPS proxy support Superior load balance and high availability. Multiple superiors repeat -P parameters.
Load balancing have 5 kinds of policy, It can be specified by the `--lb-method` parameter.:
roundrobin take turns
leastconn Using minimum connection number
leasttime Use minimum connection time
hash Use the client address to calculate a fixed superior
weight According to the weight and connection number of each superior, choose a superior
Tips:
The load balance check interval can be set by `--lb-retrytime`, unit milliseconds.
Load balancing connection timeout can be set by `--lb-timeout`, unit milliseconds.
If the load balance policy is weighted (weight), the -P format is: 2.2.2.2:3880@1,1 is the weight which is greater than 0.
If the load balance strategy is hash, the default is to select the parent based on the client address, and the parent can be selected by switching `- lb-hashtarget', using the access destination address.
### **1.HTTP proxy**
#### **1.1.common HTTP proxy**
![1.1](/docs/images/http-1.png)
@ -287,7 +328,7 @@ accessing the local 8080 port is accessing the proxy port 38080 above VPS.  
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`
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](/docs/images/http-tls-3.png)
@ -459,7 +500,40 @@ Local third level execution:
`proxy http -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **1.14.view help**
### **1.14 Load balance**
HTTP (S) proxy supports superior load balance, and multiple -P parameters can be repeated by multiple superiors.
`proxy http --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080`
#### **1.14.1 Set retry interval and timeout time**
`proxy http --lb-method=leastconn --lb-retrytime 300 --lb-timeout 300 -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
#### **1.14.2 Set weight**
`proxy http --lb-method=weight -T tcp -P 1.1.1.1:33080@1 -P 2.1.1.1:33080@2 -P 3.1.1.1:33080@1 -t tcp -p :33080`
#### **1.14.3 Use target address to select superior**
`proxy http --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
### **1.15 Speed limit**
The speed limit is 100K, which can be specified through the `-l` parameter, for example: 100K 1.5M. 0 means unlimited.
`proxy http -t tcp -p 2.2.2.2:33080 -l 100K`
### **1.16 Designated exporting 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`
### **1.17 Certificate parameters using Base64 data**
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.
#### **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`
### **2.TCP proxy**
@ -868,41 +942,88 @@ Local third level execution:
`proxy socks -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **5.12.view help**
#### **5.12 Load balance**
SOCKS proxy supports the load balancing of superior authorities, and the -P parameters can be repeated by multiple superiors.
`proxy socks --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
#### **5.12.1 Set retry interval and timeout time**
`proxy socks --lb-method=leastconn --lb-retrytime 300 --lb-timeout 300 -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
#### **5.12.2 Set weight**
`proxy socks --lb-method=weight -T tcp -P 1.1.1.1:33080@1 -P 2.1.1.1:33080@2 -P 3.1.1.1:33080@1 -p :33080 -t tcp`
#### **5.12.3 Use target address to select parent proxy**
`proxy socks --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
#### **5.13 Speed limit**
The speed limit is 100K, which can be specified through the -l parameter, for example: 100K 1.5M. 0 means unlimited.
`proxy socks -t tcp -p 2.2.2.2:33080 -l 100K`
#### **5.14 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..
`proxy socks -t tcp -p 2.2.2.2:33080 --bind-listen`
#### **5.15 Cascade authentication**
SOCKS5 supports cascading authentication, and -A can set up parents proxy's authentication information..
parents proxy:
`proxy socks -t tcp -p 2.2.2.2:33080 -a user:pass`
localhost:
`proxy socks -T tcp -P 2.2.2.2:33080 -A user:pass -t tcp -p :33080`
#### **5.16 Certificate parameters using Base64 data**
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.
#### **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`
### **6.Proxy protocol conversion**
#### **6.1.Functional introduction**
The proxy protocol conversion use the SPS subcommand (abbreviation of socks+https), SPS itself does not provide the proxy function, just accept the proxy request and then converse protocol and forwarded to the existing HTTP (s) or Socks5 proxy. SPS can use existing HTTP (s) or Socks5 proxy converse to support HTTP (s) and Socks5 HTTP (s) proxy at the same time by one port, and proxy supports forward and reverse proxy (SNI), SOCKS5 proxy which is also does support UDP when parent is Socks5. in addition to the existing HTTP or Socks5 proxy, which supports TLS, TCP, KCP three modes and chain-style connection. That is more than one SPS node connection can build encryption channel.
The proxy protocol conversion use the SPS subcommand, SPS itself does not provide the proxy function, just accept the proxy request and then converse protocol and forwarded to the existing HTTP (s) or Socks5 proxy. SPS can use existing HTTP (s) or Socks5 proxy converse to support HTTP (s) and Socks5 HTTP (s) proxy at the same time by one port, and proxy supports forward and reverse proxy (SNI), SOCKS5 proxy which is also does support UDP when parent is Socks5. in addition to the existing HTTP or Socks5 proxy, which supports TLS, TCP, KCP three modes and chain-style connection. That is more than one SPS node connection can build encryption channel.
#### **6.2.HTTP(S) to HTTP(S) + SOCKS5**
Suppose there is a common HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080.
Suppose there is a common HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time. The local port after transformation is 18080. ss's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`
Suppose that there is a TLS HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080, TLS needs certificate file.
Suppose that there is a TLS HTTP (s) proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time. The local port after transformation is 18080, TLS needs certificate filess's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S http -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
`./proxy sps -S http -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key -h aes-192-cfb -j pass`
Suppose there is a KCP HTTP (s) proxy (password: demo123): 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time. The local port after transformation is 18080.
Suppose there is a KCP HTTP (s) proxy (password: demo123): 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time. The local port after transformation is 18080. ss's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`
`./proxy sps -S http -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123 -h aes-192-cfb -j pass`
#### **6.3.SOCKS5 to HTTP(S) + SOCKS5**
Suppose there is a common Socks5 proxy: 127.0.0.1:8080, now we turn it into a common proxy that supports HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
Suppose there is a common Socks5 proxy: 127.0.0.1:8080, now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time, and the local port after transformation is 18080. ss's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S socks -T tcp -P 127.0.0.1:8080 -t tcp -p :18080`
`./proxy sps -S socks -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`
Suppose there is a TLS Socks5 proxy: 127.0.0.1:8080. Now we turn it into a common proxy that support HTTP (s) and Socks5 at the same time. The local port after transformation is 18080, TLS needs certificate file.
Suppose there is a TLS Socks5 proxy: 127.0.0.1:8080. Now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time. The local port after transformation is 18080, TLS needs certificate file. ss's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S socks -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key`
`./proxy sps -S socks -T tls -P 127.0.0.1:8080 -t tcp -p :18080 -C proxy.crt -K proxy.key -h aes-192-cfb -j pass`
Suppose there is a KCP Socks5 proxy (password: demo123): 127.0.0.1:8080, now we turn it into a common proxy that support HTTP (s) and Socks5 at the same time, and the local port after transformation is 18080.
Suppose there is a KCP Socks5 proxy (password: demo123): 127.0.0.1:8080, now we turn it into a common proxy that supports HTTP (s), Socks5 and ss at the same time, and the local port after transformation is 18080. ss's Encryption method is aes-192-cfb and its password is pass.
command
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123`  
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123 -h aes-192-cfb -j pass`  
#### **6.4.Chain style connection**
#### **6.4 SS to HTTP(S)+SOCKS5+SS**
SPS support the SS protocol with the local authorities. The parent proxy can be SPS or standard SS services.
By default, SPS provides three proxies, HTTP (S), SOCKS5 and SPS. the converted SOCKS5 and SS support UDP when the parent proxy is SOCKS5.
Suppose there is an ordinary SS or SPS proxy (open SS, encryption: aes-256-cfb, password: Demo)127.0.0.1:8080,Now we turn it into a common proxy that supports both http (s) and Socks5 and ss. The converted local port is 18080, and the converted ss encryption mode is aes-192-cfb, ss password:pass.
command
`./proxy sps -S socks -T kcp -P 127.0.0.1:8080 -t tcp -p :18080 --kcp-key demo123` `./proxy sps -S ss -H aes-256-cfb -J pass -T tcp -P 127.0.0.1:8080 -t tcp -p :18080 -h aes-192-cfb -j pass`.
#### **6.5.Chain style connection**
![6.4](/docs/images/sps-tls.png)
It is mentioned above that multiple SPS nodes can be connected to build encrypted channels, assuming you have the following VPS and a PC.
vps012.2.2.2
@ -922,11 +1043,11 @@ Then run a SPS node on the PCexcute
finish。
#### **6.5.Listening on multiple ports**
#### **6.6.Listening on multiple ports**
In general, listening one port is enough, but if you need to monitor 80 and 443 ports at the same time as a reverse proxy, the -p parameter can support it.
The format is`-p 0.0.0.0:80,0.0.0.0:443`, Multiple bindings are separated by a comma.
#### **6.6.Authentication**
#### **6.7.Authentication**
SPS supports HTTP(s)\socks5 proxy authentication, which can concatenate authentication, there are four important information:
1:Users send authentication information`user-auth`
2:Local authentication information set up`local-auth`
@ -968,7 +1089,20 @@ 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 parameter, the connection to the father proxy does not use authentication.
#### **6.7 Custom encryption**
**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**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
Suppose there is already a HTTP (s) proxy:`6.6.6.6:6666`
@ -989,7 +1123,7 @@ Local third level execution:
`proxy sps -T tcp -P 3.3.3.3:8888 -Z other_password -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by encryption transmission with the parents proxy.
#### **6.8 Compressed transmission**
#### **6.9 Compressed transmission**
HTTP(s) proxy can encrypt TCP data through TCP standard encryption and KCP protocol encryption, and can also compress data before custom encryption.
That is to say, compression and custom encryption and tls|kcp can be used together, compression is divided into two parts, the one is whether the local (-z) is compressed transmission, the other is whether the parents (-Z) is compressed transmission.
The compression requires both ends are proxy. Compression also protects the (encryption) data in certain extent. we use two level example and three level example as examples:
@ -1004,13 +1138,36 @@ through this way, When you visits the website by local proxy 8080, it visits the
**three level example**
First level VPS (ip:2.2.2.2) execution:
`proxy sps -t tcp -m -p :7777`
Second level VPS (ip:3.3.3.3) execution::
Second level VPS (ip:3.3.3.3) execution:
`proxy sps -T tcp -P 2.2.2.2:7777 -M -t tcp -m -p :8888`
Local third level execution:
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080`
through this way, When you visits the website by local proxy 8080, it visits the target website by compressed transmission with the parents proxy.
#### **6.9.view help**
#### **6.10 Disable protocol**
By default, SPS's port supports two proxy protocols, http (s) and socks5, and we can disable a protocol with parameters.
for example:
1.Disable the HTTP (S) proxy, retaining only the SOCKS5 proxy,parameter:`--disable-http`.
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
1.Disable the SOCKS5 proxy, retaining only the HTTP (S) proxy,parameter:`--disable-socks`.
`proxy sps -T tcp -P 3.3.3.3:8888 -M -t tcp -p :8080 --disable-http`
#### **6.11 Speed limit**
Suppose there has a SOCKS5 parent proxy:
`proxy socks -p 2.2.2.2:33080 -z password -t tcp`
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`
It can be specified through the `-l` parameter, for example: 100K 1.5M. 0 means unlimited.
#### **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.
`proxy sps -S socks -P 2.2.2.2:33080 -T tcp -Z password -l 100K -t tcp --bind-listen -p :33080`
#### **6.13 Certificate parameters using Base64 data**
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.
#### **6.14.view help**
`./proxy help sps`
### **7.KCP Configuration**
@ -1128,16 +1285,15 @@ execution: `go run *.go`
### License
Proxy is licensed under GPLv3 license.
### Contact
proxy QQ group:189618940
proxy QQ group: 793015219 , 189618940 (full)
### Donation
if proxy help you a lot,you can support us by:
### AliPay
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/alipay.jpg?raw=true" width="200"/>
### Wechat Pay
<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"/>
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,9 +9,11 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
**[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_ZH.md)**
### 如何贡献代码(Pull Request)?
@ -54,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)查看.
### 怎么找到组织?
@ -97,7 +99,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
- [1.15 限速](#115-限速)
- [1.16 指定出口IP](#116-指定出口ip)
- [1.17 证书参数使用base64数据](#117-证书参数使用base64数据)
- [1.18 查看帮助](#118-查看帮助)
- [1.18 智能模式](#118-智能模式)
- [1.19 查看帮助](#119-查看帮助)
- [2. TCP代理(端口映射)](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理)
@ -142,7 +145,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
- [5.14 指定出口IP](#514-指定出口ip)
- [5.15 级联认证](#515-级联认证)
- [5.16 证书参数使用base64数据](#516-证书参数使用base64数据)
- [5.17 查看帮助](#517查看帮助)
- [5.17 智能模式](#517-智能模式)
- [5.18 查看帮助](#518-查看帮助)
- [6. 代理协议转换](#6代理协议转换)
- [6.1 功能介绍](#61-功能介绍)
- [6.2 HTTP(S)转HTTP(S)+SOCKS5+SS](#62-https转httpssocks5ss)
@ -169,21 +173,27 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
提示:所有操作需要root权限.
#### 自动安装
#### **0.如果你的VPS是linux64位的系统,那么只需要执行下面一句,就可以完成自动安装和配置.**
```shell
curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.sh | bash
```
安装完成,配置目录是/etc/proxy,更详细的使用方法请参考上面的手册目录,进一步了解你想要使用的功能.
如果安装失败或者你的vps不是linux64位系统,请按照下面的半自动步骤安装:
#### 手动安装
#### **1.下载proxy**
下载地址:https://github.com/snail007/goproxy/releases
下载地址:https://github.com/snail007/goproxy/releases/latest
下面以v6.2为例,如果有最新版,请使用最新版链接.
```shell
cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v6.0/proxy-linux-amd64.tar.gz
wget https://github.com/snail007/goproxy/releases/download/v6.2/proxy-linux-amd64.tar.gz
```
#### **2.下载自动安装脚本**
```shell
cd /root/proxy/
wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
@ -192,6 +202,9 @@ chmod +x install.sh
```
#### Docker安装
[docker](https://hub.docker.com/r/snail007/goproxy)
项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
或者使用参数GOPROXY_VERSION指定构建的goproxy版本.
@ -356,11 +369,12 @@ weight 根据每个上级的权重和连接数情况,选择出一个上级
比如:
`./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,target四个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
带上user,pass,ip,local_ip,target五个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}&target={TARGET}
user:用户名
pass:密码
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
如果没有-a或-F或--auth-url参数,就是关闭Basic认证.
@ -378,7 +392,7 @@ target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.c
##### ***1.7.1 ssh用户名和密码的方式***
本地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用户名和密钥的方式***
本地HTTP(S)代理28080端口,执行:
`./proxy http -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
@ -523,7 +537,7 @@ HTTP(S)代理支持上级负载均衡,多个上级重复-P参数即可.
#### **1.14.3 使用目标地址选择上级**
`proxy http --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
`proxy http --lb-hashtarget --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -t tcp -p :33080`
### **1.15 限速**
@ -543,7 +557,15 @@ HTTP(S)代理支持上级负载均衡,多个上级重复-P参数即可.
如果是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`
### **2.TCP代理**
@ -877,7 +899,7 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
##### ***5.6.1 ssh用户名和密码的方式***
本地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用户名和密钥的方式***
本地SOCKS5代理28080端口,执行:
`./proxy socks -T ssh -P "2.2.2.2:22" -u user -S user.key -t tcp -p ":28080"`
@ -897,11 +919,12 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
比如:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}
带上user,pass,ip,local_ip四个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}
user:用户名
pass:密码
ip:用户的IP,比如:192.168.1.200
local_ip:用户访问的服务器的IP,比如:3.3.3.3
如果没有-a或-F或--auth-url参数,就是关闭认证.
@ -989,7 +1012,7 @@ SOCKS代理支持上级负载均衡,多个上级重复-P参数即可.
#### **5.12.3 使用目标地址选择上级**
`proxy socks --lb-hashtarget --lb-method=leasttime -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
`proxy socks --lb-hashtarget --lb-method=hash -T tcp -P 1.1.1.1:33080 -P 2.1.1.1:33080 -P 3.1.1.1:33080 -p :33080 -t tcp`
#### **5.13 限速**
@ -1022,7 +1045,15 @@ SOCKS5支持级联认证,-A可以设置上级认证信息.
如果是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`
### **6.代理协议转换**
@ -1129,6 +1160,18 @@ target:如果客户端是http(s)代理请求,这里代表的是请求的完整ur
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
如果没有-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 自定义加密**
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
@ -1342,7 +1385,7 @@ utils是工具包,service是具体的每个服务类.
### License
Proxy is licensed under GPLv3 license.
### Contact
QQ交流群:189618940
官方QQ交流群: 793015219 (2群), 189618940 (1群满)
### Donation

View File

@ -1 +1 @@
6.0
6.9

View File

@ -12,12 +12,14 @@ import (
"path/filepath"
"runtime/debug"
"runtime/pprof"
"strings"
"time"
"github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
sdk "github.com/snail007/goproxy/sdk/android-ios"
services "github.com/snail007/goproxy/services"
httpx "github.com/snail007/goproxy/services/http"
"github.com/snail007/goproxy/services/kcpcfg"
keygenx "github.com/snail007/goproxy/services/keygen"
mux "github.com/snail007/goproxy/services/mux"
socksx "github.com/snail007/goproxy/services/socks"
@ -35,8 +37,9 @@ var (
app *kingpin.Application
service *services.ServiceItem
cmd *exec.Cmd
cpuProfilingFile, memProfilingFile, blockProfilingFile, goroutineProfilingFile, threadcreateProfilingFile *os.File
isDebug bool
cpuProfilingFile, memProfilingFile, blockProfilingFile,
goroutineProfilingFile, threadcreateProfilingFile *os.File
isDebug *bool
)
func initConfig() (err error) {
@ -58,7 +61,7 @@ func initConfig() (err error) {
//build srvice args
app = kingpin.New("proxy", "happy with proxy")
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()
forever := app.Flag("forever", "run proxy in forever,fail and retry").Default("false").Bool()
logfile := app.Flag("log", "log file path").Default("").String()
@ -114,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.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.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.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.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.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
//########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode")
@ -147,7 +152,7 @@ func initConfig() (err error) {
//########mux-server#########
muxServer := app.Command("server", "proxy on mux server mode")
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('T').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
@ -157,11 +162,15 @@ func initConfig() (err error) {
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxServerArgs.Jumper = muxServer.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()
muxServerArgs.TCPSMethod = muxServer.Flag("tcps-method", "method of parent tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxServerArgs.TCPSPassword = muxServer.Flag("tcps-password", "password of parent tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxServerArgs.TOUMethod = muxServer.Flag("tou-method", "method of parent tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxServerArgs.TOUPassword = muxServer.Flag("tou-password", "password of parent tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode")
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('T').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
@ -169,6 +178,10 @@ func initConfig() (err error) {
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxClientArgs.Jumper = muxClient.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()
muxClientArgs.TCPSMethod = muxClient.Flag("tcps-method", "method of parent tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxClientArgs.TCPSPassword = muxClient.Flag("tcps-password", "password of parent tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxClientArgs.TOUMethod = muxClient.Flag("tou-method", "method of parent tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxClientArgs.TOUPassword = muxClient.Flag("tou-password", "password of parent tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -176,7 +189,11 @@ func initConfig() (err error) {
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tls").Short('t').Enum("tls", "tcp", "kcp")
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('t').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxBridgeArgs.TCPSMethod = muxBridge.Flag("tcps-method", "method of local tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxBridgeArgs.TCPSPassword = muxBridge.Flag("tcps-password", "password of local tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxBridgeArgs.TOUMethod = muxBridge.Flag("tou-method", "method of local tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxBridgeArgs.TOUPassword = muxBridge.Flag("tou-password", "password of local tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########tunnel-server#########
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
@ -205,7 +222,7 @@ func initConfig() (err error) {
tunnelBridgeArgs.Timeout = tunnelBridge.Flag("timeout", "tcp timeout with milliseconds").Short('t').Default("2000").Int()
tunnelBridgeArgs.Local = tunnelBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
//########ssh#########
//########socks#########
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.ParentType = socks.Flag("parent-type", "parent protocol type <tls|tcp|kcp|ssh>").Default("tcp").Short('T').Enum("tls", "tcp", "kcp", "ssh")
@ -237,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.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.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.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()
@ -246,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.Debug = isDebug
//########socks+http(s)#########
//########sps#########
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.CertFile = sps.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
@ -278,12 +296,14 @@ func initConfig() (err error) {
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.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.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.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.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
//########dns#########
@ -418,7 +438,7 @@ func initConfig() (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for {
@ -442,7 +462,7 @@ func initConfig() (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for scanner.Scan() {
@ -452,7 +472,7 @@ func initConfig() (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for scannerStdErr.Scan() {

View File

@ -11,10 +11,10 @@ import (
"strings"
"time"
"github.com/snail007/goproxy/core/dst"
"github.com/snail007/goproxy/core/lib/kcpcfg"
compressconn "github.com/snail007/goproxy/core/lib/transport"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
"github.com/snail007/goproxy/core/dst"
kcp "github.com/xtaci/kcp-go"
)
@ -35,6 +35,9 @@ func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes
}
return *tls.Client(_conn, conf), err
}
func TlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
}
func getRequestTlsConfig(certBytes, keyBytes, caCertBytes []byte) (conf *tls.Config, err error) {
var cert tls.Certificate

View File

@ -11,10 +11,10 @@ import (
"runtime/debug"
"strconv"
tou "github.com/snail007/goproxy/core/dst"
compressconn "github.com/snail007/goproxy/core/lib/transport"
transportc "github.com/snail007/goproxy/core/lib/transport"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
tou "github.com/snail007/goproxy/core/dst"
"github.com/snail007/goproxy/core/lib/kcpcfg"
@ -120,7 +120,7 @@ func (s *ServerChannel) listenTLS(ip string, port int, certBytes, keyBytes, caCe
config.ClientCAs = clientCertPool
config.ClientAuth = tls.RequireAndVerifyClientCert
}
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
_ln, err := tls.Listen("tcp", net.JoinHostPort(ip, fmt.Sprintf("%d", port)), config)
if err == nil {
ln = &_ln
}
@ -141,7 +141,7 @@ func (s *ServerChannel) ListenTCPS(method, password string, compress bool, fn fu
}
func (s *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
var l net.Listener
l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.ip, s.port))
l, err = net.Listen("tcp", net.JoinHostPort(s.ip, fmt.Sprintf("%d", s.port)))
if err == nil {
s.Listener = &l
go func() {
@ -172,7 +172,7 @@ func (s *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
}
return
}
func (s *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
func (s *ServerChannel) ListenUDP(fn func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
addr := &net.UDPAddr{IP: net.ParseIP(s.ip), Port: s.port}
l, err := net.ListenUDP("udp", addr)
if err == nil {
@ -194,7 +194,7 @@ func (s *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net
s.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
fn(packet, addr, srcAddr)
fn(s.UDPListener, packet, addr, srcAddr)
}()
} else {
s.errAcceptHandler(err)
@ -207,7 +207,7 @@ func (s *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net
return
}
func (s *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", s.ip, s.port), config.Block, *config.DataShard, *config.ParityShard)
lis, err := kcp.ListenWithOptions(net.JoinHostPort(s.ip, fmt.Sprintf("%d", s.port)), config.Block, *config.DataShard, *config.ParityShard)
if err == nil {
if err = lis.SetDSCP(*config.DSCP); err != nil {
log.Println("SetDSCP:", err)
@ -230,7 +230,6 @@ func (s *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.
}
}()
for {
//var conn net.Conn
conn, err := lis.AcceptKCP()
if err == nil {
go func() {

View File

@ -137,7 +137,7 @@ func (c *Conn) start() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
c.reader()
@ -433,6 +433,12 @@ func (c *Conn) String() string {
// Read can be made to time out and return a Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Conn) Read(b []byte) (n int, err error) {
defer func() {
if e := recover(); e != nil {
n = 0
err = io.EOF
}
}()
c.inbufMut.Lock()
defer c.inbufMut.Unlock()
for c.inbuf.Len() == 0 {
@ -497,6 +503,9 @@ func (c *Conn) Write(b []byte) (n int, err error) {
// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
func (c *Conn) Close() error {
defer func() {
_ = recover()
}()
c.closeOnce.Do(func() {
if debugConnection {
log.Println(c, "explicit close start")

View File

@ -82,7 +82,7 @@ func NewMux(conn net.PacketConn, packetSize int) *Mux {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
m.readerLoop()

View File

@ -56,7 +56,7 @@ func newSendBuffer(m *Mux) *sendBuffer {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
b.writerLoop()

View File

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

View File

@ -39,8 +39,11 @@ func (c *CompStream) Write(p []byte) (n int, err error) {
return n, err
}
func (c *CompStream) Close() error {
return c.conn.Close()
func (c *CompStream) Close() (err error) {
err = c.conn.Close()
c.r = nil
c.w = nil
return
}
func (c *CompStream) LocalAddr() net.Addr {
return c.conn.LocalAddr()

View File

@ -2,6 +2,7 @@ package encrypt
import (
"crypto/cipher"
"fmt"
"io"
"net"
@ -33,8 +34,23 @@ func NewConn(c net.Conn, method, password string) (conn net.Conn, err error) {
return
}
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)
}
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)
}
func (s *Conn) Close() (err error) {
if s.Cipher != nil {
err = s.Conn.Close()
s.Cipher = nil
s.r = nil
s.w = nil
}
return
}

View File

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

View File

@ -10,11 +10,11 @@ import (
"strings"
"time"
socks5c "github.com/snail007/goproxy/core/proxy/common/socks5"
socks5c "github.com/snail007/goproxy/core/lib/socks5"
)
type BasicAuther interface {
CheckUserPass(username, password, fromIP, ToTarget string) bool
CheckUserPass(username, password, userIP, localIP, toTarget string) bool
}
type Request struct {
ver uint8
@ -239,15 +239,16 @@ func (s *ServerConn) Target() string {
}
func (s *ServerConn) Handshake() (err error) {
remoteAddr := (*s.conn).RemoteAddr()
localAddr := (*s.conn).LocalAddr()
//协商开始
//method select request
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)
(*s.conn).SetReadDeadline(time.Time{})
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)
(*s.conn).SetReadDeadline(time.Time{})
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
//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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -275,7 +276,7 @@ func (s *ServerConn) Handshake() (err error) {
} else {
//auth
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)
(*s.conn).SetReadDeadline(time.Time{})
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
//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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -293,7 +294,7 @@ func (s *ServerConn) Handshake() (err error) {
//read auth
buf := make([]byte, 500)
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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -305,9 +306,10 @@ func (s *ServerConn) Handshake() (err error) {
s.password = string(r[2+r[1]+1:])
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
//auth
_addr := strings.Split(remoteAddr.String(), ":")
if s.auth == nil || (*s.auth).CheckUserPass(s.user, s.password, _addr[0], "") {
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
_userAddr := strings.Split(remoteAddr.String(), ":")
_localAddr := strings.Split(localAddr.String(), ":")
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})
(*s.conn).SetDeadline(time.Time{})
if err != nil {
@ -315,7 +317,7 @@ func (s *ServerConn) Handshake() (err error) {
return
}
} 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})
(*s.conn).SetDeadline(time.Time{})
if err != nil {
@ -327,7 +329,7 @@ func (s *ServerConn) Handshake() (err error) {
}
}
//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)
(*s.conn).SetReadDeadline(time.Time{})
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`
如果输出有下面的结果说明支持.
If the output has the following result description is supported.
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
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

View File

@ -81,7 +81,7 @@ func dtoi(s string, i0 int) (n int, i int, ok bool) {
return n, i, true
}
// IPTcpAddrToUnixSocksAddr ---
// IPTcpAddrToUnixSocksAddr returns Sockaddr for specified TCP addr.
func IPTcpAddrToUnixSocksAddr(addr string) (sa unix.Sockaddr, err error) {
if Debug {
fmt.Println("DEBUG: IPTcpAddrToUnixSocksAddr recieved address:", addr)
@ -97,7 +97,7 @@ func IPTcpAddrToUnixSocksAddr(addr string) (sa unix.Sockaddr, err error) {
return ipToSocksAddr(ipType(addr), tcpAddr.IP, tcpAddr.Port, tcpAddr.Zone)
}
// IPv6UdpAddrToUnixSocksAddr ---
// IPv6UdpAddrToUnixSocksAddr returns Sockaddr for specified IPv6 addr.
func IPv6UdpAddrToUnixSocksAddr(addr string) (sa unix.Sockaddr, err error) {
tcpAddr, err := net.ResolveTCPAddr("udp6", addr)
if err != nil {

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
- [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)
- [v5.3 Manual](https://github.com/snail007/goproxy/tree/v5.3)
- [v5.2 Manual](https://github.com/snail007/goproxy/tree/v5.2)
- [v5.1 Manual](https://github.com/snail007/goproxy/tree/v5.1)
- [v5.0 Manual](https://github.com/snail007/goproxy/tree/v5.0)
- [v4.9 Manual](https://github.com/snail007/goproxy/tree/v4.9)
- [v4.8 Manual](https://github.com/snail007/goproxy/tree/v4.8)
- [v4.7 Manual](https://github.com/snail007/goproxy/tree/v4.7)
- [v4.6 Manual](https://github.com/snail007/goproxy/tree/v4.6)
- [v4.5 Manual](https://github.com/snail007/goproxy/tree/v4.5)
- [v4.4 Manual](https://github.com/snail007/goproxy/tree/v4.4)
- [v4.3 Manual](https://github.com/snail007/goproxy/tree/v4.3)
- [v4.2 Manual](https://github.com/snail007/goproxy/tree/v4.2)
- [v4.0-v4.1 Manual](https://github.com/snail007/goproxy/tree/v4.1)
- [v3.9 Manual](https://github.com/snail007/goproxy/tree/v3.9)
- [v3.8 Manual](https://github.com/snail007/goproxy/tree/v3.8)
- [v3.6-v3.7 Manual](https://github.com/snail007/goproxy/tree/v3.6)
- [v3.5 Manual](https://github.com/snail007/goproxy/tree/v3.5)
- [v3.4 Manual](https://github.com/snail007/goproxy/tree/v3.4)
- [v3.3 Manual](https://github.com/snail007/goproxy/tree/v3.3)
- [v3.2 Manual](https://github.com/snail007/goproxy/tree/v3.2)
- [v3.1 Manual](https://github.com/snail007/goproxy/tree/v3.1)
- [v3.0 Manual](https://github.com/snail007/goproxy/tree/v3.0)
- [v2.x Manual](https://github.com/snail007/goproxy/tree/v2.2)

View File

@ -1,13 +1,13 @@
# 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
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui)
- Official java version, Project Homepage:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## Linux
- 官方java版本,项目主页:[goproxy-jui](https://github.com/snail007/goproxy-jui)
- Official java version, Project Homepage:[goproxy-jui](https://github.com/snail007/goproxy-jui)
## MacOS
@ -15,13 +15,13 @@
## 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
- 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
mkdir /tmp/proxy
cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v6.0/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
tar zxvf proxy-linux-amd64.tar.gz

View File

@ -36,10 +36,10 @@ func Clean(s *services.Service) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", 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...")
if s != nil && *s != nil {
(*s).Clean()
@ -48,11 +48,12 @@ func Clean(s *services.Service) {
log.Printf("clean process %d", cmd.Process.Pid)
cmd.Process.Kill()
}
if isDebug {
if *isDebug {
saveProfiling()
}
cleanupDone <- true
}
}()
<-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
#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

@ -13,8 +13,8 @@ import (
"github.com/miekg/dns"
gocache "github.com/pmylund/go-cache"
"github.com/snail007/goproxy/core/lib/kcpcfg"
services "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
)
type DNSArgs struct {
@ -57,10 +57,21 @@ func (s *DNS) CheckArgs() (err error) {
func (s *DNS) InitService() (err error) {
s.cache = gocache.New(time.Second*time.Duration(*s.cfg.DNSTTL), time.Second*60)
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() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for {
@ -81,7 +92,7 @@ func (s *DNS) InitService() (err error) {
nil,
&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
KeepAlive: 2 * time.Second,
},
)
if err != nil {
@ -122,7 +133,7 @@ func (s *DNS) StopService() {
if e != nil {
s.log.Printf("stop dns service crashed,%s", e)
} else {
s.log.Printf("service dns stoped")
s.log.Printf("service dns stopped")
}
}()
Stop(s.serviceKey)
@ -142,7 +153,7 @@ func (s *DNS) Start(args interface{}, log *logger.Logger) (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
log.Printf("dns server on udp %s", *s.cfg.Local)

View File

@ -8,11 +8,14 @@ import (
"os"
"path"
"path/filepath"
"runtime/pprof"
"strings"
"sync"
"github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
"github.com/snail007/goproxy/services"
httpx "github.com/snail007/goproxy/services/http"
"github.com/snail007/goproxy/services/kcpcfg"
keygenx "github.com/snail007/goproxy/services/keygen"
mux "github.com/snail007/goproxy/services/mux"
socksx "github.com/snail007/goproxy/services/socks"
@ -30,6 +33,10 @@ var SDK_VERSION = "No Version Provided"
var (
app *kingpin.Application
cpuProfilingFile, memProfilingFile, blockProfilingFile,
goroutineProfilingFile, threadcreateProfilingFile *os.File
isProfiling bool
profilingLock = &sync.Mutex{}
)
type LogCallback interface {
@ -84,8 +91,8 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
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.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.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("450").Int()
kcpArgs.Mode = app.Flag("kcp-mode", "profiles: fast3, fast2, fast, normal, manual").Default("fast3").Enum("fast3", "fast2", "fast", "normal", "manual")
kcpArgs.MTU = app.Flag("kcp-mtu", "set maximum transmission unit for UDP packets").Default("1350").Int()
kcpArgs.SndWnd = app.Flag("kcp-sndwnd", "set send window size(num of packets)").Default("1024").Int()
kcpArgs.RcvWnd = app.Flag("kcp-rcvwnd", "set receive window size(num of packets)").Default("1024").Int()
kcpArgs.DataShard = app.Flag("kcp-ds", "set reed-solomon erasure coding - datashard").Default("10").Int()
@ -133,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.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.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.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.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.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
//########tcp#########
tcp := app.Command("tcp", "proxy on tcp mode")
@ -166,7 +175,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
//########mux-server#########
muxServer := app.Command("server", "proxy on mux server mode")
muxServerArgs.Parent = muxServer.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
muxServerArgs.ParentType = muxServer.Flag("parent-type", "parent protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('T').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxServerArgs.CertFile = muxServer.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
muxServerArgs.KeyFile = muxServer.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxServerArgs.Timeout = muxServer.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
@ -176,11 +185,15 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxServerArgs.IsCompress = muxServer.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxServerArgs.SessionCount = muxServer.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxServerArgs.Jumper = muxServer.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()
muxServerArgs.TCPSMethod = muxServer.Flag("tcps-method", "method of parent tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxServerArgs.TCPSPassword = muxServer.Flag("tcps-password", "password of parent tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxServerArgs.TOUMethod = muxServer.Flag("tou-method", "method of parent tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxServerArgs.TOUPassword = muxServer.Flag("tou-password", "password of parent tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########mux-client#########
muxClient := app.Command("client", "proxy on mux client mode")
muxClientArgs.Parent = muxClient.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Default("tls").Short('T').Enum("tls", "tcp", "kcp")
muxClientArgs.ParentType = muxClient.Flag("parent-type", "parent protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('T').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxClientArgs.CertFile = muxClient.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
muxClientArgs.KeyFile = muxClient.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxClientArgs.Timeout = muxClient.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
@ -188,6 +201,10 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxClientArgs.IsCompress = muxClient.Flag("c", "compress data when tcp|tls mode").Default("false").Bool()
muxClientArgs.SessionCount = muxClient.Flag("session-count", "session count which connect to bridge").Short('n').Default("10").Int()
muxClientArgs.Jumper = muxClient.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()
muxClientArgs.TCPSMethod = muxClient.Flag("tcps-method", "method of parent tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxClientArgs.TCPSPassword = muxClient.Flag("tcps-password", "password of parent tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxClientArgs.TOUMethod = muxClient.Flag("tou-method", "method of parent tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxClientArgs.TOUPassword = muxClient.Flag("tou-password", "password of parent tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########mux-bridge#########
muxBridge := app.Command("bridge", "proxy on mux bridge mode")
@ -195,7 +212,11 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxBridgeArgs.KeyFile = muxBridge.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
muxBridgeArgs.Timeout = muxBridge.Flag("timeout", "tcp timeout with milliseconds").Short('i').Default("2000").Int()
muxBridgeArgs.Local = muxBridge.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String()
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tls").Short('t').Enum("tls", "tcp", "kcp")
muxBridgeArgs.LocalType = muxBridge.Flag("local-type", "local protocol type <tls|tcp|tcps|kcp|tou>").Default("tls").Short('t').Enum("tls", "tcp", "tcps", "kcp", "tou")
muxBridgeArgs.TCPSMethod = muxBridge.Flag("tcps-method", "method of local tcps's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxBridgeArgs.TCPSPassword = muxBridge.Flag("tcps-password", "password of local tcps's encrpyt/decrypt").Default("snail007's_goproxy").String()
muxBridgeArgs.TOUMethod = muxBridge.Flag("tou-method", "method of local tou's encrpyt/decrypt, these below are supported :\n"+strings.Join(encryptconn.GetCipherMethods(), ",")).Default("aes-192-cfb").String()
muxBridgeArgs.TOUPassword = muxBridge.Flag("tou-password", "password of local tou's encrpyt/decrypt").Default("snail007's_goproxy").String()
//########tunnel-server#########
tunnelServer := app.Command("tserver", "proxy on tunnel server mode")
@ -256,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.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.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.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()
@ -303,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.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.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
//########dns#########
@ -394,7 +418,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxClientArgs.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
if *debug {
flags |= logger.Lshortfile | logger.Lmicroseconds
@ -460,3 +484,41 @@ func Stop(serviceID string) {
func Version() string {
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())
}
//export StartProfiling
func StartProfiling(storePath *C.char) {
sdk.StartProfiling(C.GoString(storePath))
}
//export StopProfiling
func StopProfiling() {
sdk.StopProfiling()
}
func main() {
}

View File

@ -12,11 +12,13 @@ import (
"strings"
"time"
server "github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils/datasize"
"github.com/snail007/goproxy/utils/dnsx"
"github.com/snail007/goproxy/utils/iolimiter"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/lb"
"github.com/snail007/goproxy/utils/mapx"
@ -64,6 +66,7 @@ type HTTPArgs struct {
ParentKey *string
LocalCompress *bool
ParentCompress *bool
Intelligent *string
LoadBalanceMethod *string
LoadBalanceTimeout *int
LoadBalanceRetryTime *int
@ -74,6 +77,7 @@ type HTTPArgs struct {
RateLimitBytes float64
BindListen *bool
Debug *bool
Jumper *string
}
type HTTP struct {
cfg HTTPArgs
@ -83,10 +87,11 @@ type HTTP struct {
lockChn chan bool
domainResolver dnsx.DomainResolver
isStop bool
serverChannels []*utils.ServerChannel
serverChannels []*server.ServerChannel
userConns mapx.ConcurrentMap
log *logger.Logger
lb *lb.Group
jumper *jumper.Jumper
}
func NewHTTP() services.Service {
@ -96,7 +101,7 @@ func NewHTTP() services.Service {
basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1),
isStop: false,
serverChannels: []*utils.ServerChannel{},
serverChannels: []*server.ServerChannel{},
userConns: mapx.NewConcurrentMap(),
}
}
@ -162,17 +167,30 @@ func (s *HTTP) CheckArgs() (err error) {
}
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
}
func (s *HTTP) InitService() (err error) {
s.InitBasicAuth()
//init lb
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()
}
if *s.cfg.DNSAddress != "" {
(*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 *s.cfg.ParentType == "ssh" {
err = s.ConnectSSH()
@ -183,7 +201,7 @@ func (s *HTTP) InitService() (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
//循环检查ssh网络连通性
@ -192,7 +210,7 @@ func (s *HTTP) InitService() (err error) {
return
}
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)))
_, err = conn.Write([]byte{0})
conn.SetDeadline(time.Time{})
@ -221,7 +239,7 @@ func (s *HTTP) StopService() {
if e != nil {
s.log.Printf("stop http(s) service crashed,%s", e)
} else {
s.log.Printf("service http(s) stoped")
s.log.Printf("service http(s) stopped")
}
s.basicAuth = utils.BasicAuth{}
s.cfg = HTTPArgs{}
@ -230,6 +248,7 @@ func (s *HTTP) StopService() {
s.lb = nil
s.lockChn = nil
s.log = nil
s.jumper = nil
s.serverChannels = nil
s.sshClient = nil
s.userConns = nil
@ -273,11 +292,11 @@ func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
if addr != "" {
host, port, _ := net.SplitHostPort(addr)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := server.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.callback)
} 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 == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
}
@ -367,12 +386,17 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
}
if useProxy {
// s.log.Printf("%v", s.outPool)
if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(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)
}
} else {
outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr)
}
@ -392,7 +416,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn)
}
if *s.cfg.ParentKey != "" {
if useProxy && *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey,
})
@ -407,7 +431,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
//https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
//直连目标或上级非代理或非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))
} else {
_, err = outConn.Write(req.HeadBuf)
@ -496,6 +520,9 @@ func (s *HTTP) ConnectSSH() (err error) {
s.sshClient.Close()
}
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
return
}
@ -601,11 +628,24 @@ func (s *HTTP) Resolve(address string) string {
}
func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
var _conn tls.Conn
_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 {
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" {
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
} else if *s.cfg.ParentType == "ssh" {
@ -615,7 +655,11 @@ func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
err = fmt.Errorf("%s", e)
}
} else {
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
}

View File

@ -8,16 +8,15 @@ import (
"math/rand"
"net"
"runtime/debug"
"strconv"
"strings"
"sync"
"time"
srvtransport "github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/mapx"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
)
@ -32,6 +31,10 @@ type MuxBridgeArgs struct {
Timeout *int
IsCompress *bool
KCP kcpcfg.KCPConfigArgs
TCPSMethod *string
TCPSPassword *string
TOUMethod *string
TOUPassword *string
}
type MuxBridge struct {
cfg MuxBridgeArgs
@ -40,7 +43,7 @@ type MuxBridge struct {
router utils.ClientKeyRouter
l *sync.Mutex
isStop bool
sc *utils.ServerChannel
sc *srvtransport.ServerChannel
log *logger.Logger
}
@ -78,7 +81,7 @@ func (s *MuxBridge) StopService() {
if e != nil {
s.log.Printf("stop bridge service crashed,%s", e)
} else {
s.log.Printf("service bridge stoped")
s.log.Printf("service bridge stopped")
}
s.cfg = MuxBridgeArgs{}
s.clientControlConns = nil
@ -112,21 +115,27 @@ func (s *MuxBridge) Start(args interface{}, log *logger.Logger) (err error) {
return
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := srvtransport.NewServerChannelHost(*s.cfg.Local, s.log)
if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.handler)
} else if *s.cfg.LocalType == "tls" {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.handler)
} else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.handler, s.log)
} else if *s.cfg.LocalType == "tcps" {
err = sc.ListenTCPS(*s.cfg.TCPSMethod, *s.cfg.TCPSPassword, false, s.handler)
} else if *s.cfg.LocalType == "tou" {
err = sc.ListenTOU(*s.cfg.TOUMethod, *s.cfg.TOUPassword, false, s.handler)
}
if err != nil {
return
}
s.sc = &sc
if *s.cfg.LocalType == "tou" {
s.log.Printf("%s bridge on %s", *s.cfg.LocalType, sc.UDPListener.LocalAddr())
} else {
s.log.Printf("%s bridge on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
}
return
}
func (s *MuxBridge) Clean() {
@ -206,21 +215,25 @@ func (s *MuxBridge) handler(inConn net.Conn) {
index := keyInfo[1]
s.l.Lock()
defer s.l.Unlock()
var group *mapx.ConcurrentMap
if !s.clientControlConns.Has(groupKey) {
item := mapx.NewConcurrentMap()
s.clientControlConns.Set(groupKey, &item)
}
_g := mapx.NewConcurrentMap()
group = &_g
s.clientControlConns.Set(groupKey, group)
//s.log.Printf("init client session group %s", groupKey)
} else {
_group, _ := s.clientControlConns.Get(groupKey)
group := _group.(*mapx.ConcurrentMap)
group = _group.(*mapx.ConcurrentMap)
}
if v, ok := group.Get(index); ok {
v.(*smux.Session).Close()
}
group.Set(index, session)
// s.clientControlConns.Set(key, session)
//s.log.Printf("set client session %s to group %s,grouplen:%d", index, groupKey, group.Count())
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for {
@ -232,10 +245,12 @@ func (s *MuxBridge) handler(inConn net.Conn) {
defer s.l.Unlock()
if sess, ok := group.Get(index); ok && sess.(*smux.Session).IsClosed() {
group.Remove(index)
//s.log.Printf("client session %s removed from group %s, grouplen:%d", key, groupKey, group.Count())
s.log.Printf("client connection %s released", key)
}
if group.IsEmpty() {
s.clientControlConns.Remove(groupKey)
//s.log.Printf("client session group %s removed", groupKey)
}
break
}
@ -259,6 +274,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
if key == "*" {
key = s.router.GetKey()
}
//s.log.Printf("server get client session %s", key)
_group, ok := s.clientControlConns.Get(key)
if !ok {
s.log.Printf("client %s session not exists for server stream %s, retrying...", key, serverID)
@ -266,8 +282,12 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
continue
}
group := _group.(*mapx.ConcurrentMap)
keys := group.Keys()
keys := []string{}
group.IterCb(func(key string, v interface{}) {
keys = append(keys, key)
})
keysLen := len(keys)
//s.log.Printf("client session %s , len:%d , keysLen: %d", key, group.Count(), keysLen)
i := 0
if keysLen > 0 {
i = rand.Intn(keysLen)
@ -293,7 +313,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(stream, inConn)
@ -302,7 +322,7 @@ func (s *MuxBridge) callback(inConn net.Conn, serverID, key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(inConn, stream)

View File

@ -8,15 +8,17 @@ import (
"net"
"runtime/debug"
"strings"
"sync"
"time"
"github.com/golang/snappy"
clienttransport "github.com/snail007/goproxy/core/cs/client"
"github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/mapx"
"github.com/golang/snappy"
//"github.com/xtaci/smux"
smux "github.com/hashicorp/yamux"
)
@ -34,6 +36,10 @@ type MuxClientArgs struct {
SessionCount *int
KCP kcpcfg.KCPConfigArgs
Jumper *string
TCPSMethod *string
TCPSPassword *string
TOUMethod *string
TOUPassword *string
}
type ClientUDPConnItem struct {
conn *smux.Stream
@ -105,7 +111,7 @@ func (s *MuxClient) StopService() {
if e != nil {
s.log.Printf("stop client service crashed,%s", e)
} else {
s.log.Printf("service client stoped")
s.log.Printf("service client stopped")
}
s.cfg = MuxClientArgs{}
s.jumper = nil
@ -140,7 +146,7 @@ func (s *MuxClient) Start(args interface{}, log *logger.Logger) (err error) {
defer func() {
e := recover()
if e != nil {
s.log.Printf("session worker crashed: %s", e)
s.log.Printf("session worker crashed: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for {
@ -154,7 +160,16 @@ func (s *MuxClient) Start(args interface{}, log *logger.Logger) (err error) {
continue
}
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
g := sync.WaitGroup{}
g.Add(1)
go func() {
defer func() {
_ = recover()
g.Done()
}()
_, err = conn.Write(utils.BuildPacket(CONN_CLIENT, fmt.Sprintf("%s-%d", *s.cfg.Key, i)))
}()
g.Wait()
conn.SetDeadline(time.Time{})
if err != nil {
conn.Close()
@ -222,14 +237,14 @@ func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
_conn, err = clienttransport.TlsConnectHost(*s.cfg.Parent, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err == nil {
conn = net.Conn(&_conn)
}
} else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if err != nil {
return nil, err
conf, e := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, nil)
if e != nil {
return nil, e
}
var _c net.Conn
_c, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
@ -239,10 +254,22 @@ func (s *MuxClient) getParentConn() (conn net.Conn, err error) {
}
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
conn, err = clienttransport.KCPConnectHost(*s.cfg.Parent, s.cfg.KCP)
} else if *s.cfg.ParentType == "tcps" {
if s.jumper == nil {
conn, err = clienttransport.TCPSConnectHost(*s.cfg.Parent, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword, false, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn, err = encryptconn.NewConn(conn, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword)
}
}
} else if *s.cfg.ParentType == "tou" {
conn, err = clienttransport.TOUConnectHost(*s.cfg.Parent, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword, false, *s.cfg.Timeout)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
conn, err = clienttransport.TCPConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
}
@ -299,14 +326,17 @@ func (s *MuxClient) ServeUDP(inConn *smux.Stream, localAddr, ID string) {
item = v.(*ClientUDPConnItem)
}
(*item).touchtime = time.Now().Unix()
go (*item).udpConn.Write(body)
go func() {
defer func() { _ = recover() }()
(*item).udpConn.Write(body)
}()
}
}
func (s *MuxClient) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
s.log.Printf("udp conn %s connected", ID)
@ -336,7 +366,7 @@ func (s *MuxClient) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
cui.conn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
@ -355,7 +385,7 @@ func (s *MuxClient) UDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
if s.isStop {
@ -414,7 +444,7 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(outConn, snappy.NewReader(inConn))
@ -423,7 +453,7 @@ func (s *MuxClient) ServeConn(inConn *smux.Stream, localAddr, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(snappy.NewWriter(inConn), outConn)

View File

@ -12,8 +12,11 @@ import (
"strings"
"time"
clienttransport "github.com/snail007/goproxy/core/cs/client"
server "github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/mapx"
@ -47,10 +50,14 @@ type MuxServerArgs struct {
SessionCount *int
KCP kcpcfg.KCPConfigArgs
Jumper *string
TCPSMethod *string
TCPSPassword *string
TOUMethod *string
TOUPassword *string
}
type MuxServer struct {
cfg MuxServerArgs
sc utils.ServerChannel
sc server.ServerChannel
sessions mapx.ConcurrentMap
lockChn chan bool
isStop bool
@ -133,6 +140,10 @@ func (s *MuxServerManager) Start(args interface{}, log *logger.Logger) (err erro
KCP: s.cfg.KCP,
ParentType: s.cfg.ParentType,
Jumper: s.cfg.Jumper,
TCPSMethod: s.cfg.TCPSMethod,
TCPSPassword: s.cfg.TCPSPassword,
TOUMethod: s.cfg.TOUMethod,
TOUPassword: s.cfg.TOUPassword,
}, log)
if err != nil {
@ -196,13 +207,13 @@ func (s *MuxServer) StopService() {
if e != nil {
s.log.Printf("stop server service crashed,%s", e)
} else {
s.log.Printf("service server stoped")
s.log.Printf("service server stopped")
}
s.cfg = MuxServerArgs{}
s.jumper = nil
s.lockChn = nil
s.log = nil
s.sc = utils.ServerChannel{}
s.sc = server.ServerChannel{}
s.sessions = nil
s.udpConns = nil
s = nil
@ -254,7 +265,7 @@ func (s *MuxServer) Start(args interface{}, log *logger.Logger) (err error) {
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p, s.log)
s.sc = server.NewServerChannel(host, p, s.log)
if *s.cfg.IsUDP {
err = s.sc.ListenUDP(func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr) {
s.UDPSend(packet, localAddr, srcAddr)
@ -293,7 +304,7 @@ func (s *MuxServer) Start(args interface{}, log *logger.Logger) (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(inConn, snappy.NewReader(outConn))
@ -302,7 +313,7 @@ func (s *MuxServer) Start(args interface{}, log *logger.Logger) (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
io.Copy(snappy.NewWriter(outConn), inConn)
@ -397,7 +408,7 @@ func (s *MuxServer) GetConn(index string) (conn net.Conn, err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
for {
@ -443,6 +454,18 @@ func (s *MuxServer) getParentConn() (conn net.Conn, err error) {
} else if *s.cfg.ParentType == "kcp" {
conn, err = utils.ConnectKCPHost(*s.cfg.Parent, s.cfg.KCP)
} else if *s.cfg.ParentType == "tcps" {
if s.jumper == nil {
conn, err = clienttransport.TCPSConnectHost(*s.cfg.Parent, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword, false, *s.cfg.Timeout)
} else {
conn, err = s.jumper.Dial(*s.cfg.Parent, time.Millisecond*time.Duration(*s.cfg.Timeout))
if err == nil {
conn, err = encryptconn.NewConn(conn, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword)
}
}
} else if *s.cfg.ParentType == "tou" {
conn, err = clienttransport.TOUConnectHost(*s.cfg.Parent, *s.cfg.TCPSMethod, *s.cfg.TCPSPassword, false, *s.cfg.Timeout)
} else {
if s.jumper == nil {
conn, err = utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout)
@ -457,7 +480,7 @@ func (s *MuxServer) UDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
if s.isStop {
@ -536,7 +559,7 @@ func (s *MuxServer) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
s.log.Printf("udp conn %s connected", ID)
@ -569,7 +592,7 @@ func (s *MuxServer) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
s.sc.UDPListener.WriteToUDP(body, uc.srcAddr)

View File

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

View File

@ -12,8 +12,9 @@ import (
"strings"
"time"
server "github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
"github.com/snail007/goproxy/utils/datasize"
@ -63,6 +64,7 @@ type SocksArgs struct {
ParentKey *string
LocalCompress *bool
ParentCompress *bool
Intelligent *string
LoadBalanceMethod *string
LoadBalanceTimeout *int
LoadBalanceRetryTime *int
@ -80,8 +82,8 @@ type Socks struct {
basicAuth utils.BasicAuth
sshClient *ssh.Client
lockChn chan bool
udpSC utils.ServerChannel
sc *utils.ServerChannel
udpSC server.ServerChannel
sc *server.ServerChannel
domainResolver dnsx.DomainResolver
isStop bool
userConns mapx.ConcurrentMap
@ -179,7 +181,7 @@ func (s *Socks) InitService() (err error) {
(*s).domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
}
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()
}
if *s.cfg.ParentType == "ssh" {
@ -191,7 +193,7 @@ func (s *Socks) InitService() (err error) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
//循环检查ssh网络连通性
@ -229,7 +231,7 @@ func (s *Socks) StopService() {
if e != nil {
s.log.Printf("stop socks service crashed,%s", e)
} else {
s.log.Printf("service socks stoped")
s.log.Printf("service socks stopped")
}
s.basicAuth = utils.BasicAuth{}
s.cfg = SocksArgs{}
@ -243,7 +245,7 @@ func (s *Socks) StopService() {
s.udpLocalKey = nil
s.udpParentKey = nil
s.udpRelatedPacketConns = nil
s.udpSC = utils.ServerChannel{}
s.udpSC = server.ServerChannel{}
s.userConns = nil
s = nil
}()
@ -283,11 +285,11 @@ func (s *Socks) Start(args interface{}, log *logger.Logger) (err error) {
if len(*s.cfg.Parent) > 0 {
s.log.Printf("use %s parent %v [ %s ]", *s.cfg.ParentType, *s.cfg.Parent, strings.ToUpper(*s.cfg.LoadBalanceMethod))
}
sc := utils.NewServerChannelHost(*s.cfg.Local, s.log)
sc := server.NewServerChannelHost(*s.cfg.Local, s.log)
if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.socksConnCallback)
} else if *s.cfg.LocalType == "tls" {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.socksConnCallback)
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.socksConnCallback)
} else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.socksConnCallback, s.log)
}
@ -462,11 +464,7 @@ func (s *Socks) proxyTCP(inConn *net.Conn, serverConn *socks.ServerConn) {
}
func (s *Socks) GetParentConn(parentAddress string, serverConn *socks.ServerConn) (outConn net.Conn, err interface{}) {
switch *s.cfg.ParentType {
case "kcp":
fallthrough
case "tls":
fallthrough
case "tcp":
case "kcp", "tls", "tcp":
if *s.cfg.ParentType == "tls" {
var _conn tls.Conn
_conn, err = utils.TlsConnectHost(parentAddress, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)

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())
//relay
for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil {
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())
//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 {
clean("handshake fail", fmt.Sprintf("%s", err))
return
@ -126,9 +126,9 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
//s.log.Printf("parent udp address %s", client.UDPAddr)
destAddr, _ = net.ResolveUDPAddr("udp", client.UDPAddr)
//relay
for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
n, srcAddr, err := udpListener.ReadFromUDP(buf)
if err != nil {
s.log.Printf("udp listener read fail, %s", err.Error())

View File

@ -13,15 +13,19 @@ import (
"runtime/debug"
"strconv"
"strings"
"sync"
"time"
"github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt"
cryptool "github.com/snail007/goproxy/utils/crypt"
"github.com/snail007/goproxy/utils/datasize"
"github.com/snail007/goproxy/utils/dnsx"
"github.com/snail007/goproxy/utils/iolimiter"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/lb"
"github.com/snail007/goproxy/utils/mapx"
"github.com/snail007/goproxy/utils/sni"
@ -69,16 +73,18 @@ type SPSArgs struct {
LoadBalanceRetryTime *int
LoadBalanceHashTarget *bool
LoadBalanceOnlyHA *bool
ParentTLSSingle *bool
RateLimit *string
RateLimitBytes float64
Debug *bool
Jumper *string
}
type SPS struct {
cfg SPSArgs
domainResolver dnsx.DomainResolver
basicAuth utils.BasicAuth
serverChannels []*utils.ServerChannel
serverChannels []*server.ServerChannel
userConns mapx.ConcurrentMap
log *logger.Logger
localCipher *ss.Cipher
@ -87,15 +93,20 @@ type SPS struct {
lb *lb.Group
udpLocalKey []byte
udpParentKey []byte
jumper *jumper.Jumper
parentAuthData *sync.Map
parentCipherData *sync.Map
}
func NewSPS() services.Service {
return &SPS{
cfg: SPSArgs{},
basicAuth: utils.BasicAuth{},
serverChannels: []*utils.ServerChannel{},
serverChannels: []*server.ServerChannel{},
userConns: mapx.NewConcurrentMap(),
udpRelatedPacketConns: mapx.NewConcurrentMap(),
parentAuthData: &sync.Map{},
parentCipherData: &sync.Map{},
}
}
func (s *SPS) CheckArgs() (err error) {
@ -117,10 +128,12 @@ func (s *SPS) CheckArgs() (err error) {
return
}
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
if !*s.cfg.ParentTLSSingle {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
return
}
}
if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
if err != nil {
@ -140,16 +153,32 @@ func (s *SPS) CheckArgs() (err error) {
}
s.udpLocalKey = s.LocalUDPKey()
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
}
func (s *SPS) InitService() (err error) {
if *s.cfg.DNSAddress != "" {
(*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 {
s.InitLB()
err = s.InitLB()
if err != nil {
return
}
}
err = s.InitBasicAuth()
@ -176,13 +205,14 @@ func (s *SPS) StopService() {
if e != nil {
s.log.Printf("stop sps service crashed,%s", e)
} else {
s.log.Printf("service sps stoped")
s.log.Printf("service sps stopped")
}
s.basicAuth = utils.BasicAuth{}
s.cfg = SPSArgs{}
s.domainResolver = dnsx.DomainResolver{}
s.lb = nil
s.localCipher = nil
s.jumper = nil
s.log = nil
s.parentCipher = nil
s.serverChannels = nil
@ -190,6 +220,8 @@ func (s *SPS) StopService() {
s.udpParentKey = nil
s.udpRelatedPacketConns = nil
s.userConns = nil
s.parentAuthData = nil
s.parentCipherData = nil
s = nil
}()
for _, sc := range s.serverChannels {
@ -230,15 +262,18 @@ func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
if addr != "" {
host, port, _ := net.SplitHostPort(addr)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := server.NewServerChannel(host, p, s.log)
s.serverChannels = append(s.serverChannels, &sc)
if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == "tls" {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == "tcp" {
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
} else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
}
if err != nil {
return
}
if *s.cfg.ParentServiceType == "socks" {
err = s.RunSSUDP(addr)
} else {
@ -273,11 +308,7 @@ func (s *SPS) callback(inConn net.Conn) {
var err error
lbAddr := ""
switch *s.cfg.ParentType {
case "kcp":
fallthrough
case "tcp":
fallthrough
case "tls":
case "kcp", "tcp", "tls":
lbAddr, err = s.OutToTCP(&inConn)
default:
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
@ -363,7 +394,6 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
request.HTTPSReply()
//s.log.Printf("https reply: %s", request.Host)
} else {
//forwardBytes = bytes.TrimRight(request.HeadBuf,"\r\n")
forwardBytes = request.HeadBuf
}
address = request.Host
@ -412,15 +442,14 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
selectAddr = address
}
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
//lbAddr = s.lb.Select((*inConn).RemoteAddr().String())
outConn, err = s.GetParentConn(lbAddr)
if err != nil {
s.log.Printf("connect to %s , err:%s", lbAddr, err)
utils.CloseConn(inConn)
return
}
if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
ParentAuth := s.getParentAuth(lbAddr)
if ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
}
@ -440,8 +469,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
pb.WriteString("Connection: Keep-Alive\r\n")
u := ""
if *s.cfg.ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":")
if ParentAuth != "" {
a := strings.Split(ParentAuth, ":")
if len(a) != 2 {
err = fmt.Errorf("parent auth data format error")
return
@ -492,7 +521,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
s.log.Printf("connect %s", address)
//socks client
_, err = s.HandshakeSocksParent(&outConn, "tcp", address, auth, false)
_, err = s.HandshakeSocksParent(ParentAuth, &outConn, "tcp", address, auth, false)
if err != nil {
s.log.Printf("handshake fail, %s", err)
return
@ -505,7 +534,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
return
}
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy())
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.getParentCipher(lbAddr))
if err != nil {
err = fmt.Errorf("dial ss parent fail, err : %s", err)
return
@ -565,10 +594,41 @@ func (s *SPS) InitBasicAuth() (err error) {
}
return
}
func (s *SPS) InitLB() {
func (s *SPS) InitLB() (err error) {
configs := lb.BackendsConfig{}
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]
weight := 1
if len(_addrInfo) == 2 {
@ -585,6 +645,19 @@ func (s *SPS) InitLB() {
}
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
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 {
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
@ -640,15 +713,41 @@ func (s *SPS) Resolve(address string) string {
}
func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" {
if s.jumper == nil {
var _conn tls.Conn
if *s.cfg.ParentTLSSingle {
_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" {
conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
} else {
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 *s.cfg.ParentCompress {
@ -662,9 +761,9 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
}
return
}
func (s *SPS) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
if *s.cfg.ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":")
func (s *SPS) HandshakeSocksParent(parentAuth string, outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
if parentAuth != "" {
a := strings.Split(parentAuth, ":")
if len(a) != 2 {
err = fmt.Errorf("parent auth data format error")
return
@ -688,7 +787,9 @@ func (s *SPS) ParentUDPKey() (key []byte) {
return []byte(v)[:24]
}
case "tls":
if s.cfg.KeyBytes != nil {
return s.cfg.KeyBytes[:24]
}
case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
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()))
}
}()
for {
buf := utils.LeakyBuffer.Get()
defer utils.LeakyBuffer.Put(buf)
for {
n, srcAddr, err := listener.ReadFrom(buf)
if err != nil {
s.log.Printf("read from client error %s", err)
@ -88,7 +88,7 @@ func (s *SPS) RunSSUDP(addr string) (err error) {
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 {
clean("handshake fail", fmt.Sprintf("%s", err))
return

View File

@ -9,8 +9,9 @@ import (
"strings"
"time"
"github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
"github.com/snail007/goproxy/utils/mapx"
@ -43,7 +44,7 @@ type UDPConnItem struct {
}
type TCP struct {
cfg TCPArgs
sc *utils.ServerChannel
sc *server.ServerChannel
isStop bool
userConns mapx.ConcurrentMap
log *logger.Logger
@ -99,7 +100,7 @@ func (s *TCP) StopService() {
if e != nil {
s.log.Printf("stop tcp service crashed,%s", e)
} else {
s.log.Printf("service tcp stoped")
s.log.Printf("service tcp stopped")
}
s.cfg = TCPArgs{}
s.jumper = nil
@ -131,12 +132,12 @@ func (s *TCP) Start(args interface{}, log *logger.Logger) (err error) {
s.log.Printf("use %s parent %v", *s.cfg.ParentType, *s.cfg.Parent)
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := server.NewServerChannel(host, p, s.log)
if *s.cfg.LocalType == "tcp" {
err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == "tls" {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
} else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
}
@ -160,11 +161,7 @@ func (s *TCP) callback(inConn net.Conn) {
var err error
lbAddr := ""
switch *s.cfg.ParentType {
case "kcp":
fallthrough
case "tcp":
fallthrough
case "tls":
case "kcp", "tcp", "tls":
err = s.OutToTCP(&inConn)
case "udp":
s.OutToUDP(&inConn)
@ -208,8 +205,8 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
srcAddr := ""
defer func() {
if item != nil {
(*(*item).conn).Close()
(*item).udpConn.Close()
(*item.conn).Close()
item.udpConn.Close()
s.udpConns.Remove(srcAddr)
(*inConn).Close()
}
@ -252,15 +249,15 @@ func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
} else {
item = v.(*UDPConnItem)
}
(*item).touchtime = time.Now().Unix()
go (*item).udpConn.Write(body)
item.touchtime = time.Now().Unix()
go item.udpConn.Write(body)
}
}
func (s *TCP) UDPRevecive(key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
s.log.Printf("udp conn %s connected", key)
@ -290,7 +287,7 @@ func (s *TCP) UDPRevecive(key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
(*cui.conn).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
@ -309,7 +306,7 @@ func (s *TCP) UDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
if s.isStop {

View File

@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/mapx"
@ -71,7 +72,7 @@ func (s *TunnelBridge) StopService() {
if e != nil {
s.log.Printf("stop tbridge service crashed,%s", e)
} else {
s.log.Printf("service tbridge stoped")
s.log.Printf("service tbridge stopped")
}
s.cfg = TunnelBridgeArgs{}
s.clientControlConns = nil
@ -98,9 +99,9 @@ func (s *TunnelBridge) Start(args interface{}, log *logger.Logger) (err error) {
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := server.NewServerChannel(host, p, s.log)
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, nil, s.callback)
if err != nil {
return
}

View File

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

View File

@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/jumper"
@ -38,7 +39,7 @@ type TunnelServerArgs struct {
}
type TunnelServer struct {
cfg TunnelServerArgs
sc utils.ServerChannel
sc server.ServerChannel
isStop bool
udpConn *net.Conn
userConns mapx.ConcurrentMap
@ -175,12 +176,12 @@ func (s *TunnelServer) StopService() {
if e != nil {
s.log.Printf("stop server service crashed,%s", e)
} else {
s.log.Printf("service server stoped")
s.log.Printf("service server stopped")
}
s.cfg = TunnelServerArgs{}
s.jumper = nil
s.log = nil
s.sc = utils.ServerChannel{}
s.sc = server.ServerChannel{}
s.udpConn = nil
s.udpConns = nil
s.userConns = nil
@ -233,7 +234,7 @@ func (s *TunnelServer) Start(args interface{}, log *logger.Logger) (err error) {
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
s.sc = utils.NewServerChannel(host, p, s.log)
s.sc = server.NewServerChannel(host, p, s.log)
if *s.cfg.IsUDP {
err = s.sc.ListenUDP(func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr) {
s.UDPSend(packet, localAddr, srcAddr)
@ -368,7 +369,7 @@ func (s *TunnelServer) UDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
if s.isStop {
@ -439,7 +440,7 @@ func (s *TunnelServer) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
s.log.Printf("udp conn %s connected", ID)
@ -472,7 +473,7 @@ func (s *TunnelServer) UDPRevecive(key, ID string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
s.sc.UDPListener.WriteToUDP(body, uc.srcAddr)

View File

@ -11,6 +11,7 @@ import (
"strings"
"time"
"github.com/snail007/goproxy/core/cs/server"
"github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/mapx"
@ -30,7 +31,7 @@ type UDPArgs struct {
type UDP struct {
p mapx.ConcurrentMap
cfg UDPArgs
sc *utils.ServerChannel
sc *server.ServerChannel
isStop bool
log *logger.Logger
outUDPConnCtxMap mapx.ConcurrentMap
@ -93,7 +94,7 @@ func (s *UDP) StopService() {
if e != nil {
s.log.Printf("stop udp service crashed,%s", e)
} else {
s.log.Printf("service udp stoped")
s.log.Printf("service udp stopped")
}
s.cfg = UDPArgs{}
s.log = nil
@ -121,7 +122,7 @@ func (s *UDP) Start(args interface{}, log *logger.Logger) (err error) {
}
host, port, _ := net.SplitHostPort(*s.cfg.Local)
p, _ := strconv.Atoi(port)
sc := utils.NewServerChannel(host, p, s.log)
sc := server.NewServerChannel(host, p, s.log)
s.sc = &sc
err = sc.ListenUDP(s.callback)
if err != nil {
@ -141,9 +142,7 @@ func (s *UDP) callback(listener *net.UDPConn, packet []byte, localAddr, srcAddr
}
}()
switch *s.cfg.ParentType {
case "tcp":
fallthrough
case "tls":
case "tcp", "tls":
s.OutToTCP(packet, localAddr, srcAddr)
case "udp":
s.OutToUDP(packet, localAddr, srcAddr)
@ -175,7 +174,7 @@ func (s *UDP) OutToUDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
if s.isStop {
@ -217,7 +216,7 @@ func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", 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())
@ -239,7 +238,7 @@ func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", 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)))
@ -276,7 +275,7 @@ func (s *UDP) UDPGCDeamon() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
if s.isStop {
@ -353,7 +352,7 @@ func (s *UDP) UDPRevecive(key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
s.log.Printf("udp conn %s connected", key)
@ -367,7 +366,7 @@ func (s *UDP) UDPRevecive(key string) {
}()
v, ok := s.udpConns.Get(key)
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
}
uc = v.(*UDPConnItem)
@ -386,7 +385,7 @@ func (s *UDP) UDPRevecive(key string) {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:\n%s", e, string(debug.Stack()))
}
}()
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

@ -20,10 +20,9 @@ import (
"net"
"net/http"
"os"
"os/exec"
"strings"
"github.com/snail007/goproxy/services/kcpcfg"
"github.com/snail007/goproxy/core/lib/kcpcfg"
"github.com/snail007/goproxy/utils/lb"
"golang.org/x/crypto/pbkdf2"
@ -123,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) {
h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1])
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) {
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
if err != nil {
@ -245,98 +287,6 @@ func CloseConn(conn *net.Conn) {
(*conn).Close()
}
}
func Keygen() (err error) {
CList := []string{"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BR", "BS", "BW", "BY", "BZ", "CA", "CF", "CG", "CH", "CK", "CL", "CM", "CN", "CO", "CR", "CS", "CU", "CY", "CZ", "DE", "DJ", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FR", "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GM", "GN", "GR", "GT", "GU", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KP", "KR", "KT", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "ML", "MM", "MN", "MO", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PR", "PT", "PY", "QA", "RO", "RU", "SA", "SB", "SC", "SD", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TD", "TG", "TH", "TJ", "TM", "TN", "TO", "TR", "TT", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "YE", "YU", "ZA", "ZM", "ZR", "ZW"}
domainSubfixList := []string{".com", ".edu", ".gov", ".int", ".mil", ".net", ".org", ".biz", ".info", ".pro", ".name", ".museum", ".coop", ".aero", ".xxx", ".idv", ".ac", ".ad", ".ae", ".af", ".ag", ".ai", ".al", ".am", ".an", ".ao", ".aq", ".ar", ".as", ".at", ".au", ".aw", ".az", ".ba", ".bb", ".bd", ".be", ".bf", ".bg", ".bh", ".bi", ".bj", ".bm", ".bn", ".bo", ".br", ".bs", ".bt", ".bv", ".bw", ".by", ".bz", ".ca", ".cc", ".cd", ".cf", ".cg", ".ch", ".ci", ".ck", ".cl", ".cm", ".cn", ".co", ".cr", ".cu", ".cv", ".cx", ".cy", ".cz", ".de", ".dj", ".dk", ".dm", ".do", ".dz", ".ec", ".ee", ".eg", ".eh", ".er", ".es", ".et", ".eu", ".fi", ".fj", ".fk", ".fm", ".fo", ".fr", ".ga", ".gd", ".ge", ".gf", ".gg", ".gh", ".gi", ".gl", ".gm", ".gn", ".gp", ".gq", ".gr", ".gs", ".gt", ".gu", ".gw", ".gy", ".hk", ".hm", ".hn", ".hr", ".ht", ".hu", ".id", ".ie", ".il", ".im", ".in", ".io", ".iq", ".ir", ".is", ".it", ".je", ".jm", ".jo", ".jp", ".ke", ".kg", ".kh", ".ki", ".km", ".kn", ".kp", ".kr", ".kw", ".ky", ".kz", ".la", ".lb", ".lc", ".li", ".lk", ".lr", ".ls", ".lt", ".lu", ".lv", ".ly", ".ma", ".mc", ".md", ".mg", ".mh", ".mk", ".ml", ".mm", ".mn", ".mo", ".mp", ".mq", ".mr", ".ms", ".mt", ".mu", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nc", ".ne", ".nf", ".ng", ".ni", ".nl", ".no", ".np", ".nr", ".nu", ".nz", ".om", ".pa", ".pe", ".pf", ".pg", ".ph", ".pk", ".pl", ".pm", ".pn", ".pr", ".ps", ".pt", ".pw", ".py", ".qa", ".re", ".ro", ".ru", ".rw", ".sa", ".sb", ".sc", ".sd", ".se", ".sg", ".sh", ".si", ".sj", ".sk", ".sl", ".sm", ".sn", ".so", ".sr", ".st", ".sv", ".sy", ".sz", ".tc", ".td", ".tf", ".tg", ".th", ".tj", ".tk", ".tl", ".tm", ".tn", ".to", ".tp", ".tr", ".tt", ".tv", ".tw", ".tz", ".ua", ".ug", ".uk", ".um", ".us", ".uy", ".uz", ".va", ".vc", ".ve", ".vg", ".vi", ".vn", ".vu", ".wf", ".ws", ".ye", ".yt", ".yu", ".yr", ".za", ".zm", ".zw"}
C := CList[int(RandInt(4))%len(CList)]
ST := RandString(int(RandInt(4) % 10))
O := RandString(int(RandInt(4) % 10))
CN := strings.ToLower(RandString(int(RandInt(4)%10)) + domainSubfixList[int(RandInt(4))%len(domainSubfixList)])
//log.Printf("C: %s, ST: %s, O: %s, CN: %s", C, ST, O, CN)
var out []byte
if len(os.Args) == 3 && os.Args[2] == "ca" {
cmd := exec.Command("sh", "-c", "openssl genrsa -out ca.key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key ca.key -x509 -days 36500 -out ca.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, "*."+CN)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
} else if len(os.Args) == 5 && os.Args[2] == "ca" && os.Args[3] != "" && os.Args[4] != "" {
certBytes, _ := ioutil.ReadFile("ca.crt")
block, _ := pem.Decode(certBytes)
if block == nil || certBytes == nil {
panic("failed to parse ca certificate PEM")
}
x509Cert, _ := x509.ParseCertificate(block.Bytes)
if x509Cert == nil {
panic("failed to parse block")
}
name := os.Args[3]
days := os.Args[4]
cmd := exec.Command("sh", "-c", "openssl genrsa -out "+name+".key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key %s.key -out %s.csr -subj /C=%s/ST=%s/O=%s/CN=%s", name, name, C, ST, O, CN)
fmt.Printf("%s", cmdStr)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr = fmt.Sprintf("openssl x509 -req -days %s -in %s.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out %s.crt", days, name, name)
fmt.Printf("%s", cmdStr)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
} else if len(os.Args) == 3 && os.Args[2] == "usage" {
fmt.Println(`proxy keygen //generate proxy.crt and proxy.key
proxy keygen ca //generate ca.crt and ca.key
proxy keygen ca client0 30 //generate client0.crt client0.key and use ca.crt sign it with 30 days
`)
} else if len(os.Args) == 2 {
cmd := exec.Command("sh", "-c", "openssl genrsa -out proxy.key 2048")
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
cmdStr := fmt.Sprintf("openssl req -new -key proxy.key -x509 -days 36500 -out proxy.crt -subj /C=%s/ST=%s/O=%s/CN=%s", C, ST, O, CN)
cmd = exec.Command("sh", "-c", cmdStr)
out, err = cmd.CombinedOutput()
if err != nil {
logger.Printf("err:%s", err)
return
}
fmt.Println(string(out))
}
return
}
var allInterfaceAddrCache []net.IP
@ -464,11 +414,20 @@ func RandInt(strLen int) int64 {
return i
}
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
err = binary.Read(r, binary.LittleEndian, &len)
if err != nil {
return
}
if len == 0 || len > ^uint64(0) {
err = fmt.Errorf("data len out of range, %d", len)
return
}
var n int
data = make([]byte, len)
n, err = r.Read(data)

View File

@ -102,6 +102,19 @@ func (s *conn) Write(p []byte) (int, error) {
}
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.
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) {
u, err := url.Parse(proxyURL)
if err != nil {
u, e := url.Parse(proxyURL)
if e != nil {
err = e
return
}
j = Jumper{
@ -34,7 +35,7 @@ func New(proxyURL string, timeout time.Duration) (j Jumper, err error) {
}
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 {
case "https":
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)
conn.SetDeadline(time.Now().Add(timeout))
n, err := conn.Read(reply)
n, e := conn.Read(reply)
conn.SetDeadline(time.Time{})
if err != nil {
err = fmt.Errorf("error read reply from proxy: %s", err)
if e != nil {
err = fmt.Errorf("error read reply from proxy: %s", e)
conn.Close()
conn = nil
return
@ -94,9 +95,9 @@ func (j *Jumper) dialSOCKS5(address string, timeout time.Duration) (conn net.Con
} else {
auth = nil
}
dialSocksProxy, err := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout})
if err != nil {
err = fmt.Errorf("error connecting to proxy: %s", err)
dialSocksProxy, e := proxy.SOCKS5("tcp", j.proxyURL.Host, auth, socks5Dialer{timeout: timeout})
if e != nil {
err = fmt.Errorf("error connecting to proxy: %s", e)
return
}
return dialSocksProxy.Dial("tcp", address)

View File

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

View File

@ -36,6 +36,7 @@ type Group struct {
lock *sync.Mutex
last *Backend
debug bool
bks []*Backend
}
func NewGroup(selectType int, configs BackendsConfig, dr *dnsx.DomainResolver, log *log.Logger, debug bool) Group {
@ -68,9 +69,19 @@ func NewGroup(selectType int, configs BackendsConfig, dr *dnsx.DomainResolver, l
dr: dr,
lock: &sync.Mutex{},
debug: debug,
bks: bks,
}
}
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 {
return false, g.bks[0].Address
}
if onlyHa {
g.lock.Lock()
defer g.lock.Unlock()
@ -79,16 +90,20 @@ func (g *Group) Select(srcAddr string, onlyHa bool) (addr string) {
g.log.Printf("############ choosed %s from lastest ############", g.last.Address)
printDebug(true, g.log, nil, srcAddr, (*g.selector).Backends())
}
return g.last.Address
return false, g.last.Address
}
g.last = (*g.selector).SelectBackend(srcAddr)
if !g.last.Active && g.last.ConnectUsedMillisecond > 0 {
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)
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) {
@ -121,6 +136,7 @@ func (g *Group) Reset(addrs []string) {
configs = append(configs, &c)
}
(*g.selector).Reset(configs, g.dr, g.log)
g.bks = (*g.selector).Backends()
}
func (g *Group) Backends() []*Backend {
return (*g.selector).Backends()

View File

@ -152,14 +152,7 @@ type Tuple struct {
func (m ConcurrentMap) Iter() <-chan Tuple {
chans := snapshot(m)
ch := make(chan Tuple)
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
}
}()
fanIn(chans, ch)
}()
go fanIn(chans, ch)
return ch
}
@ -171,14 +164,7 @@ func (m ConcurrentMap) IterBuffered() <-chan Tuple {
total += cap(c)
}
ch := make(chan Tuple, total)
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
}
}()
fanIn(chans, ch)
}()
go fanIn(chans, ch)
return ch
}
@ -193,11 +179,6 @@ func snapshot(m ConcurrentMap) (chans []chan Tuple) {
// Foreach shard.
for index, shard := range m {
go func(index int, shard *ConcurrentMapShared) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
}
}()
// Foreach key, value pair.
shard.RLock()
chans[index] = make(chan Tuple, len(shard.items))
@ -215,22 +196,25 @@ func snapshot(m ConcurrentMap) (chans []chan Tuple) {
// fanIn reads elements from channels `chans` into channel `out`
func fanIn(chans []chan Tuple, out chan Tuple) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
wg := sync.WaitGroup{}
wg.Add(len(chans))
for _, ch := range chans {
go func() {
go func(ch chan Tuple) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
func(ch chan Tuple) {
for t := range ch {
out <- t
}
wg.Done()
}(ch)
}()
}
wg.Wait()
close(out)
@ -274,20 +258,19 @@ func (m ConcurrentMap) Keys() []string {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
// Foreach shard.
wg := sync.WaitGroup{}
wg.Add(SHARD_COUNT)
for _, shard := range m {
go func() {
go func(shard *ConcurrentMapShared) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
func(shard *ConcurrentMapShared) {
// Foreach key, value pair.
shard.RLock()
for key := range shard.items {
@ -296,7 +279,6 @@ func (m ConcurrentMap) Keys() []string {
shard.RUnlock()
wg.Done()
}(shard)
}()
}
wg.Wait()
close(ch)

View File

@ -1,230 +0,0 @@
package utils
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
logger "log"
"net"
"runtime/debug"
"strconv"
"github.com/snail007/goproxy/services/kcpcfg"
kcp "github.com/xtaci/kcp-go"
)
type ServerChannel struct {
ip string
port int
Listener *net.Listener
UDPListener *net.UDPConn
errAcceptHandler func(err error)
log *logger.Logger
}
func NewServerChannel(ip string, port int, log *logger.Logger) ServerChannel {
return ServerChannel{
ip: ip,
port: port,
log: log,
errAcceptHandler: func(err error) {
log.Printf("accept error , ERR:%s", err)
},
}
}
func NewServerChannelHost(host string, log *logger.Logger) ServerChannel {
h, port, _ := net.SplitHostPort(host)
p, _ := strconv.Atoi(port)
return ServerChannel{
ip: h,
port: p,
log: log,
errAcceptHandler: func(err error) {
log.Printf("accept error , ERR:%s", err)
},
}
}
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
sc.errAcceptHandler = fn
}
func (sc *ServerChannel) ListenTls(certBytes, keyBytes, caCertBytes []byte, fn func(conn net.Conn)) (err error) {
sc.Listener, err = sc.listenTls(sc.ip, sc.port, certBytes, keyBytes, caCertBytes)
if err == nil {
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("ListenTls crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
for {
var conn net.Conn
conn, err = (*sc.Listener).Accept()
if err == nil {
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("tls connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
fn(conn)
}()
} else {
sc.errAcceptHandler(err)
(*sc.Listener).Close()
break
}
}
}()
}
return
}
func (sc *ServerChannel) listenTls(ip string, port int, certBytes, keyBytes, caCertBytes []byte) (ln *net.Listener, err error) {
var cert tls.Certificate
cert, err = tls.X509KeyPair(certBytes, keyBytes)
if err != nil {
return
}
clientCertPool := x509.NewCertPool()
caBytes := certBytes
if caCertBytes != nil {
caBytes = caCertBytes
}
ok := clientCertPool.AppendCertsFromPEM(caBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
config := &tls.Config{
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
}
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
if err == nil {
ln = &_ln
}
return
}
func (sc *ServerChannel) ListenTCP(fn func(conn net.Conn)) (err error) {
var l net.Listener
l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
if err == nil {
sc.Listener = &l
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("ListenTCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
for {
var conn net.Conn
conn, err = (*sc.Listener).Accept()
if err == nil {
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("tcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
fn(conn)
}()
} else {
sc.errAcceptHandler(err)
break
}
}
}()
}
return
}
func (sc *ServerChannel) ListenUDP(fn func(listener *net.UDPConn, packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
addr := &net.UDPAddr{IP: net.ParseIP(sc.ip), Port: sc.port}
l, err := net.ListenUDP("udp", addr)
if err == nil {
sc.UDPListener = l
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("ListenUDP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
for {
var buf = make([]byte, 2048)
n, srcAddr, err := (*sc.UDPListener).ReadFromUDP(buf)
if err == nil {
packet := buf[0:n]
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("udp data handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
fn(l, packet, addr, srcAddr)
}()
} else {
sc.errAcceptHandler(err)
break
}
}
}()
}
return
}
func (sc *ServerChannel) ListenKCP(config kcpcfg.KCPConfigArgs, fn func(conn net.Conn), log *logger.Logger) (err error) {
lis, err := kcp.ListenWithOptions(fmt.Sprintf("%s:%d", sc.ip, sc.port), config.Block, *config.DataShard, *config.ParityShard)
if err == nil {
if err = lis.SetDSCP(*config.DSCP); err != nil {
log.Println("SetDSCP:", err)
return
}
if err = lis.SetReadBuffer(*config.SockBuf); err != nil {
log.Println("SetReadBuffer:", err)
return
}
if err = lis.SetWriteBuffer(*config.SockBuf); err != nil {
log.Println("SetWriteBuffer:", err)
return
}
sc.Listener = new(net.Listener)
*sc.Listener = lis
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("ListenKCP crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
for {
//var conn net.Conn
conn, err := lis.AcceptKCP()
if err == nil {
go func() {
defer func() {
if e := recover(); e != nil {
sc.log.Printf("kcp connection handler crashed , err : %s , \ntrace:%s", e, string(debug.Stack()))
}
}()
conn.SetStreamMode(true)
conn.SetWriteDelay(true)
conn.SetNoDelay(*config.NoDelay, *config.Interval, *config.Resend, *config.NoCongestion)
conn.SetMtu(*config.MTU)
conn.SetWindowSize(*config.SndWnd, *config.RcvWnd)
conn.SetACKNoDelay(*config.AckNodelay)
if *config.NoComp {
fn(conn)
} else {
cconn := NewCompStream(conn)
fn(cconn)
}
}()
} else {
sc.errAcceptHandler(err)
break
}
}
}()
}
return
}

View File

@ -106,15 +106,16 @@ func (s *ServerConn) Port() string {
}
func (s *ServerConn) Handshake() (err error) {
remoteAddr := (*s.conn).RemoteAddr()
localAddr := (*s.conn).LocalAddr()
//协商开始
//method select request
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)
(*s.conn).SetReadDeadline(time.Time{})
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)
(*s.conn).SetReadDeadline(time.Time{})
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))
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
// if !methodReq.Select(Method_NO_AUTH) {
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
// (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
// methodReq.Reply(Method_NONE_ACCEPTABLE)
// (*s.conn).SetReadDeadline(time.Time{})
// err = fmt.Errorf("none method found : Method_NO_AUTH")
@ -131,7 +132,7 @@ func (s *ServerConn) Handshake() (err error) {
// }
s.method = Method_NO_AUTH
//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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -142,7 +143,7 @@ func (s *ServerConn) Handshake() (err error) {
} else {
//auth
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)
(*s.conn).SetReadDeadline(time.Time{})
err = fmt.Errorf("none method found : Method_USER_PASS")
@ -150,7 +151,7 @@ func (s *ServerConn) Handshake() (err error) {
}
s.method = Method_USER_PASS
//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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -160,7 +161,7 @@ func (s *ServerConn) Handshake() (err error) {
//read auth
buf := make([]byte, 500)
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)
(*s.conn).SetReadDeadline(time.Time{})
if err != nil {
@ -172,9 +173,10 @@ func (s *ServerConn) Handshake() (err error) {
s.password = string(r[2+r[1]+1:])
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
//auth
_addr := strings.Split(remoteAddr.String(), ":")
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
_userAddr := strings.Split(remoteAddr.String(), ":")
_localAddr := strings.Split(localAddr.String(), ":")
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})
(*s.conn).SetDeadline(time.Time{})
if err != nil {
@ -182,7 +184,7 @@ func (s *ServerConn) Handshake() (err error) {
return
}
} 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})
(*s.conn).SetDeadline(time.Time{})
if err != nil {
@ -194,7 +196,7 @@ func (s *ServerConn) Handshake() (err error) {
}
}
//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)
(*s.conn).SetReadDeadline(time.Time{})
if e != nil {

View File

@ -30,6 +30,7 @@ type Checker struct {
interval int64
timeout int
isStop bool
intelligent string
log *logger.Logger
}
type CheckerItem struct {
@ -43,12 +44,13 @@ type CheckerItem struct {
//NewChecker args:
//timeout : tcp timeout milliseconds ,connect to host
//interval: recheck domain interval seconds
func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger) Checker {
func NewChecker(timeout int, interval int64, blockedFile, directFile string, log *logger.Logger, intelligent string) Checker {
ch := Checker{
data: mapx.NewConcurrentMap(),
interval: interval,
timeout: timeout,
isStop: false,
intelligent: intelligent,
log: log,
}
ch.blockedMap = ch.loadMap(blockedFile)
@ -90,7 +92,7 @@ func (c *Checker) start() {
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
//log.Printf("checker started")
@ -100,7 +102,7 @@ func (c *Checker) start() {
go func(item CheckerItem) {
defer func() {
if e := recover(); e != nil {
fmt.Printf("crashed:%s", string(debug.Stack()))
fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
}
}()
if c.isNeedCheck(item) {
@ -164,10 +166,19 @@ func (c *Checker) IsBlocked(domain string) (blocked, isInMap bool, failN, succes
//log.Printf("%s not in map, blocked true", address)
return true, false, 0, 0
}
switch c.intelligent {
case "direct":
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 {
u, err := url.Parse("http://" + address)
if err != nil {
@ -176,11 +187,9 @@ func (c *Checker) domainIsInMap(address string, blockedMap bool) bool {
}
domainSlice := strings.Split(u.Hostname(), ".")
if len(domainSlice) > 1 {
subSlice := domainSlice[:len(domainSlice)-1]
topDomain := strings.Join(domainSlice[len(domainSlice)-1:], ".")
checkDomain := topDomain
for i := len(subSlice) - 1; i >= 0; i-- {
checkDomain = subSlice[i] + "." + checkDomain
checkDomain := ""
for i := len(domainSlice) - 1; i >= 0; i-- {
checkDomain = strings.Join(domainSlice[i:], ".")
if !blockedMap && c.directMap.Has(checkDomain) {
return true
}
@ -237,7 +246,7 @@ func (ba *BasicAuth) AddFromFile(file string) (n int, err error) {
}
userpassArr := strings.Split(strings.Replace(string(_content), "\r", "", -1), "\n")
for _, userpass := range userpassArr {
if strings.HasPrefix("#", userpass) {
if strings.HasPrefix(userpass, "#") {
continue
}
u := strings.Split(strings.Trim(userpass, " "), ":")
@ -259,18 +268,23 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
}
return
}
func (ba *BasicAuth) CheckUserPass(user, pass, ip, target string) (ok bool) {
return ba.Check(user+":"+pass, ip, target)
func (ba *BasicAuth) Delete(userArr []string) {
for _, u := range userArr {
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, " "), ":")
if len(u) == 2 {
if p, _ok := ba.data.Get(u[0]); _ok {
return p.(string) == u[1]
}
if ba.authURL != "" {
err := ba.checkFromURL(userpass, ip, target)
err := ba.checkFromURL(userpass, userIP, localIP, target)
if err == nil {
return true
}
@ -280,7 +294,7 @@ func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
}
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, " "), ":")
if len(u) != 2 {
return
@ -292,7 +306,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
} else {
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
var domain string
if ba.dns != nil {
@ -309,7 +323,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if err == nil && code == ba.authOkCode {
break
} 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 {
if len(body) > 0 {
err = fmt.Errorf(string(body[0:100]))
@ -320,7 +334,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if len(b) > 50 {
b = b[:50]
}
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b)
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 {
ba.log.Print(err)
@ -474,7 +488,8 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
return
}
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 := ""
if req.IsHTTPS() {
URL = "https://" + req.Host
@ -485,7 +500,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
if err != nil {
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)
if !authOk {
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

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