func (this *AesCfb) NewEncodingStream(key []byte, iv []byte, writer io.Writer) (io.Writer, error) { stream, err := crypto.NewAesEncryptionStream(key, iv) if err != nil { return nil, err } aesWriter := crypto.NewCryptionWriter(stream, writer) return aesWriter, nil }
func (this *VMessInboundHandler) HandleConnection(connection *net.TCPConn) error { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) requestReader := protocol.NewVMessRequestReader(this.clients) request, err := requestReader.Read(connReader) if err != nil { log.Access(connection.RemoteAddr().String(), "", log.AccessRejected, err.Error()) log.Warning("VMessIn: Invalid request from (%s): %v", connection.RemoteAddr().String(), err) return err } log.Access(connection.RemoteAddr().String(), request.Address.String(), log.AccessAccepted, "") log.Debug("VMessIn: Received request for %s", request.Address.String()) ray := this.space.PacketDispatcher().DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := vmess.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) go handleInput(request, connReader, input, &readFinish) responseKey := md5.Sum(request.RequestKey) responseIV := md5.Sum(request.RequestIV) aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:]) if err != nil { log.Error("VMessIn: Failed to create AES decryption stream: %v", err) close(input) return err } responseWriter := v2crypto.NewCryptionWriter(aesStream, connection) // Optimize for small response packet buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader[0] ^ request.ResponseHeader[1]) buffer.AppendBytes(request.ResponseHeader[2] ^ request.ResponseHeader[3]) buffer.AppendBytes(byte(0), byte(0)) if data, open := <-output; open { buffer.Append(data.Value) data.Release() responseWriter.Write(buffer.Value) go handleOutput(request, responseWriter, output, &writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() return nil }
func (this *VMessOutboundHandler) handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: ", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(protocol.NewRandomTimestampGenerator(protocol.Timestamp(time.Now().Unix()), 30), buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: ", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } if request.IsChunkStream() { vmessio.Authenticate(firstChunk) } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: ", err) return } if moreChunks { var streamWriter v2io.Writer streamWriter = v2io.NewAdaptiveWriter(encryptRequestWriter) if request.IsChunkStream() { streamWriter = vmessio.NewAuthChunkWriter(streamWriter) } v2io.ChanToWriter(streamWriter, input) } return }
func (this *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { responseBodyKey := md5.Sum(this.requestBodyKey) responseBodyIV := md5.Sum(this.requestBodyIV) this.responseBodyKey = responseBodyKey[:] this.responseBodyIV = responseBodyIV[:] aesStream := crypto.NewAesEncryptionStream(this.responseBodyKey, this.responseBodyIV) encryptionWriter := crypto.NewCryptionWriter(aesStream, writer) this.responseWriter = encryptionWriter encryptionWriter.Write([]byte{this.responseHeader, 0x00}) err := MarshalCommand(header.Command, encryptionWriter) if err != nil { encryptionWriter.Write([]byte{0x00, 0x00}) } }
func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) { defer finish.Unlock() aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:]) if err != nil { log.Error("VMessOut: Failed to create AES encryption stream: %v", err) return } encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn) buffer := alloc.NewBuffer().Clear() defer buffer.Release() buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer) if err != nil { log.Error("VMessOut: Failed to serialize VMess request: %v", err) return } // Send first packet of payload together with request, in favor of small requests. firstChunk := firstPacket.Chunk() moreChunks := firstPacket.MoreChunks() for firstChunk == nil && moreChunks { firstChunk, moreChunks = <-input } if firstChunk == nil && !moreChunks { log.Warning("VMessOut: Nothing to send. Existing...") return } aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) buffer.Append(firstChunk.Value) firstChunk.Release() _, err = conn.Write(buffer.Value) if err != nil { log.Error("VMessOut: Failed to write VMess request: %v", err) return } if moreChunks { v2net.ChanToWriter(encryptRequestWriter, input) } return }
func (this *Server) handlerUDPPayload(payload *alloc.Buffer, source v2net.Destination) { defer payload.Release() ivLen := this.config.Cipher.IVSize() iv := payload.Value[:ivLen] key := this.config.Key payload.SliceFrom(ivLen) stream, err := this.config.Cipher.NewDecodingStream(key, iv) if err != nil { log.Error("Shadowsocks: Failed to create decoding stream: ", err) return } reader := crypto.NewCryptionReader(stream, payload) request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), true) if err != nil { if err != io.EOF { log.Access(source, "", log.AccessRejected, err) log.Warning("Shadowsocks: Invalid request from ", source, ": ", err) } return } //defer request.Release() dest := v2net.UDPDestination(request.Address, request.Port) log.Access(source, dest, log.AccessAccepted, "") log.Info("Shadowsocks: Tunnelling request to ", dest) this.udpServer.Dispatch(source, dest, request.DetachUDPPayload(), func(destination v2net.Destination, payload *alloc.Buffer) { defer payload.Release() response := alloc.NewBuffer().Slice(0, ivLen) defer response.Release() rand.Read(response.Value) respIv := response.Value stream, err := this.config.Cipher.NewEncodingStream(key, respIv) if err != nil { log.Error("Shadowsocks: Failed to create encoding stream: ", err) return } writer := crypto.NewCryptionWriter(stream, response) switch { case request.Address.IsIPv4(): writer.Write([]byte{AddrTypeIPv4}) writer.Write(request.Address.IP()) case request.Address.IsIPv6(): writer.Write([]byte{AddrTypeIPv6}) writer.Write(request.Address.IP()) case request.Address.IsDomain(): writer.Write([]byte{AddrTypeDomain, byte(len(request.Address.Domain()))}) writer.Write([]byte(request.Address.Domain())) } writer.Write(request.Port.Bytes()) writer.Write(payload.Value) if request.OTA { respAuth := NewAuthenticator(HeaderKeyGenerator(key, respIv)) respAuth.Authenticate(response.Value, response.Value[ivLen:]) } this.udpHub.WriteTo(response.Value, source) }) }
func (this *Server) handleConnection(conn internet.Connection) { defer conn.Close() buffer := alloc.NewSmallBuffer() defer buffer.Release() timedReader := v2net.NewTimeOutReader(16, conn) defer timedReader.Release() bufferedReader := v2io.NewBufferedReader(timedReader) defer bufferedReader.Release() ivLen := this.config.Cipher.IVSize() _, err := io.ReadFull(bufferedReader, buffer.Value[:ivLen]) if err != nil { if err != io.EOF { log.Access(conn.RemoteAddr(), "", log.AccessRejected, err) log.Warning("Shadowsocks: Failed to read IV: ", err) } return } iv := buffer.Value[:ivLen] key := this.config.Key stream, err := this.config.Cipher.NewDecodingStream(key, iv) if err != nil { log.Error("Shadowsocks: Failed to create decoding stream: ", err) return } reader := crypto.NewCryptionReader(stream, bufferedReader) request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), false) if err != nil { log.Access(conn.RemoteAddr(), "", log.AccessRejected, err) log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err) return } defer request.Release() bufferedReader.SetCached(false) userSettings := protocol.GetUserSettings(this.config.Level) timedReader.SetTimeOut(userSettings.PayloadReadTimeout) dest := v2net.TCPDestination(request.Address, request.Port) log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "") log.Info("Shadowsocks: Tunnelling request to ", dest) ray := this.packetDispatcher.DispatchToOutbound(dest) defer ray.InboundOutput().Release() var writeFinish sync.Mutex writeFinish.Lock() go func() { if payload, err := ray.InboundOutput().Read(); err == nil { payload.SliceBack(ivLen) rand.Read(payload.Value[:ivLen]) stream, err := this.config.Cipher.NewEncodingStream(key, payload.Value[:ivLen]) if err != nil { log.Error("Shadowsocks: Failed to create encoding stream: ", err) return } stream.XORKeyStream(payload.Value[ivLen:], payload.Value[ivLen:]) conn.Write(payload.Value) payload.Release() writer := crypto.NewCryptionWriter(stream, conn) v2writer := v2io.NewAdaptiveWriter(writer) v2io.Pipe(ray.InboundOutput(), v2writer) writer.Release() v2writer.Release() } writeFinish.Unlock() }() var payloadReader v2io.Reader if request.OTA { payloadAuth := NewAuthenticator(ChunkKeyGenerator(iv)) payloadReader = NewChunkReader(reader, payloadAuth) } else { payloadReader = v2io.NewAdaptiveReader(reader) } v2io.Pipe(payloadReader, ray.InboundInput()) ray.InboundInput().Close() payloadReader.Release() writeFinish.Lock() }
func (this *ClientSession) EncodeRequestBody(writer io.Writer) io.Writer { aesStream := crypto.NewAesEncryptionStream(this.requestBodyKey, this.requestBodyIV) return crypto.NewCryptionWriter(aesStream, writer) }
func (this *VMessInboundHandler) HandleConnection(connection *hub.TCPConn) { defer connection.Close() connReader := v2net.NewTimeOutReader(16, connection) requestReader := protocol.NewVMessRequestReader(this.clients) request, err := requestReader.Read(connReader) if err != nil { log.Access(connection.RemoteAddr(), serial.StringLiteral(""), log.AccessRejected, serial.StringLiteral(err.Error())) log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err) return } log.Access(connection.RemoteAddr(), request.Address, log.AccessAccepted, serial.StringLiteral("")) log.Debug("VMessIn: Received request for ", request.Address) ray := this.packetDispatcher.DispatchToOutbound(v2net.NewPacket(request.Destination(), nil, true)) input := ray.InboundInput() output := ray.InboundOutput() var readFinish, writeFinish sync.Mutex readFinish.Lock() writeFinish.Lock() userSettings := vmess.GetUserSettings(request.User.Level) connReader.SetTimeOut(userSettings.PayloadReadTimeout) go handleInput(request, connReader, input, &readFinish) responseKey := md5.Sum(request.RequestKey) responseIV := md5.Sum(request.RequestIV) aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:]) if err != nil { log.Error("VMessIn: Failed to create AES decryption stream: ", err) close(input) return } responseWriter := v2crypto.NewCryptionWriter(aesStream, connection) // Optimize for small response packet buffer := alloc.NewLargeBuffer().Clear() defer buffer.Release() buffer.AppendBytes(request.ResponseHeader, byte(0)) this.generateCommand(buffer) if data, open := <-output; open { if request.IsChunkStream() { vmessio.Authenticate(data) } buffer.Append(data.Value) data.Release() responseWriter.Write(buffer.Value) go func(finish *sync.Mutex) { var writer v2io.Writer writer = v2io.NewAdaptiveWriter(responseWriter) if request.IsChunkStream() { writer = vmessio.NewAuthChunkWriter(writer) } v2io.ChanToWriter(writer, output) finish.Unlock() }(&writeFinish) writeFinish.Lock() } connection.CloseWrite() readFinish.Lock() }