| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 | package encodingimport (	"crypto/aes"	"crypto/cipher"	"crypto/md5"	"hash/fnv"	"io"	"golang.org/x/crypto/chacha20poly1305"	"v2ray.com/core/common/buf"	"v2ray.com/core/common/crypto"	"v2ray.com/core/common/errors"	"v2ray.com/core/common/log"	v2net "v2ray.com/core/common/net"	"v2ray.com/core/common/protocol"	"v2ray.com/core/common/serial"	"v2ray.com/core/proxy/vmess")type ServerSession struct {	userValidator   protocol.UserValidator	requestBodyKey  []byte	requestBodyIV   []byte	responseBodyKey []byte	responseBodyIV  []byte	responseHeader  byte	responseWriter  io.Writer}// NewServerSession creates a new ServerSession, using the given UserValidator.// The ServerSession instance doesn't take ownership of the validator.func NewServerSession(validator protocol.UserValidator) *ServerSession {	return &ServerSession{		userValidator: validator,	}}func (v *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) {	buffer := make([]byte, 512)	_, err := io.ReadFull(reader, buffer[:protocol.IDBytesLen])	if err != nil {		log.Info("VMess|Server: Failed to read request header: ", err)		return nil, io.EOF	}	user, timestamp, valid := v.userValidator.Get(buffer[:protocol.IDBytesLen])	if !valid {		return nil, errors.New("VMess|Server: Invalid user.")	}	timestampHash := md5.New()	timestampHash.Write(hashTimestamp(timestamp))	iv := timestampHash.Sum(nil)	account, err := user.GetTypedAccount()	if err != nil {		return nil, errors.Base(err).Message("VMess|Server: Failed to get user account.")	}	aesStream := crypto.NewAesDecryptionStream(account.(*vmess.InternalAccount).ID.CmdKey(), iv)	decryptor := crypto.NewCryptionReader(aesStream, reader)	nBytes, err := io.ReadFull(decryptor, buffer[:41])	if err != nil {		return nil, errors.Base(err).Message("VMess|Server: Failed to read request header.")	}	bufferLen := nBytes	request := &protocol.RequestHeader{		User:    user,		Version: buffer[0],	}	if request.Version != Version {		return nil, errors.New("VMess|Server: Invalid protocol version ", request.Version)	}	v.requestBodyIV = append([]byte(nil), buffer[1:17]...)   // 16 bytes	v.requestBodyKey = append([]byte(nil), buffer[17:33]...) // 16 bytes	v.responseHeader = buffer[33]                            // 1 byte	request.Option = protocol.RequestOption(buffer[34])      // 1 byte	padingLen := int(buffer[35] >> 4)	request.Security = protocol.NormSecurity(protocol.Security(buffer[35] & 0x0F))	// 1 bytes reserved	request.Command = protocol.RequestCommand(buffer[37])	request.Port = v2net.PortFromBytes(buffer[38:40])	switch buffer[40] {	case AddrTypeIPv4:		_, err = io.ReadFull(decryptor, buffer[41:45]) // 4 bytes		bufferLen += 4		if err != nil {			return nil, errors.Base(err).Message("VMess|Server: Failed to read IPv4.")		}		request.Address = v2net.IPAddress(buffer[41:45])	case AddrTypeIPv6:		_, err = io.ReadFull(decryptor, buffer[41:57]) // 16 bytes		bufferLen += 16		if err != nil {			return nil, errors.Base(err).Message("VMess|Server: Failed to read IPv6 address.")		}		request.Address = v2net.IPAddress(buffer[41:57])	case AddrTypeDomain:		_, err = io.ReadFull(decryptor, buffer[41:42])		if err != nil {			return nil, errors.Base(err).Message("VMess:Server: Failed to read domain.")		}		domainLength := int(buffer[41])		if domainLength == 0 {			return nil, errors.New("VMess|Server: Zero length domain.")		}		_, err = io.ReadFull(decryptor, buffer[42:42+domainLength])		if err != nil {			return nil, errors.Base(err).Message("VMess|Server: Failed to read domain.")		}		bufferLen += 1 + domainLength		request.Address = v2net.DomainAddress(string(buffer[42 : 42+domainLength]))	}	if padingLen > 0 {		_, err = io.ReadFull(decryptor, buffer[bufferLen:bufferLen+padingLen])		if err != nil {			return nil, errors.New("VMess|Server: Failed to read padding.")		}		bufferLen += padingLen	}	_, err = io.ReadFull(decryptor, buffer[bufferLen:bufferLen+4])	if err != nil {		return nil, errors.Base(err).Message("VMess|Server: Failed to read checksum.")	}	fnv1a := fnv.New32a()	fnv1a.Write(buffer[:bufferLen])	actualHash := fnv1a.Sum32()	expectedHash := serial.BytesToUint32(buffer[bufferLen : bufferLen+4])	if actualHash != expectedHash {		return nil, errors.New("VMess|Server: Invalid auth.")	}	if request.Address == nil {		return nil, errors.New("VMess|Server: Invalid remote address.")	}	return request, nil}func (v *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader {	aggressive := (request.Command == protocol.RequestCommandTCP)	var authReader io.Reader	if request.Security.Is(protocol.SecurityType_NONE) {		if request.Option.Has(protocol.RequestOptionChunkStream) {			auth := &crypto.AEADAuthenticator{				AEAD:                    new(FnvAuthenticator),				NonceGenerator:          crypto.NoOpBytesGenerator{},				AdditionalDataGenerator: crypto.NoOpBytesGenerator{},			}			authReader = crypto.NewAuthenticationReader(auth, reader, aggressive)		} else {			authReader = reader		}	} else if request.Security.Is(protocol.SecurityType_LEGACY) {		aesStream := crypto.NewAesDecryptionStream(v.requestBodyKey, v.requestBodyIV)		cryptionReader := crypto.NewCryptionReader(aesStream, reader)		if request.Option.Has(protocol.RequestOptionChunkStream) {			auth := &crypto.AEADAuthenticator{				AEAD:                    new(FnvAuthenticator),				NonceGenerator:          crypto.NoOpBytesGenerator{},				AdditionalDataGenerator: crypto.NoOpBytesGenerator{},			}			authReader = crypto.NewAuthenticationReader(auth, cryptionReader, aggressive)		} else {			authReader = cryptionReader		}	} else if request.Security.Is(protocol.SecurityType_AES128_GCM) {		block, _ := aes.NewCipher(v.requestBodyKey)		aead, _ := cipher.NewGCM(block)		auth := &crypto.AEADAuthenticator{			AEAD: aead,			NonceGenerator: &ChunkNonceGenerator{				Nonce: append([]byte(nil), v.requestBodyIV...),				Size:  aead.NonceSize(),			},			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},		}		authReader = crypto.NewAuthenticationReader(auth, reader, aggressive)	} else if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(v.requestBodyKey))		auth := &crypto.AEADAuthenticator{			AEAD: aead,			NonceGenerator: &ChunkNonceGenerator{				Nonce: append([]byte(nil), v.requestBodyIV...),				Size:  aead.NonceSize(),			},			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},		}		authReader = crypto.NewAuthenticationReader(auth, reader, aggressive)	}	return buf.NewReader(authReader)}func (v *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) {	responseBodyKey := md5.Sum(v.requestBodyKey)	responseBodyIV := md5.Sum(v.requestBodyIV)	v.responseBodyKey = responseBodyKey[:]	v.responseBodyIV = responseBodyIV[:]	aesStream := crypto.NewAesEncryptionStream(v.responseBodyKey, v.responseBodyIV)	encryptionWriter := crypto.NewCryptionWriter(aesStream, writer)	v.responseWriter = encryptionWriter	encryptionWriter.Write([]byte{v.responseHeader, byte(header.Option)})	err := MarshalCommand(header.Command, encryptionWriter)	if err != nil {		encryptionWriter.Write([]byte{0x00, 0x00})	}}func (v *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {	var authWriter io.Writer	if request.Security.Is(protocol.SecurityType_NONE) {		if request.Option.Has(protocol.RequestOptionChunkStream) {			auth := &crypto.AEADAuthenticator{				AEAD:                    new(FnvAuthenticator),				NonceGenerator:          crypto.NoOpBytesGenerator{},				AdditionalDataGenerator: crypto.NoOpBytesGenerator{},			}			authWriter = crypto.NewAuthenticationWriter(auth, writer)		} else {			authWriter = writer		}	} else if request.Security.Is(protocol.SecurityType_LEGACY) {		if request.Option.Has(protocol.RequestOptionChunkStream) {			auth := &crypto.AEADAuthenticator{				AEAD:                    new(FnvAuthenticator),				NonceGenerator:          crypto.NoOpBytesGenerator{},				AdditionalDataGenerator: crypto.NoOpBytesGenerator{},			}			authWriter = crypto.NewAuthenticationWriter(auth, v.responseWriter)		} else {			authWriter = v.responseWriter		}	} else if request.Security.Is(protocol.SecurityType_AES128_GCM) {		block, _ := aes.NewCipher(v.responseBodyKey)		aead, _ := cipher.NewGCM(block)		auth := &crypto.AEADAuthenticator{			AEAD: aead,			NonceGenerator: &ChunkNonceGenerator{				Nonce: append([]byte(nil), v.responseBodyIV...),				Size:  aead.NonceSize(),			},			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},		}		authWriter = crypto.NewAuthenticationWriter(auth, writer)	} else if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(v.responseBodyKey))		auth := &crypto.AEADAuthenticator{			AEAD: aead,			NonceGenerator: &ChunkNonceGenerator{				Nonce: append([]byte(nil), v.responseBodyIV...),				Size:  aead.NonceSize(),			},			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},		}		authWriter = crypto.NewAuthenticationWriter(auth, writer)	}	return buf.NewWriter(authWriter)}
 |