Skip to content

Instantly share code, notes, and snippets.

@didge
Last active June 17, 2022 02:33
Show Gist options
  • Save didge/0ad090139ad254320ad25291422dd6fe to your computer and use it in GitHub Desktop.
Save didge/0ad090139ad254320ad25291422dd6fe to your computer and use it in GitHub Desktop.
Static C# TCP Proxy
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace didge {
public class StaticTcpProxy {
// Use this method to proxy from the proxy's port to the target server's end point. Stop the proxy using returned the CancellationTokenSource.
public static CancellationTokenSource Start(IPEndPoint proxyServerEndPoint, IPEndPoint serverEndPoint) {
var cancellationTokenSource = new CancellationTokenSource();
Task.Run(async () => {
await Start(proxyServerEndPoint, serverEndPoint, cancellationTokenSource.Token);
});
return cancellationTokenSource;
}
// Use this method with Task.WhenAny to share a single CancellationToken between several proxies
public static async Task Start(IPEndPoint proxyServerEndPoint, IPEndPoint serverEndPoint, CancellationToken token) {
var proxyServer = new TcpListener(proxyServerEndPoint);
proxyServer.Start();
token.Register(() => proxyServer.Stop());
while(true) {
try {
var proxyClient = await proxyServer.AcceptTcpClientAsync();
proxyClient.NoDelay = true;
Run(proxyClient, serverEndPoint);
}
catch(Exception exc) {
Console.WriteLine(exc);
}
}
}
private static void Run(TcpClient proxyClient, IPEndPoint serverEndPoint) {
Task.Run(async () => {
try {
using(proxyClient)
using(var serverClient = new TcpClient()) {
serverClient.NoDelay = true;
await serverClient.ConnectAsync(serverEndPoint.Address, serverEndPoint.Port);
var serverStream = serverClient.GetStream();
var proxyStream = proxyClient.GetStream();
await Task.WhenAny(proxyStream.CopyToAsync(serverStream), serverStream.CopyToAsync(proxyStream));
}
}
catch(Exception exc) {
Console.WriteLine(exc);
}
});
}
}
}
// An interesting TCP proxy demonstrating await and using static methods only.
// E.g proxy from port 8080 to port 80 on the localhost:
// 1. Start:
var cancellationTokenSource = TcpProxy.Start(
new IPEndPoint(IPAddress.Any, 8080),
new IPEndPoint(IPAddress.Loopback, 80)
);
// 2. Stop:
cancellationTokenSource.Cancel();
@BarelyAliveMau5
Copy link

BarelyAliveMau5 commented Jan 28, 2022

Great job! i have a few corrections to suggest that were necessary to make it work:

in StaticTcpProxy.cs replace line 13:
from:

Start(proxyServerEndPoint, serverEndPoint, cancellationTokenSource.Token);

to:

await Start(proxyServerEndPoint, serverEndPoint, cancellationTokenSource.Token);

in StaticTcpProxy.cs replace line 43:
from:

await Task.WhenAny(proxyStream.CopyToAsync(serverClient.GetStream()), serverStream.CopyToAsync(proxyClient.GetStream()));

to:

await Task.WhenAny(proxyClient.GetStream().CopyToAsync(serverClient.GetStream()), serverClient.GetStream().CopyToAsync(proxyClient.GetStream()));

@didge
Copy link
Author

didge commented Jan 28, 2022

Done and thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment