Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
20
CHANGELOG
@ -1,5 +1,25 @@
|
||||
proxy更新日志
|
||||
|
||||
v6.9
|
||||
1.修复了sps的start潜在的crash问题.
|
||||
2.sps代理增加了--parent-tls-single参数用来支持单向tls上级。
|
||||
3.sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置.
|
||||
现在上级格式: -P YTpi#2.2.2.2:33080@1
|
||||
说明:
|
||||
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
|
||||
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
|
||||
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#.
|
||||
2.2.2.2:33080 是上级地址
|
||||
@1 是设置权重,可以参考手册权重部分.
|
||||
4.修复了socks5代理错误处理超时的问题.
|
||||
5.修复了http(s)代理错误处理-Z的问题.
|
||||
|
||||
v6.8
|
||||
1.HTTP(S)\SOCKS5代理,API认证功能,发送给认证接口的参数增加了本地IP,local_ip字段,
|
||||
代表用户访问的是本地服务器的哪个IP.
|
||||
2.fix #194 , fix #134 , 代理更稳定.
|
||||
3.增加了一波英文文档.
|
||||
|
||||
v6.6
|
||||
1.优化了limitconn的关闭逻辑,释放更多资源.
|
||||
2.http(s)\socks代理增加了--intelligent,智能模式设置,可以是intelligent|direct|parent三者之一,
|
||||
|
||||
@ -201,6 +201,8 @@ chmod +x install.sh
|
||||
|
||||
#### Docker installation
|
||||
|
||||
[docker](https://hub.docker.com/r/snail007/goproxy)
|
||||
|
||||
Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.10.3 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy latest version.
|
||||
|
||||
The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 6.0:
|
||||
@ -1271,7 +1273,7 @@ execution: `go run *.go`
|
||||
Proxy is licensed under GPLv3 license.
|
||||
|
||||
### Contact
|
||||
proxy QQ group: 7930152191 , 189618940 (full)
|
||||
proxy QQ group: 793015219 , 189618940 (full)
|
||||
|
||||
### Donation
|
||||
if proxy help you a lot,you can support us by:
|
||||
|
||||
29
README_ZH.md
29
README_ZH.md
@ -1,7 +1,7 @@
|
||||
<img src="https://github.com/snail007/goproxy/blob/master/docs/images/logo.jpg?raw=true" width="200"/>
|
||||
Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5,ss代理服务器,支持正向代理、反向代理、透明代理、内网穿透、TCP/UDP端口映射、SSH中转、TLS加密传输、协议转换、防污染DNS代理。
|
||||
|
||||
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群: 7930152191 (2群), 189618940 (1群满)
|
||||
[点击下载](https://github.com/snail007/goproxy/releases) 官方QQ交流群: 793015219 (2群), 189618940 (1群满)
|
||||
|
||||
---
|
||||
|
||||
@ -202,6 +202,9 @@ chmod +x install.sh
|
||||
```
|
||||
|
||||
#### Docker安装
|
||||
|
||||
[docker](https://hub.docker.com/r/snail007/goproxy)
|
||||
|
||||
项目根目录的Dockerfile文件用来构建,使用golang 1.10.3,构建基于goproxy的master分支最新版本,
|
||||
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile
|
||||
或者使用参数GOPROXY_VERSION指定构建的goproxy版本.
|
||||
@ -366,11 +369,12 @@ weight 根据每个上级的权重和连接数情况,选择出一个上级
|
||||
比如:
|
||||
`./proxy http -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
|
||||
带上user,pass,ip,target四个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&target={TARGET}
|
||||
带上user,pass,ip,local_ip,target五个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}&target={TARGET}
|
||||
user:用户名
|
||||
pass:密码
|
||||
ip:用户的IP,比如:192.168.1.200
|
||||
local_ip:用户访问的服务器的IP,比如:3.3.3.3
|
||||
target:用户访问的URL,比如:http://demo.com:80/1.html或https://www.baidu.com:80
|
||||
|
||||
如果没有-a或-F或--auth-url参数,就是关闭Basic认证.
|
||||
@ -915,11 +919,12 @@ SOCKS5代理,支持CONNECT,UDP协议,不支持BIND,支持用户名密码认证.
|
||||
比如:
|
||||
`./proxy socks -t tcp -p ":33080" --auth-url "http://test.com/auth.php"`
|
||||
用户连接的时候,proxy会GET方式请求这url("http://test.com/auth.php"),
|
||||
带上user,pass,ip,三个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}
|
||||
带上user,pass,ip,local_ip四个参数:
|
||||
http://test.com/auth.php?user={USER}&pass={PASS}&ip={IP}&local_ip={LOCAL_IP}
|
||||
user:用户名
|
||||
pass:密码
|
||||
ip:用户的IP,比如:192.168.1.200
|
||||
local_ip:用户访问的服务器的IP,比如:3.3.3.3
|
||||
|
||||
如果没有-a或-F或--auth-url参数,就是关闭认证.
|
||||
|
||||
@ -1155,6 +1160,18 @@ target:如果客户端是http(s)代理请求,这里代表的是请求的完整ur
|
||||
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
|
||||
如果没有-A参数,连接上级不使用认证.
|
||||
|
||||
**设置单独认证信息**
|
||||
|
||||
如果存在多个不同上级,而且他们的密码有的一样有的不一样,那么可以针对每个上级设置认证信息,
|
||||
同时还可以用-A参数设置一个全局认证信息,如果某个上级没有单独设置认证信息就使用全局设置的认证信息.
|
||||
认证信息和上级写在一起.
|
||||
格式是: YTpi#2.2.2.2:33080@1
|
||||
说明:
|
||||
YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi
|
||||
如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz
|
||||
# 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#
|
||||
2.2.2.2:33080 是上级地址
|
||||
@1 是设置权重,没有可以省略,详细说明可以参考手册***权重部分***
|
||||
|
||||
#### **6.8 自定义加密**
|
||||
proxy的sps代理在tcp之上可以通过tls标准加密以及kcp协议加密tcp数据,除此之外还支持在tls和kcp之后进行
|
||||
@ -1368,7 +1385,7 @@ utils是工具包,service是具体的每个服务类.
|
||||
### License
|
||||
Proxy is licensed under GPLv3 license.
|
||||
### Contact
|
||||
官方QQ交流群: 7930152191 (2群), 189618940 (1群满)
|
||||
官方QQ交流群: 793015219 (2群), 189618940 (1群满)
|
||||
|
||||
|
||||
### 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.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
|
||||
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
|
||||
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
|
||||
spsArgs.Debug = isDebug
|
||||
|
||||
//########dns#########
|
||||
|
||||
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
type BasicAuther interface {
|
||||
CheckUserPass(username, password, fromIP, ToTarget string) bool
|
||||
CheckUserPass(username, password, userIP, localIP, toTarget string) bool
|
||||
}
|
||||
type Request struct {
|
||||
ver uint8
|
||||
@ -239,15 +239,16 @@ func (s *ServerConn) Target() string {
|
||||
}
|
||||
func (s *ServerConn) Handshake() (err error) {
|
||||
remoteAddr := (*s.conn).RemoteAddr()
|
||||
localAddr := (*s.conn).LocalAddr()
|
||||
//协商开始
|
||||
//method select request
|
||||
var methodReq MethodsRequest
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
|
||||
methodReq, e := NewMethodsRequest((*s.conn), s.header)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||
@ -264,7 +265,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
// }
|
||||
s.method = socks5c.Method_NO_AUTH
|
||||
//method select reply
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
err = methodReq.Reply(socks5c.Method_NO_AUTH)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -275,7 +276,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
} else {
|
||||
//auth
|
||||
if !methodReq.Select(socks5c.Method_USER_PASS) {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
methodReq.Reply(socks5c.Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("none method found : Method_USER_PASS")
|
||||
@ -283,7 +284,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
}
|
||||
s.method = socks5c.Method_USER_PASS
|
||||
//method reply need auth
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
err = methodReq.Reply(socks5c.Method_USER_PASS)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -293,7 +294,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
//read auth
|
||||
buf := make([]byte, 500)
|
||||
var n int
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
n, err = (*s.conn).Read(buf)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -305,9 +306,10 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
s.password = string(r[2+r[1]+1:])
|
||||
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
|
||||
//auth
|
||||
_addr := strings.Split(remoteAddr.String(), ":")
|
||||
if s.auth == nil || (*s.auth).CheckUserPass(s.user, s.password, _addr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_userAddr := strings.Split(remoteAddr.String(), ":")
|
||||
_localAddr := strings.Split(localAddr.String(), ":")
|
||||
if s.auth == nil || (*s.auth).CheckUserPass(s.user, s.password, _userAddr[0], _localAddr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x00})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -315,7 +317,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x01})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -327,7 +329,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
}
|
||||
}
|
||||
//request detail
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
request, e := NewRequest(*s.conn)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
v4.8
|
||||
1.修复了多个服务同时开启日志,只会输出到最后一个日志文件的bug.
|
||||
2.增加了获取sdk版本的Version()方法.
|
||||
v6.8
|
||||
1.sdk增加了调试锁,避免潜在的并发问题.
|
||||
2.sdk的Stop方法增加了锁,避免潜在的并发问题.
|
||||
3.sdk的Stop方法增加了关闭文件操作.
|
||||
@ -8,7 +8,9 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/snail007/goproxy/core/lib/kcpcfg"
|
||||
encryptconn "github.com/snail007/goproxy/core/lib/transport/encrypt"
|
||||
@ -31,6 +33,10 @@ var SDK_VERSION = "No Version Provided"
|
||||
|
||||
var (
|
||||
app *kingpin.Application
|
||||
cpuProfilingFile, memProfilingFile, blockProfilingFile,
|
||||
goroutineProfilingFile, threadcreateProfilingFile *os.File
|
||||
isProfiling bool
|
||||
profilingLock = &sync.Mutex{}
|
||||
)
|
||||
|
||||
type LogCallback interface {
|
||||
@ -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.RateLimit = sps.Flag("rate-limit", "rate limit (bytes/second) of each connection, such as: 100K 1.5M . 0 means no limitation").Short('l').Default("0").String()
|
||||
spsArgs.Jumper = sps.Flag("jumper", "https or socks5 proxies used when connecting to parent, only worked of -T is tls or tcp, format is https://username:password@host:port https://host:port or socks5://username:password@host:port socks5://host:port").Default("").String()
|
||||
spsArgs.ParentTLSSingle = sps.Flag("parent-tls-single", "conntect to parent insecure skip verify").Default("false").Bool()
|
||||
spsArgs.Debug = debug
|
||||
|
||||
//########dns#########
|
||||
@ -411,7 +418,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
||||
muxClientArgs.KCP = kcpArgs
|
||||
dnsArgs.KCP = kcpArgs
|
||||
|
||||
log := logger.New(os.Stderr, "", logger.Ldate|logger.Ltime)
|
||||
log := logger.New(os.Stdout, "", logger.Ldate|logger.Ltime)
|
||||
flags := logger.Ldate
|
||||
if *debug {
|
||||
flags |= logger.Lshortfile | logger.Lmicroseconds
|
||||
@ -477,3 +484,41 @@ func Stop(serviceID string) {
|
||||
func Version() string {
|
||||
return SDK_VERSION
|
||||
}
|
||||
func StartProfiling(storePath string) {
|
||||
profilingLock.Lock()
|
||||
defer profilingLock.Unlock()
|
||||
if !isProfiling {
|
||||
isProfiling = true
|
||||
if storePath == "" {
|
||||
storePath = "."
|
||||
}
|
||||
cpuProfilingFile, _ = os.Create(filepath.Join(storePath, "cpu.prof"))
|
||||
memProfilingFile, _ = os.Create(filepath.Join(storePath, "memory.prof"))
|
||||
blockProfilingFile, _ = os.Create(filepath.Join(storePath, "block.prof"))
|
||||
goroutineProfilingFile, _ = os.Create(filepath.Join(storePath, "goroutine.prof"))
|
||||
threadcreateProfilingFile, _ = os.Create(filepath.Join(storePath, "threadcreate.prof"))
|
||||
pprof.StartCPUProfile(cpuProfilingFile)
|
||||
}
|
||||
}
|
||||
func StopProfiling() {
|
||||
profilingLock.Lock()
|
||||
defer profilingLock.Unlock()
|
||||
if isProfiling {
|
||||
isProfiling = false
|
||||
pprof.StopCPUProfile()
|
||||
goroutine := pprof.Lookup("goroutine")
|
||||
goroutine.WriteTo(goroutineProfilingFile, 1)
|
||||
heap := pprof.Lookup("heap")
|
||||
heap.WriteTo(memProfilingFile, 1)
|
||||
block := pprof.Lookup("block")
|
||||
block.WriteTo(blockProfilingFile, 1)
|
||||
threadcreate := pprof.Lookup("threadcreate")
|
||||
threadcreate.WriteTo(threadcreateProfilingFile, 1)
|
||||
//close
|
||||
goroutineProfilingFile.Close()
|
||||
memProfilingFile.Close()
|
||||
blockProfilingFile.Close()
|
||||
threadcreateProfilingFile.Close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -21,5 +21,15 @@ func Version() (ver *C.char) {
|
||||
return C.CString(sdk.Version())
|
||||
}
|
||||
|
||||
//export StartProfiling
|
||||
func StartProfiling(storePath *C.char) {
|
||||
sdk.StartProfiling(C.GoString(storePath))
|
||||
}
|
||||
|
||||
//export StopProfiling
|
||||
func StopProfiling() {
|
||||
sdk.StopProfiling()
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ func (s *HTTP) InitService() (err error) {
|
||||
return
|
||||
}
|
||||
conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
|
||||
if err == nil {
|
||||
if err == nil && conn != nil {
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write([]byte{0})
|
||||
conn.SetDeadline(time.Time{})
|
||||
@ -386,12 +386,17 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
|
||||
}
|
||||
if useProxy {
|
||||
// s.log.Printf("%v", s.outPool)
|
||||
selectAddr := (*inConn).RemoteAddr().String()
|
||||
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||
selectAddr = address
|
||||
if *s.cfg.ParentType == "ssh" {
|
||||
outConn, err = s.getSSHConn(address)
|
||||
} else {
|
||||
selectAddr := (*inConn).RemoteAddr().String()
|
||||
if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
|
||||
selectAddr = address
|
||||
}
|
||||
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||
outConn, err = s.GetParentConn(lbAddr)
|
||||
}
|
||||
lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
|
||||
outConn, err = s.GetParentConn(lbAddr)
|
||||
|
||||
} else {
|
||||
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 {
|
||||
outConn = utils.NewCompConn(outConn)
|
||||
}
|
||||
if *s.cfg.ParentKey != "" {
|
||||
if useProxy && *s.cfg.ParentKey != "" {
|
||||
outConn = conncrypt.New(outConn, &conncrypt.Config{
|
||||
Password: *s.cfg.ParentKey,
|
||||
})
|
||||
@ -515,6 +520,9 @@ func (s *HTTP) ConnectSSH() (err error) {
|
||||
s.sshClient.Close()
|
||||
}
|
||||
s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config)
|
||||
if err != nil {
|
||||
s.log.Printf("connect to ssh %s fail", s.cfg.Parent)
|
||||
}
|
||||
<-s.lockChn
|
||||
return
|
||||
}
|
||||
|
||||
@ -39,6 +39,9 @@ func GetService(name string) *ServiceItem {
|
||||
func Stop(name string) {
|
||||
if s, ok := servicesMap.Load(name); ok && s.(*ServiceItem).S != nil {
|
||||
s.(*ServiceItem).S.Clean()
|
||||
*s.(*ServiceItem) = ServiceItem{}
|
||||
s = nil
|
||||
servicesMap.Store(name, nil)
|
||||
servicesMap.Delete(name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ func (s *SPS) proxyUDP(inConn *net.Conn, serverConn *socks.ServerConn) {
|
||||
s.log.Printf("connect %s for udp", serverConn.Target())
|
||||
//socks client
|
||||
|
||||
client, err := s.HandshakeSocksParent(&outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
|
||||
client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", serverConn.Target(), serverConn.AuthData(), false)
|
||||
if err != nil {
|
||||
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||
return
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/core/cs/server"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/snail007/goproxy/services"
|
||||
"github.com/snail007/goproxy/utils"
|
||||
"github.com/snail007/goproxy/utils/conncrypt"
|
||||
cryptool "github.com/snail007/goproxy/utils/crypt"
|
||||
"github.com/snail007/goproxy/utils/datasize"
|
||||
"github.com/snail007/goproxy/utils/dnsx"
|
||||
"github.com/snail007/goproxy/utils/iolimiter"
|
||||
@ -71,6 +73,7 @@ type SPSArgs struct {
|
||||
LoadBalanceRetryTime *int
|
||||
LoadBalanceHashTarget *bool
|
||||
LoadBalanceOnlyHA *bool
|
||||
ParentTLSSingle *bool
|
||||
|
||||
RateLimit *string
|
||||
RateLimitBytes float64
|
||||
@ -91,6 +94,8 @@ type SPS struct {
|
||||
udpLocalKey []byte
|
||||
udpParentKey []byte
|
||||
jumper *jumper.Jumper
|
||||
parentAuthData *sync.Map
|
||||
parentCipherData *sync.Map
|
||||
}
|
||||
|
||||
func NewSPS() services.Service {
|
||||
@ -100,6 +105,8 @@ func NewSPS() services.Service {
|
||||
serverChannels: []*server.ServerChannel{},
|
||||
userConns: mapx.NewConcurrentMap(),
|
||||
udpRelatedPacketConns: mapx.NewConcurrentMap(),
|
||||
parentAuthData: &sync.Map{},
|
||||
parentCipherData: &sync.Map{},
|
||||
}
|
||||
}
|
||||
func (s *SPS) CheckArgs() (err error) {
|
||||
@ -121,9 +128,11 @@ func (s *SPS) CheckArgs() (err error) {
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
if !*s.cfg.ParentTLSSingle {
|
||||
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if *s.cfg.CaCertFile != "" {
|
||||
s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
|
||||
@ -166,7 +175,10 @@ func (s *SPS) InitService() (err error) {
|
||||
}
|
||||
|
||||
if len(*s.cfg.Parent) > 0 {
|
||||
s.InitLB()
|
||||
err = s.InitLB()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = s.InitBasicAuth()
|
||||
@ -208,6 +220,8 @@ func (s *SPS) StopService() {
|
||||
s.udpParentKey = nil
|
||||
s.udpRelatedPacketConns = nil
|
||||
s.userConns = nil
|
||||
s.parentAuthData = nil
|
||||
s.parentCipherData = nil
|
||||
s = nil
|
||||
}()
|
||||
for _, sc := range s.serverChannels {
|
||||
@ -257,6 +271,9 @@ func (s *SPS) Start(args interface{}, log *logger.Logger) (err error) {
|
||||
} else if *s.cfg.LocalType == "kcp" {
|
||||
err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentServiceType == "socks" {
|
||||
err = s.RunSSUDP(addr)
|
||||
} else {
|
||||
@ -431,8 +448,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
|
||||
utils.CloseConn(inConn)
|
||||
return
|
||||
}
|
||||
|
||||
if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
|
||||
ParentAuth := s.getParentAuth(lbAddr)
|
||||
if ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
|
||||
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
|
||||
}
|
||||
|
||||
@ -452,8 +469,8 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
|
||||
pb.WriteString("Connection: Keep-Alive\r\n")
|
||||
|
||||
u := ""
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
if ParentAuth != "" {
|
||||
a := strings.Split(ParentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
err = fmt.Errorf("parent auth data format error")
|
||||
return
|
||||
@ -504,7 +521,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
|
||||
s.log.Printf("connect %s", address)
|
||||
|
||||
//socks client
|
||||
_, err = s.HandshakeSocksParent(&outConn, "tcp", address, auth, false)
|
||||
_, err = s.HandshakeSocksParent(ParentAuth, &outConn, "tcp", address, auth, false)
|
||||
if err != nil {
|
||||
s.log.Printf("handshake fail, %s", err)
|
||||
return
|
||||
@ -517,7 +534,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (lbAddr string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy())
|
||||
outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.getParentCipher(lbAddr))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("dial ss parent fail, err : %s", err)
|
||||
return
|
||||
@ -577,10 +594,41 @@ func (s *SPS) InitBasicAuth() (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SPS) InitLB() {
|
||||
func (s *SPS) InitLB() (err error) {
|
||||
configs := lb.BackendsConfig{}
|
||||
for _, addr := range *s.cfg.Parent {
|
||||
_addrInfo := strings.Split(addr, "@")
|
||||
var _addrInfo []string
|
||||
if strings.Contains(addr, "#") {
|
||||
_s := addr[:strings.Index(addr, "#")]
|
||||
_auth, err := cryptool.CryptTools.Base64Decode(_s)
|
||||
if err != nil {
|
||||
s.log.Printf("decoding parent auth data [ %s ] fail , error : %s", _s, err)
|
||||
return err
|
||||
}
|
||||
_addrInfo = strings.Split(addr[strings.Index(addr, "#")+1:], "@")
|
||||
if *s.cfg.ParentServiceType == "ss" {
|
||||
_s := strings.Split(_auth, ":")
|
||||
m := _s[0]
|
||||
k := _s[1]
|
||||
if m == "" {
|
||||
m = *s.cfg.ParentSSMethod
|
||||
}
|
||||
if k == "" {
|
||||
k = *s.cfg.ParentSSKey
|
||||
}
|
||||
cipher, err := ss.NewCipher(m, k)
|
||||
if err != nil {
|
||||
s.log.Printf("error generating cipher, ssMethod: %s, ssKey: %s, error : %s", m, k, err)
|
||||
return err
|
||||
}
|
||||
s.parentCipherData.Store(_addrInfo[0], cipher)
|
||||
} else {
|
||||
s.parentAuthData.Store(_addrInfo[0], _auth)
|
||||
}
|
||||
|
||||
} else {
|
||||
_addrInfo = strings.Split(addr, "@")
|
||||
}
|
||||
_addr := _addrInfo[0]
|
||||
weight := 1
|
||||
if len(_addrInfo) == 2 {
|
||||
@ -597,6 +645,19 @@ func (s *SPS) InitLB() {
|
||||
}
|
||||
LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
|
||||
s.lb = &LB
|
||||
return
|
||||
}
|
||||
func (s *SPS) getParentAuth(lbAddr string) string {
|
||||
if v, ok := s.parentAuthData.Load(lbAddr); ok {
|
||||
return v.(string)
|
||||
}
|
||||
return *s.cfg.ParentAuth
|
||||
}
|
||||
func (s *SPS) getParentCipher(lbAddr string) *ss.Cipher {
|
||||
if v, ok := s.parentCipherData.Load(lbAddr); ok {
|
||||
return v.(*ss.Cipher).Copy()
|
||||
}
|
||||
return s.parentCipher.Copy()
|
||||
}
|
||||
func (s *SPS) IsBasicAuth() bool {
|
||||
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||
@ -654,12 +715,21 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
if s.jumper == nil {
|
||||
var _conn tls.Conn
|
||||
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
|
||||
if *s.cfg.ParentTLSSingle {
|
||||
_conn, err = utils.SingleTlsConnectHost(address, *s.cfg.Timeout, s.cfg.CaCertBytes)
|
||||
} else {
|
||||
_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
|
||||
}
|
||||
if err == nil {
|
||||
conn = net.Conn(&_conn)
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
@ -691,9 +761,9 @@ func (s *SPS) GetParentConn(address string) (conn net.Conn, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *SPS) HandshakeSocksParent(outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
|
||||
if *s.cfg.ParentAuth != "" {
|
||||
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||
func (s *SPS) HandshakeSocksParent(parentAuth string, outconn *net.Conn, network, dstAddr string, auth socks.Auth, fromSS bool) (client *socks.ClientConn, err error) {
|
||||
if parentAuth != "" {
|
||||
a := strings.Split(parentAuth, ":")
|
||||
if len(a) != 2 {
|
||||
err = fmt.Errorf("parent auth data format error")
|
||||
return
|
||||
@ -717,7 +787,9 @@ func (s *SPS) ParentUDPKey() (key []byte) {
|
||||
return []byte(v)[:24]
|
||||
}
|
||||
case "tls":
|
||||
return s.cfg.KeyBytes[:24]
|
||||
if s.cfg.KeyBytes != nil {
|
||||
return s.cfg.KeyBytes[:24]
|
||||
}
|
||||
case "kcp":
|
||||
v := fmt.Sprintf("%x", md5.Sum([]byte(*s.cfg.KCP.Key)))
|
||||
return []byte(v)[:24]
|
||||
|
||||
@ -88,7 +88,7 @@ func (s *SPS) RunSSUDP(addr string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
client, err := s.HandshakeSocksParent(&outconn, "udp", socksPacket.Addr(), socks.Auth{}, true)
|
||||
client, err := s.HandshakeSocksParent(s.getParentAuth(lbAddr), &outconn, "udp", socksPacket.Addr(), socks.Auth{}, true)
|
||||
if err != nil {
|
||||
clean("handshake fail", fmt.Sprintf("%s", err))
|
||||
return
|
||||
|
||||
38
utils/crypt/misc.go
Normal file
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) {
|
||||
h := strings.Split(host, ":")
|
||||
port, _ := strconv.Atoi(h[1])
|
||||
return TlsConnect(h[0], port, timeout, certBytes, keyBytes, caCertBytes)
|
||||
}
|
||||
|
||||
func TlsConnect(host string, port, timeout int, certBytes, keyBytes, caCertBytes []byte) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(certBytes, keyBytes, caCertBytes)
|
||||
if err != nil {
|
||||
|
||||
@ -73,6 +73,7 @@ func NewGroup(selectType int, configs BackendsConfig, dr *dnsx.DomainResolver, l
|
||||
}
|
||||
}
|
||||
func (g *Group) Select(srcAddr string, onlyHa bool) (addr string) {
|
||||
addr=""
|
||||
if len(g.bks) == 1 {
|
||||
return g.bks[0].Address
|
||||
}
|
||||
|
||||
@ -106,15 +106,16 @@ func (s *ServerConn) Port() string {
|
||||
}
|
||||
func (s *ServerConn) Handshake() (err error) {
|
||||
remoteAddr := (*s.conn).RemoteAddr()
|
||||
localAddr := (*s.conn).LocalAddr()
|
||||
//协商开始
|
||||
//method select request
|
||||
var methodReq MethodsRequest
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
|
||||
methodReq, e := NewMethodsRequest((*s.conn), s.header)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||
@ -123,7 +124,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
|
||||
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
|
||||
// if !methodReq.Select(Method_NO_AUTH) {
|
||||
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
// (*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
// methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
// (*s.conn).SetReadDeadline(time.Time{})
|
||||
// err = fmt.Errorf("none method found : Method_NO_AUTH")
|
||||
@ -131,7 +132,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
// }
|
||||
s.method = Method_NO_AUTH
|
||||
//method select reply
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
err = methodReq.Reply(Method_NO_AUTH)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -142,7 +143,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
} else {
|
||||
//auth
|
||||
if !methodReq.Select(Method_USER_PASS) {
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
err = fmt.Errorf("none method found : Method_USER_PASS")
|
||||
@ -150,7 +151,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
}
|
||||
s.method = Method_USER_PASS
|
||||
//method reply need auth
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
err = methodReq.Reply(Method_USER_PASS)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -160,7 +161,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
//read auth
|
||||
buf := make([]byte, 500)
|
||||
var n int
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
n, err = (*s.conn).Read(buf)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -172,9 +173,10 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
s.password = string(r[2+r[1]+1:])
|
||||
//err = fmt.Errorf("user:%s,pass:%s", user, pass)
|
||||
//auth
|
||||
_addr := strings.Split(remoteAddr.String(), ":")
|
||||
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
_userAddr := strings.Split(remoteAddr.String(), ":")
|
||||
_localAddr := strings.Split(localAddr.String(), ":")
|
||||
if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _userAddr[0], _localAddr[0], "") {
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x00})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -182,7 +184,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(s.timeout)))
|
||||
(*s.conn).SetDeadline(time.Now().Add(s.timeout))
|
||||
_, err = (*s.conn).Write([]byte{0x01, 0x01})
|
||||
(*s.conn).SetDeadline(time.Time{})
|
||||
if err != nil {
|
||||
@ -194,7 +196,7 @@ func (s *ServerConn) Handshake() (err error) {
|
||||
}
|
||||
}
|
||||
//request detail
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||
(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
|
||||
request, e := NewRequest(*s.conn)
|
||||
(*s.conn).SetReadDeadline(time.Time{})
|
||||
if e != nil {
|
||||
|
||||
@ -268,18 +268,23 @@ func (ba *BasicAuth) Add(userpassArr []string) (n int) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (ba *BasicAuth) CheckUserPass(user, pass, ip, target string) (ok bool) {
|
||||
|
||||
return ba.Check(user+":"+pass, ip, target)
|
||||
func (ba *BasicAuth) Delete(userArr []string) {
|
||||
for _, u := range userArr {
|
||||
ba.data.Remove(u)
|
||||
}
|
||||
}
|
||||
func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
|
||||
func (ba *BasicAuth) CheckUserPass(user, pass, userIP, localIP, target string) (ok bool) {
|
||||
|
||||
return ba.Check(user+":"+pass, userIP, localIP, target)
|
||||
}
|
||||
func (ba *BasicAuth) Check(userpass string, userIP, localIP, target string) (ok bool) {
|
||||
u := strings.Split(strings.Trim(userpass, " "), ":")
|
||||
if len(u) == 2 {
|
||||
if p, _ok := ba.data.Get(u[0]); _ok {
|
||||
return p.(string) == u[1]
|
||||
}
|
||||
if ba.authURL != "" {
|
||||
err := ba.checkFromURL(userpass, ip, target)
|
||||
err := ba.checkFromURL(userpass, userIP, localIP, target)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
@ -289,7 +294,7 @@ func (ba *BasicAuth) Check(userpass string, ip, target string) (ok bool) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
|
||||
func (ba *BasicAuth) checkFromURL(userpass, userIP, localIP, target string) (err error) {
|
||||
u := strings.Split(strings.Trim(userpass, " "), ":")
|
||||
if len(u) != 2 {
|
||||
return
|
||||
@ -301,7 +306,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
|
||||
} else {
|
||||
URL += "?"
|
||||
}
|
||||
URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&target=%s", u[0], u[1], ip, url.QueryEscape(target))
|
||||
URL += fmt.Sprintf("user=%s&pass=%s&ip=%s&local_ip=%s&target=%s", u[0], u[1], userIP, localIP, url.QueryEscape(target))
|
||||
getURL := URL
|
||||
var domain string
|
||||
if ba.dns != nil {
|
||||
@ -318,7 +323,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
|
||||
if err == nil && code == ba.authOkCode {
|
||||
break
|
||||
} else if err != nil {
|
||||
err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s", URL, err, ip)
|
||||
err = fmt.Errorf("auth fail from url %s,resonse err:%s , %s -> %s", URL, err, userIP, localIP)
|
||||
} else {
|
||||
if len(body) > 0 {
|
||||
err = fmt.Errorf(string(body[0:100]))
|
||||
@ -329,7 +334,7 @@ func (ba *BasicAuth) checkFromURL(userpass, ip, target string) (err error) {
|
||||
if len(b) > 50 {
|
||||
b = b[:50]
|
||||
}
|
||||
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s , %s", URL, code, ba.authOkCode, ip, b)
|
||||
err = fmt.Errorf("auth fail from url %s,resonse code: %d, except: %d , %s -> %s, %s", URL, code, ba.authOkCode, userIP, localIP, b)
|
||||
}
|
||||
if err != nil && tryCount < ba.authRetry {
|
||||
ba.log.Print(err)
|
||||
@ -483,7 +488,8 @@ func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||
return
|
||||
}
|
||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||
userIP := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||
localIP := strings.Split((*req.conn).LocalAddr().String(), ":")
|
||||
URL := ""
|
||||
if req.IsHTTPS() {
|
||||
URL = "https://" + req.Host
|
||||
@ -494,7 +500,7 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
||||
authOk := (*req.basicAuth).Check(string(user), userIP[0], localIP[0], URL)
|
||||
//log.Printf("auth %s,%v", string(user), authOk)
|
||||
if !authOk {
|
||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Proxy Authentication Required\r\n\r\nProxy Authentication Required", "407")
|
||||
|
||||
Reference in New Issue
Block a user