From 5a31a0a925f92e17e55782ee0b713f5d424a6b93 Mon Sep 17 00:00:00 2001 From: xiaoli Date: Fri, 27 Oct 2017 03:07:11 +0800 Subject: [PATCH 1/2] add redis server based auth support for SOCKS5 --- cmd/gost/main.go | 35 ++++++++++++++++++++++++++++++++++- cmd/gost/redis.yml | 5 +++++ handler.go | 21 +++++++++++++++------ socks.go | 39 +++++++++++++++++++++++++-------------- 4 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 cmd/gost/redis.yml diff --git a/cmd/gost/main.go b/cmd/gost/main.go index a7ce5c5..10e82ef 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -17,8 +17,10 @@ import ( "strings" "time" - "github.com/ginuerzh/gost" "github.com/go-log/log" + "github.com/go-redis/redis" + "github.com/jinzhu/configor" + "github.com/xiaoli/gost" ) var ( @@ -26,6 +28,7 @@ var ( ChainNodes, ServeNodes stringList Debug bool } + redisClient *redis.Client ) func init() { @@ -234,6 +237,10 @@ func serve(chain *gost.Chain) error { if node.User != nil { users = append(users, node.User) } + redisClient, err := parseRedisUsersAuth(node.Values.Get("redis")) + if err != nil { + return err + } certFile, keyFile := node.Values.Get("cert"), node.Values.Get("key") tlsCfg, err := tlsConfig(certFile, keyFile) if err != nil && certFile != "" && keyFile != "" { @@ -334,6 +341,7 @@ func serve(chain *gost.Chain) error { gost.TLSConfigHandlerOption(tlsCfg), gost.WhitelistHandlerOption(whitelist), gost.BlacklistHandlerOption(blacklist), + gost.RedisClientHandlerOption(redisClient), ) var handler gost.Handler switch node.Protocol { @@ -478,6 +486,31 @@ func parseUsers(authFile string) (users []*url.Userinfo, err error) { return } +func parseRedisUsersAuth(configFile string) (client *redis.Client, err error) { + if configFile == "" { + return + } + + var Config = struct { + RedisServer struct { + Address string `default:"localhost:6379"` + Password string `default:""` + DB int `default:0` + } + }{} + + configor.Load(&Config, configFile) + client = redis.NewClient(&redis.Options{ + Addr: Config.RedisServer.Address, + Password: Config.RedisServer.Password, + DB: Config.RedisServer.DB, + }) + + _, err = client.Ping().Result() + + return +} + func parseIP(s string) (ips []string) { if s == "" { return nil diff --git a/cmd/gost/redis.yml b/cmd/gost/redis.yml new file mode 100644 index 0000000..e8e92c1 --- /dev/null +++ b/cmd/gost/redis.yml @@ -0,0 +1,5 @@ +redisserver: + address: localhost:6379 + password: + db: + diff --git a/handler.go b/handler.go index 451c4a6..bb4fe88 100644 --- a/handler.go +++ b/handler.go @@ -9,6 +9,7 @@ import ( "github.com/ginuerzh/gosocks4" "github.com/ginuerzh/gosocks5" "github.com/go-log/log" + "github.com/go-redis/redis" ) // Handler is a proxy server handler @@ -18,12 +19,13 @@ type Handler interface { // HandlerOptions describes the options for Handler. type HandlerOptions struct { - Addr string - Chain *Chain - Users []*url.Userinfo - TLSConfig *tls.Config - Whitelist *Permissions - Blacklist *Permissions + Addr string + Chain *Chain + Users []*url.Userinfo + TLSConfig *tls.Config + Whitelist *Permissions + Blacklist *Permissions + RedisClient *redis.Client } // HandlerOption allows a common way to set handler options. @@ -71,6 +73,13 @@ func BlacklistHandlerOption(blacklist *Permissions) HandlerOption { } } +// RedisClientHandlerOption sets the RedisClient option of HandlerOptions. +func RedisClientHandlerOption(client *redis.Client) HandlerOption { + return func(opts *HandlerOptions) { + opts.RedisClient = client + } +} + type autoHandler struct { options []HandlerOption } diff --git a/socks.go b/socks.go index 1bb4533..ea59916 100644 --- a/socks.go +++ b/socks.go @@ -15,6 +15,7 @@ import ( "github.com/ginuerzh/gosocks4" "github.com/ginuerzh/gosocks5" "github.com/go-log/log" + "github.com/go-redis/redis" ) const ( @@ -90,9 +91,10 @@ func (selector *clientSelector) OnSelected(method uint8, conn net.Conn) (net.Con } type serverSelector struct { - methods []uint8 - Users []*url.Userinfo - TLSConfig *tls.Config + methods []uint8 + Users []*url.Userinfo + TLSConfig *tls.Config + RedisClient *redis.Client } func (selector *serverSelector) Methods() []uint8 { @@ -116,7 +118,7 @@ func (selector *serverSelector) Select(methods ...uint8) (method uint8) { } // when user/pass is set, auth is mandatory - if len(selector.Users) > 0 { + if len(selector.Users) > 0 || selector.RedisClient != nil { if method == gosocks5.MethodNoAuth { method = gosocks5.MethodUserPass } @@ -150,17 +152,25 @@ func (selector *serverSelector) OnSelected(method uint8, conn net.Conn) (net.Con log.Log("[socks5]", req.String()) } valid := false - for _, user := range selector.Users { - username := user.Username() - password, _ := user.Password() - if (req.Username == username && req.Password == password) || - (req.Username == username && password == "") || - (username == "" && req.Password == password) { + if selector.RedisClient != nil { + password, err := selector.RedisClient.Get(req.Username).Result() + if err == nil && req.Password == password { valid = true - break } } - if len(selector.Users) > 0 && !valid { + if len(selector.Users) > 0 { + for _, user := range selector.Users { + username := user.Username() + password, _ := user.Password() + if (req.Username == username && req.Password == password) || + (req.Username == username && password == "") || + (username == "" && req.Password == password) { + valid = true + break + } + } + } + if (selector.RedisClient != nil || len(selector.Users) > 0) && !valid { resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Failure) if err := resp.Write(conn); err != nil { log.Log("[socks5]", err) @@ -353,8 +363,9 @@ func SOCKS5Handler(opts ...HandlerOption) Handler { tlsConfig = DefaultTLSConfig } selector := &serverSelector{ // socks5 server selector - Users: options.Users, - TLSConfig: tlsConfig, + Users: options.Users, + TLSConfig: tlsConfig, + RedisClient: options.RedisClient, } // methods that socks5 server supported selector.AddMethod( From d194186353da76a7717e3cafe801988beca0204f Mon Sep 17 00:00:00 2001 From: xiaoli Date: Wed, 22 Nov 2017 22:43:43 +0800 Subject: [PATCH 2/2] remove jinzhu/configor dependency --- cmd/gost/main.go | 39 +++++++++++++++++++++++---------------- cmd/gost/redis.json | 5 +++++ cmd/gost/redis.yml | 5 ----- 3 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 cmd/gost/redis.json delete mode 100644 cmd/gost/redis.yml diff --git a/cmd/gost/main.go b/cmd/gost/main.go index 512e0e8..3cd3f7d 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -19,7 +19,6 @@ import ( "github.com/go-log/log" "github.com/go-redis/redis" - "github.com/jinzhu/configor" "github.com/ginuerzh/gost" ) @@ -325,7 +324,7 @@ func (r *route) serve() error { if node.User != nil { users = append(users, node.User) } - redisClient, err := parseRedisUsersAuth(node.Values.Get("redis")) + redisClient, err := connectToRedis(node.Values.Get("redis")) if err != nil { return err } @@ -611,24 +610,32 @@ func parseUsers(authFile string) (users []*url.Userinfo, err error) { return } -func parseRedisUsersAuth(configFile string) (client *redis.Client, err error) { - if configFile == "" { +type redisConfig struct { + Address string `json:"address"` + Password string `json:"password"` + DB int `json:"db"` +} + +func connectToRedis(redisCfg string) (client *redis.Client, err error){ + if redisCfg == "" { return } - var Config = struct { - RedisServer struct { - Address string `default:"localhost:6379"` - Password string `default:""` - DB int `default:0` - } - }{} + content, err := ioutil.ReadFile(redisCfg) + if err != nil { + return + } + + config := new(redisConfig) + err = json.Unmarshal(content, &config) + if err != nil { + return + } - configor.Load(&Config, configFile) client = redis.NewClient(&redis.Options{ - Addr: Config.RedisServer.Address, - Password: Config.RedisServer.Password, - DB: Config.RedisServer.DB, + Addr: config.Address, + Password: config.Password, + DB: config.DB, }) _, err = client.Ping().Result() @@ -636,7 +643,7 @@ func parseRedisUsersAuth(configFile string) (client *redis.Client, err error) { return } -func parseIP(s string) (ips []string) { +func parseIP(s string, port string) (ips []string) { if s == "" { return } diff --git a/cmd/gost/redis.json b/cmd/gost/redis.json new file mode 100644 index 0000000..2e5ca9c --- /dev/null +++ b/cmd/gost/redis.json @@ -0,0 +1,5 @@ +{ + "address": "localhost:6379", + "password": "", + "db": 0 +} diff --git a/cmd/gost/redis.yml b/cmd/gost/redis.yml deleted file mode 100644 index e8e92c1..0000000 --- a/cmd/gost/redis.yml +++ /dev/null @@ -1,5 +0,0 @@ -redisserver: - address: localhost:6379 - password: - db: -