diff --git a/CHANGELOG b/CHANGELOG index 0c5f576..eb9fcf0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,14 @@ proxy更新日志 v6.9 1.修复了sps的start潜在的crash问题. 2.sps代理增加了--parent-tls-single参数用来支持单向tls上级。 +3.sps代理增加了对单个上级认证信息的支持,如果没有单独设置,就使用全局-A设置. + 现在上级格式: YTpi#2.2.2.2:33080@1 + 说明: + YTpi 是经过base64编码的认证信息,比如是http(s)/socks原始认证信息a:b,用户是a密码是b,base64编码之后是:YTpi + 如果是ss,那么a就是加密方法,b是密码,比如:aes-192-cfb:your_pass,base64编码之后是:YWVzLTE5Mi1jZmI6eW91cl9wYXNz + # 是间隔符号,如果有认证信息,必须有#,没有认证信息可以省略#. + 2.2.2.2:33080 是上级地址 + @1 是设置权重,可以参考手册权重部分. v6.8 1.HTTP(S)\SOCKS5代理,API认证功能,发送给认证接口的参数增加了本地IP,local_ip字段, diff --git a/README_ZH.md b/README_ZH.md index f2cae1b..281cb98 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1157,6 +1157,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之后进行 diff --git a/services/sps/socksudp.go b/services/sps/socksudp.go index 5a58eb4..91c3082 100644 --- a/services/sps/socksudp.go +++ b/services/sps/socksudp.go @@ -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 diff --git a/services/sps/sps.go b/services/sps/sps.go index 6547f1f..b1a09a8 100644 --- a/services/sps/sps.go +++ b/services/sps/sps.go @@ -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" @@ -92,6 +94,8 @@ type SPS struct { udpLocalKey []byte udpParentKey []byte jumper *jumper.Jumper + parentAuthData *sync.Map + parentCipherData *sync.Map } func NewSPS() services.Service { @@ -101,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) { @@ -169,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() @@ -211,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 { @@ -437,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) } @@ -458,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 @@ -510,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 @@ -523,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 @@ -583,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 { @@ -603,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 != "" @@ -706,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 diff --git a/services/sps/ssudp.go b/services/sps/ssudp.go index a3dd71a..559ad95 100644 --- a/services/sps/ssudp.go +++ b/services/sps/ssudp.go @@ -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 diff --git a/utils/crypt/misc.go b/utils/crypt/misc.go new file mode 100644 index 0000000..293bd78 --- /dev/null +++ b/utils/crypt/misc.go @@ -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)) +}