Wednesday, August 13, 2014

A simple TCP proxy forwarder in .NET

Here's a way of doing a super simple TCP proxy in C#.

Warning: this should only be used for testing purposes, as it will leak threads.

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

class Program
{
    static void ProxyStream(string stream1name, NetworkStream stream1, string stream2name, NetworkStream stream2)
    {
        var buffer = new byte[65536];

        try
        {
            while (true)
            {
                var len = stream1.Read(buffer, 0, 65536);
                stream2.Write(buffer, 0, len);
            }
        }
        catch (Exception)
        {
            Console.WriteLine("Stream from " + stream1name + " to " + stream2name + " closed");
        }
    }

    static void Main(string[] args)
    {
        if (args.Length != 3)
        {
            Console.WriteLine("Usage: program.exe localport remoteServerHost remoteServerPort");
            Console.WriteLine("Example: program.exe 13389 10.1.2.3 3389");
            return;
        }

        var localPort = int.Parse(args[0]);
        var remoteServerHost = args[1];
        var remoteServerPort = int.Parse(args[2]);

        var l = new TcpListener(IPAddress.Any, localPort);
        l.Start();
        while (true)
        {
            var client1 = l.AcceptTcpClient();
            var remoteAddress = (client1.Client.RemoteEndPoint as IPEndPoint).Address.ToString();
            Console.WriteLine("Accepted session from " + remoteAddress);
            var client2 = new TcpClient(remoteServerHost, remoteServerPort);
            Console.WriteLine("Created connection to " + remoteServerHost + ":" + remoteServerPort);

            new Thread(() => { ProxyStream(remoteAddress, client1.GetStream(), remoteServerHost, client2.GetStream()); }).Start();
            new Thread(() => { ProxyStream(remoteServerHost, client2.GetStream(), remoteAddress, client1.GetStream()); }).Start();
        }
    }
}

Or, if you need this from PowerShell, I would suggest wrapping it (as threads in PowerShell are painful):
$source = '
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

class Program
{
    static void ProxyStream(string stream1name, NetworkStream stream1, string stream2name, NetworkStream stream2)
    {
        var buffer = new byte[65536];

        try
        {
            while (true)
            {
                var len = stream1.Read(buffer, 0, 65536);
                stream2.Write(buffer, 0, len);
            }
        }
        catch (Exception)
        {
            Console.WriteLine("Stream from " + stream1name + " to " + stream2name + " closed");
        }
    }

    static void Main(string[] args)
    {
        if (args.Length != 3)
        {
            Console.WriteLine("Usage: program.exe localport remoteServerHost remoteServerPort");
            Console.WriteLine("Example: program.exe 13389 10.1.2.3 3389");
            return;
        }

        var localPort = int.Parse(args[0]);
        var remoteServerHost = args[1];
        var remoteServerPort = int.Parse(args[2]);

        var l = new TcpListener(IPAddress.Any, localPort);
        l.Start();
        while (true)
        {
            var client1 = l.AcceptTcpClient();
            var remoteAddress = (client1.Client.RemoteEndPoint as IPEndPoint).Address.ToString();
            Console.WriteLine("Accepted session from " + remoteAddress);
            var client2 = new TcpClient(remoteServerHost, remoteServerPort);
            Console.WriteLine("Created connection to " + remoteServerHost + ":" + remoteServerPort);

            new Thread(() => { ProxyStream(remoteAddress, client1.GetStream(), remoteServerHost, client2.GetStream()); }).Start();
            new Thread(() => { ProxyStream(remoteServerHost, client2.GetStream(), remoteAddress, client1.GetStream()); }).Start();
        }
    }
}

'
Add-Type `
    -TypeDefinition $source `
    -Language CSharp `
    -OutputAssembly 'c:\windows\temp\tcpproxy.exe' `
    -OutputType 'ConsoleApplication'

No comments:

Post a Comment