Exemple #1
0
func (this *Server) handleConnection(connection internet.Connection) {
	defer connection.Close()

	timedReader := v2net.NewTimeOutReader(this.config.Timeout, connection)
	reader := v2io.NewBufferedReader(timedReader)
	defer reader.Release()

	writer := v2io.NewBufferedWriter(connection)
	defer writer.Release()

	auth, auth4, err := protocol.ReadAuthentication(reader)
	if err != nil && err != protocol.Socks4Downgrade {
		if err != io.EOF {
			log.Warning("Socks: failed to read authentication: ", err)
		}
		return
	}

	clientAddr := connection.RemoteAddr().String()
	if err != nil && err == protocol.Socks4Downgrade {
		this.handleSocks4(clientAddr, reader, writer, auth4)
	} else {
		this.handleSocks5(clientAddr, reader, writer, auth)
	}
}
Exemple #2
0
func (this *VMessOutboundHandler) handleRequest(session *encoding.ClientSession, conn internet.Connection, request *protocol.RequestHeader, payload *alloc.Buffer, input v2io.Reader, finish *sync.Mutex) {
	defer finish.Unlock()

	writer := v2io.NewBufferedWriter(conn)
	defer writer.Release()
	session.EncodeRequestHeader(request, writer)

	bodyWriter := session.EncodeRequestBody(writer)
	var streamWriter v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter)
	if request.Option.Has(protocol.RequestOptionChunkStream) {
		streamWriter = vmessio.NewAuthChunkWriter(streamWriter)
	}
	if err := streamWriter.Write(payload); err != nil {
		conn.SetReusable(false)
	}
	writer.SetCached(false)

	err := v2io.Pipe(input, streamWriter)
	if err != io.EOF {
		conn.SetReusable(false)
	}

	if request.Option.Has(protocol.RequestOptionChunkStream) {
		err := streamWriter.Write(alloc.NewSmallBuffer().Clear())
		if err != nil {
			conn.SetReusable(false)
		}
	}
	streamWriter.Release()
	return
}
Exemple #3
0
func (this *Server) handlePlainHTTP(request *http.Request, dest v2net.Destination, reader *bufio.Reader, writer io.Writer) {
	if len(request.URL.Host) <= 0 {
		response := this.GenerateResponse(400, "Bad Request")
		response.Write(writer)

		return
	}

	request.Host = request.URL.Host
	StripHopByHopHeaders(request)

	ray := this.packetDispatcher.DispatchToOutbound(dest)
	defer ray.InboundInput().Close()
	defer ray.InboundOutput().Release()

	var finish sync.WaitGroup
	finish.Add(1)
	go func() {
		defer finish.Done()
		requestWriter := v2io.NewBufferedWriter(v2io.NewChainWriter(ray.InboundInput()))
		err := request.Write(requestWriter)
		if err != nil {
			log.Warning("HTTP: Failed to write request: ", err)
			return
		}
		requestWriter.Flush()
	}()

	finish.Add(1)
	go func() {
		defer finish.Done()
		responseReader := bufio.NewReader(v2io.NewChanReader(ray.InboundOutput()))
		response, err := http.ReadResponse(responseReader, request)
		if err != nil {
			log.Warning("HTTP: Failed to read response: ", err)
			response = this.GenerateResponse(503, "Service Unavailable")
		}
		responseWriter := v2io.NewBufferedWriter(writer)
		err = response.Write(responseWriter)
		if err != nil {
			log.Warning("HTTP: Failed to write response: ", err)
			return
		}
		responseWriter.Flush()
	}()
	finish.Wait()
}
Exemple #4
0
func (this *SocksServer) handleConnection(connection *hub.TCPConn) {
	defer connection.Close()

	timedReader := v2net.NewTimeOutReader(120, connection)
	reader := v2io.NewBufferedReader(timedReader)

	writer := v2io.NewBufferedWriter(connection)

	auth, auth4, err := protocol.ReadAuthentication(reader)
	if err != nil && err != protocol.Socks4Downgrade {
		log.Error("Socks: failed to read authentication: ", err)
		return
	}

	if err != nil && err == protocol.Socks4Downgrade {
		this.handleSocks4(reader, writer, auth4)
	} else {
		this.handleSocks5(reader, writer, auth)
	}
}
Exemple #5
0
func (this *VMessOutboundHandler) handleRequest(session *raw.ClientSession, conn net.Conn, request *proto.RequestHeader, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) {
	defer finish.Unlock()

	writer := v2io.NewBufferedWriter(conn)
	session.EncodeRequestHeader(request, writer)

	// 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.Option.IsChunkStream() {
		vmessio.Authenticate(firstChunk)
	}

	bodyWriter := session.EncodeRequestBody(writer)
	bodyWriter.Write(firstChunk.Value)
	firstChunk.Release()

	writer.SetCached(false)

	if moreChunks {
		var streamWriter v2io.ReleasableWriter = v2io.NewAdaptiveWriter(bodyWriter)
		if request.Option.IsChunkStream() {
			streamWriter = vmessio.NewAuthChunkWriter(streamWriter)
		}
		v2io.ChanToWriter(streamWriter, input)
		streamWriter.Release()
	}
	return
}
Exemple #6
0
func (this *VMessInboundHandler) HandleConnection(connection internet.Connection) {
	defer connection.Close()

	if !this.accepting {
		return
	}

	connReader := v2net.NewTimeOutReader(8, connection)
	defer connReader.Release()

	reader := v2io.NewBufferedReader(connReader)
	defer reader.Release()

	this.RLock()
	if !this.accepting {
		this.RUnlock()
		return
	}
	session := raw.NewServerSession(this.clients)
	defer session.Release()

	request, err := session.DecodeRequestHeader(reader)
	this.RUnlock()

	if err != nil {
		if err != io.EOF {
			log.Access(connection.RemoteAddr(), "", log.AccessRejected, err)
			log.Warning("VMessIn: Invalid request from ", connection.RemoteAddr(), ": ", err)
		}
		connection.SetReusable(false)
		return
	}
	log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "")
	log.Info("VMessIn: Received request for ", request.Destination())

	connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse))

	ray := this.packetDispatcher.DispatchToOutbound(request.Destination())
	input := ray.InboundInput()
	output := ray.InboundOutput()
	defer input.Close()
	defer output.Release()

	var readFinish sync.Mutex
	readFinish.Lock()

	userSettings := protocol.GetUserSettings(request.User.Level)
	connReader.SetTimeOut(userSettings.PayloadReadTimeout)
	reader.SetCached(false)

	go func() {
		bodyReader := session.DecodeRequestBody(reader)
		var requestReader v2io.Reader
		if request.Option.Has(protocol.RequestOptionChunkStream) {
			requestReader = vmessio.NewAuthChunkReader(bodyReader)
		} else {
			requestReader = v2io.NewAdaptiveReader(bodyReader)
		}
		err := v2io.Pipe(requestReader, input)
		if err != io.EOF {
			connection.SetReusable(false)
		}

		requestReader.Release()
		input.Close()
		readFinish.Unlock()
	}()

	writer := v2io.NewBufferedWriter(connection)
	defer writer.Release()

	response := &protocol.ResponseHeader{
		Command: this.generateCommand(request),
	}

	if connection.Reusable() {
		response.Option.Set(protocol.ResponseOptionConnectionReuse)
	}

	session.EncodeResponseHeader(response, writer)

	bodyWriter := session.EncodeResponseBody(writer)
	var v2writer v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter)
	if request.Option.Has(protocol.RequestOptionChunkStream) {
		v2writer = vmessio.NewAuthChunkWriter(v2writer)
	}

	// Optimize for small response packet
	if data, err := output.Read(); err == nil {
		if err := v2writer.Write(data); err != nil {
			connection.SetReusable(false)
		}

		writer.SetCached(false)

		err = v2io.Pipe(output, v2writer)
		if err != io.EOF {
			connection.SetReusable(false)
		}

	}
	output.Release()
	if request.Option.Has(protocol.RequestOptionChunkStream) {
		if err := v2writer.Write(alloc.NewSmallBuffer().Clear()); err != nil {
			connection.SetReusable(false)
		}
	}
	v2writer.Release()

	readFinish.Lock()
}
Exemple #7
0
func (this *VMessInboundHandler) HandleConnection(connection *hub.TCPConn) {
	defer connection.Close()

	connReader := v2net.NewTimeOutReader(16, connection)

	reader := v2io.NewBufferedReader(connReader)
	session := raw.NewServerSession(this.clients)

	request, err := session.DecodeRequestHeader(reader)
	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.Destination(), log.AccessAccepted, serial.StringLiteral(""))
	log.Debug("VMessIn: Received request for ", request.Destination())

	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 := proto.GetUserSettings(request.User.Level)
	connReader.SetTimeOut(userSettings.PayloadReadTimeout)
	reader.SetCached(false)
	go func() {
		defer close(input)
		defer readFinish.Unlock()
		bodyReader := session.DecodeRequestBody(reader)
		var requestReader v2io.Reader
		if request.Option.IsChunkStream() {
			requestReader = vmessio.NewAuthChunkReader(bodyReader)
		} else {
			requestReader = v2io.NewAdaptiveReader(bodyReader)
		}
		v2io.ReaderToChan(input, requestReader)
	}()

	writer := v2io.NewBufferedWriter(connection)

	response := &proto.ResponseHeader{
		Command: this.generateCommand(request),
	}

	session.EncodeResponseHeader(response, writer)

	bodyWriter := session.EncodeResponseBody(writer)

	// Optimize for small response packet
	if data, open := <-output; open {
		if request.Option.IsChunkStream() {
			vmessio.Authenticate(data)
		}
		bodyWriter.Write(data.Value)
		data.Release()

		writer.SetCached(false)
		go func(finish *sync.Mutex) {
			var writer v2io.Writer = v2io.NewAdaptiveWriter(bodyWriter)
			if request.Option.IsChunkStream() {
				writer = vmessio.NewAuthChunkWriter(writer)
			}
			v2io.ChanToWriter(writer, output)
			finish.Unlock()
		}(&writeFinish)
		writeFinish.Lock()
	}

	connection.CloseWrite()
	readFinish.Lock()
}