I've written a console application that acts as a proxy server. Now I like to implement SSL as well. Do not like to decrypt any traffic. Just like a normal https proxy. I'm not sure how I should go on.
var host = text.Remove(0, connectText.Length + 1);
var hostIndex = host.IndexOf(" ", StringComparison.Ordinal);
var hostEntry = host.Remove(hostIndex).Split(new []{":"}, StringSplitOptions.None);
requestClient.Connect(hostEntry[0], Convert.ToInt32(hostEntry[1]));
requestStream = requestClient.GetStream();
var sslStream = new SslStream(requestStream, false, (x1,x2,x3,x4) => true);
sslStream.AuthenticateAsClient(hostEntry[0]);
const string sslResponse = "HTTP/1.0 200 Connection established\r\n\r\n";
var sslResponseBytes = Encoding.UTF8.GetBytes(sslResponse);
proxyStream.Write(sslResponseBytes, 0, sslResponseBytes.Length);
proxyStream.Flush();
Should I directly write everything into sslStream? What about the browser connection proxyClient
. Did I need to wrap the stream as well or can I just write everything directly into proxyStream
? Should I use AuthenticateAsServer and pass somehow the certificate from AuthenticateAsClient?
- IE issues a CONNECT request to my proxy
- my proxy sees that it's a CONNECT request and gets the IP: port of the destination (eg, www.hotmail.com:443)
- my proxy creates a new TCP connection to www.hotmail.com:443
- my proxy gets a SslStream from this destination and calls AuthenticateAsClient - this gives my proxy a secure connection to the Hotmail side of things
- my proxy then sends an "HTTP/1.0 200" message back to the browser to say that the CONNECT was successful
- my proxy then gets a SslStream from the browser connection and calls AuthenticateAsServer - gives my proxy a secure connection to the browser side of things
I saw this, but how AuthenticateAsServer without a fake certificate. Can I just write that like in my normal streams or should i consider something?
static void Main(string[] args)
{
var tcpServer = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
tcpServer.Start();
while (true)
{
var proxyClient = tcpServer.AcceptTcpClient();
var requestClient = new TcpClient();
var proxyStream = proxyClient.GetStream();
NetworkStream requestStream = null;
var bytes = new byte[proxyClient.ReceiveBufferSize];
var hostHeaderAvailable = 0;
int count;
while (proxyStream.DataAvailable)
{
count = proxyStream.Read(bytes, 0, bytes.Length);
if (hostHeaderAvailable == 0)
{
var text = Encoding.UTF8.GetString(bytes);
const string connectText = "connect";
const string hostText = "Host: ";
//HTTPS NOT FULLY IMPLEMENTED YET
if (text.ToLower().StartsWith(connectText))
{
var host = text.Remove(0, connectText.Length + 1);
var hostIndex = host.IndexOf(" ", StringComparison.Ordinal);
var hostEntry = host.Remove(hostIndex).Split(new []{":"}, StringSplitOptions.None);
requestClient.Connect(hostEntry[0], Convert.ToInt32(hostEntry[1]));
requestStream = requestClient.GetStream();
var sslStream = new SslStream(requestStream, false, (x1,x2,x3,x4) => true);
sslStream.AuthenticateAsClient(hostEntry[0]);
const string sslResponse = "HTTP/1.0 200 Connection established\r\n\r\n";
var sslResponseBytes = Encoding.UTF8.GetBytes(sslResponse);
proxyStream.Write(sslResponseBytes, 0, sslResponseBytes.Length);
proxyStream.Flush();
}
//HTTP WORKS LIKE A CHARM
else {
var hostIndex = text.IndexOf(hostText, StringComparison.Ordinal);
if (hostIndex < 0)
continue;
var host = text.Remove(0, hostIndex + hostText.Length);
hostIndex = host.IndexOf("\n", StringComparison.Ordinal);
if (hostIndex < 0)
continue;
host = host.Remove(hostIndex).Replace("\r", "");
requestClient.Connect(host, 80);
requestStream = requestClient.GetStream();
}
}
hostHeaderAvailable++;
if (requestClient.Connected) {
requestStream.Write(bytes, 0, count);
}
}
if (!requestClient.Connected) {
proxyStream.Close();
proxyClient.Close();
continue;
}
var timeout = 0;
while (!requestStream.DataAvailable) {
if (timeout > 12)
break;
Thread.Sleep(500);
timeout++;
}
while (requestStream.DataAvailable)
{
count = requestStream.Read(bytes, 0, bytes.Length);
proxyStream.Write(bytes, 0, count);
}
proxyStream.Close();
proxyClient.Close();
}
}