Skip to content

Instantly share code, notes, and snippets.

@didge
Last active June 17, 2022 02:33
Show Gist options
  • Select an option

  • Save didge/0ad090139ad254320ad25291422dd6fe to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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
Copy Markdown
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