udp.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package protocol
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "encoding/binary"
  6. "hash/fnv"
  7. "time"
  8. "github.com/v2ray/v2ray-core/common/errors"
  9. "github.com/v2ray/v2ray-core/common/log"
  10. v2net "github.com/v2ray/v2ray-core/common/net"
  11. "github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
  12. )
  13. type VMessUDP struct {
  14. user user.ID
  15. version byte
  16. address v2net.Address
  17. data []byte
  18. }
  19. func ReadVMessUDP(buffer []byte, userset user.UserSet) (*VMessUDP, error) {
  20. userHash := buffer[:user.IDBytesLen]
  21. userId, timeSec, valid := userset.GetUser(userHash)
  22. if !valid {
  23. return nil, errors.NewAuthenticationError(userHash)
  24. }
  25. buffer = buffer[user.IDBytesLen:]
  26. aesCipher, err := aes.NewCipher(userId.CmdKey())
  27. if err != nil {
  28. return nil, err
  29. }
  30. aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec))
  31. aesStream.XORKeyStream(buffer, buffer)
  32. fnvHash := binary.BigEndian.Uint32(buffer[:4])
  33. fnv1a := fnv.New32a()
  34. fnv1a.Write(buffer[4:])
  35. fnvHashActual := fnv1a.Sum32()
  36. if fnvHash != fnvHashActual {
  37. log.Warning("Unexpected fhv hash %d, should be %d", fnvHashActual, fnvHash)
  38. return nil, errors.NewCorruptedPacketError()
  39. }
  40. buffer = buffer[4:]
  41. vmess := &VMessUDP{
  42. user: *userId,
  43. version: buffer[0],
  44. }
  45. // buffer[1] is reserved
  46. port := binary.BigEndian.Uint16(buffer[2:4])
  47. addrType := buffer[4]
  48. var address v2net.Address
  49. switch addrType {
  50. case addrTypeIPv4:
  51. address = v2net.IPAddress(buffer[5:9], port)
  52. buffer = buffer[9:]
  53. case addrTypeIPv6:
  54. address = v2net.IPAddress(buffer[5:21], port)
  55. buffer = buffer[21:]
  56. case addrTypeDomain:
  57. domainLength := buffer[5]
  58. domain := string(buffer[6 : 6+domainLength])
  59. address = v2net.DomainAddress(domain, port)
  60. buffer = buffer[6+domainLength:]
  61. default:
  62. log.Warning("Unexpected address type %d", addrType)
  63. return nil, errors.NewCorruptedPacketError()
  64. }
  65. vmess.address = address
  66. vmess.data = buffer
  67. return vmess, nil
  68. }
  69. func (vmess *VMessUDP) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer []byte) []byte {
  70. if buffer == nil {
  71. buffer = make([]byte, 0, 2*1024)
  72. }
  73. counter := randomRangeInt64(time.Now().UTC().Unix(), 30)
  74. hash := idHash.Hash(vmess.user.Bytes[:], counter)
  75. buffer = append(buffer, hash...)
  76. encryptBegin := 16
  77. // Placeholder for fnv1a hash
  78. buffer = append(buffer, byte(0), byte(0), byte(0), byte(0))
  79. fnvHash := 16
  80. fnvHashBegin := 20
  81. buffer = append(buffer, vmess.version)
  82. buffer = append(buffer, byte(0x00))
  83. buffer = append(buffer, vmess.address.PortBytes()...)
  84. switch {
  85. case vmess.address.IsIPv4():
  86. buffer = append(buffer, addrTypeIPv4)
  87. buffer = append(buffer, vmess.address.IP()...)
  88. case vmess.address.IsIPv6():
  89. buffer = append(buffer, addrTypeIPv6)
  90. buffer = append(buffer, vmess.address.IP()...)
  91. case vmess.address.IsDomain():
  92. buffer = append(buffer, addrTypeDomain)
  93. buffer = append(buffer, byte(len(vmess.address.Domain())))
  94. buffer = append(buffer, []byte(vmess.address.Domain())...)
  95. }
  96. buffer = append(buffer, vmess.data...)
  97. fnv1a := fnv.New32a()
  98. fnv1a.Write(buffer[fnvHashBegin:])
  99. fnvHashValue := fnv1a.Sum32()
  100. buffer[fnvHash] = byte(fnvHashValue >> 24)
  101. buffer[fnvHash+1] = byte(fnvHashValue >> 16)
  102. buffer[fnvHash+2] = byte(fnvHashValue >> 8)
  103. buffer[fnvHash+3] = byte(fnvHashValue)
  104. aesCipher, err := aes.NewCipher(vmess.user.CmdKey())
  105. if err != nil {
  106. log.Error("VMess failed to create AES cipher: %v", err)
  107. return nil
  108. }
  109. aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter))
  110. aesStream.XORKeyStream(buffer[encryptBegin:], buffer[encryptBegin:])
  111. return buffer
  112. }