private async Task HandleAsync(Socket socket, CancellationToken token)
    {
        try
        {
            IDuplexPipe pipe   = socket.AsDuplexPipe();
            ReadResult  result = await pipe.Input.ReadAsync(token);

            ReadOnlySequence <byte> buffer = result.Buffer;

            if (IsSocks5Header(buffer))
            {
                using TcpClient socks5 = new();
                await socks5.ConnectAsync(_socks5CreateOption.Address !, _socks5CreateOption.Port, token);

                IDuplexPipe socks5Pipe = socks5.Client.AsDuplexPipe();

                await socks5Pipe.Output.WriteAsync(buffer, token);

                pipe.Input.AdvanceTo(buffer.End);

                await socks5Pipe.LinkToAsync(pipe, token);
            }
            else
            {
                pipe.Input.AdvanceTo(buffer.Start, buffer.End);
                pipe.Input.CancelPendingRead();

                await _httpToSocks5.ForwardToSocks5Async(pipe, _socks5CreateOption, token);
            }
        }
        finally
        {
            socket.FullClose();
        }
    private async Task HandleAsync(Socket socket, CancellationToken token)
    {
        EndPoint?remoteEndPoint = socket.RemoteEndPoint;

        try
        {
            IDuplexPipe pipe   = socket.AsDuplexPipe(DefaultSocketPipeReaderOptions, DefaultSocketPipeWriterOptions);
            ReadResult  result = await pipe.Input.ReadAsync(token);

            ReadOnlySequence <byte> buffer = result.Buffer;

            ILocalTcpService?service = _services.FirstOrDefault(tcpService => tcpService.IsHandle(buffer));

            if (service is null)
            {
                throw new InvalidDataException(@"Cannot handle incoming pipe.");
            }

            pipe.Input.AdvanceTo(buffer.Start, buffer.End);
            pipe.Input.CancelPendingRead();

            // In every service.HandleAsync, first ReadResult.IsCanceled always true
            await service.HandleAsync(pipe, token);
        }
        catch (ObjectDisposedException)
        {
        }
        catch (IOException ex) when(ex.InnerException is SocketException)
        {
        }
        catch (OperationCanceledException)
        {
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, @"Handle Error");
        }
        finally
        {
            socket.FullClose();
            _logger.LogInformation(@"{Remote} disconnected", remoteEndPoint);
        }
    }
Example #3
0
    private async ValueTask HandleAsync(Socket socket, CancellationToken token)
    {
        try
        {
            IDuplexPipe            pipe    = socket.AsDuplexPipe();
            Socks5ServerConnection service = new(pipe, _credential);
            await service.AcceptClientAsync(token);

            switch (service.Command)
            {
            case Command.Connect:
            {
                using TcpClient tcp = new();
                if (service.Target.Type is AddressType.Domain)
                {
                    Assumes.NotNull(service.Target.Domain);
                    await tcp.ConnectAsync(service.Target.Domain, service.Target.Port, token);
                }
                else
                {
                    Assumes.NotNull(service.Target.Address);
                    await tcp.ConnectAsync(service.Target.Address, service.Target.Port, token);
                }

                await service.SendReplyAsync(Socks5Reply.Succeeded, ReplyTcpBound, token);

                IDuplexPipe tcpPipe = tcp.Client.AsDuplexPipe();

                await tcpPipe.LinkToAsync(pipe, token);

                break;
            }

            case Command.Bind:
            {
                await service.SendReplyAsync(Socks5Reply.CommandNotSupported, ReplyTcpBound, token);

                break;
            }

            case Command.UdpAssociate:
            {
                IPEndPoint remote = (IPEndPoint)socket.RemoteEndPoint !;
                IPEndPoint local  = new(((IPEndPoint)TcpListener.LocalEndpoint).Address, IPEndPoint.MinPort);
                using SimpleSocks5UdpServer udpServer = new(local, remote);
                udpServer.StartAsync().Forget();

                ServerBound replyUdpBound = new()
                {
                    Type    = AddressType.IPv4,
                    Address = local.Address,
                    Domain  = default,
                    Port    = (ushort)((IPEndPoint)udpServer.UdpListener.Client.LocalEndPoint !).Port,
                };

                await service.SendReplyAsync(Socks5Reply.Succeeded, replyUdpBound, token);

                // wait remote close
                ReadResult result = await pipe.Input.ReadAsync(token);

                Report.IfNot(result.IsCompleted);

                break;
            }