v2ray-core/proxy/vmess/protocol/vmess.go

236 lines
6.9 KiB
Go
Raw Normal View History

2015-09-07 15:12:31 +00:00
// Package vmess contains protocol definition, io lib for VMess.
package protocol
2015-09-05 15:48:38 +00:00
import (
2016-01-12 10:38:43 +00:00
"crypto/md5"
2015-09-08 23:11:02 +00:00
"encoding/binary"
"hash/fnv"
2015-09-07 21:13:55 +00:00
"io"
2015-09-08 23:11:02 +00:00
2015-10-21 19:53:55 +00:00
"github.com/v2ray/v2ray-core/common/alloc"
2015-11-03 20:26:16 +00:00
v2crypto "github.com/v2ray/v2ray-core/common/crypto"
2015-10-13 11:55:06 +00:00
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
proto "github.com/v2ray/v2ray-core/common/protocol"
"github.com/v2ray/v2ray-core/proxy"
2015-10-13 11:55:06 +00:00
"github.com/v2ray/v2ray-core/transport"
2015-09-08 23:11:02 +00:00
)
const (
addrTypeIPv4 = byte(0x01)
addrTypeIPv6 = byte(0x03)
addrTypeDomain = byte(0x02)
CmdTCP = byte(0x01)
CmdUDP = byte(0x02)
2015-09-10 22:24:18 +00:00
Version = byte(0x01)
2015-09-14 16:19:17 +00:00
2016-02-01 11:22:29 +00:00
OptionChunk = byte(0x01)
2015-09-14 16:19:17 +00:00
blockSize = 16
2015-09-05 15:48:38 +00:00
)
2015-09-21 17:56:58 +00:00
// VMessRequest implements the request message of VMess protocol. It only contains the header of a
2016-02-05 21:04:43 +00:00
// request message. The data part will be handled by connection handler directly, in favor of data
2015-09-21 17:56:58 +00:00
// streaming.
type VMessRequest struct {
Version byte
User *proto.User
RequestIV []byte
RequestKey []byte
ResponseHeader byte
Command byte
2016-02-01 11:22:29 +00:00
Option byte
2015-09-12 20:11:54 +00:00
Address v2net.Address
2015-12-16 22:53:38 +00:00
Port v2net.Port
2015-09-08 23:11:02 +00:00
}
2015-09-21 17:56:58 +00:00
// Destination is the final destination of this request.
2015-11-27 20:57:15 +00:00
func (this *VMessRequest) Destination() v2net.Destination {
if this.Command == CmdTCP {
2015-12-16 22:53:38 +00:00
return v2net.TCPDestination(this.Address, this.Port)
2015-09-20 16:22:29 +00:00
} else {
2015-12-16 22:53:38 +00:00
return v2net.UDPDestination(this.Address, this.Port)
2015-09-20 16:22:29 +00:00
}
}
2016-02-01 11:22:29 +00:00
func (this *VMessRequest) IsChunkStream() bool {
return (this.Option & OptionChunk) == OptionChunk
}
2015-09-21 17:56:58 +00:00
// VMessRequestReader is a parser to read VMessRequest from a byte stream.
2015-09-08 23:11:02 +00:00
type VMessRequestReader struct {
2016-01-12 10:52:40 +00:00
vUserSet UserSet
2015-09-08 23:11:02 +00:00
}
2015-09-21 17:56:58 +00:00
// NewVMessRequestReader creates a new VMessRequestReader with a given UserSet
2016-01-12 10:52:40 +00:00
func NewVMessRequestReader(vUserSet UserSet) *VMessRequestReader {
2015-09-16 14:27:36 +00:00
return &VMessRequestReader{
vUserSet: vUserSet,
}
2015-09-08 23:11:02 +00:00
}
2015-09-21 17:56:58 +00:00
// Read reads a VMessRequest from a byte stream.
2015-11-27 20:57:15 +00:00
func (this *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
2015-10-21 19:53:55 +00:00
buffer := alloc.NewSmallBuffer()
2016-01-04 12:01:32 +00:00
defer buffer.Release()
nBytes, err := io.ReadFull(reader, buffer.Value[:proto.IDBytesLen])
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read request ID (", nBytes, " bytes): ", err)
2015-09-08 23:11:02 +00:00
return nil, err
}
2015-09-15 22:06:22 +00:00
2015-11-27 20:57:15 +00:00
userObj, timeSec, valid := this.vUserSet.GetUser(buffer.Value[:nBytes])
2015-09-08 23:11:02 +00:00
if !valid {
2016-01-30 11:23:56 +00:00
return nil, proxy.ErrorInvalidAuthentication
2015-09-08 23:11:02 +00:00
}
2015-09-14 16:19:17 +00:00
2016-01-12 10:52:40 +00:00
timestampHash := TimestampHash()
2016-01-12 10:38:43 +00:00
timestampHash.Write(timeSec.HashBytes())
iv := timestampHash.Sum(nil)
aesStream, err := v2crypto.NewAesDecryptionStream(userObj.ID.CmdKey(), iv)
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to create AES stream: ", err)
return nil, err
}
2015-09-08 23:11:02 +00:00
2015-11-03 20:26:16 +00:00
decryptor := v2crypto.NewCryptionReader(aesStream, reader)
2015-09-08 23:11:02 +00:00
nBytes, err = io.ReadFull(decryptor, buffer.Value[:41])
2015-09-14 19:59:44 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read request header (", nBytes, " bytes): ", err)
2015-09-14 19:59:44 +00:00
return nil, err
}
bufferLen := nBytes
2015-09-14 19:59:44 +00:00
2015-09-16 14:27:36 +00:00
request := &VMessRequest{
2015-10-31 13:08:13 +00:00
User: userObj,
2015-10-21 19:53:55 +00:00
Version: buffer.Value[0],
2015-09-16 14:27:36 +00:00
}
2015-09-14 19:59:44 +00:00
if request.Version != Version {
2016-01-18 11:24:33 +00:00
log.Warning("VMess: Invalid protocol version ", request.Version)
2016-01-30 11:23:56 +00:00
return nil, proxy.ErrorInvalidProtocolVersion
2015-09-14 19:59:44 +00:00
}
request.RequestIV = append([]byte(nil), buffer.Value[1:17]...) // 16 bytes
request.RequestKey = append([]byte(nil), buffer.Value[17:33]...) // 16 bytes
2016-02-01 11:22:29 +00:00
request.ResponseHeader = buffer.Value[33] // 1 byte
request.Option = buffer.Value[34] // 1 byte + 2 bytes reserved
2015-10-21 19:53:55 +00:00
request.Command = buffer.Value[37]
2015-09-08 23:11:02 +00:00
2015-12-16 22:53:38 +00:00
request.Port = v2net.PortFromBytes(buffer.Value[38:40])
2015-09-08 23:11:02 +00:00
2015-10-21 19:53:55 +00:00
switch buffer.Value[40] {
2015-09-08 23:11:02 +00:00
case addrTypeIPv4:
nBytes, err = io.ReadFull(decryptor, buffer.Value[41:45]) // 4 bytes
bufferLen += 4
2015-09-08 23:11:02 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read target IPv4 (", nBytes, " bytes): ", err)
2015-09-08 23:11:02 +00:00
return nil, err
}
2015-12-16 22:53:38 +00:00
request.Address = v2net.IPAddress(buffer.Value[41:45])
2015-09-08 23:11:02 +00:00
case addrTypeIPv6:
nBytes, err = io.ReadFull(decryptor, buffer.Value[41:57]) // 16 bytes
bufferLen += 16
2015-09-08 23:11:02 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read target IPv6 (", nBytes, " bytes): ", nBytes, err)
2015-09-08 23:11:02 +00:00
return nil, err
}
2015-12-16 22:53:38 +00:00
request.Address = v2net.IPAddress(buffer.Value[41:57])
2015-09-08 23:11:02 +00:00
case addrTypeDomain:
nBytes, err = io.ReadFull(decryptor, buffer.Value[41:42])
2015-09-08 23:11:02 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read target domain (", nBytes, " bytes): ", nBytes, err)
2015-09-08 23:11:02 +00:00
return nil, err
}
2015-10-21 19:53:55 +00:00
domainLength := int(buffer.Value[41])
2016-01-04 21:02:22 +00:00
if domainLength == 0 {
return nil, transport.ErrorCorruptedPacket
2016-01-04 21:02:22 +00:00
}
nBytes, err = io.ReadFull(decryptor, buffer.Value[42:42+domainLength])
2015-09-08 23:11:02 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read target domain (", nBytes, " bytes): ", nBytes, err)
2015-09-08 23:11:02 +00:00
return nil, err
}
bufferLen += 1 + domainLength
2016-01-04 14:16:52 +00:00
domainBytes := append([]byte(nil), buffer.Value[42:42+domainLength]...)
2016-01-04 12:01:32 +00:00
request.Address = v2net.DomainAddress(string(domainBytes))
2015-09-08 23:11:02 +00:00
}
nBytes, err = io.ReadFull(decryptor, buffer.Value[bufferLen:bufferLen+4])
2015-09-08 23:11:02 +00:00
if err != nil {
2016-01-18 11:24:33 +00:00
log.Debug("VMess: Failed to read checksum (", nBytes, " bytes): ", nBytes, err)
2015-09-08 23:11:02 +00:00
return nil, err
}
fnv1a := fnv.New32a()
2015-10-21 19:53:55 +00:00
fnv1a.Write(buffer.Value[:bufferLen])
actualHash := fnv1a.Sum32()
2015-10-21 19:53:55 +00:00
expectedHash := binary.BigEndian.Uint32(buffer.Value[bufferLen : bufferLen+4])
if actualHash != expectedHash {
return nil, transport.ErrorCorruptedPacket
2015-09-08 23:11:02 +00:00
}
return request, nil
}
2015-09-21 17:56:58 +00:00
// ToBytes returns a VMessRequest in the form of byte array.
2016-01-12 10:52:40 +00:00
func (this *VMessRequest) ToBytes(timestampGenerator RandomTimestampGenerator, buffer *alloc.Buffer) (*alloc.Buffer, error) {
2015-09-22 12:50:34 +00:00
if buffer == nil {
2015-10-21 20:28:26 +00:00
buffer = alloc.NewSmallBuffer().Clear()
2015-09-22 12:50:34 +00:00
}
2015-09-15 22:06:22 +00:00
2016-01-12 10:38:43 +00:00
timestamp := timestampGenerator.Next()
2016-01-12 10:52:40 +00:00
idHash := IDHash(this.User.AnyValidID().Bytes())
2016-01-12 10:38:43 +00:00
idHash.Write(timestamp.Bytes())
2015-09-16 19:13:13 +00:00
hashStart := buffer.Len()
buffer.Slice(0, hashStart+16)
idHash.Sum(buffer.Value[hashStart:hashStart])
2015-09-08 23:11:02 +00:00
2015-10-21 20:28:26 +00:00
encryptionBegin := buffer.Len()
2015-09-08 23:11:02 +00:00
2015-11-27 20:57:15 +00:00
buffer.AppendBytes(this.Version)
buffer.Append(this.RequestIV)
buffer.Append(this.RequestKey)
2016-02-01 11:22:29 +00:00
buffer.AppendBytes(this.ResponseHeader, this.Option, byte(0), byte(0))
2015-11-27 20:57:15 +00:00
buffer.AppendBytes(this.Command)
2015-12-16 22:53:38 +00:00
buffer.Append(this.Port.Bytes())
switch {
2015-11-27 20:57:15 +00:00
case this.Address.IsIPv4():
2015-10-21 20:28:26 +00:00
buffer.AppendBytes(addrTypeIPv4)
2015-11-27 20:57:15 +00:00
buffer.Append(this.Address.IP())
case this.Address.IsIPv6():
2015-10-21 20:28:26 +00:00
buffer.AppendBytes(addrTypeIPv6)
2015-11-27 20:57:15 +00:00
buffer.Append(this.Address.IP())
case this.Address.IsDomain():
buffer.AppendBytes(addrTypeDomain, byte(len(this.Address.Domain())))
buffer.Append([]byte(this.Address.Domain()))
}
2015-09-08 23:11:02 +00:00
2015-10-21 20:28:26 +00:00
encryptionEnd := buffer.Len()
2015-09-08 23:11:02 +00:00
fnv1a := fnv.New32a()
2015-10-21 20:28:26 +00:00
fnv1a.Write(buffer.Value[encryptionBegin:encryptionEnd])
fnvHash := fnv1a.Sum32()
2015-10-21 20:28:26 +00:00
buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash))
encryptionEnd += 4
2016-01-12 10:38:43 +00:00
timestampHash := md5.New()
timestampHash.Write(timestamp.HashBytes())
iv := timestampHash.Sum(nil)
aesStream, err := v2crypto.NewAesEncryptionStream(this.User.ID.CmdKey(), iv)
2015-09-08 23:11:02 +00:00
if err != nil {
return nil, err
2015-09-08 23:11:02 +00:00
}
2015-10-21 20:28:26 +00:00
aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd])
2015-09-07 21:21:47 +00:00
return buffer, nil
2015-09-05 15:48:38 +00:00
}