1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-06 10:20:44 -05:00
v2fly/proxy/vmess/protocol/vmess.go

213 lines
5.8 KiB
Go
Raw Normal View History

2015-09-07 11:12:31 -04:00
// Package vmess contains protocol definition, io lib for VMess.
package protocol
2015-09-05 11:48:38 -04:00
import (
2015-09-08 19:11:02 -04:00
"crypto/aes"
"crypto/cipher"
"encoding/binary"
"hash/fnv"
2015-09-07 17:13:55 -04:00
"io"
2015-09-16 15:13:13 -04:00
"time"
2015-09-08 19:11:02 -04:00
2015-10-21 15:53:55 -04:00
"github.com/v2ray/v2ray-core/common/alloc"
v2io "github.com/v2ray/v2ray-core/common/io"
2015-10-13 07:55:06 -04:00
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
proxyerrors "github.com/v2ray/v2ray-core/proxy/common/errors"
2015-10-16 06:03:22 -04:00
"github.com/v2ray/v2ray-core/proxy/vmess/config"
2015-09-19 18:50:21 -04:00
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
2015-10-13 07:55:06 -04:00
"github.com/v2ray/v2ray-core/transport"
2015-09-08 19:11:02 -04:00
)
const (
addrTypeIPv4 = byte(0x01)
addrTypeIPv6 = byte(0x03)
addrTypeDomain = byte(0x02)
CmdTCP = byte(0x01)
CmdUDP = byte(0x02)
2015-09-10 18:24:18 -04:00
Version = byte(0x01)
2015-09-14 12:19:17 -04:00
blockSize = 16
2015-09-05 11:48:38 -04:00
)
2015-09-21 13:56:58 -04:00
// VMessRequest implements the request message of VMess protocol. It only contains the header of a
// request message. The data part will be handled by conection handler directly, in favor of data
// streaming.
type VMessRequest struct {
Version byte
2015-10-31 04:39:45 -04:00
User config.User
RequestIV []byte
RequestKey []byte
ResponseHeader []byte
Command byte
2015-09-12 16:11:54 -04:00
Address v2net.Address
2015-09-08 19:11:02 -04:00
}
2015-09-21 13:56:58 -04:00
// Destination is the final destination of this request.
2015-09-20 12:22:29 -04:00
func (request *VMessRequest) Destination() v2net.Destination {
if request.Command == CmdTCP {
return v2net.NewTCPDestination(request.Address)
} else {
return v2net.NewUDPDestination(request.Address)
}
}
2015-09-21 13:56:58 -04:00
// VMessRequestReader is a parser to read VMessRequest from a byte stream.
2015-09-08 19:11:02 -04:00
type VMessRequestReader struct {
2015-09-19 18:11:14 -04:00
vUserSet user.UserSet
2015-09-08 19:11:02 -04:00
}
2015-09-21 13:56:58 -04:00
// NewVMessRequestReader creates a new VMessRequestReader with a given UserSet
2015-09-19 18:11:14 -04:00
func NewVMessRequestReader(vUserSet user.UserSet) *VMessRequestReader {
2015-09-16 10:27:36 -04:00
return &VMessRequestReader{
vUserSet: vUserSet,
}
2015-09-08 19:11:02 -04:00
}
2015-09-21 13:56:58 -04:00
// Read reads a VMessRequest from a byte stream.
2015-09-08 19:11:02 -04:00
func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
2015-10-21 15:53:55 -04:00
buffer := alloc.NewSmallBuffer()
2015-10-21 15:53:55 -04:00
nBytes, err := v2net.ReadAllBytes(reader, buffer.Value[:config.IDBytesLen])
if err != nil {
2015-09-08 19:11:02 -04:00
return nil, err
}
2015-09-15 18:06:22 -04:00
2015-10-30 19:38:31 -04:00
userObj, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes])
2015-09-08 19:11:02 -04:00
if !valid {
return nil, proxyerrors.InvalidAuthentication
2015-09-08 19:11:02 -04:00
}
2015-09-14 12:19:17 -04:00
2015-10-30 19:38:31 -04:00
aesCipher, err := aes.NewCipher(userObj.ID().CmdKey())
if err != nil {
return nil, err
}
2015-09-19 18:11:14 -04:00
aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec))
decryptor := v2io.NewCryptionReader(aesStream, reader)
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
2015-10-21 15:53:55 -04:00
nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41])
2015-09-14 15:59:44 -04:00
if err != nil {
return nil, err
}
bufferLen := nBytes
2015-09-14 15:59:44 -04:00
2015-09-16 10:27:36 -04:00
request := &VMessRequest{
2015-10-31 04:39:45 -04:00
User: userObj,
2015-10-21 15:53:55 -04:00
Version: buffer.Value[0],
2015-09-16 10:27:36 -04:00
}
2015-09-14 15:59:44 -04:00
if request.Version != Version {
2015-10-13 07:55:06 -04:00
log.Warning("Invalid protocol version %d", request.Version)
return nil, proxyerrors.InvalidProtocolVersion
2015-09-14 15:59:44 -04:00
}
2015-10-21 15:53:55 -04:00
request.RequestIV = buffer.Value[1:17] // 16 bytes
request.RequestKey = buffer.Value[17:33] // 16 bytes
request.ResponseHeader = buffer.Value[33:37] // 4 bytes
request.Command = buffer.Value[37]
2015-09-08 19:11:02 -04:00
2015-10-21 15:53:55 -04:00
port := binary.BigEndian.Uint16(buffer.Value[38:40])
2015-09-08 19:11:02 -04:00
2015-10-21 15:53:55 -04:00
switch buffer.Value[40] {
2015-09-08 19:11:02 -04:00
case addrTypeIPv4:
2015-10-21 15:53:55 -04:00
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:45]) // 4 bytes
bufferLen += 4
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
2015-10-21 15:53:55 -04:00
request.Address = v2net.IPAddress(buffer.Value[41:45], port)
2015-09-08 19:11:02 -04:00
case addrTypeIPv6:
2015-10-21 15:53:55 -04:00
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:57]) // 16 bytes
bufferLen += 16
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
2015-10-21 15:53:55 -04:00
request.Address = v2net.IPAddress(buffer.Value[41:57], port)
2015-09-08 19:11:02 -04:00
case addrTypeDomain:
2015-10-21 15:53:55 -04:00
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:42])
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
2015-10-21 15:53:55 -04:00
domainLength := int(buffer.Value[41])
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[42:42+domainLength])
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
bufferLen += 1 + domainLength
2015-10-21 15:53:55 -04:00
request.Address = v2net.DomainAddress(string(buffer.Value[42:42+domainLength]), port)
2015-09-08 19:11:02 -04:00
}
2015-10-21 15:53:55 -04:00
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[bufferLen:bufferLen+4])
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
}
fnv1a := fnv.New32a()
2015-10-21 15:53:55 -04:00
fnv1a.Write(buffer.Value[:bufferLen])
actualHash := fnv1a.Sum32()
2015-10-21 15:53:55 -04:00
expectedHash := binary.BigEndian.Uint32(buffer.Value[bufferLen : bufferLen+4])
if actualHash != expectedHash {
2015-10-13 07:55:06 -04:00
return nil, transport.CorruptedPacket
2015-09-08 19:11:02 -04:00
}
return request, nil
}
2015-09-21 13:56:58 -04:00
// ToBytes returns a VMessRequest in the form of byte array.
2015-10-21 16:28:26 -04:00
func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer *alloc.Buffer) (*alloc.Buffer, error) {
2015-09-22 08:50:34 -04:00
if buffer == nil {
2015-10-21 16:28:26 -04:00
buffer = alloc.NewSmallBuffer().Clear()
2015-09-22 08:50:34 -04:00
}
2015-09-15 18:06:22 -04:00
counter := randomRangeInt64(time.Now().Unix(), 30)
2015-10-31 04:39:45 -04:00
hash := idHash.Hash(request.User.ID().Bytes[:], counter)
2015-09-16 15:13:13 -04:00
2015-10-21 16:28:26 -04:00
buffer.Append(hash)
2015-09-08 19:11:02 -04:00
2015-10-21 16:28:26 -04:00
encryptionBegin := buffer.Len()
2015-09-08 19:11:02 -04:00
2015-10-21 16:28:26 -04:00
buffer.AppendBytes(request.Version)
buffer.Append(request.RequestIV)
buffer.Append(request.RequestKey)
buffer.Append(request.ResponseHeader)
buffer.AppendBytes(request.Command)
buffer.Append(request.Address.PortBytes())
switch {
case request.Address.IsIPv4():
2015-10-21 16:28:26 -04:00
buffer.AppendBytes(addrTypeIPv4)
buffer.Append(request.Address.IP())
case request.Address.IsIPv6():
2015-10-21 16:28:26 -04:00
buffer.AppendBytes(addrTypeIPv6)
buffer.Append(request.Address.IP())
case request.Address.IsDomain():
2015-10-21 16:28:26 -04:00
buffer.AppendBytes(addrTypeDomain, byte(len(request.Address.Domain())))
buffer.Append([]byte(request.Address.Domain()))
}
2015-09-08 19:11:02 -04:00
2015-10-21 16:28:26 -04:00
encryptionEnd := buffer.Len()
2015-09-08 19:11:02 -04:00
fnv1a := fnv.New32a()
2015-10-21 16:28:26 -04:00
fnv1a.Write(buffer.Value[encryptionBegin:encryptionEnd])
fnvHash := fnv1a.Sum32()
2015-10-21 16:28:26 -04:00
buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash))
encryptionEnd += 4
2015-10-31 04:39:45 -04:00
aesCipher, err := aes.NewCipher(request.User.ID().CmdKey())
2015-09-08 19:11:02 -04:00
if err != nil {
return nil, err
2015-09-08 19:11:02 -04:00
}
2015-09-19 18:11:14 -04:00
aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter))
2015-10-21 16:28:26 -04:00
aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd])
2015-09-07 17:21:47 -04:00
return buffer, nil
2015-09-05 11:48:38 -04:00
}