Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
This commit is contained in:
@ -1,4 +1,10 @@
|
|||||||
proxy更新日志
|
proxy更新日志
|
||||||
|
v4.6
|
||||||
|
1.sps,http(s),socks5,内网穿透都做了大量的超时优化处理,更加稳定.
|
||||||
|
2.sps增加了强大的树形级联认证支持,可以轻松构建你的认证代理网络.
|
||||||
|
3.手册增加了6.6对sps认证功能的介绍.
|
||||||
|
|
||||||
|
|
||||||
v4.5
|
v4.5
|
||||||
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
1.优化了mux内网穿透连接管理逻辑,增强了稳定性.
|
||||||
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
2.mux内网穿透增加了tcp和kcp协议支持,之前是tls,现在支持三种协议tcp,tls,kcp.
|
||||||
|
|||||||
45
README_ZH.md
45
README_ZH.md
@ -127,7 +127,8 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
|
|||||||
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
- [6.3 SOCKS5转HTTP(S)+SOCKS5](#63-socks5转httpssocks5)
|
||||||
- [6.4 链式连接](#64-链式连接)
|
- [6.4 链式连接](#64-链式连接)
|
||||||
- [6.5 监听多个端口](#65-监听多个端口)
|
- [6.5 监听多个端口](#65-监听多个端口)
|
||||||
- [6.6 查看帮助](#66-查看帮助)
|
- [6.6 认证功能](#66-认证功能)
|
||||||
|
- [6.7 查看帮助](#67-查看帮助)
|
||||||
- [7. KCP配置](#7kcp配置)
|
- [7. KCP配置](#7kcp配置)
|
||||||
- [7.1 配置介绍](#71-配置介绍)
|
- [7.1 配置介绍](#71-配置介绍)
|
||||||
- [7.2 详细配置](#72-详细配置)
|
- [7.2 详细配置](#72-详细配置)
|
||||||
@ -736,7 +737,47 @@ vps02:3.3.3.3
|
|||||||
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
一般情况下监听一个端口就可以,不过如果作为反向代理需要同时监听80和443两个端口,那么-p参数是支持的,
|
||||||
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
格式是:`-p 0.0.0.0:80,0.0.0.0:443`,多个绑定用逗号分隔即可。
|
||||||
|
|
||||||
#### **6.6 查看帮助**
|
#### **6.6 认证功能**
|
||||||
|
sps支持http(s)\socks5代理认证,可以级联认证,有四个重要的信息:
|
||||||
|
1:用户发送认证信息`user-auth`。
|
||||||
|
2:设置的本地认证信息`local-auth`。
|
||||||
|
3:设置的连接上级使用的认证信息`parent-auth`。
|
||||||
|
4:最终发送给上级的认证信息`auth-info-to-parent`。
|
||||||
|
他们的情况关系如下:
|
||||||
|
| user-auth | local-auth | parent-auth | auth-info-to-parent
|
||||||
|
| 有/没有 | 有 | 有 | 来自parent-auth
|
||||||
|
| 有/没有 | 没有 | 有 | 来自parent-auth
|
||||||
|
| 有/没有 | 有 | 没有 | 无
|
||||||
|
| 没有 | 没有 | 没有 | 无
|
||||||
|
| 有 | 没有 | 没有 | 来自user-auth
|
||||||
|
|
||||||
|
对于sps代理我们可以进行用户名密码认证,认证的用户名和密码可以在命令行指定
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
多个用户,重复-a参数即可.
|
||||||
|
也可以放在文件中,格式是一行一个"用户名:密码",然后用-F指定.
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -F auth-file.txt`
|
||||||
|
|
||||||
|
如果上级有认证,下级可以通过-A参数设置认证信息,比如:
|
||||||
|
上级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -t tcp -p ":33080" -a "user1:pass1" -a "user2:pass2"`
|
||||||
|
下级:`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -A "user1:pass1" -t tcp -p ":33080" `
|
||||||
|
|
||||||
|
另外,sps代理,本地认证集成了外部HTTP API认证,我们可以通过--auth-url参数指定一个http url接口地址,
|
||||||
|
然后有用户连接的时候,proxy会GET方式请求这url,带上下面四个参数,如果返回HTTP状态码204,代表认证成功
|
||||||
|
其它情况认为认证失败.
|
||||||
|
比如:
|
||||||
|
`./proxy sps -S http -T tcp -P 127.0.0.1:8080 -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}&target={TARGET}
|
||||||
|
user:用户名
|
||||||
|
pass:密码
|
||||||
|
ip:用户的IP,比如:192.168.1.200
|
||||||
|
target:如果客户端是http(s)代理请求,这里代表的是请求的完整url,其它情况为空.
|
||||||
|
|
||||||
|
如果没有-a或-F或--auth-url参数,就是关闭本地认证.
|
||||||
|
如果没有-A参数,连接上级不使用认证.
|
||||||
|
|
||||||
|
#### **6.7 查看帮助**
|
||||||
`./proxy help sps`
|
`./proxy help sps`
|
||||||
|
|
||||||
### **7.KCP配置**
|
### **7.KCP配置**
|
||||||
|
|||||||
@ -223,7 +223,14 @@ func initConfig() (err error) {
|
|||||||
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
|
||||||
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
|
||||||
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
|
||||||
|
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
|
||||||
|
spsArgs.Auth = sps.Flag("auth", "socks auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
|
||||||
|
spsArgs.LocalIPS = sps.Flag("local bind ips", "if your host behind a nat,set your public ip here avoid dead loop").Short('g').Strings()
|
||||||
|
spsArgs.AuthURL = sps.Flag("auth-url", "auth username and password will send to this url,response http code equal to 'auth-code' means ok,others means fail.").Default("").String()
|
||||||
|
spsArgs.AuthURLTimeout = sps.Flag("auth-timeout", "access 'auth-url' timeout milliseconds").Default("3000").Int()
|
||||||
|
spsArgs.AuthURLOkCode = sps.Flag("auth-code", "access 'auth-url' success http code").Default("204").Int()
|
||||||
|
spsArgs.AuthURLRetry = sps.Flag("auth-retry", "access 'auth-url' fail and retry count").Default("0").Int()
|
||||||
|
spsArgs.ParentAuth = sps.Flag("parent-auth", "parent socks auth username and password, such as: -A user1:pass1").Short('A').String()
|
||||||
//parse args
|
//parse args
|
||||||
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||||
|
|
||||||
|
|||||||
@ -215,6 +215,14 @@ type SPSArgs struct {
|
|||||||
ParentServiceType *string
|
ParentServiceType *string
|
||||||
DNSAddress *string
|
DNSAddress *string
|
||||||
DNSTTL *int
|
DNSTTL *int
|
||||||
|
AuthFile *string
|
||||||
|
Auth *[]string
|
||||||
|
AuthURL *string
|
||||||
|
AuthURLOkCode *int
|
||||||
|
AuthURLTimeout *int
|
||||||
|
AuthURLRetry *int
|
||||||
|
LocalIPS *[]string
|
||||||
|
ParentAuth *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SPSArgs) Protocol() string {
|
func (a *SPSArgs) Protocol() string {
|
||||||
|
|||||||
204
services/sps.go
204
services/sps.go
@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -12,18 +13,21 @@ import (
|
|||||||
"snail007/proxy/utils/socks"
|
"snail007/proxy/utils/socks"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SPS struct {
|
type SPS struct {
|
||||||
outPool utils.OutPool
|
outPool utils.OutPool
|
||||||
cfg SPSArgs
|
cfg SPSArgs
|
||||||
domainResolver utils.DomainResolver
|
domainResolver utils.DomainResolver
|
||||||
|
basicAuth utils.BasicAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSPS() Service {
|
func NewSPS() Service {
|
||||||
return &SPS{
|
return &SPS{
|
||||||
outPool: utils.OutPool{},
|
outPool: utils.OutPool{},
|
||||||
cfg: SPSArgs{},
|
cfg: SPSArgs{},
|
||||||
|
basicAuth: utils.BasicAuth{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (s *SPS) CheckArgs() {
|
func (s *SPS) CheckArgs() {
|
||||||
@ -46,6 +50,10 @@ func (s *SPS) CheckArgs() {
|
|||||||
}
|
}
|
||||||
func (s *SPS) InitService() {
|
func (s *SPS) InitService() {
|
||||||
s.InitOutConnPool()
|
s.InitOutConnPool()
|
||||||
|
if *s.cfg.DNSAddress != "" {
|
||||||
|
(*s).domainResolver = utils.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL)
|
||||||
|
}
|
||||||
|
s.InitBasicAuth()
|
||||||
}
|
}
|
||||||
func (s *SPS) InitOutConnPool() {
|
func (s *SPS) InitOutConnPool() {
|
||||||
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.ParentType == TYPE_TCP || *s.cfg.ParentType == TYPE_KCP {
|
||||||
@ -117,7 +125,7 @@ func (s *SPS) callback(inConn net.Conn) {
|
|||||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
log.Printf("connect to %s parent %s fail, ERR:%s from %s", *s.cfg.ParentType, *s.cfg.Parent, err, inConn.RemoteAddr())
|
||||||
utils.CloseConn(&inConn)
|
utils.CloseConn(&inConn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,51 +139,32 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
address := ""
|
address := ""
|
||||||
|
var auth socks.Auth
|
||||||
var forwardBytes []byte
|
var forwardBytes []byte
|
||||||
//fmt.Printf("%v", header)
|
//fmt.Printf("%v", header)
|
||||||
if header[0] == socks.VERSION_V5 {
|
if header[0] == socks.VERSION_V5 {
|
||||||
//socks
|
//socks5 server
|
||||||
methodReq, e := socks.NewMethodsRequest(*inConn, header)
|
var serverConn *socks.ServerConn
|
||||||
if e != nil {
|
if s.IsBasicAuth() {
|
||||||
log.Printf("new method request err:%s", e)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), &s.basicAuth, "", header)
|
||||||
utils.CloseConn(inConn)
|
} else {
|
||||||
err = e.(error)
|
serverConn = socks.NewServerConn(inConn, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, "", header)
|
||||||
|
}
|
||||||
|
if err = serverConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !methodReq.Select(socks.Method_NO_AUTH) {
|
address = serverConn.Target()
|
||||||
methodReq.Reply(socks.Method_NONE_ACCEPTABLE)
|
auth = serverConn.AuthData()
|
||||||
utils.CloseConn(inConn)
|
|
||||||
log.Printf("none method found : Method_NO_AUTH")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//method select reply
|
|
||||||
err = methodReq.Reply(socks.Method_NO_AUTH)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("reply answer data fail,ERR: %s", err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//request detail
|
|
||||||
request, e := socks.NewRequest(*inConn)
|
|
||||||
if e != nil {
|
|
||||||
log.Printf("read request data fail,ERR: %s", e)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
err = e.(error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if request.CMD() != socks.CMD_CONNECT {
|
|
||||||
//只支持tcp
|
|
||||||
request.TCPReply(socks.REP_UNKNOWN)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
err = errors.New("cmd not supported")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
address = request.Addr()
|
|
||||||
request.TCPReply(socks.REP_SUCCESS)
|
|
||||||
} else if bytes.IndexByte(header, '\n') != -1 {
|
} else if bytes.IndexByte(header, '\n') != -1 {
|
||||||
//http
|
//http
|
||||||
var request utils.HTTPRequest
|
var request utils.HTTPRequest
|
||||||
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
(*inConn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
if s.IsBasicAuth() {
|
||||||
|
request, err = utils.NewHTTPRequest(inConn, 1024, true, &s.basicAuth, header)
|
||||||
|
} else {
|
||||||
|
request, err = utils.NewHTTPRequest(inConn, 1024, false, nil, header)
|
||||||
|
}
|
||||||
|
(*inConn).SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("new http request fail,ERR: %s", err)
|
log.Printf("new http request fail,ERR: %s", err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -189,6 +178,17 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
forwardBytes = request.HeadBuf
|
forwardBytes = request.HeadBuf
|
||||||
}
|
}
|
||||||
address = request.Host
|
address = request.Host
|
||||||
|
var userpass string
|
||||||
|
if s.IsBasicAuth() {
|
||||||
|
userpass, err = request.GetAuthDataStr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userpassA := strings.Split(userpass, ":")
|
||||||
|
if len(userpassA) == 2 {
|
||||||
|
auth = socks.Auth{User: userpassA[0], Password: userpassA[1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
log.Printf("unknown request from: %s,%s", (*inConn).RemoteAddr(), string(header))
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -207,12 +207,42 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//ask parent for connect to target address
|
//ask parent for connect to target address
|
||||||
if *s.cfg.ParentServiceType == "http" {
|
if *s.cfg.ParentServiceType == "http" {
|
||||||
//http parent
|
//http parent
|
||||||
fmt.Fprintf(outConn, "CONNECT %s HTTP/1.1\r\n", address)
|
pb := new(bytes.Buffer)
|
||||||
|
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\nProxy-Connection: Keep-Alive\r\n", address)))
|
||||||
|
//Proxy-Authorization:\r\n
|
||||||
|
u := ""
|
||||||
|
if *s.cfg.ParentAuth != "" {
|
||||||
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
|
if len(a) != 2 {
|
||||||
|
err = fmt.Errorf("parent auth data format error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u = fmt.Sprintf("%s:%s", a[0], a[1])
|
||||||
|
} else {
|
||||||
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
u = fmt.Sprintf("%s:%s", auth.User, auth.Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if u != "" {
|
||||||
|
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization:Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
|
||||||
|
}
|
||||||
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
_, err = outConn.Write(pb.Bytes())
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("write CONNECT to %s , err:%s", *s.cfg.Parent, err)
|
||||||
|
utils.CloseConn(inConn)
|
||||||
|
utils.CloseConn(&outConn)
|
||||||
|
return
|
||||||
|
}
|
||||||
reply := make([]byte, 100)
|
reply := make([]byte, 100)
|
||||||
n, err = outConn.Read(reply)
|
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||||
|
_, err = outConn.Read(reply)
|
||||||
|
outConn.SetDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
||||||
utils.CloseConn(inConn)
|
utils.CloseConn(inConn)
|
||||||
@ -222,53 +252,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
//log.Printf("reply: %s", string(reply[:n]))
|
//log.Printf("reply: %s", string(reply[:n]))
|
||||||
} else {
|
} else {
|
||||||
log.Printf("connect %s", address)
|
log.Printf("connect %s", address)
|
||||||
//socks parent
|
//socks client
|
||||||
//send auth type
|
var clientConn *socks.ClientConn
|
||||||
_, err = outConn.Write([]byte{0x05, 0x01, 0x00})
|
if *s.cfg.ParentAuth != "" {
|
||||||
if err != nil {
|
a := strings.Split(*s.cfg.ParentAuth, ":")
|
||||||
log.Printf("write method to %s fail, err:%s", *s.cfg.Parent, err)
|
if len(a) != 2 {
|
||||||
utils.CloseConn(inConn)
|
err = fmt.Errorf("parent auth data format error")
|
||||||
utils.CloseConn(&outConn)
|
return
|
||||||
|
}
|
||||||
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &socks.Auth{User: a[0], Password: a[1]}, header)
|
||||||
|
} else {
|
||||||
|
if !s.IsBasicAuth() && auth.Password != "" && auth.User != "" {
|
||||||
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), &auth, header)
|
||||||
|
} else {
|
||||||
|
clientConn = socks.NewClientConn(&outConn, "tcp", address, time.Millisecond*time.Duration(*s.cfg.Timeout), nil, header)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = clientConn.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//read reply
|
|
||||||
reply := make([]byte, 512)
|
|
||||||
n, err = outConn.Read(reply)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//log.Printf("method reply %v", reply[:n])
|
|
||||||
|
|
||||||
//build request
|
|
||||||
buf, err = s.buildRequest(address)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("build request to %s fail , err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//send address request
|
|
||||||
_, err = outConn.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("write request to %s fail, err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//read reply
|
|
||||||
reply = make([]byte, 512)
|
|
||||||
n, err = outConn.Read(reply)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("read reply from %s , err:%s", *s.cfg.Parent, err)
|
|
||||||
utils.CloseConn(inConn)
|
|
||||||
utils.CloseConn(&outConn)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.Printf("request reply %v", reply[:n])
|
|
||||||
}
|
}
|
||||||
//forward client data to target,if necessary.
|
//forward client data to target,if necessary.
|
||||||
if len(forwardBytes) > 0 {
|
if len(forwardBytes) > 0 {
|
||||||
@ -283,6 +285,34 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
|
|||||||
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
log.Printf("conn %s - %s connected", inAddr, outAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *SPS) InitBasicAuth() (err error) {
|
||||||
|
if *s.cfg.DNSAddress != "" {
|
||||||
|
s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver)
|
||||||
|
} else {
|
||||||
|
s.basicAuth = utils.NewBasicAuth(nil)
|
||||||
|
}
|
||||||
|
if *s.cfg.AuthURL != "" {
|
||||||
|
s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
|
||||||
|
log.Printf("auth from %s", *s.cfg.AuthURL)
|
||||||
|
}
|
||||||
|
if *s.cfg.AuthFile != "" {
|
||||||
|
var n = 0
|
||||||
|
n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("auth-file ERR:%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
if len(*s.cfg.Auth) > 0 {
|
||||||
|
n := s.basicAuth.Add(*s.cfg.Auth)
|
||||||
|
log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *SPS) IsBasicAuth() bool {
|
||||||
|
return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
|
||||||
|
}
|
||||||
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
func (s *SPS) buildRequest(address string) (buf []byte, err error) {
|
||||||
host, portStr, err := net.SplitHostPort(address)
|
host, portStr, err := net.SplitHostPort(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -63,7 +63,7 @@ func NewClientConn(conn *net.Conn, network, target string, timeout time.Duration
|
|||||||
// connect takes an existing connection to a socks5 proxy server,
|
// connect takes an existing connection to a socks5 proxy server,
|
||||||
// and commands the server to extend that connection to target,
|
// and commands the server to extend that connection to target,
|
||||||
// which must be a canonical address with a host and port.
|
// which must be a canonical address with a host and port.
|
||||||
func (s *ClientConn) Connect() error {
|
func (s *ClientConn) Handshake() error {
|
||||||
host, portStr, err := net.SplitHostPort(s.addr)
|
host, portStr, err := net.SplitHostPort(s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -106,14 +106,15 @@ func (s *ServerConn) Handshake() (err error) {
|
|||||||
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
err = fmt.Errorf("new methods request fail,ERR: %s", e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.auth == nil {
|
//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
|
||||||
if !methodReq.Select(Method_NO_AUTH) {
|
if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
|
||||||
(*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
// if !methodReq.Select(Method_NO_AUTH) {
|
||||||
methodReq.Reply(Method_NONE_ACCEPTABLE)
|
// (*s.conn).SetReadDeadline(time.Now().Add(time.Second * s.timeout))
|
||||||
(*s.conn).SetReadDeadline(time.Time{})
|
// methodReq.Reply(Method_NONE_ACCEPTABLE)
|
||||||
err = fmt.Errorf("none method found : Method_NO_AUTH")
|
// (*s.conn).SetReadDeadline(time.Time{})
|
||||||
return
|
// err = fmt.Errorf("none method found : Method_NO_AUTH")
|
||||||
}
|
// return
|
||||||
|
// }
|
||||||
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(time.Second * s.timeout))
|
||||||
@ -158,7 +159,7 @@ func (s *ServerConn) Handshake() (err error) {
|
|||||||
//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(), ":")
|
_addr := strings.Split(remoteAddr.String(), ":")
|
||||||
if s.auth.CheckUserPass(s.user, s.password, _addr[0], "") {
|
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)))
|
(*s.conn).SetDeadline(time.Now().Add(time.Millisecond * time.Duration(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{})
|
||||||
|
|||||||
@ -317,7 +317,7 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
|
|||||||
req = HTTPRequest{
|
req = HTTPRequest{
|
||||||
conn: inConn,
|
conn: inConn,
|
||||||
}
|
}
|
||||||
if len(header) == 1 {
|
if header != nil && len(header) == 1 && len(header[0]) > 1 {
|
||||||
buf = header[0]
|
buf = header[0]
|
||||||
n = len(header[0])
|
n = len(header[0])
|
||||||
} else {
|
} else {
|
||||||
@ -402,18 +402,13 @@ func (req *HTTPRequest) IsHTTPS() bool {
|
|||||||
return req.Method == "CONNECT"
|
return req.Method == "CONNECT"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *HTTPRequest) BasicAuth() (err error) {
|
func (req *HTTPRequest) GetAuthDataStr() (basicInfo string, err error) {
|
||||||
|
|
||||||
// log.Printf("request :%s", string(req.HeadBuf))
|
// log.Printf("request :%s", string(req.HeadBuf))
|
||||||
code := "407"
|
|
||||||
authorization := req.getHeader("Proxy-Authorization")
|
authorization := req.getHeader("Proxy-Authorization")
|
||||||
// if authorization == "" {
|
|
||||||
// authorization = req.getHeader("Authorization")
|
|
||||||
// code = "401"
|
|
||||||
// }
|
|
||||||
authorization = strings.Trim(authorization, " \r\n\t")
|
authorization = strings.Trim(authorization, " \r\n\t")
|
||||||
if authorization == "" {
|
if authorization == "" {
|
||||||
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", code)
|
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\nWWW-Authenticate: Basic realm=\"\"\r\n\r\nUnauthorized", "407")
|
||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
err = errors.New("require auth header data")
|
err = errors.New("require auth header data")
|
||||||
return
|
return
|
||||||
@ -431,6 +426,10 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
|||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
basicInfo = string(user)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (req *HTTPRequest) BasicAuth() (err error) {
|
||||||
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
addr := strings.Split((*req.conn).RemoteAddr().String(), ":")
|
||||||
URL := ""
|
URL := ""
|
||||||
if req.IsHTTPS() {
|
if req.IsHTTPS() {
|
||||||
@ -438,10 +437,14 @@ func (req *HTTPRequest) BasicAuth() (err error) {
|
|||||||
} else {
|
} else {
|
||||||
URL = req.getHTTPURL()
|
URL = req.getHTTPURL()
|
||||||
}
|
}
|
||||||
|
user, err := req.GetAuthDataStr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
authOk := (*req.basicAuth).Check(string(user), addr[0], URL)
|
authOk := (*req.basicAuth).Check(string(user), addr[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 Unauthorized\r\n\r\nUnauthorized", code)
|
fmt.Fprintf((*req.conn), "HTTP/1.1 %s Unauthorized\r\n\r\nUnauthorized", "407")
|
||||||
CloseConn(req.conn)
|
CloseConn(req.conn)
|
||||||
err = fmt.Errorf("basic auth fail")
|
err = fmt.Errorf("basic auth fail")
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user