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); } }
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; }