github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/proxy/vmess/encoding/server.go (about) 1 package encoding 2 3 import ( 4 "bytes" 5 "crypto/aes" 6 "crypto/cipher" 7 "crypto/md5" 8 "crypto/sha256" 9 "encoding/binary" 10 "hash/fnv" 11 "io" 12 "io/ioutil" 13 "sync" 14 "time" 15 16 "golang.org/x/crypto/chacha20poly1305" 17 "v2ray.com/core/common" 18 "v2ray.com/core/common/bitmask" 19 "v2ray.com/core/common/buf" 20 "v2ray.com/core/common/crypto" 21 "v2ray.com/core/common/dice" 22 "v2ray.com/core/common/net" 23 "v2ray.com/core/common/protocol" 24 "v2ray.com/core/common/task" 25 "v2ray.com/core/proxy/vmess" 26 vmessaead "v2ray.com/core/proxy/vmess/aead" 27 ) 28 29 type sessionId struct { 30 user [16]byte 31 key [16]byte 32 nonce [16]byte 33 } 34 35 // SessionHistory keeps track of historical session ids, to prevent replay attacks. 36 type SessionHistory struct { 37 sync.RWMutex 38 cache map[sessionId]time.Time 39 task *task.Periodic 40 } 41 42 // NewSessionHistory creates a new SessionHistory object. 43 func NewSessionHistory() *SessionHistory { 44 h := &SessionHistory{ 45 cache: make(map[sessionId]time.Time, 128), 46 } 47 h.task = &task.Periodic{ 48 Interval: time.Second * 30, 49 Execute: h.removeExpiredEntries, 50 } 51 return h 52 } 53 54 // Close implements common.Closable. 55 func (h *SessionHistory) Close() error { 56 return h.task.Close() 57 } 58 59 func (h *SessionHistory) addIfNotExits(session sessionId) bool { 60 h.Lock() 61 62 if expire, found := h.cache[session]; found && expire.After(time.Now()) { 63 h.Unlock() 64 return false 65 } 66 67 h.cache[session] = time.Now().Add(time.Minute * 3) 68 h.Unlock() 69 common.Must(h.task.Start()) 70 return true 71 } 72 73 func (h *SessionHistory) removeExpiredEntries() error { 74 now := time.Now() 75 76 h.Lock() 77 defer h.Unlock() 78 79 if len(h.cache) == 0 { 80 return newError("nothing to do") 81 } 82 83 for session, expire := range h.cache { 84 if expire.Before(now) { 85 delete(h.cache, session) 86 } 87 } 88 89 if len(h.cache) == 0 { 90 h.cache = make(map[sessionId]time.Time, 128) 91 } 92 93 return nil 94 } 95 96 // ServerSession keeps information for a session in VMess server. 97 type ServerSession struct { 98 userValidator *vmess.TimedUserValidator 99 sessionHistory *SessionHistory 100 requestBodyKey [16]byte 101 requestBodyIV [16]byte 102 responseBodyKey [16]byte 103 responseBodyIV [16]byte 104 responseWriter io.Writer 105 responseHeader byte 106 107 isAEADRequest bool 108 109 isAEADForced bool 110 } 111 112 // NewServerSession creates a new ServerSession, using the given UserValidator. 113 // The ServerSession instance doesn't take ownership of the validator. 114 func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *SessionHistory) *ServerSession { 115 return &ServerSession{ 116 userValidator: validator, 117 sessionHistory: sessionHistory, 118 } 119 } 120 121 func parseSecurityType(b byte) protocol.SecurityType { 122 if _, f := protocol.SecurityType_name[int32(b)]; f { 123 st := protocol.SecurityType(b) 124 // For backward compatibility. 125 if st == protocol.SecurityType_UNKNOWN { 126 st = protocol.SecurityType_LEGACY 127 } 128 return st 129 } 130 return protocol.SecurityType_UNKNOWN 131 } 132 133 // DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. 134 func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) { 135 buffer := buf.New() 136 behaviorRand := dice.NewDeterministicDice(int64(s.userValidator.GetBehaviorSeed())) 137 BaseDrainSize := behaviorRand.Roll(3266) 138 RandDrainMax := behaviorRand.Roll(64) + 1 139 RandDrainRolled := dice.Roll(RandDrainMax) 140 DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled 141 readSizeRemain := DrainSize 142 143 drainConnection := func(e error) error { 144 //We read a deterministic generated length of data before closing the connection to offset padding read pattern 145 readSizeRemain -= int(buffer.Len()) 146 if readSizeRemain > 0 { 147 err := s.DrainConnN(reader, readSizeRemain) 148 if err != nil { 149 return newError("failed to drain connection DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(err).Base(e) 150 } 151 return newError("connection drained DrainSize = ", BaseDrainSize, " ", RandDrainMax, " ", RandDrainRolled).Base(e) 152 } 153 return e 154 } 155 156 defer func() { 157 buffer.Release() 158 }() 159 160 if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil { 161 return nil, newError("failed to read request header").Base(err) 162 } 163 164 var decryptor io.Reader 165 var vmessAccount *vmess.MemoryAccount 166 167 user, foundAEAD, errorAEAD := s.userValidator.GetAEAD(buffer.Bytes()) 168 169 var fixedSizeAuthID [16]byte 170 copy(fixedSizeAuthID[:], buffer.Bytes()) 171 172 if foundAEAD { 173 vmessAccount = user.Account.(*vmess.MemoryAccount) 174 var fixedSizeCmdKey [16]byte 175 copy(fixedSizeCmdKey[:], vmessAccount.ID.CmdKey()) 176 aeadData, shouldDrain, errorReason, bytesRead := vmessaead.OpenVMessAEADHeader(fixedSizeCmdKey, fixedSizeAuthID, reader) 177 if errorReason != nil { 178 if shouldDrain { 179 readSizeRemain -= bytesRead 180 return nil, drainConnection(newError("AEAD read failed").Base(errorReason)) 181 } else { 182 return nil, drainConnection(newError("AEAD read failed, drain skiped").Base(errorReason)) 183 } 184 } 185 decryptor = bytes.NewReader(aeadData) 186 s.isAEADRequest = true 187 } else if !s.isAEADForced && errorAEAD == vmessaead.ErrNotFound { 188 userLegacy, timestamp, valid, userValidationError := s.userValidator.Get(buffer.Bytes()) 189 if !valid || userValidationError != nil { 190 return nil, drainConnection(newError("invalid user").Base(userValidationError)) 191 } 192 user = userLegacy 193 iv := hashTimestamp(md5.New(), timestamp) 194 vmessAccount = userLegacy.Account.(*vmess.MemoryAccount) 195 196 aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv[:]) 197 decryptor = crypto.NewCryptionReader(aesStream, reader) 198 } else { 199 return nil, drainConnection(newError("invalid user").Base(errorAEAD)) 200 } 201 202 readSizeRemain -= int(buffer.Len()) 203 buffer.Clear() 204 if _, err := buffer.ReadFullFrom(decryptor, 38); err != nil { 205 return nil, newError("failed to read request header").Base(err) 206 } 207 208 request := &protocol.RequestHeader{ 209 User: user, 210 Version: buffer.Byte(0), 211 } 212 213 copy(s.requestBodyIV[:], buffer.BytesRange(1, 17)) // 16 bytes 214 copy(s.requestBodyKey[:], buffer.BytesRange(17, 33)) // 16 bytes 215 var sid sessionId 216 copy(sid.user[:], vmessAccount.ID.Bytes()) 217 sid.key = s.requestBodyKey 218 sid.nonce = s.requestBodyIV 219 if !s.sessionHistory.addIfNotExits(sid) { 220 if !s.isAEADRequest { 221 drainErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 222 if drainErr != nil { 223 return nil, drainConnection(newError("duplicated session id, possibly under replay attack, and failed to taint userHash").Base(drainErr)) 224 } 225 return nil, drainConnection(newError("duplicated session id, possibly under replay attack, userHash tainted")) 226 } else { 227 return nil, newError("duplicated session id, possibly under replay attack, but this is a AEAD request") 228 } 229 230 } 231 232 s.responseHeader = buffer.Byte(33) // 1 byte 233 request.Option = bitmask.Byte(buffer.Byte(34)) // 1 byte 234 padingLen := int(buffer.Byte(35) >> 4) 235 request.Security = parseSecurityType(buffer.Byte(35) & 0x0F) 236 // 1 bytes reserved 237 request.Command = protocol.RequestCommand(buffer.Byte(37)) 238 239 switch request.Command { 240 case protocol.RequestCommandMux: 241 request.Address = net.DomainAddress("v1.mux.cool") 242 request.Port = 0 243 case protocol.RequestCommandTCP, protocol.RequestCommandUDP: 244 if addr, port, err := addrParser.ReadAddressPort(buffer, decryptor); err == nil { 245 request.Address = addr 246 request.Port = port 247 } 248 } 249 250 if padingLen > 0 { 251 if _, err := buffer.ReadFullFrom(decryptor, int32(padingLen)); err != nil { 252 if !s.isAEADRequest { 253 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 254 if burnErr != nil { 255 return nil, newError("failed to read padding, failed to taint userHash").Base(burnErr).Base(err) 256 } 257 return nil, newError("failed to read padding, userHash tainted").Base(err) 258 } 259 return nil, newError("failed to read padding").Base(err) 260 } 261 } 262 263 if _, err := buffer.ReadFullFrom(decryptor, 4); err != nil { 264 if !s.isAEADRequest { 265 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 266 if burnErr != nil { 267 return nil, newError("failed to read checksum, failed to taint userHash").Base(burnErr).Base(err) 268 } 269 return nil, newError("failed to read checksum, userHash tainted").Base(err) 270 } 271 return nil, newError("failed to read checksum").Base(err) 272 } 273 274 fnv1a := fnv.New32a() 275 common.Must2(fnv1a.Write(buffer.BytesTo(-4))) 276 actualHash := fnv1a.Sum32() 277 expectedHash := binary.BigEndian.Uint32(buffer.BytesFrom(-4)) 278 279 if actualHash != expectedHash { 280 if !s.isAEADRequest { 281 Autherr := newError("invalid auth, legacy userHash tainted") 282 burnErr := s.userValidator.BurnTaintFuse(fixedSizeAuthID[:]) 283 if burnErr != nil { 284 Autherr = newError("invalid auth, can't taint legacy userHash").Base(burnErr) 285 } 286 //It is possible that we are under attack described in https://github.com/v2ray/v2ray-core/issues/2523 287 return nil, drainConnection(Autherr) 288 } else { 289 return nil, newError("invalid auth, but this is a AEAD request") 290 } 291 292 } 293 294 if request.Address == nil { 295 return nil, newError("invalid remote address") 296 } 297 298 if request.Security == protocol.SecurityType_UNKNOWN || request.Security == protocol.SecurityType_AUTO { 299 return nil, newError("unknown security type: ", request.Security) 300 } 301 302 return request, nil 303 } 304 305 // DecodeRequestBody returns Reader from which caller can fetch decrypted body. 306 func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader { 307 var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{} 308 if request.Option.Has(protocol.RequestOptionChunkMasking) { 309 sizeParser = NewShakeSizeParser(s.requestBodyIV[:]) 310 } 311 var padding crypto.PaddingLengthGenerator 312 if request.Option.Has(protocol.RequestOptionGlobalPadding) { 313 padding = sizeParser.(crypto.PaddingLengthGenerator) 314 } 315 316 switch request.Security { 317 case protocol.SecurityType_NONE: 318 if request.Option.Has(protocol.RequestOptionChunkStream) { 319 if request.Command.TransferType() == protocol.TransferTypeStream { 320 return crypto.NewChunkStreamReader(sizeParser, reader) 321 } 322 323 auth := &crypto.AEADAuthenticator{ 324 AEAD: new(NoOpAuthenticator), 325 NonceGenerator: crypto.GenerateEmptyBytes(), 326 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 327 } 328 return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding) 329 } 330 331 return buf.NewReader(reader) 332 case protocol.SecurityType_LEGACY: 333 aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:]) 334 cryptionReader := crypto.NewCryptionReader(aesStream, reader) 335 if request.Option.Has(protocol.RequestOptionChunkStream) { 336 auth := &crypto.AEADAuthenticator{ 337 AEAD: new(FnvAuthenticator), 338 NonceGenerator: crypto.GenerateEmptyBytes(), 339 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 340 } 341 return crypto.NewAuthenticationReader(auth, sizeParser, cryptionReader, request.Command.TransferType(), padding) 342 } 343 344 return buf.NewReader(cryptionReader) 345 case protocol.SecurityType_AES128_GCM: 346 aead := crypto.NewAesGcm(s.requestBodyKey[:]) 347 348 auth := &crypto.AEADAuthenticator{ 349 AEAD: aead, 350 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 351 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 352 } 353 return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) 354 case protocol.SecurityType_CHACHA20_POLY1305: 355 aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:])) 356 357 auth := &crypto.AEADAuthenticator{ 358 AEAD: aead, 359 NonceGenerator: GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 360 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 361 } 362 return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType(), padding) 363 default: 364 panic("Unknown security type.") 365 } 366 } 367 368 // EncodeResponseHeader writes encoded response header into the given writer. 369 func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { 370 var encryptionWriter io.Writer 371 if !s.isAEADRequest { 372 s.responseBodyKey = md5.Sum(s.requestBodyKey[:]) 373 s.responseBodyIV = md5.Sum(s.requestBodyIV[:]) 374 } else { 375 BodyKey := sha256.Sum256(s.requestBodyKey[:]) 376 copy(s.responseBodyKey[:], BodyKey[:16]) 377 BodyIV := sha256.Sum256(s.requestBodyIV[:]) 378 copy(s.responseBodyIV[:], BodyIV[:16]) 379 } 380 381 aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:]) 382 encryptionWriter = crypto.NewCryptionWriter(aesStream, writer) 383 s.responseWriter = encryptionWriter 384 385 aeadEncryptedHeaderBuffer := bytes.NewBuffer(nil) 386 387 if s.isAEADRequest { 388 encryptionWriter = aeadEncryptedHeaderBuffer 389 } 390 391 common.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)})) 392 err := MarshalCommand(header.Command, encryptionWriter) 393 if err != nil { 394 common.Must2(encryptionWriter.Write([]byte{0x00, 0x00})) 395 } 396 397 if s.isAEADRequest { 398 399 aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderLenKey) 400 aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderLenIV)[:12] 401 402 aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block) 403 aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD) 404 405 aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil) 406 407 decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16(aeadEncryptedHeaderBuffer.Len()) 408 409 common.Must(binary.Write(aeadResponseHeaderLengthEncryptionBuffer, binary.BigEndian, decryptedResponseHeaderLengthBinaryDeserializeBuffer)) 410 411 AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD.Seal(nil, aeadResponseHeaderLengthEncryptionIV, aeadResponseHeaderLengthEncryptionBuffer.Bytes(), nil) 412 common.Must2(io.Copy(writer, bytes.NewReader(AEADEncryptedLength))) 413 414 aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadKey) 415 aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConst_AEADRespHeaderPayloadIV)[:12] 416 417 aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block) 418 aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD) 419 420 aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil) 421 common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload))) 422 } 423 } 424 425 // EncodeResponseBody returns a Writer that auto-encrypt content written by caller. 426 func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer { 427 var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{} 428 if request.Option.Has(protocol.RequestOptionChunkMasking) { 429 sizeParser = NewShakeSizeParser(s.responseBodyIV[:]) 430 } 431 var padding crypto.PaddingLengthGenerator 432 if request.Option.Has(protocol.RequestOptionGlobalPadding) { 433 padding = sizeParser.(crypto.PaddingLengthGenerator) 434 } 435 436 switch request.Security { 437 case protocol.SecurityType_NONE: 438 if request.Option.Has(protocol.RequestOptionChunkStream) { 439 if request.Command.TransferType() == protocol.TransferTypeStream { 440 return crypto.NewChunkStreamWriter(sizeParser, writer) 441 } 442 443 auth := &crypto.AEADAuthenticator{ 444 AEAD: new(NoOpAuthenticator), 445 NonceGenerator: crypto.GenerateEmptyBytes(), 446 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 447 } 448 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding) 449 } 450 451 return buf.NewWriter(writer) 452 case protocol.SecurityType_LEGACY: 453 if request.Option.Has(protocol.RequestOptionChunkStream) { 454 auth := &crypto.AEADAuthenticator{ 455 AEAD: new(FnvAuthenticator), 456 NonceGenerator: crypto.GenerateEmptyBytes(), 457 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 458 } 459 return crypto.NewAuthenticationWriter(auth, sizeParser, s.responseWriter, request.Command.TransferType(), padding) 460 } 461 462 return &buf.SequentialWriter{Writer: s.responseWriter} 463 case protocol.SecurityType_AES128_GCM: 464 aead := crypto.NewAesGcm(s.responseBodyKey[:]) 465 466 auth := &crypto.AEADAuthenticator{ 467 AEAD: aead, 468 NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 469 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 470 } 471 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) 472 case protocol.SecurityType_CHACHA20_POLY1305: 473 aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:])) 474 475 auth := &crypto.AEADAuthenticator{ 476 AEAD: aead, 477 NonceGenerator: GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 478 AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 479 } 480 return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType(), padding) 481 default: 482 panic("Unknown security type.") 483 } 484 } 485 486 func (s *ServerSession) DrainConnN(reader io.Reader, n int) error { 487 _, err := io.CopyN(ioutil.Discard, reader, int64(n)) 488 return err 489 }