Pārlūkot izejas kodu

auto user creation for dynamic port

v2ray 9 gadi atpakaļ
vecāks
revīzija
9f50692d15

+ 3 - 1
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)

+ 1 - 1
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
 }

+ 3 - 2
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(),

+ 6 - 0
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
 }

+ 25 - 0
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
 }
 

+ 48 - 5
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) {

+ 1 - 1
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)
 }

+ 2 - 2
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)

+ 1 - 9
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,