Thursday, August 05, 2010

Implementing a multithreaded http/https debugging proxy server in C#

A complete proxy server except instead of SSL Tunneling, will perform a "man-in-the-middle" decryption on SSL traffic allowing you to inspect the encrypted traffic
Download HTTPProxy-src - 10.14 KB
Download HTTPProxy-bin - 10.4 KB
Introduction
This article will show you how to implement a multithreaded http proxy server in C# with a non-standard proxy server feature of terminating and then proxying https traffic. I've added a simple caching mechanism, and have simplified the code by ignoring http/1.1 requests for keeping connections alive, etc.
Disclaimer:Understand that this code is for debugging and testing purposes only. The author does not intend for this code or the executable to be used in any way that may compromise someone's sensitive information. Do not use this server in any environment which has users that are unaware of its use. By using this code or the executable found in this article you are taking responsibility for the data which may be collected through its use.
Background
If you are familiar with fiddler, then you already know how this proxy server works. It essentially performs a "man-in-the-middle" on the http client to dump and debug http traffic. The System.Net.Security.SslStream class is utilitzed to handle all the heavy lifting.
Using the code
The most important part about this code is that when the client asks for a CONNECT, instead of just passing tcp traffic, we're going to handle an ssl handshake and estabish an ssl session and  receive a request from the client. In the mean time we'll send the same request to the destination https server.
First, let's look at creating a server that can handle multiple concurrent tcp connections. We'll use the System.Threading.Thread object to start listening for connections in a separate thread. This thread's job will be to listen for incoming connections, and then spawn a new thread to handle processing, thus allowing the listening thread to continue listening for new connections without blocking while one client is processed.
public sealed class ProxyServer
{
  private TcpListener _listener;
  private Thread _listenerThread;
  public void Start()
  {
     _listener = new TcpListener(IPAddress.Loopback, 8888);
     _listenerThread = new Thread(new ParameterizedThreadStart(Listen));
     _listenerThread.Start(_listener);
  }
     
  public void Stop()
  {
     //stop listening for incoming connections
     _listener.Stop();
     //wait for server to finish processing current connections...
     _listenerThread.Abort();
     _listenerThread.Join();
  }
  private static void Listen(Object obj)
  {
     TcpListener listener = (TcpListener)obj;
     try
     {
        while (true)
        {
           TcpClient client = listener.AcceptTcpClient();
           while (!ThreadPool.QueueUserWorkItem(new WaitCallback(ProxyServer.ProcessClient), client)) ;
        }
     }
     catch (ThreadAbortException) { }
     catch (SocketException) { }
  }
  private static void ProcessClient(Object obj)
  {
     TcpClient client = (TcpClient)obj;
     try
     {
Read more: Codeproject