From 9112cfd39c2105d5b513275f9659b26e92fa7b67 Mon Sep 17 00:00:00 2001 From: yuhan6665 <1588741+yuhan6665@users.noreply.github.com> Date: Mon, 12 Jun 2023 10:32:25 -0400 Subject: [PATCH] Clean legacy vmess (#2199) * Remove legacy Vmess * validators * protos --- .github/docker/files/config.json | 3 +- common/protocol/headers.go | 6 +- common/protocol/headers.pb.go | 30 ++--- common/protocol/headers.proto | 3 +- common/protocol/id.go | 33 ----- infra/conf/vmess.go | 9 +- infra/conf/vmess_test.go | 1 - proxy/vmess/account.go | 13 -- proxy/vmess/account.pb.go | 41 +++--- proxy/vmess/account.proto | 2 - proxy/vmess/encoding/auth.go | 29 +---- proxy/vmess/encoding/auth_test.go | 26 ---- proxy/vmess/encoding/client.go | 157 +++++++---------------- proxy/vmess/encoding/commands.go | 9 +- proxy/vmess/encoding/commands_test.go | 2 - proxy/vmess/encoding/encoding_test.go | 12 +- proxy/vmess/encoding/server.go | 142 ++++----------------- proxy/vmess/inbound/config.pb.go | 75 ++++------- proxy/vmess/inbound/config.proto | 3 +- proxy/vmess/inbound/inbound.go | 45 +------ proxy/vmess/outbound/command.go | 3 +- proxy/vmess/outbound/outbound.go | 13 +- proxy/vmess/validator.go | 175 ++------------------------ proxy/vmess/validator_test.go | 75 +---------- proxy/vmess/vmessCtxInterface.go | 4 - 25 files changed, 150 insertions(+), 761 deletions(-) delete mode 100644 proxy/vmess/encoding/auth_test.go delete mode 100644 proxy/vmess/vmessCtxInterface.go diff --git a/.github/docker/files/config.json b/.github/docker/files/config.json index 9dded728..10675856 100644 --- a/.github/docker/files/config.json +++ b/.github/docker/files/config.json @@ -6,8 +6,7 @@ "clients": [ { "id": "1eb6e917-774b-4a84-aff6-b058577c60a5", - "level": 1, - "alterId": 64 + "level": 1 } ] } diff --git a/common/protocol/headers.go b/common/protocol/headers.go index 0058d1c5..261e21d9 100644 --- a/common/protocol/headers.go +++ b/common/protocol/headers.go @@ -30,11 +30,10 @@ func (c RequestCommand) TransferType() TransferType { } const ( - // RequestOptionChunkStream indicates request payload is chunked. Each chunk consists of length, authentication and payload. + // [DEPRECATED 2023-06] RequestOptionChunkStream indicates request payload is chunked. Each chunk consists of length, authentication and payload. RequestOptionChunkStream bitmask.Byte = 0x01 - // RequestOptionConnectionReuse indicates client side expects to reuse the connection. - RequestOptionConnectionReuse bitmask.Byte = 0x02 + // 0x02 legacy setting RequestOptionChunkMasking bitmask.Byte = 0x04 @@ -76,7 +75,6 @@ type CommandSwitchAccount struct { Port net.Port ID uuid.UUID Level uint32 - AlterIds uint16 ValidMin byte } diff --git a/common/protocol/headers.pb.go b/common/protocol/headers.pb.go index 1392fc62..b90db8c7 100644 --- a/common/protocol/headers.pb.go +++ b/common/protocol/headers.pb.go @@ -24,7 +24,6 @@ type SecurityType int32 const ( SecurityType_UNKNOWN SecurityType = 0 - SecurityType_LEGACY SecurityType = 1 SecurityType_AUTO SecurityType = 2 SecurityType_AES128_GCM SecurityType = 3 SecurityType_CHACHA20_POLY1305 SecurityType = 4 @@ -36,7 +35,6 @@ const ( var ( SecurityType_name = map[int32]string{ 0: "UNKNOWN", - 1: "LEGACY", 2: "AUTO", 3: "AES128_GCM", 4: "CHACHA20_POLY1305", @@ -45,7 +43,6 @@ var ( } SecurityType_value = map[string]int32{ "UNKNOWN": 0, - "LEGACY": 1, "AUTO": 2, "AES128_GCM": 3, "CHACHA20_POLY1305": 4, @@ -139,20 +136,19 @@ var file_common_protocol_headers_proto_rawDesc = []byte{ 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, - 0x6c, 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x4f, - 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x45, 0x53, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, - 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, - 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, - 0x45, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x45, 0x52, 0x4f, 0x10, 0x06, 0x42, 0x5e, 0x0a, - 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, - 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x60, 0x0a, 0x0c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, + 0x41, 0x55, 0x54, 0x4f, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x45, 0x53, 0x31, 0x32, 0x38, + 0x5f, 0x47, 0x43, 0x4d, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, + 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x10, 0x04, 0x12, 0x08, 0x0a, + 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x5a, 0x45, 0x52, 0x4f, 0x10, + 0x06, 0x42, 0x5e, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x50, 0x01, 0x5a, + 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, + 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0xaa, 0x02, 0x14, 0x58, 0x72, 0x61, + 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protocol/headers.proto b/common/protocol/headers.proto index cb0b8ff0..1ae3537f 100644 --- a/common/protocol/headers.proto +++ b/common/protocol/headers.proto @@ -8,11 +8,10 @@ option java_multiple_files = true; enum SecurityType { UNKNOWN = 0; - LEGACY = 1; AUTO = 2; AES128_GCM = 3; CHACHA20_POLY1305 = 4; - NONE = 5; + NONE = 5; // [DEPRECATED 2023-06] ZERO = 6; } diff --git a/common/protocol/id.go b/common/protocol/id.go index 2a1eb17a..211fc578 100644 --- a/common/protocol/id.go +++ b/common/protocol/id.go @@ -1,9 +1,7 @@ package protocol import ( - "crypto/hmac" "crypto/md5" - "hash" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/uuid" @@ -13,12 +11,6 @@ const ( IDBytesLen = 16 ) -type IDHash func(key []byte) hash.Hash - -func DefaultIDHash(key []byte) hash.Hash { - return hmac.New(md5.New, key) -} - // The ID of en entity, in the form of a UUID. type ID struct { uuid uuid.UUID @@ -55,28 +47,3 @@ func NewID(uuid uuid.UUID) *ID { md5hash.Sum(id.cmdKey[:0]) return id } - -func nextID(u *uuid.UUID) uuid.UUID { - md5hash := md5.New() - common.Must2(md5hash.Write(u.Bytes())) - common.Must2(md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81"))) - var newid uuid.UUID - for { - md5hash.Sum(newid[:0]) - if !newid.Equals(u) { - return newid - } - common.Must2(md5hash.Write([]byte("533eff8a-4113-4b10-b5ce-0f5d76b98cd2"))) - } -} - -func NewAlterIDs(primary *ID, alterIDCount uint16) []*ID { - alterIDs := make([]*ID, alterIDCount) - prevID := primary.UUID() - for idx := range alterIDs { - newid := nextID(&prevID) - alterIDs[idx] = NewID(newid) - prevID = newid - } - return alterIDs -} diff --git a/infra/conf/vmess.go b/infra/conf/vmess.go index c646bebb..e3361646 100644 --- a/infra/conf/vmess.go +++ b/infra/conf/vmess.go @@ -15,7 +15,6 @@ import ( type VMessAccount struct { ID string `json:"id"` - AlterIds uint16 `json:"alterId"` Security string `json:"security"` Experiments string `json:"experiments"` } @@ -39,7 +38,6 @@ func (a *VMessAccount) Build() *vmess.Account { } return &vmess.Account{ Id: a.ID, - AlterId: uint32(a.AlterIds), SecuritySettings: &protocol.SecurityConfig{ Type: st, }, @@ -63,14 +61,12 @@ type FeaturesConfig struct { } type VMessDefaultConfig struct { - AlterIDs uint16 `json:"alterId"` Level byte `json:"level"` } // Build implements Buildable func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig { config := new(inbound.DefaultConfig) - config.AlterId = uint32(c.AlterIDs) config.Level = uint32(c.Level) return config } @@ -80,14 +76,11 @@ type VMessInboundConfig struct { Features *FeaturesConfig `json:"features"` Defaults *VMessDefaultConfig `json:"default"` DetourConfig *VMessDetourConfig `json:"detour"` - SecureOnly bool `json:"disableInsecureEncryption"` } // Build implements Buildable func (c *VMessInboundConfig) Build() (proto.Message, error) { - config := &inbound.Config{ - SecureEncryptionOnly: c.SecureOnly, - } + config := &inbound.Config{} if c.Defaults != nil { config.Default = c.Defaults.Build() diff --git a/infra/conf/vmess_test.go b/infra/conf/vmess_test.go index 17cda04d..8adda170 100644 --- a/infra/conf/vmess_test.go +++ b/infra/conf/vmess_test.go @@ -105,7 +105,6 @@ func TestVMessInbound(t *testing.T) { Detour: &inbound.DetourConfig{ To: "tag_to_detour", }, - SecureEncryptionOnly: true, }, }, }) diff --git a/proxy/vmess/account.go b/proxy/vmess/account.go index 809bca21..d0a776e6 100644 --- a/proxy/vmess/account.go +++ b/proxy/vmess/account.go @@ -3,7 +3,6 @@ package vmess import ( "strings" - "github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/uuid" ) @@ -12,8 +11,6 @@ import ( type MemoryAccount struct { // ID is the main ID of the account. ID *protocol.ID - // AlterIDs are the alternative IDs of the account. - AlterIDs []*protocol.ID // Security type of the account. Used for client connections. Security protocol.SecurityType @@ -21,21 +18,12 @@ type MemoryAccount struct { NoTerminationSignal bool } -// AnyValidID returns an ID that is either the main ID or one of the alternative IDs if any. -func (a *MemoryAccount) AnyValidID() *protocol.ID { - if len(a.AlterIDs) == 0 { - return a.ID - } - return a.AlterIDs[dice.Roll(len(a.AlterIDs))] -} - // Equals implements protocol.Account. func (a *MemoryAccount) Equals(account protocol.Account) bool { vmessAccount, ok := account.(*MemoryAccount) if !ok { return false } - // TODO: handle AlterIds difference return a.ID.Equals(vmessAccount.ID) } @@ -55,7 +43,6 @@ func (a *Account) AsAccount() (protocol.Account, error) { } return &MemoryAccount{ ID: protoID, - AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)), Security: a.SecuritySettings.GetSecurityType(), AuthenticatedLengthExperiment: AuthenticatedLength, NoTerminationSignal: NoTerminationSignal, diff --git a/proxy/vmess/account.pb.go b/proxy/vmess/account.pb.go index 67f2586e..9938cfb1 100644 --- a/proxy/vmess/account.pb.go +++ b/proxy/vmess/account.pb.go @@ -29,8 +29,6 @@ type Account struct { // ID of the account, in the form of a UUID, e.g., // "66ad4540-b58c-4ad2-9926-ea63445a9b57". Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // Number of alternative IDs. Client and server must share the same number. - AlterId uint32 `protobuf:"varint,2,opt,name=alter_id,json=alterId,proto3" json:"alter_id,omitempty"` // Security settings. Only applies to client side. SecuritySettings *protocol.SecurityConfig `protobuf:"bytes,3,opt,name=security_settings,json=securitySettings,proto3" json:"security_settings,omitempty"` // Define tests enabled for this account @@ -76,13 +74,6 @@ func (x *Account) GetId() string { return "" } -func (x *Account) GetAlterId() uint32 { - if x != nil { - return x.AlterId - } - return 0 -} - func (x *Account) GetSecuritySettings() *protocol.SecurityConfig { if x != nil { return x.SecuritySettings @@ -104,24 +95,22 @@ var file_proxy_vmess_account_proto_rawDesc = []byte{ 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x1a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xac, 0x01, 0x0a, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x91, 0x01, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x6c, 0x74, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x51, 0x0a, 0x11, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, - 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x73, 0x5f, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, - 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x52, 0x0a, 0x14, 0x63, - 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, - 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, - 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0xaa, 0x02, 0x10, 0x58, - 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x51, 0x0a, 0x11, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, + 0x65, 0x73, 0x74, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x73, 0x74, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, + 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, + 0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, + 0x6d, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proxy/vmess/account.proto b/proxy/vmess/account.proto index 98dc681e..3fac6399 100644 --- a/proxy/vmess/account.proto +++ b/proxy/vmess/account.proto @@ -12,8 +12,6 @@ message Account { // ID of the account, in the form of a UUID, e.g., // "66ad4540-b58c-4ad2-9926-ea63445a9b57". string id = 1; - // Number of alternative IDs. Client and server must share the same number. - uint32 alter_id = 2; // Security settings. Only applies to client side. xray.common.protocol.SecurityConfig security_settings = 3; // Define tests enabled for this account diff --git a/proxy/vmess/encoding/auth.go b/proxy/vmess/encoding/auth.go index 09689cea..5d9623b1 100644 --- a/proxy/vmess/encoding/auth.go +++ b/proxy/vmess/encoding/auth.go @@ -17,6 +17,7 @@ func Authenticate(b []byte) uint32 { return fnv1hash.Sum32() } +// [DEPRECATED 2023-06] type NoOpAuthenticator struct{} func (NoOpAuthenticator) NonceSize() int { @@ -37,34 +38,6 @@ func (NoOpAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([] return append(dst[:0], ciphertext...), nil } -// FnvAuthenticator is an AEAD based on Fnv hash. -type FnvAuthenticator struct{} - -// NonceSize implements AEAD.NonceSize(). -func (*FnvAuthenticator) NonceSize() int { - return 0 -} - -// Overhead impelements AEAD.Overhead(). -func (*FnvAuthenticator) Overhead() int { - return 4 -} - -// Seal implements AEAD.Seal(). -func (*FnvAuthenticator) Seal(dst, nonce, plaintext, additionalData []byte) []byte { - dst = append(dst, 0, 0, 0, 0) - binary.BigEndian.PutUint32(dst, Authenticate(plaintext)) - return append(dst, plaintext...) -} - -// Open implements AEAD.Open(). -func (*FnvAuthenticator) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { - if binary.BigEndian.Uint32(ciphertext[:4]) != Authenticate(ciphertext[4:]) { - return dst, newError("invalid authentication") - } - return append(dst, ciphertext[4:]...), nil -} - // GenerateChacha20Poly1305Key generates a 32-byte key from a given 16-byte array. func GenerateChacha20Poly1305Key(b []byte) []byte { key := make([]byte, 32) diff --git a/proxy/vmess/encoding/auth_test.go b/proxy/vmess/encoding/auth_test.go deleted file mode 100644 index ae83076f..00000000 --- a/proxy/vmess/encoding/auth_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package encoding_test - -import ( - "crypto/rand" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/xtls/xray-core/common" - . "github.com/xtls/xray-core/proxy/vmess/encoding" -) - -func TestFnvAuth(t *testing.T) { - fnvAuth := new(FnvAuthenticator) - - expectedText := make([]byte, 256) - _, err := rand.Read(expectedText) - common.Must(err) - - buffer := make([]byte, 512) - b := fnvAuth.Seal(buffer[:0], nil, expectedText, nil) - b, err = fnvAuth.Open(buffer[:0], nil, b, nil) - common.Must(err) - if r := cmp.Diff(b, expectedText); r != "" { - t.Error(r) - } -} diff --git a/proxy/vmess/encoding/client.go b/proxy/vmess/encoding/client.go index ba08843e..0b7a0098 100644 --- a/proxy/vmess/encoding/client.go +++ b/proxy/vmess/encoding/client.go @@ -5,11 +5,9 @@ import ( "context" "crypto/aes" "crypto/cipher" - "crypto/md5" "crypto/rand" "crypto/sha256" "encoding/binary" - "hash" "hash/fnv" "io" @@ -20,24 +18,13 @@ import ( "github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/drain" "github.com/xtls/xray-core/common/protocol" - "github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/proxy/vmess" vmessaead "github.com/xtls/xray-core/proxy/vmess/aead" "golang.org/x/crypto/chacha20poly1305" ) -func hashTimestamp(h hash.Hash, t protocol.Timestamp) []byte { - common.Must2(serial.WriteUint64(h, uint64(t))) - common.Must2(serial.WriteUint64(h, uint64(t))) - common.Must2(serial.WriteUint64(h, uint64(t))) - common.Must2(serial.WriteUint64(h, uint64(t))) - return h.Sum(nil) -} - // ClientSession stores connection session info for VMess client. type ClientSession struct { - isAEAD bool - idHash protocol.IDHash requestBodyKey [16]byte requestBodyIV [16]byte responseBodyKey [16]byte @@ -49,11 +36,8 @@ type ClientSession struct { } // NewClientSession creates a new ClientSession. -func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash, behaviorSeed int64) *ClientSession { - session := &ClientSession{ - isAEAD: isAEAD, - idHash: idHash, - } +func NewClientSession(ctx context.Context, behaviorSeed int64) *ClientSession { + session := &ClientSession{} randomBytes := make([]byte, 33) // 16 + 16 + 1 common.Must2(rand.Read(randomBytes)) @@ -61,15 +45,10 @@ func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash, copy(session.requestBodyIV[:], randomBytes[16:32]) session.responseHeader = randomBytes[32] - if !session.isAEAD { - session.responseBodyKey = md5.Sum(session.requestBodyKey[:]) - session.responseBodyIV = md5.Sum(session.requestBodyIV[:]) - } else { - BodyKey := sha256.Sum256(session.requestBodyKey[:]) - copy(session.responseBodyKey[:], BodyKey[:16]) - BodyIV := sha256.Sum256(session.requestBodyIV[:]) - copy(session.responseBodyIV[:], BodyIV[:16]) - } + BodyKey := sha256.Sum256(session.requestBodyKey[:]) + copy(session.responseBodyKey[:], BodyKey[:16]) + BodyIV := sha256.Sum256(session.requestBodyIV[:]) + copy(session.responseBodyIV[:], BodyIV[:16]) { var err error session.readDrainer, err = drain.NewBehaviorSeedLimitedDrainer(behaviorSeed, 18, 3266, 64) @@ -83,13 +62,7 @@ func NewClientSession(ctx context.Context, isAEAD bool, idHash protocol.IDHash, } func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) error { - timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)() account := header.User.Account.(*vmess.MemoryAccount) - if !c.isAEAD { - idHash := c.idHash(account.AnyValidID().Bytes()) - common.Must2(serial.WriteUint64(idHash, uint64(timestamp))) - common.Must2(writer.Write(idHash.Sum(nil))) - } buffer := buf.New() defer buffer.Release() @@ -121,17 +94,10 @@ func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ fnv1a.Sum(hashBytes[:0]) } - if !c.isAEAD { - iv := hashTimestamp(md5.New(), timestamp) - aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv) - aesStream.XORKeyStream(buffer.Bytes(), buffer.Bytes()) - common.Must2(writer.Write(buffer.Bytes())) - } else { - var fixedLengthCmdKey [16]byte - copy(fixedLengthCmdKey[:], account.ID.CmdKey()) - vmessout := vmessaead.SealVMessAEADHeader(fixedLengthCmdKey, buffer.Bytes()) - common.Must2(io.Copy(writer, bytes.NewReader(vmessout))) - } + var fixedLengthCmdKey [16]byte + copy(fixedLengthCmdKey[:], account.ID.CmdKey()) + vmessout := vmessaead.SealVMessAEADHeader(fixedLengthCmdKey, buffer.Bytes()) + common.Must2(io.Copy(writer, bytes.NewReader(vmessout))) return nil } @@ -165,19 +131,6 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write } return buf.NewWriter(writer), nil - case protocol.SecurityType_LEGACY: - aesStream := crypto.NewAesEncryptionStream(c.requestBodyKey[:], c.requestBodyIV[:]) - cryptionWriter := crypto.NewCryptionWriter(aesStream, writer) - if request.Option.Has(protocol.RequestOptionChunkStream) { - auth := &crypto.AEADAuthenticator{ - AEAD: new(FnvAuthenticator), - NonceGenerator: crypto.GenerateEmptyBytes(), - AdditionalDataGenerator: crypto.GenerateEmptyBytes(), - } - return crypto.NewAuthenticationWriter(auth, sizeParser, cryptionWriter, request.Command.TransferType(), padding), nil - } - - return &buf.SequentialWriter{Writer: cryptionWriter}, nil case protocol.SecurityType_AES128_GCM: aead := crypto.NewAesGcm(c.requestBodyKey[:]) auth := &crypto.AEADAuthenticator{ @@ -225,53 +178,48 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write } func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.ResponseHeader, error) { - if !c.isAEAD { - aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:]) - c.responseReader = crypto.NewCryptionReader(aesStream, reader) - } else { - aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey) - aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12] + aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey) + aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12] - aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) - aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) + aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) + aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) - var aeadEncryptedResponseHeaderLength [18]byte - var decryptedResponseHeaderLength int - var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16 + var aeadEncryptedResponseHeaderLength [18]byte + var decryptedResponseHeaderLength int + var decryptedResponseHeaderLengthBinaryDeserializeBuffer uint16 - if n, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil { - c.readDrainer.AcknowledgeReceive(n) - return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Len").Base(err)) - } else { // nolint: golint - c.readDrainer.AcknowledgeReceive(n) - } - if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil { - return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Length").Base(err)) - } else { // nolint: golint - common.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer)) - decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer) - } + if n, err := io.ReadFull(reader, aeadEncryptedResponseHeaderLength[:]); err != nil { + c.readDrainer.AcknowledgeReceive(n) + return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Len").Base(err)) + } else { // nolint: golint + c.readDrainer.AcknowledgeReceive(n) + } + if decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil); err != nil { + return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Length").Base(err)) + } else { // nolint: golint + common.Must(binary.Read(bytes.NewReader(decryptedResponseHeaderLengthBinaryBuffer), binary.BigEndian, &decryptedResponseHeaderLengthBinaryDeserializeBuffer)) + decryptedResponseHeaderLength = int(decryptedResponseHeaderLengthBinaryDeserializeBuffer) + } - aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey) - aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12] + aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey) + aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12] - aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) - aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) + aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) + aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) - encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16) + encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16) - if n, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil { - c.readDrainer.AcknowledgeReceive(n) - return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Data").Base(err)) - } else { // nolint: golint - c.readDrainer.AcknowledgeReceive(n) - } + if n, err := io.ReadFull(reader, encryptedResponseHeaderBuffer); err != nil { + c.readDrainer.AcknowledgeReceive(n) + return nil, drain.WithError(c.readDrainer, reader, newError("Unable to Read Header Data").Base(err)) + } else { // nolint: golint + c.readDrainer.AcknowledgeReceive(n) + } - if decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil { - return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Payload").Base(err)) - } else { // nolint: golint - c.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer) - } + if decryptedResponseHeaderBuffer, err := aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil); err != nil { + return nil, drain.WithError(c.readDrainer, reader, newError("Failed To Decrypt Payload").Base(err)) + } else { // nolint: golint + c.responseReader = bytes.NewReader(decryptedResponseHeaderBuffer) } buffer := buf.StackNew() @@ -302,10 +250,8 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon header.Command = command } } - if c.isAEAD { - aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:]) - c.responseReader = crypto.NewCryptionReader(aesStream, reader) - } + aesStream := crypto.NewAesDecryptionStream(c.responseBodyKey[:], c.responseBodyIV[:]) + c.responseReader = crypto.NewCryptionReader(aesStream, reader) return header, nil } @@ -340,17 +286,6 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read } return buf.NewReader(reader), nil - case protocol.SecurityType_LEGACY: - if request.Option.Has(protocol.RequestOptionChunkStream) { - auth := &crypto.AEADAuthenticator{ - AEAD: new(FnvAuthenticator), - NonceGenerator: crypto.GenerateEmptyBytes(), - AdditionalDataGenerator: crypto.GenerateEmptyBytes(), - } - return crypto.NewAuthenticationReader(auth, sizeParser, c.responseReader, request.Command.TransferType(), padding), nil - } - - return buf.NewReader(c.responseReader), nil case protocol.SecurityType_AES128_GCM: aead := crypto.NewAesGcm(c.responseBodyKey[:]) diff --git a/proxy/vmess/encoding/commands.go b/proxy/vmess/encoding/commands.go index 1b420021..5a4d3708 100644 --- a/proxy/vmess/encoding/commands.go +++ b/proxy/vmess/encoding/commands.go @@ -101,7 +101,7 @@ func (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Wri idBytes := cmd.ID.Bytes() common.Must2(writer.Write(idBytes)) - common.Must2(serial.WriteUint16(writer, cmd.AlterIds)) + common.Must2(serial.WriteUint16(writer, 0)) // compatible with legacy alterId common.Must2(writer.Write([]byte{byte(cmd.Level)})) common.Must2(writer.Write([]byte{cmd.ValidMin})) @@ -130,12 +130,7 @@ func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error return nil, ErrInsufficientLength } cmd.ID, _ = uuid.ParseBytes(data[idStart : idStart+16]) - alterIDStart := idStart + 16 - if len(data) < alterIDStart+2 { - return nil, ErrInsufficientLength - } - cmd.AlterIds = binary.BigEndian.Uint16(data[alterIDStart : alterIDStart+2]) - levelStart := alterIDStart + 2 + levelStart := idStart + 16 + 2 if len(data) < levelStart+1 { return nil, ErrInsufficientLength } diff --git a/proxy/vmess/encoding/commands_test.go b/proxy/vmess/encoding/commands_test.go index 17892bb6..c5415959 100644 --- a/proxy/vmess/encoding/commands_test.go +++ b/proxy/vmess/encoding/commands_test.go @@ -16,7 +16,6 @@ func TestSwitchAccount(t *testing.T) { sa := &protocol.CommandSwitchAccount{ Port: 1234, ID: uuid.New(), - AlterIds: 1024, Level: 128, ValidMin: 16, } @@ -40,7 +39,6 @@ func TestSwitchAccountBugOffByOne(t *testing.T) { sa := &protocol.CommandSwitchAccount{ Port: 1234, ID: uuid.New(), - AlterIds: 1024, Level: 128, ValidMin: 16, } diff --git a/proxy/vmess/encoding/encoding_test.go b/proxy/vmess/encoding/encoding_test.go index a8fd8f3a..ddae29e1 100644 --- a/proxy/vmess/encoding/encoding_test.go +++ b/proxy/vmess/encoding/encoding_test.go @@ -41,7 +41,7 @@ func TestRequestSerialization(t *testing.T) { } buffer := buf.New() - client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0) + client := NewClientSession(context.TODO(), 0) common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) buffer2 := buf.New() @@ -50,7 +50,7 @@ func TestRequestSerialization(t *testing.T) { sessionHistory := NewSessionHistory() defer common.Close(sessionHistory) - userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash) + userValidator := vmess.NewTimedUserValidator() userValidator.Add(user) defer common.Close(userValidator) @@ -90,7 +90,7 @@ func TestInvalidRequest(t *testing.T) { } buffer := buf.New() - client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0) + client := NewClientSession(context.TODO(), 0) common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) buffer2 := buf.New() @@ -99,7 +99,7 @@ func TestInvalidRequest(t *testing.T) { sessionHistory := NewSessionHistory() defer common.Close(sessionHistory) - userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash) + userValidator := vmess.NewTimedUserValidator() userValidator.Add(user) defer common.Close(userValidator) @@ -130,7 +130,7 @@ func TestMuxRequest(t *testing.T) { } buffer := buf.New() - client := NewClientSession(context.TODO(), true, protocol.DefaultIDHash, 0) + client := NewClientSession(context.TODO(), 0) common.Must(client.EncodeRequestHeader(expectedRequest, buffer)) buffer2 := buf.New() @@ -139,7 +139,7 @@ func TestMuxRequest(t *testing.T) { sessionHistory := NewSessionHistory() defer common.Close(sessionHistory) - userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash) + userValidator := vmess.NewTimedUserValidator() userValidator.Add(user) defer common.Close(userValidator) diff --git a/proxy/vmess/encoding/server.go b/proxy/vmess/encoding/server.go index 4bdb6fb7..371bfdc0 100644 --- a/proxy/vmess/encoding/server.go +++ b/proxy/vmess/encoding/server.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/aes" "crypto/cipher" - "crypto/md5" "crypto/sha256" "encoding/binary" "hash/fnv" @@ -102,10 +101,6 @@ type ServerSession struct { responseBodyIV [16]byte responseWriter io.Writer responseHeader byte - - isAEADRequest bool - - isAEADForced bool } // NewServerSession creates a new ServerSession, using the given UserValidator. @@ -117,17 +112,12 @@ func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *Sessi } } -// SetAEADForced sets isAEADForced for a ServerSession. -func (s *ServerSession) SetAEADForced(isAEADForced bool) { - s.isAEADForced = isAEADForced -} - func parseSecurityType(b byte) protocol.SecurityType { if _, f := protocol.SecurityType_name[int32(b)]; f { st := protocol.SecurityType(b) // For backward compatibility. if st == protocol.SecurityType_UNKNOWN { - st = protocol.SecurityType_LEGACY + st = protocol.SecurityType_AUTO } return st } @@ -183,26 +173,6 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr } } decryptor = bytes.NewReader(aeadData) - s.isAEADRequest = true - - case errorAEAD == vmessaead.ErrNotFound: - userLegacy, timestamp, valid, userValidationError := s.userValidator.Get(buffer.Bytes()) - if !valid || userValidationError != nil { - return nil, drainConnection(newError("invalid user").Base(userValidationError)) - } - if s.isAEADForced { - return nil, drainConnection(newError("invalid user: VMessAEAD is enforced and a non VMessAEAD connection is received. You can still disable this security feature with environment variable xray.vmess.aead.forced = false . You will not be able to enable legacy header workaround in the future.")) - } - if s.userValidator.ShouldShowLegacyWarn() { - newError("Critical Warning: potentially invalid user: a non VMessAEAD connection is received. From 2022 Jan 1st, this kind of connection will be rejected by default. You should update or replace your client software now. This message will not be shown for further violation on this inbound.").AtWarning().WriteToLog() - } - user = userLegacy - iv := hashTimestamp(md5.New(), timestamp) - vmessAccount = userLegacy.Account.(*vmess.MemoryAccount) - - aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv) - decryptor = crypto.NewCryptionReader(aesStream, reader) - default: return nil, drainConnection(newError("invalid user").Base(errorAEAD)) } @@ -225,15 +195,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr sid.key = s.requestBodyKey sid.nonce = s.requestBodyIV if !s.sessionHistory.addIfNotExits(sid) { - if !s.isAEADRequest { - drainErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) - if drainErr != nil { - return nil, drainConnection(newError("duplicated session id, possibly under replay attack, and failed to taint userHash").Base(drainErr)) - } - return nil, drainConnection(newError("duplicated session id, possibly under replay attack, userHash tainted")) - } else { - return nil, newError("duplicated session id, possibly under replay attack, but this is a AEAD request") - } + return nil, newError("duplicated session id, possibly under replay attack, but this is a AEAD request") } s.responseHeader = buffer.Byte(33) // 1 byte @@ -257,25 +219,11 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr if paddingLen > 0 { if _, err := buffer.ReadFullFrom(decryptor, int32(paddingLen)); err != nil { - if !s.isAEADRequest { - burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) - if burnErr != nil { - return nil, newError("failed to read padding, failed to taint userHash").Base(burnErr).Base(err) - } - return nil, newError("failed to read padding, userHash tainted").Base(err) - } return nil, newError("failed to read padding").Base(err) } } if _, err := buffer.ReadFullFrom(decryptor, 4); err != nil { - if !s.isAEADRequest { - burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) - if burnErr != nil { - return nil, newError("failed to read checksum, failed to taint userHash").Base(burnErr).Base(err) - } - return nil, newError("failed to read checksum, userHash tainted").Base(err) - } return nil, newError("failed to read checksum").Base(err) } @@ -285,17 +233,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader, isDrain bool) (*pr expectedHash := binary.BigEndian.Uint32(buffer.BytesFrom(-4)) if actualHash != expectedHash { - if !s.isAEADRequest { - Autherr := newError("invalid auth, legacy userHash tainted") - burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) - if burnErr != nil { - Autherr = newError("invalid auth, can't taint legacy userHash").Base(burnErr) - } - // It is possible that we are under attack described in https://github.com/xray/xray-core/issues/2523 - return nil, drainConnection(Autherr) - } else { - return nil, newError("invalid auth, but this is a AEAD request") - } + return nil, newError("invalid auth, but this is a AEAD request") } if request.Address == nil { @@ -340,19 +278,6 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade } return buf.NewReader(reader), nil - case protocol.SecurityType_LEGACY: - aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:]) - cryptionReader := crypto.NewCryptionReader(aesStream, reader) - if request.Option.Has(protocol.RequestOptionChunkStream) { - auth := &crypto.AEADAuthenticator{ - AEAD: new(FnvAuthenticator), - NonceGenerator: crypto.GenerateEmptyBytes(), - AdditionalDataGenerator: crypto.GenerateEmptyBytes(), - } - return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding), nil - } - return buf.NewReader(cryptionReader), nil - case protocol.SecurityType_AES128_GCM: aead := crypto.NewAesGcm(s.requestBodyKey[:]) auth := &crypto.AEADAuthenticator{ @@ -403,25 +328,17 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade // EncodeResponseHeader writes encoded response header into the given writer. func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { var encryptionWriter io.Writer - if !s.isAEADRequest { - s.responseBodyKey = md5.Sum(s.requestBodyKey[:]) - s.responseBodyIV = md5.Sum(s.requestBodyIV[:]) - } else { - BodyKey := sha256.Sum256(s.requestBodyKey[:]) - copy(s.responseBodyKey[:], BodyKey[:16]) - BodyIV := sha256.Sum256(s.requestBodyIV[:]) - copy(s.responseBodyIV[:], BodyIV[:16]) - } + BodyKey := sha256.Sum256(s.requestBodyKey[:]) + copy(s.responseBodyKey[:], BodyKey[:16]) + BodyIV := sha256.Sum256(s.requestBodyIV[:]) + copy(s.responseBodyIV[:], BodyIV[:16]) aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:]) encryptionWriter = crypto.NewCryptionWriter(aesStream, writer) s.responseWriter = encryptionWriter aeadEncryptedHeaderBuffer := bytes.NewBuffer(nil) - - if s.isAEADRequest { - encryptionWriter = aeadEncryptedHeaderBuffer - } + encryptionWriter = aeadEncryptedHeaderBuffer common.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)})) err := MarshalCommand(header.Command, encryptionWriter) @@ -429,31 +346,29 @@ func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, wr common.Must2(encryptionWriter.Write([]byte{0x00, 0x00})) } - if s.isAEADRequest { - aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey) - aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12] + aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey) + aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12] - aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) - aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) + aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) + aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) - aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil) + aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil) - decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len()) + decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len()) - common.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer)) + common.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer)) - AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil) - common.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength))) + AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil) + common.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength))) - aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey) - aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12] + aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey) + aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12] - aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) - aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) + aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) + aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) - aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil) - common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload))) - } + aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil) + common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload))) } // EncodeResponseBody returns a Writer that auto-encrypt content written by caller. @@ -487,17 +402,6 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ } return buf.NewWriter(writer), nil - case protocol.SecurityType_LEGACY: - if request.Option.Has(protocol.RequestOptionChunkStream) { - auth := &crypto.AEADAuthenticator{ - AEAD: new(FnvAuthenticator), - NonceGenerator: crypto.GenerateEmptyBytes(), - AdditionalDataGenerator: crypto.GenerateEmptyBytes(), - } - return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding), nil - } - return &buf.SequentialWriter{Writer: s.responseWriter}, nil - case protocol.SecurityType_AES128_GCM: aead := crypto.NewAesGcm(s.responseBodyKey[:]) auth := &crypto.AEADAuthenticator{ diff --git a/proxy/vmess/inbound/config.pb.go b/proxy/vmess/inbound/config.pb.go index a301cede..663256aa 100644 --- a/proxy/vmess/inbound/config.pb.go +++ b/proxy/vmess/inbound/config.pb.go @@ -73,8 +73,7 @@ type DefaultConfig struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AlterId uint32 `protobuf:"varint,1,opt,name=alter_id,json=alterId,proto3" json:"alter_id,omitempty"` - Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` + Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` } func (x *DefaultConfig) Reset() { @@ -109,13 +108,6 @@ func (*DefaultConfig) Descriptor() ([]byte, []int) { return file_proxy_vmess_inbound_config_proto_rawDescGZIP(), []int{1} } -func (x *DefaultConfig) GetAlterId() uint32 { - if x != nil { - return x.AlterId - } - return 0 -} - func (x *DefaultConfig) GetLevel() uint32 { if x != nil { return x.Level @@ -128,10 +120,9 @@ type Config struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"` - Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"` - Detour *DetourConfig `protobuf:"bytes,3,opt,name=detour,proto3" json:"detour,omitempty"` - SecureEncryptionOnly bool `protobuf:"varint,4,opt,name=secure_encryption_only,json=secureEncryptionOnly,proto3" json:"secure_encryption_only,omitempty"` + User []*protocol.User `protobuf:"bytes,1,rep,name=user,proto3" json:"user,omitempty"` + Default *DefaultConfig `protobuf:"bytes,2,opt,name=default,proto3" json:"default,omitempty"` + Detour *DetourConfig `protobuf:"bytes,3,opt,name=detour,proto3" json:"detour,omitempty"` // 4 is for legacy setting } func (x *Config) Reset() { @@ -187,13 +178,6 @@ func (x *Config) GetDetour() *DetourConfig { return nil } -func (x *Config) GetSecureEncryptionOnly() bool { - if x != nil { - return x.SecureEncryptionOnly - } - return false -} - var File_proxy_vmess_inbound_config_proto protoreflect.FileDescriptor var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{ @@ -204,34 +188,29 @@ var file_proxy_vmess_inbound_config_proto_rawDesc = []byte{ 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1e, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x6c, 0x74, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x61, 0x6c, 0x74, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0xf1, 0x01, 0x0a, 0x06, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, - 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x6f, - 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, - 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x65, 0x63, 0x75, - 0x72, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x6e, - 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, - 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x6e, 0x6c, 0x79, 0x42, 0x6a, - 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, - 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, - 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, - 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, - 0x79, 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, - 0x02, 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, - 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x25, 0x0a, 0x0d, 0x44, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, + 0xbb, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x78, 0x72, + 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, + 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, + 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6d, 0x65, 0x73, 0x73, + 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x64, 0x65, 0x74, 0x6f, 0x75, 0x72, 0x42, 0x6a, 0x0a, + 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, + 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, + 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, + 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x2f, 0x76, 0x6d, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, + 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6d, 0x65, 0x73, + 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/proxy/vmess/inbound/config.proto b/proxy/vmess/inbound/config.proto index 9fc7e36f..7da1d581 100644 --- a/proxy/vmess/inbound/config.proto +++ b/proxy/vmess/inbound/config.proto @@ -13,7 +13,6 @@ message DetourConfig { } message DefaultConfig { - uint32 alter_id = 1; uint32 level = 2; } @@ -21,5 +20,5 @@ message Config { repeated xray.common.protocol.User user = 1; DefaultConfig default = 2; DetourConfig detour = 3; - bool secure_encryption_only = 4; + // 4 is for legacy setting } diff --git a/proxy/vmess/inbound/inbound.go b/proxy/vmess/inbound/inbound.go index eb24a6c6..f427bc6b 100644 --- a/proxy/vmess/inbound/inbound.go +++ b/proxy/vmess/inbound/inbound.go @@ -14,7 +14,6 @@ import ( "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/log" "github.com/xtls/xray-core/common/net" - "github.com/xtls/xray-core/common/platform" "github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/session" "github.com/xtls/xray-core/common/signal" @@ -29,23 +28,16 @@ import ( "github.com/xtls/xray-core/transport/internet/stat" ) -var ( - aeadForced = false - aeadForced2022 = false -) - type userByEmail struct { sync.Mutex cache map[string]*protocol.MemoryUser defaultLevel uint32 - defaultAlterIDs uint16 } func newUserByEmail(config *DefaultConfig) *userByEmail { return &userByEmail{ cache: make(map[string]*protocol.MemoryUser), defaultLevel: config.Level, - defaultAlterIDs: uint16(config.AlterId), } } @@ -77,7 +69,6 @@ func (v *userByEmail) Get(email string) (*protocol.MemoryUser, bool) { id := uuid.New() rawAccount := &vmess.Account{ Id: id.String(), - AlterId: uint32(v.defaultAlterIDs), } account, err := rawAccount.AsAccount() common.Must(err) @@ -112,7 +103,6 @@ type Handler struct { usersByEmail *userByEmail detours *DetourConfig sessionHistory *encoding.SessionHistory - secure bool } // New creates a new VMess inbound handler. @@ -121,11 +111,10 @@ func New(ctx context.Context, config *Config) (*Handler, error) { handler := &Handler{ policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), inboundHandlerManager: v.GetFeature(feature_inbound.ManagerType()).(feature_inbound.Manager), - clients: vmess.NewTimedUserValidator(protocol.DefaultIDHash), + clients: vmess.NewTimedUserValidator(), detours: config.Detour, usersByEmail: newUserByEmail(config.GetDefaultValue()), sessionHistory: encoding.NewSessionHistory(), - secure: config.SecureEncryptionOnly, } for _, user := range config.User { @@ -145,7 +134,6 @@ func New(ctx context.Context, config *Config) (*Handler, error) { // Close implements common.Closable. func (h *Handler) Close() error { return errors.Combine( - h.clients.Close(), h.sessionHistory.Close(), common.Close(h.usersByEmail)) } @@ -219,10 +207,6 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess return nil } -func isInsecureEncryption(s protocol.SecurityType) bool { - return s == protocol.SecurityType_NONE || s == protocol.SecurityType_LEGACY || s == protocol.SecurityType_UNKNOWN -} - // Process implements proxy.Inbound.Process(). func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error { sessionPolicy := h.policyManager.ForLevel(0) @@ -241,7 +225,6 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s reader := &buf.BufferedReader{Reader: buf.NewReader(connection)} svrSession := encoding.NewServerSession(h.clients, h.sessionHistory) - svrSession.SetAEADForced(aeadForced) request, err := svrSession.DecodeRequestHeader(reader, isDrain) if err != nil { if errors.Cause(err) != io.EOF { @@ -256,17 +239,6 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s return err } - if h.secure && isInsecureEncryption(request.Security) { - log.Record(&log.AccessMessage{ - From: connection.RemoteAddr(), - To: "", - Status: log.AccessRejected, - Reason: "Insecure encryption", - Email: request.User.Email, - }) - return newError("client is using insecure encryption: ", request.Security) - } - if request.Command != protocol.RequestCommandMux { ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ From: connection.RemoteAddr(), @@ -361,7 +333,6 @@ func (h *Handler) generateCommand(ctx context.Context, request *protocol.Request return &protocol.CommandSwitchAccount{ Port: port, ID: account.ID.UUID(), - AlterIds: uint16(len(account.AlterIDs)), Level: user.Level, ValidMin: byte(availableMin), } @@ -376,18 +347,4 @@ func init() { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { return New(ctx, config.(*Config)) })) - - defaultFlagValue := "NOT_DEFINED_AT_ALL" - - if time.Now().Year() >= 2022 { - defaultFlagValue = "true_by_default_2022" - } - - isAeadForced := platform.NewEnvFlag("xray.vmess.aead.forced").GetValue(func() string { return defaultFlagValue }) - aeadForced = (isAeadForced == "true") - - if isAeadForced == "true_by_default_2022" { - aeadForced = true - aeadForced2022 = true - } } diff --git a/proxy/vmess/outbound/command.go b/proxy/vmess/outbound/command.go index 00c6fac5..07df935c 100644 --- a/proxy/vmess/outbound/command.go +++ b/proxy/vmess/outbound/command.go @@ -12,9 +12,8 @@ import ( func (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) { rawAccount := &vmess.Account{ Id: cmd.ID.String(), - AlterId: uint32(cmd.AlterIds), SecuritySettings: &protocol.SecurityConfig{ - Type: protocol.SecurityType_LEGACY, + Type: protocol.SecurityType_AUTO, }, } diff --git a/proxy/vmess/outbound/outbound.go b/proxy/vmess/outbound/outbound.go index 64c29225..fc77f07f 100644 --- a/proxy/vmess/outbound/outbound.go +++ b/proxy/vmess/outbound/outbound.go @@ -128,11 +128,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte input := link.Reader output := link.Writer - isAEAD := false - if !aeadDisabled && len(account.AlterIDs) == 0 { - isAEAD = true - } - hashkdf := hmac.New(sha256.New, []byte("VMessBF")) hashkdf.Write(account.ID.Bytes()) @@ -144,7 +139,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte newCtx, newCancel = context.WithCancel(context.Background()) } - session := encoding.NewClientSession(ctx, isAEAD, protocol.DefaultIDHash, int64(behaviorSeed)) + session := encoding.NewClientSession(ctx, int64(behaviorSeed)) sessionPolicy := h.policyManager.ForLevel(request.User.Level) ctx, cancel := context.WithCancel(ctx) @@ -233,7 +228,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte var ( enablePadding = false - aeadDisabled = false ) func shouldEnablePadding(s protocol.SecurityType) bool { @@ -251,9 +245,4 @@ func init() { if paddingValue != defaultFlagValue { enablePadding = true } - - isAeadDisabled := platform.NewEnvFlag("xray.vmess.aead.disabled").GetValue(func() string { return defaultFlagValue }) - if isAeadDisabled == "true" { - aeadDisabled = true - } } diff --git a/proxy/vmess/validator.go b/proxy/vmess/validator.go index c638a23b..6cc96927 100644 --- a/proxy/vmess/validator.go +++ b/proxy/vmess/validator.go @@ -6,146 +6,39 @@ import ( "hash/crc64" "strings" "sync" - "sync/atomic" - "time" - "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/dice" "github.com/xtls/xray-core/common/protocol" - "github.com/xtls/xray-core/common/serial" - "github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/proxy/vmess/aead" ) -const ( - updateInterval = 10 * time.Second - cacheDurationSec = 120 -) - -type user struct { - user protocol.MemoryUser - lastSec protocol.Timestamp -} - // TimedUserValidator is a user Validator based on time. type TimedUserValidator struct { sync.RWMutex - users []*user - userHash map[[16]byte]indexTimePair - hasher protocol.IDHash - baseTime protocol.Timestamp - task *task.Periodic + users []*protocol.MemoryUser behaviorSeed uint64 behaviorFused bool aeadDecoderHolder *aead.AuthIDDecoderHolder - - legacyWarnShown bool -} - -type indexTimePair struct { - user *user - timeInc uint32 - - taintedFuse *uint32 } // NewTimedUserValidator creates a new TimedUserValidator. -func NewTimedUserValidator(hasher protocol.IDHash) *TimedUserValidator { +func NewTimedUserValidator() *TimedUserValidator { tuv := &TimedUserValidator{ - users: make([]*user, 0, 16), - userHash: make(map[[16]byte]indexTimePair, 1024), - hasher: hasher, - baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*2), + users: make([]*protocol.MemoryUser, 0, 16), aeadDecoderHolder: aead.NewAuthIDDecoderHolder(), } - tuv.task = &task.Periodic{ - Interval: updateInterval, - Execute: func() error { - tuv.updateUserHash() - return nil - }, - } - common.Must(tuv.task.Start()) return tuv } -// visible for testing -func (v *TimedUserValidator) GetBaseTime() protocol.Timestamp { - return v.baseTime -} - -func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) { - var hashValue [16]byte - genEndSec := nowSec + cacheDurationSec - genHashForID := func(id *protocol.ID) { - idHash := v.hasher(id.Bytes()) - genBeginSec := user.lastSec - if genBeginSec < nowSec-cacheDurationSec { - genBeginSec = nowSec - cacheDurationSec - } - for ts := genBeginSec; ts <= genEndSec; ts++ { - common.Must2(serial.WriteUint64(idHash, uint64(ts))) - idHash.Sum(hashValue[:0]) - idHash.Reset() - - v.userHash[hashValue] = indexTimePair{ - user: user, - timeInc: uint32(ts - v.baseTime), - taintedFuse: new(uint32), - } - } - } - - account := user.user.Account.(*MemoryAccount) - - genHashForID(account.ID) - for _, id := range account.AlterIDs { - genHashForID(id) - } - user.lastSec = genEndSec -} - -func (v *TimedUserValidator) removeExpiredHashes(expire uint32) { - for key, pair := range v.userHash { - if pair.timeInc < expire { - delete(v.userHash, key) - } - } -} - -func (v *TimedUserValidator) updateUserHash() { - now := time.Now() - nowSec := protocol.Timestamp(now.Unix()) - - v.Lock() - defer v.Unlock() - - for _, user := range v.users { - v.generateNewHashes(nowSec, user) - } - - expire := protocol.Timestamp(now.Unix() - cacheDurationSec) - if expire > v.baseTime { - v.removeExpiredHashes(uint32(expire - v.baseTime)) - } -} - func (v *TimedUserValidator) Add(u *protocol.MemoryUser) error { v.Lock() defer v.Unlock() - nowSec := time.Now().Unix() + v.users = append(v.users, u) - uu := &user{ - user: *u, - lastSec: protocol.Timestamp(nowSec - cacheDurationSec), - } - v.users = append(v.users, uu) - v.generateNewHashes(protocol.Timestamp(nowSec), uu) - - account := uu.user.Account.(*MemoryAccount) + account := u.Account.(*MemoryAccount) if !v.behaviorFused { hashkdf := hmac.New(sha256.New, []byte("VMESSBSKDF")) hashkdf.Write(account.ID.Bytes()) @@ -159,25 +52,6 @@ func (v *TimedUserValidator) Add(u *protocol.MemoryUser) error { return nil } -func (v *TimedUserValidator) Get(userHash []byte) (*protocol.MemoryUser, protocol.Timestamp, bool, error) { - v.RLock() - defer v.RUnlock() - - v.behaviorFused = true - - var fixedSizeHash [16]byte - copy(fixedSizeHash[:], userHash) - pair, found := v.userHash[fixedSizeHash] - if found { - user := pair.user.user - if atomic.LoadUint32(pair.taintedFuse) == 0 { - return &user, protocol.Timestamp(pair.timeInc) + v.baseTime, true, nil - } - return nil, 0, false, ErrTainted - } - return nil, 0, false, ErrNotFound -} - func (v *TimedUserValidator) GetAEAD(userHash []byte) (*protocol.MemoryUser, bool, error) { v.RLock() defer v.RUnlock() @@ -199,10 +73,10 @@ func (v *TimedUserValidator) Remove(email string) bool { email = strings.ToLower(email) idx := -1 for i, u := range v.users { - if strings.EqualFold(u.user.Email, email) { + if strings.EqualFold(u.Email, email) { idx = i var cmdkeyfl [16]byte - copy(cmdkeyfl[:], u.user.Account.(*MemoryAccount).ID.CmdKey()) + copy(cmdkeyfl[:], u.Account.(*MemoryAccount).ID.CmdKey()) v.aeadDecoderHolder.RemoveUser(cmdkeyfl) break } @@ -219,11 +93,6 @@ func (v *TimedUserValidator) Remove(email string) bool { return true } -// Close implements common.Closable. -func (v *TimedUserValidator) Close() error { - return v.task.Close() -} - func (v *TimedUserValidator) GetBehaviorSeed() uint64 { v.Lock() defer v.Unlock() @@ -235,36 +104,6 @@ func (v *TimedUserValidator) GetBehaviorSeed() uint64 { return v.behaviorSeed } -func (v *TimedUserValidator) BurnTaintFuse(userHash []byte) error { - v.RLock() - defer v.RUnlock() - - var userHashFL [16]byte - copy(userHashFL[:], userHash) - - pair, found := v.userHash[userHashFL] - if found { - if atomic.CompareAndSwapUint32(pair.taintedFuse, 0, 1) { - return nil - } - return ErrTainted - } - return ErrNotFound -} - -/* - ShouldShowLegacyWarn will return whether a Legacy Warning should be shown - -Not guaranteed to only return true once for every inbound, but it is okay. -*/ -func (v *TimedUserValidator) ShouldShowLegacyWarn() bool { - if v.legacyWarnShown { - return false - } - v.legacyWarnShown = true - return true -} - var ErrNotFound = newError("Not Found") var ErrTainted = newError("ErrTainted") diff --git a/proxy/vmess/validator_test.go b/proxy/vmess/validator_test.go index ee170655..83313cbc 100644 --- a/proxy/vmess/validator_test.go +++ b/proxy/vmess/validator_test.go @@ -5,7 +5,6 @@ import ( "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/protocol" - "github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/uuid" . "github.com/xtls/xray-core/proxy/vmess" ) @@ -16,81 +15,9 @@ func toAccount(a *Account) protocol.Account { return account } -func TestUserValidator(t *testing.T) { - hasher := protocol.DefaultIDHash - v := NewTimedUserValidator(hasher) - defer common.Close(v) - - id := uuid.New() - user := &protocol.MemoryUser{ - Email: "test", - Account: toAccount(&Account{ - Id: id.String(), - }), - } - common.Must(v.Add(user)) - - { - testSmallLag := func(lag int64) { - ts := int64(v.GetBaseTime()) + lag + 240 - idHash := hasher(id.Bytes()) - common.Must2(serial.WriteUint64(idHash, uint64(ts))) - userHash := idHash.Sum(nil) - - euser, ets, found, _ := v.Get(userHash) - if !found { - t.Fatal("user not found") - } - if euser.Email != user.Email { - t.Error("unexpected user email: ", euser.Email, " want ", user.Email) - } - if int64(ets) != ts { - t.Error("unexpected timestamp: ", ets, " want ", ts) - } - } - - testSmallLag(0) - testSmallLag(40) - testSmallLag(-40) - testSmallLag(80) - testSmallLag(-80) - testSmallLag(120) - testSmallLag(-120) - } - - { - testBigLag := func(lag int64) { - ts := int64(v.GetBaseTime()) + lag + 240 - idHash := hasher(id.Bytes()) - common.Must2(serial.WriteUint64(idHash, uint64(ts))) - userHash := idHash.Sum(nil) - - euser, _, found, _ := v.Get(userHash) - if found || euser != nil { - t.Error("unexpected user") - } - } - - testBigLag(121) - testBigLag(-121) - testBigLag(310) - testBigLag(-310) - testBigLag(500) - testBigLag(-500) - } - - if v := v.Remove(user.Email); !v { - t.Error("unable to remove user") - } - if v := v.Remove(user.Email); v { - t.Error("remove user twice") - } -} - func BenchmarkUserValidator(b *testing.B) { for i := 0; i < b.N; i++ { - hasher := protocol.DefaultIDHash - v := NewTimedUserValidator(hasher) + v := NewTimedUserValidator() for j := 0; j < 1500; j++ { id := uuid.New() diff --git a/proxy/vmess/vmessCtxInterface.go b/proxy/vmess/vmessCtxInterface.go deleted file mode 100644 index 5d26f9e5..00000000 --- a/proxy/vmess/vmessCtxInterface.go +++ /dev/null @@ -1,4 +0,0 @@ -package vmess - -// example -const AlterID = "VMessCtxInterface_AlterID"