Browse Source

Socks supports multiple accounts

V2Ray 10 years ago
parent
commit
213aa2ecf0

+ 26 - 6
proxy/socks/config/json/config.go

@@ -10,21 +10,41 @@ const (
 	AuthMethodUserPass = "password"
 )
 
+type SocksAccount struct {
+	Username string `json:"user"`
+	Password string `json:"pass"`
+}
+
 type SocksConfig struct {
-	AuthMethod string `json:"auth"`
-	Username   string `json:"user"`
-	Password   string `json:"pass"`
-	UDPEnabled bool   `json:"udp"`
+	AuthMethod string         `json:"auth"`
+	Accounts   []SocksAccount `json:"accounts"`
+	UDPEnabled bool           `json:"udp"`
+
+	accountMap map[string]string
 }
 
-func (config SocksConfig) IsNoAuth() bool {
+func (config *SocksConfig) Initialize() {
+	config.accountMap = make(map[string]string)
+	for _, account := range config.Accounts {
+		config.accountMap[account.Username] = account.Password
+	}
+}
+
+func (config *SocksConfig) IsNoAuth() bool {
 	return config.AuthMethod == AuthMethodNoAuth
 }
 
-func (config SocksConfig) IsPassword() bool {
+func (config *SocksConfig) IsPassword() bool {
 	return config.AuthMethod == AuthMethodUserPass
 }
 
+func (config *SocksConfig) HasAccount(user, pass string) bool {
+	if actualPass, found := config.accountMap[user]; found {
+		return actualPass == pass
+	}
+	return false
+}
+
 func init() {
 	json.RegisterConfigType("socks", config.TypeInbound, func() interface{} {
 		return new(SocksConfig)

+ 6 - 2
proxy/socks/protocol/socks.go

@@ -107,8 +107,12 @@ type Socks5UserPassRequest struct {
 	password string
 }
 
-func (request Socks5UserPassRequest) IsValid(username string, password string) bool {
-	return request.username == username && request.password == password
+func (request Socks5UserPassRequest) Username() string {
+	return request.username
+}
+
+func (request Socks5UserPassRequest) Password() string {
+	return request.password
 }
 
 func (request Socks5UserPassRequest) AuthDetail() string {

+ 1 - 1
proxy/socks/socks.go

@@ -103,7 +103,7 @@ func (server *SocksServer) handleSocks5(reader *v2net.TimeOutReader, writer io.W
 			return err
 		}
 		status := byte(0)
-		if !upRequest.IsValid(server.config.Username, server.config.Password) {
+		if server.config.HasAccount(upRequest.Username(), upRequest.Password()) {
 			status = byte(0xFF)
 		}
 		upResponse := protocol.NewSocks5UserPassResponse(status)

+ 6 - 2
proxy/socks/socks_test.go

@@ -84,8 +84,12 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
 			ProtocolValue: "socks",
 			SettingsValue: &json.SocksConfig{
 				AuthMethod: "noauth",
-				Username:   "userx",
-				Password:   "passy",
+				Accounts: []json.SocksAccount{
+					json.SocksAccount{
+						Username: "userx",
+						Password: "passy",
+					},
+				},
 			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{

+ 4 - 2
proxy/socks/socksfactory.go

@@ -8,8 +8,10 @@ import (
 type SocksServerFactory struct {
 }
 
-func (factory SocksServerFactory) Create(vp *core.Point, config interface{}) (core.InboundConnectionHandler, error) {
-	return NewSocksServer(vp, config.(*json.SocksConfig)), nil
+func (factory SocksServerFactory) Create(vp *core.Point, rawConfig interface{}) (core.InboundConnectionHandler, error) {
+	config := rawConfig.(*json.SocksConfig)
+	config.Initialize()
+	return NewSocksServer(vp, config), nil
 }
 
 func init() {