Working kinda

This commit is contained in:
Kecskeméti László 2024-03-27 01:53:17 +01:00
parent 359f94c3d9
commit f96c65f795
4 changed files with 247 additions and 2 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
##
## Get latest from `dotnet new gitignore`
log*
# dotenv files
.env

218
Listener.cs Normal file
View File

@ -0,0 +1,218 @@
using System.Net;
using System.Net.Sockets;
using Serilog;
class Listener{
public event EventHandler? Stopped;
private TcpListener listener;
private List<Client> clients = new();
public Listener(){
Log.Information("Starting listener");
this.listener=new TcpListener(IPAddress.Any,Config.listen_port);
listener.Start();
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}
private void AcceptClient(IAsyncResult res){
TcpClient? client = null;
try{
client = listener.EndAcceptTcpClient(res);
}catch(Exception ex){
Log.Error(ex, "Error while accepting incoming connection");
}
if(client!=null){
Client? new_client = null;
try{
new_client=new Client(client);
}catch(Exception ex){
Log.Error(ex, "Error creating new client instance");
}
if(new_client==null){
client.Close();
}else{
clients.Add(new_client);
new_client.Stopped+=ClientStopped;
Log.Information("Client connected: {Endpoint}", client.Client.RemoteEndPoint);
}
}
try{
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptClient), null);
}catch(Exception ex){
Log.Fatal(ex, "Failed to start new client accept cycle");
Stop();
}
}
private void ClientStopped(object? sender, EventArgs e){
clients.Remove((Client)sender!);
}
public void Stop(){
Log.Information("Stopping listener");
listener.Stop();
while(clients.Count>0){
clients[0].Stop();
}
Stopped?.Invoke(this,EventArgs.Empty);
}
private class Client{
public event EventHandler? Stopped;
private TcpClient client;
private NetworkStream stream;
private CancellationTokenSource cts = new CancellationTokenSource();
private EndPoint endPoint;
private TcpClient? relay_client;
private NetworkStream? relay_stream;
long data_recv = 0;
long data_sent = 0;
public Client(TcpClient client){
this.client=client;
endPoint=client.Client.RemoteEndPoint!;
Log.Debug("Starting client handler for {Endpoint}", endPoint);
stream=client.GetStream();
client.NoDelay=true;
_ = Identify();
}
private Task Identify(){
return Task.Run(async ()=>{
Log.Debug("Trying to identify {Endpoint}", endPoint);
byte[] packet = new byte[16];
int packet_size;
try{
packet_size = await stream.ReadAtLeastAsync(packet, 1, false, cts.Token);
}catch(Exception ex){
Log.Information(ex, "Error while recieving from {Endpoint}", endPoint);
Stop();
return;
}
if(packet_size==0){
Log.Information("Client disconnected {Endpoint}", endPoint);
Stop();
return;
}
bool tls;
if(packet[0] != 0x16 /*tls magic byte*/){
Log.Information("Client {Endpoint} identified as TCP", endPoint);
// simple tcp connection
tls=false;
}else{
Log.Information("Client {Endpoint} identified as TLS", endPoint);
// tls connection
tls=true;
}
try{
relay_client = new TcpClient(tls ? Config.ssl_address : Config.tcp_address, tls ? Config.ssl_port : Config.tcp_port);
relay_stream = relay_client.GetStream();
relay_client.NoDelay=true;
relay_stream.Write(packet, 0, packet_size);
data_recv+=packet_size;
Log.Information("Starting relay for {Endpoint}", endPoint);
_ = RelayFromClient();
_ = RelayToClient();
}catch(Exception ex){
Log.Error(ex, "Failed to connect client to relay server {Endpoint}", endPoint);
Stop();
return;
}
});
}
private Task RelayFromClient(){
return Task.Run(async ()=>{
try{
byte[] buffer = new byte[4096];
int bytes_read = 0;
while(!cts.Token.IsCancellationRequested){
bytes_read = await stream.ReadAsync(buffer, cts.Token);
data_recv+=bytes_read;
if(bytes_read == 0){
Log.Information("Client disconnected {Endpoint}", endPoint);
Stop();
break;
}
await relay_stream!.WriteAsync(buffer.AsMemory(0, bytes_read), cts.Token);
}
}catch(TaskCanceledException){
}catch(OperationCanceledException){
}catch(AggregateException ex){
if(ex.InnerException is not TaskCanceledException){
Log.Debug(ex, "Error while recieving from client {Endpoint}", endPoint);
Stop();
}
}catch(Exception ex){
Log.Debug(ex, "Error while recieving from client {Endpoint}", endPoint);
Stop();
}
});
}
private Task RelayToClient(){
return Task.Run(async ()=>{
try{
byte[] buffer = new byte[4096];
int bytes_read = 0;
while(!cts.Token.IsCancellationRequested){
bytes_read = await relay_stream!.ReadAsync(buffer, cts.Token);
data_sent+=bytes_read;
if(bytes_read == 0){
Log.Information("Relay disconnected {Endpoint}", endPoint);
Stop();
break;
}
await stream!.WriteAsync(buffer.AsMemory(0, bytes_read), cts.Token);
}
}catch(TaskCanceledException){
}catch(OperationCanceledException){
}catch(AggregateException ex){
if(ex.InnerException is not TaskCanceledException){
Log.Debug(ex, "Error while recieving from relay {Endpoint}", endPoint);
Stop();
}
}catch(Exception ex){
Log.Debug(ex, "Error while recieving from relay {Endpoint}", endPoint);
Stop();
}
});
}
public void Stop(){
if(cts.Token.IsCancellationRequested) return;
Log.Information("Stopping client for {Endpoint}\nTotal: Tx: {Transmit} bytes, Rx: {Recieve} bytes", endPoint, data_sent, data_recv);
cts.Cancel();
try{
client.Close();
}catch(Exception ex){
Log.Error(ex, "Error closing client: {Endpoint}", endPoint);
}
if(relay_client != null){
try{
relay_client.Close();
}catch(Exception ex){
Log.Error(ex, "Error closing relay: {Endpoint}", endPoint);
}
}
Stopped?.Invoke(this, EventArgs.Empty);
}
}
}

View File

@ -7,10 +7,28 @@ internal class Program
Log.Logger =
new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File($"log-{DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss")}.txt")
.WriteTo.File($"log-{DateTime.Now:yyyy-MM-dd-hh-mm-ss}.txt")
.MinimumLevel.Debug()
.CreateLogger();
Listener listener = new Listener();
AutoResetEvent quit = new AutoResetEvent(false);
Console.CancelKeyPress+=(object? s, ConsoleCancelEventArgs e)=>{
e.Cancel=true;
quit.Set();
};
listener.Stopped+=(object? s, EventArgs e)=>{
quit.Set();
};
quit.WaitOne();
Log.Information("Stopping...");
listener.Stop();
Log.Information("Exit");
}
}

7
config.json Normal file
View File

@ -0,0 +1,7 @@
{
"listen_port":"8080",
"ssl_address":"localhost",
"ssl_port":3000,
"tcp_address":"localhost",
"tcp_port":25569
}