//This is called when client is aware of proxy private static void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient client) { Stream clientStream = client.GetStream(); var clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); var clientStreamWriter = new StreamWriter(clientStream); Uri httpRemoteUri; try { //read the first line HTTP command var httpCmd = clientStreamReader.ReadLine(); if (string.IsNullOrEmpty(httpCmd)) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(SpaceSplit, 3); var httpVerb = httpCmdSplit[0]; if (httpVerb.ToUpper() == "CONNECT") httpRemoteUri = new Uri("http://" + httpCmdSplit[1]); else httpRemoteUri = new Uri(httpCmdSplit[1]); var httpVersion = httpCmdSplit[2]; var excluded = endPoint.ExcludedHttpsHostNameRegex != null ? endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false; //Client wants to create a secure tcp tunnel (its a HTTPS request) if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80) { httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); clientStreamReader.ReadAllLines(); WriteConnectResponse(clientStreamWriter, httpVersion); var certificate = CertManager.CreateCertificate(httpRemoteUri.Host); SslStream sslStream = null; try { sslStream = new SslStream(clientStream, true); //Successfully managed to authenticate the client using the fake certificate sslStream.AuthenticateAsServer(certificate, false, SupportedProtocols, false); clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII); clientStreamWriter = new StreamWriter(sslStream); //HTTPS server created - we can now decrypt the client's traffic clientStream = sslStream; } catch { if (sslStream != null) sslStream.Dispose(); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } httpCmd = clientStreamReader.ReadLine(); } else if (httpVerb.ToUpper() == "CONNECT") { clientStreamReader.ReadAllLines(); WriteConnectResponse(clientStreamWriter, httpVersion); TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port, false); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now create the request HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter, httpRemoteUri.Scheme == Uri.UriSchemeHttps ? true : false); } catch { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); } }
public void StartProxy() { ProxyServer.BeforeRequest += OnRequest; ProxyServer.BeforeResponse += OnResponse; //Exclude Https addresses you don't want to proxy //Usefull for clients that use certificate pinning //for example dropbox.com var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true){ ExcludedHttpsHostNameRegex = new List<string>() { "dropbox.com" } }; //An explicit endpoint is where the client knows about the existance of a proxy //So client sends request in a proxy friendly manner ProxyServer.AddEndPoint(explicitEndPoint); ProxyServer.Start(); //Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy) //A transparent endpoint usually requires a network router port forwarding HTTP(S) packets to this endpoint //Currently do not support Server Name Indication (It is not currently supported by SslStream class) //That means that the transparent endpoint will always provide the same Generic Certificate to all HTTPS requests //In this example only google.com will work for HTTPS requests //Other sites will receive a certificate mismatch warning on browser //Please read about it before asking questions! var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true) { GenericCertificateName = "google.com" }; ProxyServer.AddEndPoint(transparentEndPoint); foreach (var endPoint in ProxyServer.ProxyEndPoints) Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); //You can also add/remove end points after proxy has been started ProxyServer.RemoveEndPoint(transparentEndPoint); //Only explicit proxies can be set as system proxy! ProxyServer.SetAsSystemHttpProxy(explicitEndPoint); ProxyServer.SetAsSystemHttpsProxy(explicitEndPoint); }