From 9f50692d15081481b81799b617398f22653e1685 Mon Sep 17 00:00:00 2001 From: v2ray Date: Thu, 25 Feb 2016 14:38:41 +0100 Subject: [PATCH] auto user creation for dynamic port --- common/protocol/user.go | 4 +- common/protocol/user_json.go | 2 +- proxy/vmess/inbound/command.go | 5 ++- proxy/vmess/inbound/config.go | 6 +++ proxy/vmess/inbound/config_json.go | 25 +++++++++++ proxy/vmess/inbound/inbound.go | 53 ++++++++++++++++++++--- proxy/vmess/outbound/command.go | 2 +- proxy/vmess/outbound/receiver_test.go | 4 +- testing/scenarios/data/test_4_server.json | 10 +---- 9 files changed, 90 insertions(+), 21 deletions(-) diff --git a/common/protocol/user.go b/common/protocol/user.go index 136e0b9a..b4363ed1 100644 --- a/common/protocol/user.go +++ b/common/protocol/user.go @@ -15,12 +15,14 @@ type User struct { ID *ID AlterIDs []*ID Level UserLevel + Email string } -func NewUser(id *ID, level UserLevel, alterIdCount uint16) *User { +func NewUser(id *ID, level UserLevel, alterIdCount uint16, email string) *User { u := &User{ ID: id, Level: level, + Email: email, } if alterIdCount > 0 { u.AlterIDs = make([]*ID, alterIdCount) diff --git a/common/protocol/user_json.go b/common/protocol/user_json.go index 47e565eb..17577244 100644 --- a/common/protocol/user_json.go +++ b/common/protocol/user_json.go @@ -23,7 +23,7 @@ func (u *User) UnmarshalJSON(data []byte) error { if err != nil { return err } - *u = *NewUser(NewID(id), UserLevel(rawUserValue.LevelByte), rawUserValue.AlterIdCount) + *u = *NewUser(NewID(id), UserLevel(rawUserValue.LevelByte), rawUserValue.AlterIdCount, rawUserValue.EmailString) return nil } diff --git a/proxy/vmess/inbound/command.go b/proxy/vmess/inbound/command.go index 6fa060b1..72f31205 100644 --- a/proxy/vmess/inbound/command.go +++ b/proxy/vmess/inbound/command.go @@ -7,9 +7,10 @@ import ( "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/serial" "github.com/v2ray/v2ray-core/proxy/vmess/command" + "github.com/v2ray/v2ray-core/proxy/vmess/protocol" ) -func (this *VMessInboundHandler) generateCommand(buffer *alloc.Buffer) { +func (this *VMessInboundHandler) generateCommand(request *protocol.VMessRequest, buffer *alloc.Buffer) { cmd := byte(0) commandBytes := alloc.NewSmallBuffer().Clear() defer commandBytes.Release() @@ -26,7 +27,7 @@ func (this *VMessInboundHandler) generateCommand(buffer *alloc.Buffer) { } cmd = byte(1) log.Info("VMessIn: Pick detour handler for port ", inboundHandler.Port(), " for ", availableMin, " minutes.") - user := inboundHandler.GetUser() + user := inboundHandler.GetUser(request.User.Email) saCmd := &command.SwitchAccount{ Port: inboundHandler.Port(), ID: user.ID.UUID(), diff --git a/proxy/vmess/inbound/config.go b/proxy/vmess/inbound/config.go index 3a3921e7..328e9be6 100644 --- a/proxy/vmess/inbound/config.go +++ b/proxy/vmess/inbound/config.go @@ -12,7 +12,13 @@ type FeaturesConfig struct { Detour *DetourConfig } +type DefaultConfig struct { + AlterIDs uint16 + Level proto.UserLevel +} + type Config struct { AllowedUsers []*proto.User Features *FeaturesConfig + Defaults *DefaultConfig } diff --git a/proxy/vmess/inbound/config_json.go b/proxy/vmess/inbound/config_json.go index c4508eb9..f51c26ab 100644 --- a/proxy/vmess/inbound/config_json.go +++ b/proxy/vmess/inbound/config_json.go @@ -33,10 +33,28 @@ func (this *FeaturesConfig) UnmarshalJSON(data []byte) error { return nil } +func (this *DefaultConfig) UnmarshalJSON(data []byte) error { + type JsonDefaultConfig struct { + AlterIDs uint16 `json:"alterId"` + Level byte `json:"level"` + } + jsonConfig := new(JsonDefaultConfig) + if err := json.Unmarshal(data, jsonConfig); err != nil { + return err + } + this.AlterIDs = jsonConfig.AlterIDs + if this.AlterIDs == 0 { + this.AlterIDs = 32 + } + this.Level = proto.UserLevel(jsonConfig.Level) + return nil +} + func (this *Config) UnmarshalJSON(data []byte) error { type JsonConfig struct { Users []*proto.User `json:"clients"` Features *FeaturesConfig `json:"features"` + Defaults *DefaultConfig `json:"default"` } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { @@ -44,6 +62,13 @@ func (this *Config) UnmarshalJSON(data []byte) error { } this.AllowedUsers = jsonConfig.Users this.Features = jsonConfig.Features + this.Defaults = jsonConfig.Defaults + if this.Defaults == nil { + this.Defaults = &DefaultConfig{ + Level: proto.UserLevel(0), + AlterIDs: 32, + } + } return nil } diff --git a/proxy/vmess/inbound/inbound.go b/proxy/vmess/inbound/inbound.go index 6eba02e8..15c9319c 100644 --- a/proxy/vmess/inbound/inbound.go +++ b/proxy/vmess/inbound/inbound.go @@ -15,6 +15,7 @@ import ( v2net "github.com/v2ray/v2ray-core/common/net" proto "github.com/v2ray/v2ray-core/common/protocol" "github.com/v2ray/v2ray-core/common/serial" + "github.com/v2ray/v2ray-core/common/uuid" "github.com/v2ray/v2ray-core/proxy" "github.com/v2ray/v2ray-core/proxy/internal" vmessio "github.com/v2ray/v2ray-core/proxy/vmess/io" @@ -22,13 +23,51 @@ import ( "github.com/v2ray/v2ray-core/transport/hub" ) +type userByEmail struct { + sync.RWMutex + cache map[string]*proto.User + defaultLevel proto.UserLevel + defaultAlterIDs uint16 +} + +func NewUserByEmail(users []*proto.User, config *DefaultConfig) *userByEmail { + cache := make(map[string]*proto.User) + for _, user := range users { + cache[user.Email] = user + } + return &userByEmail{ + cache: cache, + defaultLevel: config.Level, + defaultAlterIDs: config.AlterIDs, + } +} + +func (this *userByEmail) Get(email string) (*proto.User, bool) { + var user *proto.User + var found bool + this.RLock() + user, found = this.cache[email] + this.RUnlock() + if !found { + this.Lock() + user, found = this.cache[email] + if !found { + id := proto.NewID(uuid.New()) + user = proto.NewUser(id, this.defaultLevel, this.defaultAlterIDs, email) + this.cache[email] = user + } + this.Unlock() + } + return user, found +} + // Inbound connection handler that handles messages in VMess format. type VMessInboundHandler struct { sync.Mutex packetDispatcher dispatcher.PacketDispatcher inboundHandlerManager proxyman.InboundHandlerManager clients protocol.UserSet - user *proto.User + usersByEmail *userByEmail accepting bool listener *hub.TCPHub features *FeaturesConfig @@ -49,8 +88,12 @@ func (this *VMessInboundHandler) Close() { } } -func (this *VMessInboundHandler) GetUser() *proto.User { - return this.user +func (this *VMessInboundHandler) GetUser(email string) *proto.User { + user, existing := this.usersByEmail.Get(email) + if !existing { + this.clients.AddUser(user) + } + return user } func (this *VMessInboundHandler) Listen(port v2net.Port) error { @@ -117,7 +160,7 @@ func (this *VMessInboundHandler) HandleConnection(connection *hub.TCPConn) { buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader, byte(0)) - this.generateCommand(buffer) + this.generateCommand(request, buffer) if data, open := <-output; open { if request.IsChunkStream() { @@ -177,7 +220,7 @@ func init() { packetDispatcher: space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher), clients: allowedClients, features: config.Features, - user: config.AllowedUsers[0], + usersByEmail: NewUserByEmail(config.AllowedUsers, config.Defaults), } if space.HasApp(proxyman.APP_ID_INBOUND_MANAGER) { diff --git a/proxy/vmess/outbound/command.go b/proxy/vmess/outbound/command.go index dc57cb28..b269e3c1 100644 --- a/proxy/vmess/outbound/command.go +++ b/proxy/vmess/outbound/command.go @@ -11,7 +11,7 @@ import ( ) func (this *VMessOutboundHandler) handleSwitchAccount(cmd *command.SwitchAccount) { - user := proto.NewUser(proto.NewID(cmd.ID), cmd.Level, cmd.AlterIds.Value()) + user := proto.NewUser(proto.NewID(cmd.ID), cmd.Level, cmd.AlterIds.Value(), "") dest := v2net.TCPDestination(cmd.Host, cmd.Port) this.receiverManager.AddDetour(NewReceiver(dest, user), cmd.ValidMin) } diff --git a/proxy/vmess/outbound/receiver_test.go b/proxy/vmess/outbound/receiver_test.go index 6f5172ec..3c59021b 100644 --- a/proxy/vmess/outbound/receiver_test.go +++ b/proxy/vmess/outbound/receiver_test.go @@ -15,13 +15,13 @@ func TestReceiverUser(t *testing.T) { v2testing.Current(t) id := proto.NewID(uuid.New()) - user := proto.NewUser(id, proto.UserLevel(0), 100) + user := proto.NewUser(id, proto.UserLevel(0), 100, "") rec := NewReceiver(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80), user) assert.Bool(rec.HasUser(user)).IsTrue() assert.Int(len(rec.Accounts)).Equals(1) id2 := proto.NewID(uuid.New()) - user2 := proto.NewUser(id2, proto.UserLevel(0), 100) + user2 := proto.NewUser(id2, proto.UserLevel(0), 100, "") assert.Bool(rec.HasUser(user2)).IsFalse() rec.AddUser(user2) diff --git a/testing/scenarios/data/test_4_server.json b/testing/scenarios/data/test_4_server.json index b71b7852..ed1c2c4d 100644 --- a/testing/scenarios/data/test_4_server.json +++ b/testing/scenarios/data/test_4_server.json @@ -29,15 +29,7 @@ "protocol": "vmess", "port": "50035-50039", "tag": "detour", - "settings": { - "clients": [ - { - "id": "a12f49ba-466c-4dd5-8438-5c315143bc96", - "alterId": 100, - "level": 1 - } - ] - }, + "settings": {}, "allocate": { "strategy": "random", "concurrency": 2,