Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bee025e6f0 | ||
|
|
198281b5eb | ||
|
|
426d711d0b | ||
|
|
73d3b60a2f | ||
|
|
b336b9ce03 | ||
|
|
9654efb952 | ||
|
|
c3262fc0cb | ||
|
|
2fef2c0eaa | ||
|
|
3d33cdc9f1 | ||
|
|
509ad47a71 | ||
|
|
c14a3b2773 | ||
|
|
e6e61b3cdb | ||
|
|
303587f91b | ||
|
|
5c3fd53fab | ||
|
|
0c675e6ff6 | ||
|
|
942b026a05 | ||
|
|
0b347b7f8d | ||
|
|
87322c335e | ||
|
|
1bf4b38268 | ||
|
|
60b1742088 | ||
|
|
266fa6f6fa | ||
|
|
02c3c9b374 | ||
|
|
8f7da3ed94 | ||
|
|
a5a6e8645a | ||
|
|
83022d3efc | ||
|
|
78143ce638 | ||
|
|
c66147c686 | ||
|
|
e5bf95bdc8 | ||
|
|
ed1e7253f3 | ||
|
|
db43daea0b | ||
|
|
89b5744e27 | ||
|
|
ebba94b9d1 | ||
|
|
23c379faf9 | ||
|
|
124852b3a2 | ||
|
|
e6d557f61e | ||
|
|
0a2ed2e498 | ||
|
|
4ce5fd463d | ||
|
|
367cfb36dd | ||
|
|
57555ffc1e | ||
|
|
8a86a53bd2 |
20
CHANGELOG
@ -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三者之一,
|
||||||
|
|||||||
20
README.md
@ -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:
|
||||||
|
|||||||
31
README_ZH.md
@ -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
|
||||||
|
|||||||
@ -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#########
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 19 KiB |
@ -1,3 +0,0 @@
|
|||||||
v4.8
|
|
||||||
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
|
|
||||||
2.增加了获取sdk版本的Version()方法.
|
|
||||||
263
sdk/README.md
@ -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
|
|
||||||
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-android/) []() [](https://github.com/snail007/goproxy-sdk-android/releases) [](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
|
|
||||||
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-ios/) []() [](https://github.com/snail007/goproxy-sdk-ios/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-windows/) []() [](https://github.com/snail007/goproxy-sdk-windows/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-linux/) []() [](https://github.com/snail007/goproxy-sdk-linux/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-mac/) []() [](https://github.com/snail007/goproxy-sdk-mac/releases) [](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.
|
|
||||||
|
|
||||||
|
|
||||||
259
sdk/README_ZH.md
@ -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
|
|
||||||
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-android/) []() [](https://github.com/snail007/goproxy-sdk-android/releases) [](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
|
|
||||||
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-ios/) []() [](https://github.com/snail007/goproxy-sdk-ios/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-windows/) []() [](https://github.com/snail007/goproxy-sdk-windows/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-linux/) []() [](https://github.com/snail007/goproxy-sdk-linux/releases) [](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
|
|
||||||
[](https://github.com/snail007/goproxy-sdk-mac/) []() [](https://github.com/snail007/goproxy-sdk-mac/releases) [](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参数.
|
|
||||||
|
|
||||||
|
|
||||||
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -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() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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]
|
||||||
|
|||||||
@ -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
@ -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))
|
||||||
|
}
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
BIN
vendor/github.com/xtaci/kcp-go/donate.png
generated
vendored
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
vendor/github.com/xtaci/kcp-go/frame.png
generated
vendored
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 26 KiB |