func ReadVMessUDP(buffer []byte, userset user.UserSet) (*VMessUDP, error) { userHash := buffer[:user.IDBytesLen] userId, timeSec, valid := userset.GetUser(userHash) if !valid { return nil, errors.NewAuthenticationError(userHash) } buffer = buffer[user.IDBytesLen:] aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) aesStream.XORKeyStream(buffer, buffer) fnvHash := binary.BigEndian.Uint32(buffer[:4]) fnv1a := fnv.New32a() fnv1a.Write(buffer[4:]) fnvHashActual := fnv1a.Sum32() if fnvHash != fnvHashActual { log.Warning("Unexpected fhv hash %d, should be %d", fnvHashActual, fnvHash) return nil, errors.NewCorruptedPacketError() } buffer = buffer[4:] vmess := &VMessUDP{ user: *userId, version: buffer[0], token: binary.BigEndian.Uint16(buffer[1:3]), } // buffer[3] is reserved port := binary.BigEndian.Uint16(buffer[4:6]) addrType := buffer[6] var address v2net.Address switch addrType { case addrTypeIPv4: address = v2net.IPAddress(buffer[7:11], port) buffer = buffer[11:] case addrTypeIPv6: address = v2net.IPAddress(buffer[7:23], port) buffer = buffer[23:] case addrTypeDomain: domainLength := buffer[7] domain := string(buffer[8 : 8+domainLength]) address = v2net.DomainAddress(domain, port) buffer = buffer[8+domainLength:] default: log.Warning("Unexpected address type %d", addrType) return nil, errors.NewCorruptedPacketError() } vmess.address = address vmess.data = buffer return vmess, nil }
func ReadAuthentication(reader io.Reader) (auth Socks5AuthenticationRequest, auth4 Socks4AuthenticationRequest, err error) { buffer := alloc.NewSmallBuffer() defer buffer.Release() nBytes, err := reader.Read(buffer.Value) if err != nil { return } if nBytes < 2 { log.Info("Socks expected 2 bytes read, but only %d bytes read", nBytes) err = errors.NewCorruptedPacketError() return } if buffer.Value[0] == socks4Version { auth4.Version = buffer.Value[0] auth4.Command = buffer.Value[1] auth4.Port = binary.BigEndian.Uint16(buffer.Value[2:4]) copy(auth4.IP[:], buffer.Value[4:8]) err = NewSocksVersion4Error() return } auth.version = buffer.Value[0] if auth.version != socksVersion { err = errors.NewProtocolVersionError(int(auth.version)) return } auth.nMethods = buffer.Value[1] if auth.nMethods <= 0 { log.Info("Zero length of authentication methods") err = errors.NewCorruptedPacketError() return } if nBytes-2 != int(auth.nMethods) { log.Info("Unmatching number of auth methods, expecting %d, but got %d", auth.nMethods, nBytes) err = errors.NewCorruptedPacketError() return } copy(auth.authMethods[:], buffer.Value[2:nBytes]) return }
func ReadRequest(reader io.Reader) (request *Socks5Request, err error) { buffer := alloc.NewSmallBuffer() defer buffer.Release() nBytes, err := reader.Read(buffer.Value[:4]) if err != nil { return } if nBytes < 4 { err = errors.NewCorruptedPacketError() return } request = &Socks5Request{ Version: buffer.Value[0], Command: buffer.Value[1], // buffer[2] is a reserved field AddrType: buffer.Value[3], } switch request.AddrType { case AddrTypeIPv4: nBytes, err = reader.Read(request.IPv4[:]) if err != nil { return } if nBytes != 4 { err = errors.NewCorruptedPacketError() return } case AddrTypeDomain: nBytes, err = reader.Read(buffer.Value[0:1]) if err != nil { return } domainLength := buffer.Value[0] nBytes, err = reader.Read(buffer.Value[:domainLength]) if err != nil { return } if nBytes != int(domainLength) { log.Info("Unable to read domain with %d bytes, expecting %d bytes", nBytes, domainLength) err = errors.NewCorruptedPacketError() return } request.Domain = string(buffer.Value[:domainLength]) case AddrTypeIPv6: nBytes, err = reader.Read(request.IPv6[:]) if err != nil { return } if nBytes != 16 { err = errors.NewCorruptedPacketError() return } default: log.Info("Unexpected address type %d", request.AddrType) err = errors.NewCorruptedPacketError() return } nBytes, err = reader.Read(buffer.Value[:2]) if err != nil { return } if nBytes != 2 { err = errors.NewCorruptedPacketError() return } request.Port = binary.BigEndian.Uint16(buffer.Value[:2]) return }
// Read reads a VMessRequest from a byte stream. func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { buffer := make([]byte, 256) nBytes, err := reader.Read(buffer[:user.IDBytesLen]) if err != nil { return nil, err } log.Debug("Read user hash: %v", buffer[:nBytes]) userId, timeSec, valid := r.vUserSet.GetUser(buffer[:nBytes]) if !valid { return nil, errors.NewAuthenticationError(buffer[:nBytes]) } aesCipher, err := aes.NewCipher(userId.CmdKey()) if err != nil { return nil, err } aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec)) decryptor := v2io.NewCryptionReader(aesStream, reader) if err != nil { return nil, err } nBytes, err = decryptor.Read(buffer[:41]) if err != nil { return nil, err } bufferLen := nBytes request := &VMessRequest{ UserId: *userId, Version: buffer[0], } if request.Version != Version { return nil, errors.NewProtocolVersionError(int(request.Version)) } copy(request.RequestIV[:], buffer[1:17]) // 16 bytes copy(request.RequestKey[:], buffer[17:33]) // 16 bytes copy(request.ResponseHeader[:], buffer[33:37]) // 4 bytes request.Command = buffer[37] port := binary.BigEndian.Uint16(buffer[38:40]) switch buffer[40] { case addrTypeIPv4: _, err = decryptor.Read(buffer[41:45]) // 4 bytes bufferLen += 4 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[41:45], port) case addrTypeIPv6: _, err = decryptor.Read(buffer[41:57]) // 16 bytes bufferLen += 16 if err != nil { return nil, err } request.Address = v2net.IPAddress(buffer[41:57], port) case addrTypeDomain: _, err = decryptor.Read(buffer[41:42]) if err != nil { return nil, err } domainLength := int(buffer[41]) _, err = decryptor.Read(buffer[42 : 42+domainLength]) if err != nil { return nil, err } bufferLen += 1 + domainLength request.Address = v2net.DomainAddress(string(buffer[42:42+domainLength]), port) } _, err = decryptor.Read(buffer[bufferLen : bufferLen+4]) if err != nil { return nil, err } fnv1a := fnv.New32a() fnv1a.Write(buffer[:bufferLen]) actualHash := fnv1a.Sum32() expectedHash := binary.BigEndian.Uint32(buffer[bufferLen : bufferLen+4]) if actualHash != expectedHash { return nil, errors.NewCorruptedPacketError() } return request, nil }