Browse Source

settings for forcing secure encryption in vmess server

Darien Raymond 7 năm trước cách đây
mục cha
commit
546c2fb226

+ 5 - 18
common/protocol/headers.go

@@ -38,24 +38,11 @@ const (
 	RequestOptionChunkMasking bitmask.Byte = 0x04
 )
 
-type Security byte
-
-func (s Security) Is(t SecurityType) bool {
-	return s == Security(t)
-}
-
-func NormSecurity(s Security) Security {
-	if s.Is(SecurityType_UNKNOWN) {
-		return Security(SecurityType_LEGACY)
-	}
-	return s
-}
-
 type RequestHeader struct {
 	Version  byte
 	Command  RequestCommand
 	Option   bitmask.Byte
-	Security Security
+	Security SecurityType
 	Port     net.Port
 	Address  net.Address
 	User     *User
@@ -88,14 +75,14 @@ type CommandSwitchAccount struct {
 	ValidMin byte
 }
 
-func (sc *SecurityConfig) AsSecurity() Security {
+func (sc *SecurityConfig) GetSecurityType() SecurityType {
 	if sc == nil || sc.Type == SecurityType_AUTO {
 		if runtime.GOARCH == "amd64" || runtime.GOARCH == "s390x" {
-			return Security(SecurityType_AES128_GCM)
+			return SecurityType_AES128_GCM
 		}
-		return Security(SecurityType_CHACHA20_POLY1305)
+		return SecurityType_CHACHA20_POLY1305
 	}
-	return NormSecurity(Security(sc.Type))
+	return sc.Type
 }
 
 func IsDomainTooLong(domain string) bool {

+ 2 - 2
proxy/vmess/account.go

@@ -9,7 +9,7 @@ import (
 type InternalAccount struct {
 	ID       *protocol.ID
 	AlterIDs []*protocol.ID
-	Security protocol.Security
+	Security protocol.SecurityType
 }
 
 func (a *InternalAccount) AnyValidID() *protocol.ID {
@@ -37,6 +37,6 @@ func (a *Account) AsAccount() (protocol.Account, error) {
 	return &InternalAccount{
 		ID:       protoID,
 		AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
-		Security: a.SecuritySettings.AsSecurity(),
+		Security: a.SecuritySettings.GetSecurityType(),
 	}, nil
 }

+ 14 - 24
proxy/vmess/encoding/client.go

@@ -128,7 +128,8 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 	if request.Option.Has(protocol.RequestOptionChunkMasking) {
 		sizeParser = NewShakeSizeParser(c.requestBodyIV)
 	}
-	if request.Security.Is(protocol.SecurityType_NONE) {
+	switch request.Security {
+	case protocol.SecurityType_NONE:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			if request.Command.TransferType() == protocol.TransferTypeStream {
 				return crypto.NewChunkStreamWriter(sizeParser, writer)
@@ -142,9 +143,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 		}
 
 		return buf.NewWriter(writer)
-	}
-
-	if request.Security.Is(protocol.SecurityType_LEGACY) {
+	case protocol.SecurityType_LEGACY:
 		aesStream := crypto.NewAesEncryptionStream(c.requestBodyKey, c.requestBodyIV)
 		cryptionWriter := crypto.NewCryptionWriter(aesStream, writer)
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
@@ -157,9 +156,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 		}
 
 		return buf.NewWriter(cryptionWriter)
-	}
-
-	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
+	case protocol.SecurityType_AES128_GCM:
 		block, _ := aes.NewCipher(c.requestBodyKey)
 		aead, _ := cipher.NewGCM(block)
 
@@ -172,9 +169,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
-	}
-
-	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
+	case protocol.SecurityType_CHACHA20_POLY1305:
 		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey))
 
 		auth := &crypto.AEADAuthenticator{
@@ -186,9 +181,9 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
+	default:
+		panic("Unknown security type.")
 	}
-
-	panic("Unknown security type.")
 }
 
 func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.ResponseHeader, error) {
@@ -231,7 +226,8 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
 	if request.Option.Has(protocol.RequestOptionChunkMasking) {
 		sizeParser = NewShakeSizeParser(c.responseBodyIV)
 	}
-	if request.Security.Is(protocol.SecurityType_NONE) {
+	switch request.Security {
+	case protocol.SecurityType_NONE:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			if request.Command.TransferType() == protocol.TransferTypeStream {
 				return crypto.NewChunkStreamReader(sizeParser, reader)
@@ -247,9 +243,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
 		}
 
 		return buf.NewReader(reader)
-	}
-
-	if request.Security.Is(protocol.SecurityType_LEGACY) {
+	case protocol.SecurityType_LEGACY:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			auth := &crypto.AEADAuthenticator{
 				AEAD:                    new(FnvAuthenticator),
@@ -260,9 +254,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
 		}
 
 		return buf.NewReader(c.responseReader)
-	}
-
-	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
+	case protocol.SecurityType_AES128_GCM:
 		block, _ := aes.NewCipher(c.responseBodyKey)
 		aead, _ := cipher.NewGCM(block)
 
@@ -275,9 +267,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
-	}
-
-	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
+	case protocol.SecurityType_CHACHA20_POLY1305:
 		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.responseBodyKey))
 
 		auth := &crypto.AEADAuthenticator{
@@ -289,9 +279,9 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
+	default:
+		panic("Unknown security type.")
 	}
-
-	panic("Unknown security type.")
 }
 
 type ChunkNonceGenerator struct {

+ 36 - 31
proxy/vmess/encoding/server.go

@@ -143,6 +143,13 @@ func readAddress(buffer *buf.Buffer, reader io.Reader) (net.Address, net.Port, e
 	return address, port, nil
 }
 
+func parseSecurityType(b byte) protocol.SecurityType {
+	if _, f := protocol.SecurityType_name[int32(b)]; f {
+		return protocol.SecurityType(b)
+	}
+	return protocol.SecurityType_UNKNOWN
+}
+
 func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) {
 	buffer := buf.New()
 	defer buffer.Release()
@@ -191,11 +198,24 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	s.responseHeader = buffer.Byte(33)             // 1 byte
 	request.Option = bitmask.Byte(buffer.Byte(34)) // 1 byte
 	padingLen := int(buffer.Byte(35) >> 4)
-	request.Security = protocol.NormSecurity(protocol.Security(buffer.Byte(35) & 0x0F))
+	request.Security = parseSecurityType(buffer.Byte(35) & 0x0F)
 	// 1 bytes reserved
 	request.Command = protocol.RequestCommand(buffer.Byte(37))
 
 	var invalidRequestErr error
+	defer func() {
+		if invalidRequestErr != nil {
+			randomLen := dice.Roll(64) + 1
+			// Read random number of bytes for prevent detection.
+			buffer.AppendSupplier(buf.ReadFullFrom(decryptor, randomLen))
+		}
+	}()
+
+	if request.Security == protocol.SecurityType_UNKNOWN || request.Security == protocol.SecurityType_AUTO {
+		invalidRequestErr = newError("unknown security type")
+		return nil, invalidRequestErr
+	}
+
 	switch request.Command {
 	case protocol.RequestCommandMux:
 		request.Address = net.DomainAddress("v1.mux.cool")
@@ -206,15 +226,10 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 			request.Port = port
 		} else {
 			invalidRequestErr = newError("invalid address").Base(err)
+			return nil, invalidRequestErr
 		}
 	default:
 		invalidRequestErr = newError("invalid request command: ", request.Command)
-	}
-
-	if invalidRequestErr != nil {
-		randomLen := dice.Roll(32) + 1
-		// Read random number of bytes for prevent detection.
-		buffer.AppendSupplier(buf.ReadFullFrom(decryptor, randomLen))
 		return nil, invalidRequestErr
 	}
 
@@ -249,7 +264,8 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
 	if request.Option.Has(protocol.RequestOptionChunkMasking) {
 		sizeParser = NewShakeSizeParser(s.requestBodyIV)
 	}
-	if request.Security.Is(protocol.SecurityType_NONE) {
+	switch request.Security {
+	case protocol.SecurityType_NONE:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			if request.Command.TransferType() == protocol.TransferTypeStream {
 				return crypto.NewChunkStreamReader(sizeParser, reader)
@@ -264,9 +280,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
 		}
 
 		return buf.NewReader(reader)
-	}
-
-	if request.Security.Is(protocol.SecurityType_LEGACY) {
+	case protocol.SecurityType_LEGACY:
 		aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey, s.requestBodyIV)
 		cryptionReader := crypto.NewCryptionReader(aesStream, reader)
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
@@ -279,9 +293,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
 		}
 
 		return buf.NewReader(cryptionReader)
-	}
-
-	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
+	case protocol.SecurityType_AES128_GCM:
 		block, _ := aes.NewCipher(s.requestBodyKey)
 		aead, _ := cipher.NewGCM(block)
 
@@ -294,9 +306,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
-	}
-
-	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
+	case protocol.SecurityType_CHACHA20_POLY1305:
 		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey))
 
 		auth := &crypto.AEADAuthenticator{
@@ -308,9 +318,9 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType())
+	default:
+		panic("Unknown security type.")
 	}
-
-	panic("Unknown security type.")
 }
 
 func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) {
@@ -335,7 +345,8 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
 	if request.Option.Has(protocol.RequestOptionChunkMasking) {
 		sizeParser = NewShakeSizeParser(s.responseBodyIV)
 	}
-	if request.Security.Is(protocol.SecurityType_NONE) {
+	switch request.Security {
+	case protocol.SecurityType_NONE:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			if request.Command.TransferType() == protocol.TransferTypeStream {
 				return crypto.NewChunkStreamWriter(sizeParser, writer)
@@ -350,9 +361,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
 		}
 
 		return buf.NewWriter(writer)
-	}
-
-	if request.Security.Is(protocol.SecurityType_LEGACY) {
+	case protocol.SecurityType_LEGACY:
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			auth := &crypto.AEADAuthenticator{
 				AEAD:                    new(FnvAuthenticator),
@@ -363,9 +372,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
 		}
 
 		return buf.NewWriter(s.responseWriter)
-	}
-
-	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
+	case protocol.SecurityType_AES128_GCM:
 		block, _ := aes.NewCipher(s.responseBodyKey)
 		aead, _ := cipher.NewGCM(block)
 
@@ -378,9 +385,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
-	}
-
-	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
+	case protocol.SecurityType_CHACHA20_POLY1305:
 		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey))
 
 		auth := &crypto.AEADAuthenticator{
@@ -392,7 +397,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 		}
 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType())
+	default:
+		panic("Unknown security type.")
 	}
-
-	panic("Unknown security type.")
 }

+ 33 - 23
proxy/vmess/inbound/config.pb.go

@@ -57,9 +57,10 @@ func (m *DefaultConfig) GetLevel() uint32 {
 }
 
 type Config struct {
-	User    []*v2ray_core_common_protocol.User `protobuf:"bytes,1,rep,name=user" json:"user,omitempty"`
-	Default *DefaultConfig                     `protobuf:"bytes,2,opt,name=default" json:"default,omitempty"`
-	Detour  *DetourConfig                      `protobuf:"bytes,3,opt,name=detour" json:"detour,omitempty"`
+	User                 []*v2ray_core_common_protocol.User `protobuf:"bytes,1,rep,name=user" json:"user,omitempty"`
+	Default              *DefaultConfig                     `protobuf:"bytes,2,opt,name=default" json:"default,omitempty"`
+	Detour               *DetourConfig                      `protobuf:"bytes,3,opt,name=detour" json:"detour,omitempty"`
+	SecureEncryptionOnly bool                               `protobuf:"varint,4,opt,name=secure_encryption_only,json=secureEncryptionOnly" json:"secure_encryption_only,omitempty"`
 }
 
 func (m *Config) Reset()                    { *m = Config{} }
@@ -88,6 +89,13 @@ func (m *Config) GetDetour() *DetourConfig {
 	return nil
 }
 
+func (m *Config) GetSecureEncryptionOnly() bool {
+	if m != nil {
+		return m.SecureEncryptionOnly
+	}
+	return false
+}
+
 func init() {
 	proto.RegisterType((*DetourConfig)(nil), "v2ray.core.proxy.vmess.inbound.DetourConfig")
 	proto.RegisterType((*DefaultConfig)(nil), "v2ray.core.proxy.vmess.inbound.DefaultConfig")
@@ -97,24 +105,26 @@ func init() {
 func init() { proto.RegisterFile("v2ray.com/core/proxy/vmess/inbound/config.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 297 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0xcf, 0x4e, 0x83, 0x40,
-	0x10, 0xc6, 0x03, 0xd5, 0xa2, 0x5b, 0xeb, 0x81, 0x78, 0x40, 0x0f, 0x84, 0x70, 0xaa, 0x89, 0xce,
-	0x26, 0xe8, 0x03, 0x18, 0x4b, 0x62, 0x7a, 0x23, 0x9b, 0xd8, 0x83, 0x17, 0x43, 0x97, 0xad, 0x21,
-	0x01, 0xa6, 0x59, 0x16, 0x22, 0xaf, 0xe4, 0xbb, 0xf8, 0x4e, 0xa6, 0x03, 0xc4, 0x3f, 0x07, 0x7b,
-	0xdb, 0xd9, 0xfc, 0xbe, 0x6f, 0xbe, 0x6f, 0x18, 0x6f, 0x23, 0x9d, 0x76, 0x20, 0xb1, 0xe4, 0x12,
-	0xb5, 0xe2, 0x3b, 0x8d, 0xef, 0x1d, 0x6f, 0x4b, 0x55, 0xd7, 0x3c, 0xaf, 0x36, 0xd8, 0x54, 0x19,
-	0x97, 0x58, 0x6d, 0xf3, 0x37, 0xd8, 0x69, 0x34, 0xe8, 0xfa, 0xa3, 0x40, 0x2b, 0x20, 0x18, 0x08,
-	0x86, 0x01, 0xbe, 0xba, 0xfe, 0x63, 0x28, 0xb1, 0x2c, 0xb1, 0xe2, 0x24, 0x96, 0x58, 0xf0, 0xa6,
-	0x56, 0xba, 0xb7, 0x0a, 0x7d, 0x76, 0x16, 0x2b, 0x83, 0x8d, 0x5e, 0xd2, 0x02, 0xf7, 0x9c, 0xd9,
-	0x06, 0x3d, 0x2b, 0xb0, 0x16, 0xa7, 0xc2, 0x36, 0x18, 0x3e, 0xb0, 0x79, 0xac, 0xb6, 0x69, 0x53,
-	0x98, 0x01, 0xb8, 0x64, 0x27, 0x69, 0x61, 0x94, 0x7e, 0xcd, 0x33, 0xc2, 0xe6, 0xc2, 0xa1, 0x79,
-	0x95, 0xb9, 0x17, 0xec, 0xb8, 0x50, 0xad, 0x2a, 0x3c, 0x9b, 0xfe, 0xfb, 0x21, 0xfc, 0xb4, 0xd8,
-	0x74, 0xd0, 0xde, 0xb3, 0xa3, 0xfd, 0x6a, 0xcf, 0x0a, 0x26, 0x8b, 0x59, 0x14, 0xc0, 0x8f, 0x1a,
-	0x7d, 0x44, 0x18, 0x23, 0xc2, 0x73, 0xad, 0xb4, 0x20, 0xda, 0x7d, 0x62, 0x4e, 0xd6, 0x47, 0x20,
-	0xe3, 0x59, 0x74, 0x0b, 0xff, 0xf7, 0x87, 0x5f, 0x89, 0xc5, 0xa8, 0x76, 0x63, 0x36, 0xcd, 0xa8,
-	0xab, 0x37, 0x21, 0x9f, 0x9b, 0xc3, 0x3e, 0xdf, 0x97, 0x11, 0x83, 0xf6, 0x31, 0x61, 0xa1, 0xc4,
-	0xf2, 0x80, 0x34, 0xb1, 0x5e, 0x9c, 0xe1, 0xf9, 0x61, 0xfb, 0xeb, 0x48, 0xa4, 0x1d, 0x2c, 0xf7,
-	0x6c, 0x42, 0xec, 0x9a, 0xd8, 0x55, 0x0f, 0x6c, 0xa6, 0xd4, 0xfa, 0xee, 0x2b, 0x00, 0x00, 0xff,
-	0xff, 0x8d, 0x37, 0x9e, 0x90, 0x08, 0x02, 0x00, 0x00,
+	// 333 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0x4f, 0x4f, 0xf2, 0x40,
+	0x10, 0xc6, 0xd3, 0xc2, 0x0b, 0xbc, 0x8b, 0x78, 0x68, 0x88, 0xa9, 0x1e, 0x48, 0xd3, 0x13, 0x26,
+	0xba, 0x9b, 0x54, 0x3e, 0x80, 0x11, 0x8c, 0xe1, 0x24, 0x69, 0x22, 0x07, 0x2f, 0xa4, 0x6c, 0x07,
+	0xd3, 0x64, 0xbb, 0x43, 0xb6, 0x5b, 0x62, 0xcf, 0x7e, 0x1b, 0x3f, 0xa5, 0x61, 0x5a, 0xfc, 0x77,
+	0x90, 0xdb, 0xce, 0xce, 0xef, 0x79, 0xe6, 0x99, 0x61, 0x62, 0x17, 0x99, 0xa4, 0xe2, 0x12, 0x73,
+	0x21, 0xd1, 0x80, 0xd8, 0x1a, 0x7c, 0xad, 0xc4, 0x2e, 0x87, 0xa2, 0x10, 0x99, 0x5e, 0x63, 0xa9,
+	0x53, 0x21, 0x51, 0x6f, 0xb2, 0x17, 0xbe, 0x35, 0x68, 0xd1, 0x1b, 0x1d, 0x04, 0x06, 0x38, 0xc1,
+	0x9c, 0x60, 0xde, 0xc0, 0x17, 0x97, 0xbf, 0x0c, 0x25, 0xe6, 0x39, 0x6a, 0x41, 0x62, 0x89, 0x4a,
+	0x94, 0x05, 0x98, 0xda, 0x2a, 0x1c, 0xb1, 0x93, 0x19, 0x58, 0x2c, 0xcd, 0x94, 0x06, 0x78, 0xa7,
+	0xcc, 0xb5, 0xe8, 0x3b, 0x81, 0x33, 0xfe, 0x1f, 0xbb, 0x16, 0xc3, 0x5b, 0x36, 0x98, 0xc1, 0x26,
+	0x29, 0x95, 0x6d, 0x80, 0x73, 0xd6, 0x4b, 0x94, 0x05, 0xb3, 0xca, 0x52, 0xc2, 0x06, 0x71, 0x97,
+	0xea, 0x79, 0xea, 0x0d, 0xd9, 0x3f, 0x05, 0x3b, 0x50, 0xbe, 0x4b, 0xff, 0x75, 0x11, 0xbe, 0xb9,
+	0xac, 0xd3, 0x68, 0x27, 0xac, 0xbd, 0x1f, 0xed, 0x3b, 0x41, 0x6b, 0xdc, 0x8f, 0x02, 0xfe, 0x6d,
+	0x8d, 0x3a, 0x22, 0x3f, 0x44, 0xe4, 0x4f, 0x05, 0x98, 0x98, 0x68, 0xef, 0x81, 0x75, 0xd3, 0x3a,
+	0x02, 0x19, 0xf7, 0xa3, 0x6b, 0xfe, 0xf7, 0xfe, 0xfc, 0x47, 0xe2, 0xf8, 0xa0, 0xf6, 0x66, 0xac,
+	0x93, 0xd2, 0xae, 0x7e, 0x8b, 0x7c, 0xae, 0x8e, 0xfb, 0x7c, 0x5d, 0x26, 0x6e, 0xb4, 0xde, 0x84,
+	0x9d, 0x15, 0x20, 0x4b, 0x03, 0x2b, 0xd0, 0xd2, 0x54, 0x5b, 0x9b, 0xa1, 0x5e, 0xa1, 0x56, 0x95,
+	0xdf, 0x0e, 0x9c, 0x71, 0x2f, 0x1e, 0xd6, 0xdd, 0xfb, 0xcf, 0xe6, 0xa3, 0x56, 0xd5, 0xdd, 0x82,
+	0x85, 0x12, 0xf3, 0x23, 0x03, 0x17, 0xce, 0x73, 0xb7, 0x79, 0xbe, 0xbb, 0xa3, 0x65, 0x14, 0x27,
+	0x15, 0x9f, 0xee, 0xd9, 0x05, 0xb1, 0x4b, 0x62, 0xe7, 0x35, 0xb0, 0xee, 0xd0, 0xad, 0x6e, 0x3e,
+	0x02, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x49, 0x84, 0xe1, 0x3e, 0x02, 0x00, 0x00,
 }

+ 2 - 1
proxy/vmess/inbound/config.proto

@@ -21,4 +21,5 @@ message Config {
   repeated v2ray.core.common.protocol.User user = 1;
   DefaultConfig default = 2;
   DetourConfig detour = 3;
-}
+  bool secure_encryption_only = 4;
+}

+ 16 - 0
proxy/vmess/inbound/inbound.go

@@ -101,6 +101,7 @@ type Handler struct {
 	usersByEmail          *userByEmail
 	detours               *DetourConfig
 	sessionHistory        *encoding.SessionHistory
+	secure                bool
 }
 
 // New creates a new VMess inbound handler.
@@ -113,6 +114,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
 		detours:               config.Detour,
 		usersByEmail:          newUserByEmail(config.GetDefaultValue()),
 		sessionHistory:        encoding.NewSessionHistory(),
+		secure:                config.SecureEncryptionOnly,
 	}
 
 	for _, user := range config.User {
@@ -210,6 +212,10 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
 	return nil
 }
 
+func isInecureEncryption(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 internet.Connection, dispatcher core.Dispatcher) error {
 	sessionPolicy := h.policyManager.ForLevel(0)
@@ -235,6 +241,16 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
 		return err
 	}
 
+	if h.secure && isInecureEncryption(request.Security) {
+		log.Record(&log.AccessMessage{
+			From:   connection.RemoteAddr(),
+			To:     "",
+			Status: log.AccessRejected,
+			Reason: "Insecure encryption",
+		})
+		return newError("client is using insecure encryption: ", request.Security)
+	}
+
 	log.Record(&log.AccessMessage{
 		From:   connection.RemoteAddr(),
 		To:     request.Destination(),

+ 1 - 1
proxy/vmess/outbound/outbound.go

@@ -91,7 +91,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 	account := rawAccount.(*vmess.InternalAccount)
 	request.Security = account.Security
 
-	if request.Security.Is(protocol.SecurityType_AES128_GCM) || request.Security.Is(protocol.SecurityType_NONE) || request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
+	if request.Security == protocol.SecurityType_AES128_GCM || request.Security == protocol.SecurityType_NONE || request.Security == protocol.SecurityType_CHACHA20_POLY1305 {
 		request.Option.Set(protocol.RequestOptionChunkMasking)
 	}