Ver Fonte

Refactor vmess config

Claire Raymond há 10 anos atrás
pai
commit
771d0225c7

+ 1 - 1
config/json/json_test.go

@@ -8,7 +8,7 @@ import (
 	"github.com/v2ray/v2ray-core/config/json"
 	_ "github.com/v2ray/v2ray-core/proxy/freedom/config/json"
 	_ "github.com/v2ray/v2ray-core/proxy/socks/config/json"
-	_ "github.com/v2ray/v2ray-core/proxy/vmess"
+	_ "github.com/v2ray/v2ray-core/proxy/vmess/config/json"
 
 	"github.com/v2ray/v2ray-core/testing/unit"
 )

+ 0 - 84
proxy/vmess/config.go

@@ -1,84 +0,0 @@
-package vmess
-
-import (
-	"net"
-	"strings"
-
-	"github.com/v2ray/v2ray-core/common/log"
-	v2net "github.com/v2ray/v2ray-core/common/net"
-	"github.com/v2ray/v2ray-core/config"
-	"github.com/v2ray/v2ray-core/config/json"
-	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
-)
-
-// VMessUser is an authenticated user account in VMess configuration.
-type VMessUser struct {
-	Id    string `json:"id"`
-	Email string `json:"email"`
-}
-
-func (u *VMessUser) ToUser() (user.User, error) {
-	id, err := user.NewID(u.Id)
-	return user.User{
-		Id: id,
-	}, err
-}
-
-// VMessInboundConfig is
-type VMessInboundConfig struct {
-	AllowedClients []VMessUser `json:"clients"`
-	UDPEnabled     bool        `json:"udp"`
-}
-
-type VNextConfig struct {
-	Address string      `json:"address"`
-	Port    uint16      `json:"port"`
-	Users   []VMessUser `json:"users"`
-	Network string      `json:"network"`
-}
-
-func (config VNextConfig) HasNetwork(network string) bool {
-	return strings.Contains(config.Network, network)
-}
-
-func (c VNextConfig) ToVNextServer(network string) (*VNextServer, error) {
-	users := make([]user.User, 0, len(c.Users))
-	for _, user := range c.Users {
-		vuser, err := user.ToUser()
-		if err != nil {
-			log.Error("Failed to convert %v to User.", user)
-			return nil, config.BadConfiguration
-		}
-		users = append(users, vuser)
-	}
-	ip := net.ParseIP(c.Address)
-	if ip == nil {
-		log.Error("Unable to parse VNext IP: %s", c.Address)
-		return nil, config.BadConfiguration
-	}
-	address := v2net.IPAddress(ip, c.Port)
-	var dest v2net.Destination
-	if network == "tcp" {
-		dest = v2net.NewTCPDestination(address)
-	} else {
-		dest = v2net.NewUDPDestination(address)
-	}
-	return &VNextServer{
-		Destination: dest,
-		Users:       users,
-	}, nil
-}
-
-type VMessOutboundConfig struct {
-	VNextList []VNextConfig `json:"vnext"`
-}
-
-func init() {
-	json.RegisterConfigType("vmess", config.TypeInbound, func() interface{} {
-		return new(VMessInboundConfig)
-	})
-
-	json.RegisterConfigType("vmess", config.TypeOutbound, func() interface{} {
-		return new(VMessOutboundConfig)
-	})
-}

+ 4 - 4
proxy/vmess/protocol/user/id.go → proxy/vmess/config/id.go

@@ -1,4 +1,4 @@
-package user
+package config
 
 import (
 	"crypto/md5"
@@ -23,11 +23,11 @@ type ID struct {
 	cmdKey [IDBytesLen]byte
 }
 
-func NewID(id string) (ID, error) {
+func NewID(id string) (*ID, error) {
 	idBytes, err := UUIDToID(id)
 	if err != nil {
 		log.Error("Failed to parse id %s", id)
-		return ID{}, InvalidID
+		return &ID{}, InvalidID
 	}
 
 	md5hash := md5.New()
@@ -35,7 +35,7 @@ func NewID(id string) (ID, error) {
 	md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
 	cmdKey := md5.Sum(nil)
 
-	return ID{
+	return &ID{
 		String: id,
 		Bytes:  idBytes,
 		cmdKey: cmdKey,

+ 1 - 1
proxy/vmess/protocol/user/id_test.go → proxy/vmess/config/id_test.go

@@ -1,4 +1,4 @@
-package user
+package config
 
 import (
 	"testing"

+ 6 - 0
proxy/vmess/config/inbound.go

@@ -0,0 +1,6 @@
+package config
+
+type Inbound interface {
+	AllowedUsers() []User
+	UDPEnabled() bool
+}

+ 30 - 0
proxy/vmess/config/json/inbound.go

@@ -0,0 +1,30 @@
+package json
+
+import (
+	"github.com/v2ray/v2ray-core/config"
+	"github.com/v2ray/v2ray-core/config/json"
+	vmessconfig "github.com/v2ray/v2ray-core/proxy/vmess/config"
+)
+
+type Inbound struct {
+	AllowedClients []*ConfigUser `json:"clients"`
+	UDP            bool          `json:"udp"`
+}
+
+func (c *Inbound) AllowedUsers() []vmessconfig.User {
+	users := make([]vmessconfig.User, 0, len(c.AllowedClients))
+	for _, rawUser := range c.AllowedClients {
+		users = append(users, rawUser)
+	}
+	return users
+}
+
+func (c *Inbound) UDPEnabled() bool {
+	return c.UDP
+}
+
+func init() {
+	json.RegisterConfigType("vmess", config.TypeInbound, func() interface{} {
+		return new(Inbound)
+	})
+}

+ 84 - 0
proxy/vmess/config/json/outbound.go

@@ -0,0 +1,84 @@
+package json
+
+import (
+	"encoding/json"
+	"net"
+	"strings"
+
+	"github.com/v2ray/v2ray-core/common/log"
+	v2net "github.com/v2ray/v2ray-core/common/net"
+	"github.com/v2ray/v2ray-core/config"
+	jsonconfig "github.com/v2ray/v2ray-core/config/json"
+	vmessconfig "github.com/v2ray/v2ray-core/proxy/vmess/config"
+)
+
+type RawConfigTarget struct {
+	Address string        `json:"address"`
+	Port    uint16        `json:"port"`
+	Users   []*ConfigUser `json:"users"`
+	Network string        `json:"network"`
+}
+
+func (config RawConfigTarget) HasNetwork(network string) bool {
+	return strings.Contains(config.Network, network)
+}
+
+type ConfigTarget struct {
+	Address    v2net.Address
+	Users      []*ConfigUser
+	TCPEnabled bool
+	UDPEnabled bool
+}
+
+func (t *ConfigTarget) UnmarshalJSON(data []byte) error {
+	var rawConfig RawConfigTarget
+	if err := json.Unmarshal(data, &rawConfig); err != nil {
+		return err
+	}
+	ip := net.ParseIP(rawConfig.Address)
+	if ip == nil {
+		log.Error("Unable to parse IP: %s", rawConfig.Address)
+		return config.BadConfiguration
+	}
+	t.Address = v2net.IPAddress(ip, rawConfig.Port)
+	if rawConfig.HasNetwork("tcp") {
+		t.TCPEnabled = true
+	}
+	if rawConfig.HasNetwork("udp") {
+		t.UDPEnabled = true
+	}
+	return nil
+}
+
+type Outbound struct {
+	TargetList []*ConfigTarget `json:"vnext"`
+}
+
+func (o *Outbound) Targets() []*vmessconfig.OutboundTarget {
+	targets := make([]*vmessconfig.OutboundTarget, 0, 2*len(o.TargetList))
+	for _, rawTarget := range o.TargetList {
+		users := make([]vmessconfig.User, 0, len(rawTarget.Users))
+		for _, rawUser := range rawTarget.Users {
+			users = append(users, rawUser)
+		}
+		if rawTarget.TCPEnabled {
+			targets = append(targets, &vmessconfig.OutboundTarget{
+				Destination: v2net.NewTCPDestination(rawTarget.Address),
+				Accounts:    users,
+			})
+		}
+		if rawTarget.UDPEnabled {
+			targets = append(targets, &vmessconfig.OutboundTarget{
+				Destination: v2net.NewUDPDestination(rawTarget.Address),
+				Accounts:    users,
+			})
+		}
+	}
+	return targets
+}
+
+func init() {
+	jsonconfig.RegisterConfigType("vmess", config.TypeOutbound, func() interface{} {
+		return new(Outbound)
+	})
+}

+ 35 - 0
proxy/vmess/config/json/user.go

@@ -0,0 +1,35 @@
+package json
+
+import (
+	"encoding/json"
+
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
+)
+
+// ConfigUser is an user account in VMess configuration.
+type ConfigUser struct {
+	Id    *config.ID
+	Email string
+}
+
+func (u *ConfigUser) UnmarshalJSON(data []byte) error {
+	type rawUser struct {
+		IdString    string `json:"id"`
+		EmailString string `json:"email"`
+	}
+	var rawUserValue rawUser
+	if err := json.Unmarshal(data, &rawUserValue); err != nil {
+		return err
+	}
+	id, err := config.NewID(rawUserValue.IdString)
+	if err != nil {
+		return err
+	}
+	u.Id = id
+	u.Email = rawUserValue.EmailString
+	return nil
+}
+
+func (u *ConfigUser) ID() *config.ID {
+	return u.Id
+}

+ 14 - 0
proxy/vmess/config/outbound.go

@@ -0,0 +1,14 @@
+package config
+
+import (
+	v2net "github.com/v2ray/v2ray-core/common/net"
+)
+
+type OutboundTarget struct {
+	Destination v2net.Destination
+	Accounts    []User
+}
+
+type Outbound interface {
+	Targets() []*OutboundTarget
+}

+ 5 - 0
proxy/vmess/config/user.go

@@ -0,0 +1,5 @@
+package config
+
+type User interface {
+	ID() *ID
+}

+ 0 - 6
proxy/vmess/protocol/user/user.go

@@ -1,6 +0,0 @@
-package user
-
-// User is the user account that is used for connection to a Point
-type User struct {
-	Id ID `json:"id"` // The ID of this User.
-}

+ 10 - 9
proxy/vmess/protocol/user/userset.go

@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"github.com/v2ray/v2ray-core/common/collect"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 )
 
 const (
@@ -13,12 +14,12 @@ const (
 )
 
 type UserSet interface {
-	AddUser(user User) error
-	GetUser(timeHash []byte) (*ID, int64, bool)
+	AddUser(user config.User) error
+	GetUser(timeHash []byte) (*config.ID, int64, bool)
 }
 
 type TimedUserSet struct {
-	validUserIds        []ID
+	validUserIds        []*config.ID
 	userHash            map[string]indexTimePair
 	userHashDeleteQueue *collect.TimedQueue
 	access              sync.RWMutex
@@ -31,7 +32,7 @@ type indexTimePair struct {
 
 func NewTimedUserSet() UserSet {
 	tus := &TimedUserSet{
-		validUserIds:        make([]ID, 0, 16),
+		validUserIds:        make([]*config.ID, 0, 16),
 		userHash:            make(map[string]indexTimePair, 512),
 		userHashDeleteQueue: collect.NewTimedQueue(updateIntervalSec),
 		access:              sync.RWMutex{},
@@ -49,7 +50,7 @@ func (us *TimedUserSet) removeEntries(entries <-chan interface{}) {
 	}
 }
 
-func (us *TimedUserSet) generateNewHashes(lastSec, nowSec int64, idx int, id ID) {
+func (us *TimedUserSet) generateNewHashes(lastSec, nowSec int64, idx int, id *config.ID) {
 	idHash := NewTimeHash(HMACHash{})
 	for lastSec < nowSec {
 		idHash := idHash.Hash(id.Bytes[:], lastSec)
@@ -73,8 +74,8 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
 	}
 }
 
-func (us *TimedUserSet) AddUser(user User) error {
-	id := user.Id
+func (us *TimedUserSet) AddUser(user config.User) error {
+	id := user.ID()
 	idx := len(us.validUserIds)
 	us.validUserIds = append(us.validUserIds, id)
 
@@ -85,12 +86,12 @@ func (us *TimedUserSet) AddUser(user User) error {
 	return nil
 }
 
-func (us TimedUserSet) GetUser(userHash []byte) (*ID, int64, bool) {
+func (us TimedUserSet) GetUser(userHash []byte) (*config.ID, int64, bool) {
 	defer us.access.RUnlock()
 	us.access.RLock()
 	pair, found := us.userHash[string(userHash)]
 	if found {
-		return &us.validUserIds[pair.index], pair.timeSec, true
+		return us.validUserIds[pair.index], pair.timeSec, true
 	}
 	return nil, 0, false
 }

+ 3 - 2
proxy/vmess/protocol/vmess.go

@@ -13,6 +13,7 @@ import (
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
 	"github.com/v2ray/v2ray-core/transport"
 )
@@ -35,7 +36,7 @@ const (
 // streaming.
 type VMessRequest struct {
 	Version        byte
-	UserId         user.ID
+	UserId         config.ID
 	RequestIV      []byte
 	RequestKey     []byte
 	ResponseHeader []byte
@@ -68,7 +69,7 @@ func NewVMessRequestReader(vUserSet user.UserSet) *VMessRequestReader {
 func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
 	buffer := make([]byte, 256)
 
-	nBytes, err := reader.Read(buffer[:user.IDBytesLen])
+	nBytes, err := reader.Read(buffer[:config.IDBytesLen])
 	if err != nil {
 		return nil, err
 	}

+ 17 - 8
proxy/vmess/protocol/vmess_test.go

@@ -6,25 +6,34 @@ import (
 	"testing"
 
 	v2net "github.com/v2ray/v2ray-core/common/net"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
 	"github.com/v2ray/v2ray-core/testing/mocks"
 	"github.com/v2ray/v2ray-core/testing/unit"
 )
 
+type TestUser struct {
+	id *config.ID
+}
+
+func (u *TestUser) ID() *config.ID {
+	return u.id
+}
+
 func TestVMessSerialization(t *testing.T) {
 	assert := unit.Assert(t)
 
-	userId, err := user.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
+	userId, err := config.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	userSet := mocks.MockUserSet{[]user.ID{}, make(map[string]int), make(map[string]int64)}
-	userSet.AddUser(user.User{userId})
+	userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)}
+	userSet.AddUser(&TestUser{userId})
 
 	request := new(VMessRequest)
 	request.Version = byte(0x01)
-	request.UserId = userId
+	request.UserId = *userId
 
 	randBytes := make([]byte, 36)
 	_, err = rand.Read(randBytes)
@@ -61,13 +70,13 @@ func TestVMessSerialization(t *testing.T) {
 }
 
 func BenchmarkVMessRequestWriting(b *testing.B) {
-	userId, _ := user.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
-	userSet := mocks.MockUserSet{[]user.ID{}, make(map[string]int), make(map[string]int64)}
-	userSet.AddUser(user.User{userId})
+	userId, _ := config.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
+	userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)}
+	userSet.AddUser(&TestUser{userId})
 
 	request := new(VMessRequest)
 	request.Version = byte(0x01)
-	request.UserId = userId
+	request.UserId = *userId
 
 	randBytes := make([]byte, 36)
 	rand.Read(randBytes)

+ 27 - 23
proxy/vmess/vmess_test.go

@@ -8,6 +8,8 @@ import (
 	"github.com/v2ray/v2ray-core/common/alloc"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config/json"
 	"github.com/v2ray/v2ray-core/testing/mocks"
 	"github.com/v2ray/v2ray-core/testing/unit"
 )
@@ -16,6 +18,8 @@ func TestVMessInAndOut(t *testing.T) {
 	assert := unit.Assert(t)
 
 	data2Send := "The data to be send to outbound server."
+	testAccount, err := config.NewID("ad937d9d-6e23-4a5a-ba23-bce5092a7c51")
+	assert.Error(err).IsNil()
 
 	portA := uint16(17392)
 	ich := &mocks.InboundConnectionHandler{
@@ -33,14 +37,13 @@ func TestVMessInAndOut(t *testing.T) {
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			SettingsValue: &VMessOutboundConfig{
-				[]VNextConfig{
-					VNextConfig{
-						Address: "127.0.0.1",
-						Port:    13829,
-						Network: "tcp",
-						Users: []VMessUser{
-							VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+			SettingsValue: &json.Outbound{
+				[]*json.ConfigTarget{
+					&json.ConfigTarget{
+						Address:    v2net.IPAddress([]byte{127, 0, 0, 1}, 13829),
+						TCPEnabled: true,
+						Users: []*json.ConfigUser{
+							&json.ConfigUser{Id: testAccount},
 						},
 					},
 				},
@@ -67,9 +70,9 @@ func TestVMessInAndOut(t *testing.T) {
 		PortValue: portB,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			SettingsValue: &VMessInboundConfig{
-				AllowedClients: []VMessUser{
-					VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+			SettingsValue: &json.Inbound{
+				AllowedClients: []*json.ConfigUser{
+					&json.ConfigUser{Id: testAccount},
 				},
 			},
 		},
@@ -95,6 +98,8 @@ func TestVMessInAndOutUDP(t *testing.T) {
 	assert := unit.Assert(t)
 
 	data2Send := "The data to be send to outbound server."
+	testAccount, err := config.NewID("ad937d9d-6e23-4a5a-ba23-bce5092a7c51")
+	assert.Error(err).IsNil()
 
 	portA := uint16(17394)
 	ich := &mocks.InboundConnectionHandler{
@@ -112,14 +117,13 @@ func TestVMessInAndOutUDP(t *testing.T) {
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			SettingsValue: &VMessOutboundConfig{
-				[]VNextConfig{
-					VNextConfig{
-						Address: "127.0.0.1",
-						Port:    13841,
-						Network: "udp",
-						Users: []VMessUser{
-							VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+			SettingsValue: &json.Outbound{
+				[]*json.ConfigTarget{
+					&json.ConfigTarget{
+						Address:    v2net.IPAddress([]byte{127, 0, 0, 1}, 13841),
+						UDPEnabled: true,
+						Users: []*json.ConfigUser{
+							&json.ConfigUser{Id: testAccount},
 						},
 					},
 				},
@@ -146,11 +150,11 @@ func TestVMessInAndOutUDP(t *testing.T) {
 		PortValue: portB,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			SettingsValue: &VMessInboundConfig{
-				AllowedClients: []VMessUser{
-					VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+			SettingsValue: &json.Inbound{
+				AllowedClients: []*json.ConfigUser{
+					&json.ConfigUser{Id: testAccount},
 				},
-				UDPEnabled: true,
+				UDP: true,
 			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{

+ 4 - 8
proxy/vmess/vmessin.go

@@ -13,6 +13,7 @@ import (
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/common/retry"
 	"github.com/v2ray/v2ray-core/proxy"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
 )
@@ -142,19 +143,14 @@ type VMessInboundHandlerFactory struct {
 }
 
 func (factory *VMessInboundHandlerFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (proxy.InboundConnectionHandler, error) {
-	config := rawConfig.(*VMessInboundConfig)
+	config := rawConfig.(config.Inbound)
 
 	allowedClients := user.NewTimedUserSet()
-	for _, client := range config.AllowedClients {
-		user, err := client.ToUser()
-		if err != nil {
-			log.Error("VMessIn: Failed to parse user id %s: %v", client.Id, err)
-			return nil, err
-		}
+	for _, user := range config.AllowedUsers() {
 		allowedClients.AddUser(user)
 	}
 
-	return NewVMessInboundHandler(dispatcher, allowedClients, config.UDPEnabled), nil
+	return NewVMessInboundHandler(dispatcher, allowedClients, config.UDPEnabled()), nil
 }
 
 func init() {

+ 16 - 32
proxy/vmess/vmessout.go

@@ -13,6 +13,7 @@ import (
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/proxy"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
 	"github.com/v2ray/v2ray-core/transport/ray"
@@ -22,25 +23,19 @@ const (
 	InfoTimeNotSync = "Please check the User ID in your vmess configuration, and make sure the time on your local and remote server are in sync."
 )
 
-// VNext is the next Point server in the connection chain.
-type VNextServer struct {
-	Destination v2net.Destination // Address of VNext server
-	Users       []user.User       // User accounts for accessing VNext.
-}
-
 type VMessOutboundHandler struct {
-	vNextList    []*VNextServer
-	vNextListUDP []*VNextServer
+	vNextList    []*config.OutboundTarget
+	vNextListUDP []*config.OutboundTarget
 }
 
-func NewVMessOutboundHandler(vNextList, vNextListUDP []*VNextServer) *VMessOutboundHandler {
+func NewVMessOutboundHandler(vNextList, vNextListUDP []*config.OutboundTarget) *VMessOutboundHandler {
 	return &VMessOutboundHandler{
 		vNextList:    vNextList,
 		vNextListUDP: vNextListUDP,
 	}
 }
 
-func pickVNext(serverList []*VNextServer) (v2net.Destination, user.User) {
+func pickVNext(serverList []*config.OutboundTarget) (v2net.Destination, config.User) {
 	vNextLen := len(serverList)
 	if vNextLen == 0 {
 		panic("VMessOut: Zero vNext is configured.")
@@ -51,7 +46,7 @@ func pickVNext(serverList []*VNextServer) (v2net.Destination, user.User) {
 	}
 
 	vNext := serverList[vNextIndex]
-	vNextUserLen := len(vNext.Users)
+	vNextUserLen := len(vNext.Accounts)
 	if vNextUserLen == 0 {
 		panic("VMessOut: Zero User account.")
 	}
@@ -59,7 +54,7 @@ func pickVNext(serverList []*VNextServer) (v2net.Destination, user.User) {
 	if vNextUserLen > 1 {
 		vNextUserIndex = mrand.Intn(vNextUserLen)
 	}
-	vNextUser := vNext.Users[vNextUserIndex]
+	vNextUser := vNext.Accounts[vNextUserIndex]
 	return vNext.Destination, vNextUser
 }
 
@@ -76,7 +71,7 @@ func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.
 	}
 	request := &protocol.VMessRequest{
 		Version: protocol.Version,
-		UserId:  vNextUser.Id,
+		UserId:  *vNextUser.ID(),
 		Command: command,
 		Address: firstPacket.Destination().Address(),
 	}
@@ -199,26 +194,15 @@ type VMessOutboundHandlerFactory struct {
 }
 
 func (factory *VMessOutboundHandlerFactory) Create(rawConfig interface{}) (proxy.OutboundConnectionHandler, error) {
-	config := rawConfig.(*VMessOutboundConfig)
-	servers := make([]*VNextServer, 0, len(config.VNextList))
-	udpServers := make([]*VNextServer, 0, len(config.VNextList))
-	for _, server := range config.VNextList {
-		if server.HasNetwork("tcp") {
-			aServer, err := server.ToVNextServer("tcp")
-			if err == nil {
-				servers = append(servers, aServer)
-			} else {
-				log.Warning("Discarding the server.")
-			}
+	vOutConfig := rawConfig.(config.Outbound)
+	servers := make([]*config.OutboundTarget, 0, 16)
+	udpServers := make([]*config.OutboundTarget, 0, 16)
+	for _, target := range vOutConfig.Targets() {
+		if target.Destination.IsTCP() {
+			servers = append(servers, target)
 		}
-		if server.HasNetwork("udp") {
-			aServer, err := server.ToVNextServer("udp")
-			if err == nil {
-				udpServers = append(udpServers, aServer)
-			} else {
-				log.Warning("Discarding the server.")
-			}
-
+		if target.Destination.IsUDP() {
+			udpServers = append(udpServers, target)
 		}
 	}
 	return NewVMessOutboundHandler(servers, udpServers), nil

+ 6 - 6
testing/mocks/mockuserset.go

@@ -1,24 +1,24 @@
 package mocks
 
 import (
-	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
+	"github.com/v2ray/v2ray-core/proxy/vmess/config"
 )
 
 type MockUserSet struct {
-	UserIds    []user.ID
+	UserIds    []*config.ID
 	UserHashes map[string]int
 	Timestamps map[string]int64
 }
 
-func (us *MockUserSet) AddUser(user user.User) error {
-	us.UserIds = append(us.UserIds, user.Id)
+func (us *MockUserSet) AddUser(user config.User) error {
+	us.UserIds = append(us.UserIds, user.ID())
 	return nil
 }
 
-func (us *MockUserSet) GetUser(userhash []byte) (*user.ID, int64, bool) {
+func (us *MockUserSet) GetUser(userhash []byte) (*config.ID, int64, bool) {
 	idx, found := us.UserHashes[string(userhash)]
 	if found {
-		return &us.UserIds[idx], us.Timestamps[string(userhash)], true
+		return us.UserIds[idx], us.Timestamps[string(userhash)], true
 	}
 	return nil, 0, false
 }