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 }
// 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 }