40 Commits
v6.8 ... 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
c66147c686 Merge pull request #201 from snail007/master
add more en markdown
2018-12-25 13:13:04 +08: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
arraykeys@gmail.com
89b5744e27 Merge branch 'a' into dev 2018-12-14 13:08:52 +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
50 changed files with 373 additions and 605 deletions

View File

@ -1,5 +1,25 @@
proxy更新日志 proxy更新日志
v6.9
1.修复了sps的start潜在的crash问题.
2.sps代理增加了--parent-tls-single参数用来支持单向tls上级。
3.sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
现在上级格式: -P YTpi#2.2.2.2:33080@1
说明:
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
2.2.2.2:33080 是上级地址
@1 是设置权重,可以参考手册权重部分.
4.修复了socks5代理错误处理超时的问题.
5.修复了http(s)代理错误处理-Z的问题.
v6.8
1.HTTP(S)\SOCKS5代理,API认证功能,发送给认证接口的参数增加了本地IP,local_ip字段,
代表用户访问的是本地服务器的哪个IP.
2.fix #194 , fix #134 , 代理更稳定.
3.增加了一波英文文档.
v6.6 v6.6
1.优化了limitconn的关闭逻辑,释放更多资源. 1.优化了limitconn的关闭逻辑,释放更多资源.
2.http(s)\socks代理增加了--intelligent,智能模式设置,可以是intelligent|direct|parent三者之一, 2.http(s)\socks代理增加了--intelligent,智能模式设置,可以是intelligent|direct|parent三者之一,

View File

@ -1,6 +1,7 @@
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss proxy server implemented by golang. It supports parent proxy,nat forward,TCP/UDP port forwarding, SSH transfer, TLS encrypted transmission, protocol conversion. you can expose a local server behind a NAT or firewall to the internet, secure DNS proxy.   Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss proxy server implemented by golang. It supports parent proxy,nat forward,TCP/UDP port forwarding, SSH transfer, TLS encrypted transmission, protocol conversion. you can expose a local server behind a NAT or firewall to the internet, secure DNS proxy.  
[Download](https://github.com/snail007/goproxy/releases)
--- ---
@ -10,7 +11,7 @@ Proxy is a high performance HTTP, HTTPS, HTTPS, websocket, TCP, UDP, Socks5, ss
**[Full-platform graphical interface version](/gui/README.md)** **[Full-platform graphical interface version](/gui/README.md)**
**[Full platform SDK](/sdk/README.md)** **[Full platform SDK](https://github.com/snail007/goproxy-sdk/blob/master/README.md)**
**[GoProxy special authorization](/AUTHORIZATION.md)** **[GoProxy special authorization](/AUTHORIZATION.md)**
@ -201,6 +202,8 @@ chmod +x install.sh
#### Docker installation #### Docker installation
[docker](https://hub.docker.com/r/snail007/goproxy)
Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version. Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version.
The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 6.0: The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 6.0:
@ -1086,6 +1089,19 @@ target: if the client is the HTTP (s) proxy request, this represents the complet
If there is no -a or -F or --auth-url parameters, local authentication is closed. If there is no -a or -F or --auth-url parameters, local authentication is closed.
If there is no -A parameter, the connection to the father proxy does not use authentication. If there is no -A parameter, the connection to the father proxy does not use authentication.
**Setting up separate authentication information**
If there are many different parent proxys and their passwords are the same or different, then authentication information can be set for each parent proxy.
At the same time, a global authentication information can be set with the - A parameter. If a parent proxy does not set the authentication information separately, the global authentication information can be used.
Authentication information is written together with parent proxy.
format: YTpi#2.2.2.2:33080@1
Explain:
YTpi is the Authentication information encoded by Base64, For example, http (s)/socks original authentication information, a:b,the user is a and the password is b, which is YTpi after Base64 encoding.
if it is ss, A is the encryption method and B is the password, for example, aes-192-cfb:your_pass, which is YWVzLTE5Mi1jZmI6eW91cl9wYXNz after Base64 encoding.
\# is an interval symbol. If there is authentication information, there must be #. No authentication information can be omitted #
2.2.2.2:33080 is parent proxy's address
@1 is weights, Nothing can be omitted. Detailed instructions can be referred to in the manual.***weights***
#### **6.8 Custom encryption** #### **6.8 Custom encryption**
HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted. HTTP(s) proxy can encrypt TCP data by TLS standard encryption and KCP protocol encryption, in addition to supporting custom encryption after TLS and KCP, That is to say, custom encryption and tls|kcp can be combined to use. The internal AES256 encryption is used, and it only needs to define one password by yourself. Encryption is divided into two parts, the one is whether the local (-z) is encrypted and decrypted, the other is whether the parents (-Z) is encrypted and decrypted.
Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples: Custom encryption requires both ends are proxy. Next, we use two level example and three level example as examples:
@ -1271,7 +1287,7 @@ execution: `go run *.go`
Proxy is licensed under GPLv3 license. Proxy is licensed under GPLv3 license.
### Contact ### Contact
proxy QQ group: 7930152191 , 189618940 (full) proxy QQ group: 793015219 , 189618940 (full)
### Donation ### Donation
if proxy help you a lot,you can support us by: if proxy help you a lot,you can support us by:

View File

@ -1,7 +1,7 @@
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/> <img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。 Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群: 7930152191 (2群), 189618940 (1群满) [点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群: 793015219 (2群), 189618940 (1群满)
--- ---
@ -11,7 +11,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服
**[全平台图形界面版本](/gui/README_ZH.md)** **[全平台图形界面版本](/gui/README_ZH.md)**
**[全平台SDK](/sdk/README_ZH.md)** **[全平台SDK](https://github.com/snail007/goproxy-sdk/blob/master/README_ZH.md)**
**[GoProxy特殊授权](/AUTHORIZATION_ZH.md)** **[GoProxy特殊授权](/AUTHORIZATION_ZH.md)**
@ -202,6 +202,9 @@ chmod +x install.sh
``` ```
#### Docker安装 #### Docker安装
[docker](https://hub.docker.com/r/snail007/goproxy)
项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本, 项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile 全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
或者使用参数GOPROXY_VERSION指定构建的goproxy版本. 或者使用参数GOPROXY_VERSION指定构建的goproxy版本.
@ -366,11 +369,12 @@ weight 根据每个上级的权重和连接数情况,选择出一个上级
比如: 比如:
`./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"), 用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,target四个参数: 带上user,pass,ip,local_ip,target五个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET} http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}&target={TARGET}
user:用户名 user:用户名
pass:密码 pass:密码
ip:用户的IP,比如:192.168.1.200 ip:用户的IP,比如:192.168.1.200
local_ip:用户访问的服务器的IP,比如:3.3.3.3
target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80 target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80
如果没有-a或-F或--auth-url参数,就是关闭Basic认证. 如果没有-a或-F或--auth-url参数,就是关闭Basic认证.
@ -915,11 +919,12 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
比如: 比如:
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"` `./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"), 用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
带上user,pass,ip,个参数: 带上user,pass,ip,local_ip四个参数:
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP} http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}
user:用户名 user:用户名
pass:密码 pass:密码
ip:用户的IP,比如:192.168.1.200 ip:用户的IP,比如:192.168.1.200
local_ip:用户访问的服务器的IP,比如:3.3.3.3
如果没有-a或-F或--auth-url参数,就是关闭认证. 如果没有-a或-F或--auth-url参数,就是关闭认证.
@ -1155,6 +1160,18 @@ target:如果客户端是http(s)代理请求,这里代表的是请求的完整ur
如果没有-a或-F或--auth-url参数,就是关闭本地认证. 如果没有-a或-F或--auth-url参数,就是关闭本地认证.
如果没有-A参数,连接上级不使用认证. 如果没有-A参数,连接上级不使用认证.
**设置单独认证信息**
如果存在多个不同上级,而且他们的密码有的一样有的不一样,那么可以针对每个上级设置认证信息,
同时还可以用-A参数设置一个全局认证信息,如果某个上级没有单独设置认证信息就使用全局设置的认证信息.
认证信息和上级写在一起.
格式是: YTpi#2.2.2.2:33080@1
说明:
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#
2.2.2.2:33080 是上级地址
@1 是设置权重,没有可以省略,详细说明可以参考手册***权重部分***
#### **6.8 自定义加密** #### **6.8 自定义加密**
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行 proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
@ -1368,7 +1385,7 @@ utils是工具包,service是具体的每个服务类.
### License ### License
Proxy is licensed under GPLv3 license. Proxy is licensed under GPLv3 license.
### Contact ### Contact
官方QQ交流群: 7930152191 (2群), 189618940 (1群满) 官方QQ交流群: 793015219 (2群), 189618940 (1群满)
### Donation ### Donation

View File

@ -1 +1 @@
6.6 6.9

View File

@ -303,6 +303,7 @@ func initConfig() (err error) {
spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String() spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
spsArgs.Debug = isDebug spsArgs.Debug = isDebug
//########dns######### //########dns#########

View File

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

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

View File

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

View File

@ -1,263 +0,0 @@
# Proxy SDK usage instructions
The following platforms are supported:
- Android, `.arr` library
- IOS, `.framework` library
- Windows, `.dll` library
- Linux, `.so` library
- MacOS, `.dylib` library
proxy uses gombile to compile a copy of go code into an sdk library that can be called directly from the android and ios platforms,
It also provides sdk support for linux and windows, MacOS,based on these libraries, APP developers can easily develop various forms of proxy tools.
# The following sub-platform describes the use of the 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)
[Click to download Android-SDK](https://github.com/snail007/goproxy-sdk-android/releases)
The sdk form provided in the Android system is a suffix.aar class library files, development time only need to ARR class library files into the android project can be.
### Android-SDK usage examples
#### 1. Importing packages
```java
import snail007.proxy.Porxy
```
#### 2. Start a service
```java
String serviceID="http01";// Here serviceID is a custom unique identifier string, ensure that each start of the service is not the same
String serviceArgs="http -p :8080";
String err=Proxy.start(serviceID,serviceArgs);
if (!err.isEmpty()){
// Failed to start
System.out.println("start fail,error:"+err);
}else{
// Successful launch
}
```
#### 3. Stop service
```java
String serviceID="http01";
Proxy.stop(serviceID);
// Stop over.
```
## 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)
[Click to download IOS-SDK](https://github.com/snail007/goproxy-sdk-ios/releases)
The sdk form provided in IOS is a suffix.framework Class Library folder, the development of the class library files only need to be introduced into the project, and then call the method.
### IOS-SDK usage examples
#### Importing packages
```objc
#import <Proxy/Proxy.objc.h>
```
#### 2. Start a service
```objc
-(IBAction)doStart:(id)sender
{
// Here serviceID is a custom unique identifier string, guaranteed to be different for each started service
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(@"Successful launch");
}
}
```
#### 3. Stop service
```objc
-(IBAction)doStop:(id)sender
{
NSString *serviceID = @"http01";
ProxyStop(serviceID);
// Stop over.
}
```
## 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)
[Click to download Windows-SDK](https://github.com/snail007/goproxy-sdk-windows/releases)
The sdk form provided in the Windows system is a suffix.when developing,you only need to load the dll class library file, and then call the method.
### Windows-SDK usage instance
C++examples, do not need to include header files, only need to load proxy-sdk.dll can, ieshims.dll needed and proxy-sdk.dll together.
Author: [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()
{
// Here p0 is a custom unique identifier string, guaranteed to be different for each started service
char *p0 = "http01";
char *p1 = "http -t tcp -p :38080";
printf("This is demo application.\n");
// Start the service, returns an empty string description starts successfully;returns a non-empty string description fails to start, the returned string is the cause of the error
printf("start result %s\n", Start(p0,p1));
// Stop service, no return value
Stop(p0);
return 0;
}
#ifdef __cplusplus
}
#endif
```
C++ Example 2, move step[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)
[Click to download Linux-SDK](https://github.com/snail007/goproxy-sdk-linux/releases)
The sdk form provided in the Linux system is a suffix.so library files, development time only need to load the so library, you can call the method.
### Linux-SDK usage examples
The SDK that is used below Linux is the so file i.e. libproxy-sdk. so,write a simple example of a C program that calls the method inside the so library.
`vi test-proxy.c`
```c
#include <stdio.h>
#include "libproxy-sdk.h"
int main() {
printf("This is demo application.\n");
// Here p0 is a custom unique identifier string, guaranteed to be different for each started service
char *p0 = "http01";
char *p1 = "http -t tcp -p :38080";
// Start the service, returns an empty string description starts successfully;returns a non-empty string description fails to start, the returned string is the cause of the error
printf("start result %s\n",Start(p0,p1));
// Stop service, no return value
Stop(p0);
return 0;
}
```
#### Compile test-proxy.c ####
`export LD_LIBRARY_PATH=./ && gcc -o test-proxy test-proxy.c libproxy-sdk.so`
#### Execution ####
`./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)
[Click to download MacOS-SDK](https://github.com/snail007/goproxy-sdk-mac/releases)
The sdk form provided in the MacOS system is a suffix.dylib library files, development time only need to load so library, you can call the method.
### MacOS-SDK usage instance
The sdk used below for MacOS is the dylib file i.e. libproxy-sdk.dylib, write a simple Obj-C program example, call dylib library inside the method.
```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");
}
```
### About the service
There are 11 types of proxy services:
```shell
http
socks
sps
tcp
udp
bridge
server
client
tbridge
tserver
tclient
```
When the service starts,if there is a service running with the same ID, then the previous service will be stopped and the previous service will be overwritten later.
So make sure that the first ID parameter is unique every time you start the service.
The specific usage and parameters of these services can be found in [proxy manual](https://github.com/snail007/goproxy/blob/master/README.md) the SDK service does not support the manual inside: -- daemon and -- forever parameters.

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

@ -8,7 +8,9 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"runtime/pprof"
"strings" "strings"
"sync"
"github.com/snail007/goproxy/core/lib/kcpcfg" "github.com/snail007/goproxy/core/lib/kcpcfg"
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt" encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
@ -31,6 +33,10 @@ var SDK_VERSION = "No Version Provided"
var ( var (
app *kingpin.Application app *kingpin.Application
cpuProfilingFile, memProfilingFile, blockProfilingFile,
goroutineProfilingFile, threadcreateProfilingFile *os.File
isProfiling bool
profilingLock = &sync.Mutex{}
) )
type LogCallback interface { type LogCallback interface {
@ -320,6 +326,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool() spsArgs.LoadBalanceOnlyHA = sps.Flag("lb-onlyha", "use only `high availability mode` to choose parent for LB").Default("false").Bool()
spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String() spsArgs.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String() spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
spsArgs.Debug = debug spsArgs.Debug = debug
//########dns######### //########dns#########
@ -411,7 +418,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
muxClientArgs.KCP = kcpArgs muxClientArgs.KCP = kcpArgs
dnsArgs.KCP = kcpArgs dnsArgs.KCP = kcpArgs
log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime) log := logger.New(os.Stdout, "", logger.Ldate|logger.Ltime)
flags := logger.Ldate flags := logger.Ldate
if *debug { if *debug {
flags |= logger.Lshortfile | logger.Lmicroseconds flags |= logger.Lshortfile | logger.Lmicroseconds
@ -477,3 +484,41 @@ func Stop(serviceID string) {
func Version() string { func Version() string {
return SDK_VERSION return SDK_VERSION
} }
func StartProfiling(storePath string) {
profilingLock.Lock()
defer profilingLock.Unlock()
if !isProfiling {
isProfiling = true
if storePath == "" {
storePath = "."
}
cpuProfilingFile, _ = os.Create(filepath.Join(storePath, "cpu.prof"))
memProfilingFile, _ = os.Create(filepath.Join(storePath, "memory.prof"))
blockProfilingFile, _ = os.Create(filepath.Join(storePath, "block.prof"))
goroutineProfilingFile, _ = os.Create(filepath.Join(storePath, "goroutine.prof"))
threadcreateProfilingFile, _ = os.Create(filepath.Join(storePath, "threadcreate.prof"))
pprof.StartCPUProfile(cpuProfilingFile)
}
}
func StopProfiling() {
profilingLock.Lock()
defer profilingLock.Unlock()
if isProfiling {
isProfiling = false
pprof.StopCPUProfile()
goroutine := pprof.Lookup("goroutine")
goroutine.WriteTo(goroutineProfilingFile, 1)
heap := pprof.Lookup("heap")
heap.WriteTo(memProfilingFile, 1)
block := pprof.Lookup("block")
block.WriteTo(blockProfilingFile, 1)
threadcreate := pprof.Lookup("threadcreate")
threadcreate.WriteTo(threadcreateProfilingFile, 1)
//close
goroutineProfilingFile.Close()
memProfilingFile.Close()
blockProfilingFile.Close()
threadcreateProfilingFile.Close()
}
}

View File

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

View File

@ -210,7 +210,7 @@ func (s *HTTP) InitService() (err error) {
return return
} }
conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2) conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
if err == nil { if err == nil && conn != nil {
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = conn.Write([]byte{0}) _, err = conn.Write([]byte{0})
conn.SetDeadline(time.Time{}) conn.SetDeadline(time.Time{})
@ -386,12 +386,17 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} }
if useProxy { if useProxy {
// s.log.Printf("%v", s.outPool) // s.log.Printf("%v", s.outPool)
if *s.cfg.ParentType == "ssh" {
outConn, err = s.getSSHConn(address)
} else {
selectAddr := (*inConn).RemoteAddr().String() selectAddr := (*inConn).RemoteAddr().String()
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget { if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
selectAddr = address selectAddr = address
} }
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA) lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
outConn, err = s.GetParentConn(lbAddr) outConn, err = s.GetParentConn(lbAddr)
}
} else { } else {
outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr) outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr)
} }
@ -411,7 +416,7 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
if *s.cfg.ParentCompress { if *s.cfg.ParentCompress {
outConn = utils.NewCompConn(outConn) outConn = utils.NewCompConn(outConn)
} }
if *s.cfg.ParentKey != "" { if useProxy && *s.cfg.ParentKey != "" {
outConn = conncrypt.New(outConn, &conncrypt.Config{ outConn = conncrypt.New(outConn, &conncrypt.Config{
Password: *s.cfg.ParentKey, Password: *s.cfg.ParentKey,
}) })
@ -515,6 +520,9 @@ func (s *HTTP) ConnectSSH() (err error) {
s.sshClient.Close() s.sshClient.Close()
} }
s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config) s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config)
if err != nil {
s.log.Printf("connect to ssh %s fail", s.cfg.Parent)
}
<-s.lockChn <-s.lockChn
return return
} }

View File

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

View File

@ -101,7 +101,7 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
s.log.Printf("connect %s for udp", serverConn.Target()) s.log.Printf("connect %s for udp", serverConn.Target())
//socks client //socks client
client, err := s.HandshakeSocksParent(&outconn, "udp", serverConn.Target(), serverConn.AuthData(), false) client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
if err != nil { if err != nil {
clean("handshake fail", fmt.Sprintf("%s", err)) clean("handshake fail", fmt.Sprintf("%s", err))
return return

View File

@ -13,6 +13,7 @@ import (
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/snail007/goproxy/core/cs/server" "github.com/snail007/goproxy/core/cs/server"
@ -20,6 +21,7 @@ import (
"github.com/snail007/goproxy/services" "github.com/snail007/goproxy/services"
"github.com/snail007/goproxy/utils" "github.com/snail007/goproxy/utils"
"github.com/snail007/goproxy/utils/conncrypt" "github.com/snail007/goproxy/utils/conncrypt"
cryptool "github.com/snail007/goproxy/utils/crypt"
"github.com/snail007/goproxy/utils/datasize" "github.com/snail007/goproxy/utils/datasize"
"github.com/snail007/goproxy/utils/dnsx" "github.com/snail007/goproxy/utils/dnsx"
"github.com/snail007/goproxy/utils/iolimiter" "github.com/snail007/goproxy/utils/iolimiter"
@ -71,6 +73,7 @@ type SPSArgs struct {
LoadBalanceRetryTime *int LoadBalanceRetryTime *int
LoadBalanceHashTarget *bool LoadBalanceHashTarget *bool
LoadBalanceOnlyHA *bool LoadBalanceOnlyHA *bool
ParentTLSSingle *bool
RateLimit *string RateLimit *string
RateLimitBytes float64 RateLimitBytes float64
@ -91,6 +94,8 @@ type SPS struct {
udpLocalKey []byte udpLocalKey []byte
udpParentKey []byte udpParentKey []byte
jumper *jumper.Jumper jumper *jumper.Jumper
parentAuthData *sync.Map
parentCipherData *sync.Map
} }
func NewSPS() services.Service { func NewSPS() services.Service {
@ -100,6 +105,8 @@ func NewSPS() services.Service {
serverChannels: []*server.ServerChannel{}, serverChannels: []*server.ServerChannel{},
userConns: mapx.NewConcurrentMap(), userConns: mapx.NewConcurrentMap(),
udpRelatedPacketConns: mapx.NewConcurrentMap(), udpRelatedPacketConns: mapx.NewConcurrentMap(),
parentAuthData: &sync.Map{},
parentCipherData: &sync.Map{},
} }
} }
func (s *SPS) CheckArgs() (err error) { func (s *SPS) CheckArgs() (err error) {
@ -121,10 +128,12 @@ func (s *SPS) CheckArgs() (err error) {
return return
} }
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" { if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
if !*s.cfg.ParentTLSSingle {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil { if err != nil {
return return
} }
}
if *s.cfg.CaCertFile != "" { if *s.cfg.CaCertFile != "" {
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile) s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
if err != nil { if err != nil {
@ -166,7 +175,10 @@ func (s *SPS) InitService() (err error) {
} }
if len(*s.cfg.Parent) > 0 { if len(*s.cfg.Parent) > 0 {
s.InitLB() err = s.InitLB()
if err != nil {
return
}
} }
err = s.InitBasicAuth() err = s.InitBasicAuth()
@ -208,6 +220,8 @@ func (s *SPS) StopService() {
s.udpParentKey = nil s.udpParentKey = nil
s.udpRelatedPacketConns = nil s.udpRelatedPacketConns = nil
s.userConns = nil s.userConns = nil
s.parentAuthData = nil
s.parentCipherData = nil
s = nil s = nil
}() }()
for _, sc := range s.serverChannels { for _, sc := range s.serverChannels {
@ -257,6 +271,9 @@ func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
} else if *s.cfg.LocalType == "kcp" { } else if *s.cfg.LocalType == "kcp" {
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log) err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
} }
if err != nil {
return
}
if *s.cfg.ParentServiceType == "socks" { if *s.cfg.ParentServiceType == "socks" {
err = s.RunSSUDP(addr) err = s.RunSSUDP(addr)
} else { } else {
@ -431,8 +448,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
utils.CloseConn(inConn) utils.CloseConn(inConn)
return return
} }
ParentAuth := s.getParentAuth(lbAddr)
if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() { if ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
forwardBytes = utils.RemoveProxyHeaders(forwardBytes) forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
} }
@ -452,8 +469,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
pb.WriteString("Connection: Keep-Alive\r\n") pb.WriteString("Connection: Keep-Alive\r\n")
u := "" u := ""
if *s.cfg.ParentAuth != "" { if ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":") a := strings.Split(ParentAuth, ":")
if len(a) != 2 { if len(a) != 2 {
err = fmt.Errorf("parent auth data format error") err = fmt.Errorf("parent auth data format error")
return return
@ -504,7 +521,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
s.log.Printf("connect %s", address) s.log.Printf("connect %s", address)
//socks client //socks client
_, err = s.HandshakeSocksParent(&outConn, "tcp", address, auth, false) _, err = s.HandshakeSocksParent(ParentAuth, &outConn, "tcp", address, auth, false)
if err != nil { if err != nil {
s.log.Printf("handshake fail, %s", err) s.log.Printf("handshake fail, %s", err)
return return
@ -517,7 +534,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
return return
} }
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy()) outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.getParentCipher(lbAddr))
if err != nil { if err != nil {
err = fmt.Errorf("dial ss parent fail, err : %s", err) err = fmt.Errorf("dial ss parent fail, err : %s", err)
return return
@ -577,10 +594,41 @@ func (s *SPS) InitBasicAuth() (err error) {
} }
return return
} }
func (s *SPS) InitLB() { func (s *SPS) InitLB() (err error) {
configs := lb.BackendsConfig{} configs := lb.BackendsConfig{}
for _, addr := range *s.cfg.Parent { for _, addr := range *s.cfg.Parent {
_addrInfo := strings.Split(addr, "@") var _addrInfo []string
if strings.Contains(addr, "#") {
_s := addr[:strings.Index(addr, "#")]
_auth, err := cryptool.CryptTools.Base64Decode(_s)
if err != nil {
s.log.Printf("decoding parent auth data [ %s ] fail , error : %s", _s, err)
return err
}
_addrInfo = strings.Split(addr[strings.Index(addr, "#")+1:], "@")
if *s.cfg.ParentServiceType == "ss" {
_s := strings.Split(_auth, ":")
m := _s[0]
k := _s[1]
if m == "" {
m = *s.cfg.ParentSSMethod
}
if k == "" {
k = *s.cfg.ParentSSKey
}
cipher, err := ss.NewCipher(m, k)
if err != nil {
s.log.Printf("error generating cipher, ssMethod: %s, ssKey: %s, error : %s", m, k, err)
return err
}
s.parentCipherData.Store(_addrInfo[0], cipher)
} else {
s.parentAuthData.Store(_addrInfo[0], _auth)
}
} else {
_addrInfo = strings.Split(addr, "@")
}
_addr := _addrInfo[0] _addr := _addrInfo[0]
weight := 1 weight := 1
if len(_addrInfo) == 2 { if len(_addrInfo) == 2 {
@ -597,6 +645,19 @@ func (s *SPS) InitLB() {
} }
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug) LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
s.lb = &LB s.lb = &LB
return
}
func (s *SPS) getParentAuth(lbAddr string) string {
if v, ok := s.parentAuthData.Load(lbAddr); ok {
return v.(string)
}
return *s.cfg.ParentAuth
}
func (s *SPS) getParentCipher(lbAddr string) *ss.Cipher {
if v, ok := s.parentCipherData.Load(lbAddr); ok {
return v.(*ss.Cipher).Copy()
}
return s.parentCipher.Copy()
} }
func (s *SPS) IsBasicAuth() bool { func (s *SPS) IsBasicAuth() bool {
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != "" return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
@ -654,12 +715,21 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
if s.jumper == nil { if s.jumper == nil {
var _conn tls.Conn 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) _conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
}
if err == nil { if err == nil {
conn = net.Conn(&_conn) conn = net.Conn(&_conn)
} }
} else { } else {
conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes) 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 { if err != nil {
return nil, err return nil, err
} }
@ -691,9 +761,9 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
} }
return return
} }
func (s *SPS) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) { func (s *SPS) HandshakeSocksParent(parentAuth string, outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
if *s.cfg.ParentAuth != "" { if parentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":") a := strings.Split(parentAuth, ":")
if len(a) != 2 { if len(a) != 2 {
err = fmt.Errorf("parent auth data format error") err = fmt.Errorf("parent auth data format error")
return return
@ -717,7 +787,9 @@ func (s *SPS) ParentUDPKey() (key []byte) {
return []byte(v)[:24] return []byte(v)[:24]
} }
case "tls": case "tls":
if s.cfg.KeyBytes != nil {
return s.cfg.KeyBytes[:24] return s.cfg.KeyBytes[:24]
}
case "kcp": case "kcp":
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key))) v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
return []byte(v)[:24] return []byte(v)[:24]

View File

@ -88,7 +88,7 @@ func (s *SPS) RunSSUDP(addr string) (err error) {
return return
} }
client, err := s.HandshakeSocksParent(&outconn, "udp", socksPacket.Addr(), socks.Auth{}, true) client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", socksPacket.Addr(), socks.Auth{}, true)
if err != nil { if err != nil {
clean("handshake fail", fmt.Sprintf("%s", err)) clean("handshake fail", fmt.Sprintf("%s", err))
return return

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

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

View File

@ -122,12 +122,55 @@ func ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
} }
} }
} }
func SingleTlsConnectHost(host string, timeout int, caCertBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1])
return SingleTlsConnect(h[0], port, timeout, caCertBytes)
}
func SingleTlsConnect(host string, port, timeout int, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestSingleTlsConfig(caCertBytes)
if err != nil {
return
}
_conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Duration(timeout)*time.Millisecond)
if err != nil {
return
}
return *tls.Client(_conn, conf), err
}
func SingleTlsConfig(caCertBytes []byte) (conf *tls.Config, err error) {
return getRequestSingleTlsConfig(caCertBytes)
}
func getRequestSingleTlsConfig(caCertBytes []byte) (conf *tls.Config, err error) {
conf = &tls.Config{InsecureSkipVerify: true}
serverCertPool := x509.NewCertPool()
if caCertBytes != nil {
ok := serverCertPool.AppendCertsFromPEM(caCertBytes)
if !ok {
err = errors.New("failed to parse root certificate")
}
conf.RootCAs = serverCertPool
conf.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
opts := x509.VerifyOptions{
Roots: serverCertPool,
}
for _, rawCert := range rawCerts {
cert, _ := x509.ParseCertificate(rawCert)
_, err := cert.Verify(opts)
if err != nil {
return err
}
}
return nil
}
}
return
}
func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) { func TlsConnectHost(host string, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
h := strings.Split(host, ":") h := strings.Split(host, ":")
port, _ := strconv.Atoi(h[1]) port, _ := strconv.Atoi(h[1])
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes) return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
} }
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) { func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes) conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
if err != nil { if err != nil {

View File

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

View File

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

View File

@ -268,18 +268,23 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
} }
return return
} }
func (ba *BasicAuth) CheckUserPass(user, pass, ip, target string) (ok bool) { func (ba *BasicAuth) Delete(userArr []string) {
for _, u := range userArr {
return ba.Check(user+":"+pass, ip, target) ba.data.Remove(u)
} }
func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) { }
func (ba *BasicAuth) CheckUserPass(user, pass, userIP, localIP, target string) (ok bool) {
return ba.Check(user+":"+pass, userIP, localIP, target)
}
func (ba *BasicAuth) Check(userpass string, userIP, localIP, target string) (ok bool) {
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) == 2 { if len(u) == 2 {
if p, _ok := ba.data.Get(u[0]); _ok { if p, _ok := ba.data.Get(u[0]); _ok {
return p.(string) == u[1] return p.(string) == u[1]
} }
if ba.authURL != "" { if ba.authURL != "" {
err := ba.checkFromURL(userpass, ip, target) err := ba.checkFromURL(userpass, userIP, localIP, target)
if err == nil { if err == nil {
return true return true
} }
@ -289,7 +294,7 @@ func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
} }
return return
} }
func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) { func (ba *BasicAuth) checkFromURL(userpass, userIP, localIP, target string) (err error) {
u := strings.Split(strings.Trim(userpass, " "), ":") u := strings.Split(strings.Trim(userpass, " "), ":")
if len(u) != 2 { if len(u) != 2 {
return return
@ -301,7 +306,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
} else { } else {
URL += "?" URL += "?"
} }
URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&target=%s", u[0], u[1], ip, url.QueryEscape(target)) URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&local_ip=%s&target=%s", u[0], u[1], userIP, localIP, url.QueryEscape(target))
getURL := URL getURL := URL
var domain string var domain string
if ba.dns != nil { if ba.dns != nil {
@ -318,7 +323,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if err == nil && code == ba.authOkCode { if err == nil && code == ba.authOkCode {
break break
} else if err != nil { } else if err != nil {
err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s", URL, err, ip) err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s -> %s", URL, err, userIP, localIP)
} else { } else {
if len(body) > 0 { if len(body) > 0 {
err = fmt.Errorf(string(body[0:100])) err = fmt.Errorf(string(body[0:100]))
@ -329,7 +334,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
if len(b) > 50 { if len(b) > 50 {
b = b[:50] b = b[:50]
} }
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b) err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s -> %s, %s", URL, code, ba.authOkCode, userIP, localIP, b)
} }
if err != nil && tryCount < ba.authRetry { if err != nil && tryCount < ba.authRetry {
ba.log.Print(err) ba.log.Print(err)
@ -483,7 +488,8 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
return return
} }
func (req *HTTPRequest) BasicAuth() (err error) { func (req *HTTPRequest) BasicAuth() (err error) {
addr := strings.Split((*req.conn).RemoteAddr().String(), ":") userIP := strings.Split((*req.conn).RemoteAddr().String(), ":")
localIP := strings.Split((*req.conn).LocalAddr().String(), ":")
URL := "" URL := ""
if req.IsHTTPS() { if req.IsHTTPS() {
URL = "https://" + req.Host URL = "https://" + req.Host
@ -494,7 +500,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
if err != nil { if err != nil {
return return
} }
authOk := (*req.basicAuth).Check(string(user), addr[0], URL) authOk := (*req.basicAuth).Check(string(user), userIP[0], localIP[0], URL)
//log.Printf("auth %s,%v", string(user), authOk) //log.Printf("auth %s,%v", string(user), authOk)
if !authOk { if !authOk {
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407") fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 26 KiB