Working kinda
This commit is contained in:
parent
359f94c3d9
commit
f96c65f795
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,6 +3,8 @@
|
||||
##
|
||||
## Get latest from `dotnet new gitignore`
|
||||
|
||||
|
||||
log*
|
||||
# dotenv files
|
||||
.env
|
||||
|
||||
|
||||
218
Listener.cs
Normal file
218
Listener.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
22
Program.cs
22
Program.cs
@ -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
7
config.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"listen_port":"8080",
|
||||
"ssl_address":"localhost",
|
||||
"ssl_port":3000,
|
||||
"tcp_address":"localhost",
|
||||
"tcp_port":25569
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user