public void Start() { if (IsEnabled) { Port = GetFreeTcpPort(); var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, Port); ProxyServer.AddEndPoint(explicitEndPoint); ProxyServer.Start(); ProxyServer.BeforeRequest += OnRequestCaptureTrafficEventHandler; ProxyServer.BeforeResponse += OnResponseCaptureTrafficEventHandler; ProxyServer.BeforeRequest += OnRequestBlockResourceEventHandler; ProxyServer.BeforeRequest += OnRequestRedirectTrafficEventHandler; ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation; ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; } }
public EtpSelfHostedProxyWebServer(int port, IEtpSelfHostedWebServer proxiedServer) { _proxiedServer = proxiedServer; _proxyServer = new ProxyServer(); var uri = proxiedServer.Uri; var builder = new UriBuilder(uri.Scheme, uri.Host, port, uri.AbsolutePath, uri.Query); ProxyUri = builder.Uri; var endPoint = new ExplicitProxyEndPoint(IPAddress.Loopback, ProxyUri.Port, false); endPoint.GenericCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(); _proxyServer.ProxyBasicAuthenticateFunc = HandleBasicAuthentication; _proxyServer.AddEndPoint(endPoint); }
public static void Main(string[] args) { var proxyServer = new ProxyServer(); proxyServer.CertificateManager.EnsureRootCertificate(); proxyServer.CertificateManager.TrustRootCertificate(); proxyServer.BeforeRequest += OnRequest; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 1234); proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); Console.Read(); proxyServer.Stop(); }
public void StartProxy() { proxyServer.BeforeRequest += OnRequest; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);//listen on port 8000 proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); 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); } //Only explicit proxies can be set as system proxy! proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); }
public ProxyTorController(ConfigProxy config) { Task.Run(() => listenToConsole()); _proxyServer = new ProxyServer(); _proxyServer.ExceptionFunc = async exception => { if (exception is ProxyHttpException phex) { WriteToConsole(exception.Message + ": " + phex.InnerException?.Message, ConsoleColor.Red); } else { WriteToConsole(exception.Message, ConsoleColor.Red); } }; _proxyServer.TcpTimeWaitSeconds = 60; _proxyServer.ConnectionTimeOutSeconds = 65; _proxyServer.ReuseSocket = false; _proxyServer.EnableConnectionPool = true; _proxyServer.ForwardToUpstreamGateway = true; _proxyServer.CertificateManager.SaveFakeCertificates = true; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, config.Port, false); _proxyServer.AddEndPoint(explicitEndPoint); _tors = new List <TorInfo>(); for (var i = config.Tor.PortFrom; i <= config.Tor.PortTo; i++) { _tors.Add(new TorInfo { HostName = config.Tor.HostName, Port = i }); } }
public void StartProxy(int proxyPort) { proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, proxyPort, true); //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(); 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); } }
static void Main(string[] args) { _Config = GetConfig(); var port = _Config.GetValue <int>("Proxy:Port"); var proxyServer = new ProxyServer(); proxyServer.BeforeRequest += OnRequest; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, port, false); proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); Console.WriteLine($"** Logging proxy listening on port: {port} **"); _ResetEvent.WaitOne(); proxyServer.BeforeRequest -= OnRequest; proxyServer.Stop(); }
static void Main(string[] args) { var proxyServer = new ProxyServer(); var httpEP = new ExplicitProxyEndPoint(IPAddress.Any, 14300, false); var httpsEP = new ExplicitProxyEndPoint(IPAddress.Any, 14301, true); proxyServer.AddEndPoint(httpEP); proxyServer.AddEndPoint(httpsEP); proxyServer.BeforeRequest += OnRequest; proxyServer.Start(); Console.WriteLine("Press a key when you're done."); Console.Read(); proxyServer.BeforeRequest -= OnRequest; proxyServer.Stop(); }
private static void Main(string[] args) { #if DEBUG Debug.Listeners.Add(new ConsoleTraceListener()); #endif PrintLogo(); #if !NO_PLUGINS Console.WriteLine("Loading plugins"); Manager.LoadPlugins(); foreach (IHopePlugin plugin in Manager.Plugins) { plugin.Load(); } Console.WriteLine($"Loaded {Manager.Plugins.Count} Plugin{(Manager.Plugins.Count == 1 ? "" : "s")}!"); #else #warning Plugin support disabled! Console.WriteLine("Warning: This build does not support plugins."); #endif Console.WriteLine("Preparing proxy server..."); var proxyServer = new ProxyServer(); proxyServer.TrustRootCertificate = true; //this is needed for decrypting SSL traffic proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; var endpoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true); proxyServer.AddEndPoint(endpoint); Console.WriteLine("Starting proxy server..."); proxyServer.Start(); Console.WriteLine("Setting as system proxy..."); proxyServer.SetAsSystemHttpProxy(endpoint); proxyServer.SetAsSystemHttpsProxy(endpoint); Console.WriteLine("Waiting..."); Console.ReadLine(); }
public void Start() { Log("Start"); var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) { ExcludedHttpsHostNameRegex = new List <string> { "player.com", "dropbox.com" } }; _proxyServer.AddEndPoint(explicitEndPoint); _proxyServer.Start(); _proxyServer.SetAsSystemHttpProxy(explicitEndPoint); _proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); OnStarted?.Invoke(this, EventArgs.Empty); }
public void StartProxy() { _proxyServer.BeforeRequest += OnRequest; _proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; _proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true); _proxyServer.AddEndPoint(explicitEndPoint); _proxyServer.Start(); 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); } _proxyServer.SetAsSystemHttpProxy(explicitEndPoint); _proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); }
/// <summary> /// Set the given explicit end point as the default proxy server for current machine /// </summary> /// <param name="endPoint"></param> public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) { if (RunTime.IsRunningOnMono()) { throw new Exception("Mono Runtime do not support system proxy settings."); } ValidateEndPointAsSystemProxy(endPoint); //clear any settings previously added ProxyEndPoints.OfType <ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false); systemProxySettingsManager.SetHttpProxy( Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Loopback) ? "127.0.0.1" : endPoint.IpAddress.ToString(), endPoint.Port); endPoint.IsSystemHttpProxy = true; #if !DEBUG firefoxProxySettingsManager.AddFirefox(); #endif Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTP Proxy", endPoint.IpAddress, endPoint.Port); }
public static void Start() { string certName = "rootCert.pfx"; string certPassword = "******"; proxyServer.ForwardToUpstreamGateway = true; proxyServer.CertificateManager.SaveFakeCertificates = true; proxyServer.CertificateManager.PfxPassword = certPassword; proxyServer.CertificateManager.EnsureRootCertificate(); proxyServer.CertificateManager.TrustRootCertificate(true); proxyServer.CertificateManager.TrustRootCertificateAsAdmin(true); if (!File.Exists(certName)) { proxyServer.CertificateManager.CreateRootCertificate(true); } proxyServer.CertificateManager.RootCertificate = new X509Certificate2(certName, certPassword, X509KeyStorageFlags.Exportable); proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; //proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; //proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8080); proxyServer.AddEndPoint(explicitEndPoint); // Fired when a CONNECT request is received explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectResponse += OnBeforeTunnelConnectResponse; proxyServer.Start(); //Only explicit proxies can be set as system proxy! proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); }
public void Start() { // Link up handlers _proxyServer.BeforeRequest += OnRequest; _proxyServer.BeforeResponse += OnResponse; _proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; _proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; // Set ip and port to monitor var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Parse(ip), Port, true); _proxyServer.AddEndPoint(explicitEndPoint); // Start proxy server _proxyServer.Start(); if (Out != StreamWriter.Null) { Out.WriteLine($"[+++] Proxy started: listening at {explicitEndPoint.IpAddress}:{explicitEndPoint.Port} "); Out.WriteLine(); } }
public void StartProxy(int port, SafeNode[] nodes) { this.nodes = nodes; var PEP = new ExplicitProxyEndPoint(IPAddress.Any, port, false) { }; proxyServer.TrustRootCertificate = true; proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; proxyServer.AddEndPoint(PEP); proxyServer.Start(); 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); } proxyServer.SetAsSystemHttpProxy(PEP); proxyServer.SetAsSystemHttpsProxy(PEP); }
private void LoadingForm_Shown(object sender, EventArgs e) { internalSetupLbl.CurrentStatus = StatusLabel.Status.Current; mainForm = new MainForm(); //explicitEndpoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true); explicitEndpoint = new ExplicitProxyEndPoint(IPAddress.Parse("127.0.0.1"), 8000, true); proxyServer = new ProxyServer("Test cert", "Test cert issuer"); proxyServer.ForwardToUpstreamGateway = true; mainForm.proxyServer = proxyServer; proxyServer.AddEndPoint(explicitEndpoint); proxyServer.BeforeRequest += mainForm.ProxyServer_BeforeRequest; proxyServer.BeforeResponse += mainForm.ProxyServer_BeforeResponse; proxyServer.AfterResponse += mainForm.ProxyServer_AfterResponse; explicitEndpoint.BeforeTunnelConnectRequest += mainForm.ExplicitEndpoint_BeforeTunnelConnectRequest; explicitEndpoint.BeforeTunnelConnectResponse += mainForm.ExplicitEndpoint_BeforeTunnelConnectResponse; proxyServer.ClientConnectionCountChanged += mainForm.ProxyServer_ClientConnectionCountChanged; proxyServer.ServerConnectionCountChanged += mainForm.ProxyServer_ServerConnectionCountChanged; internalSetupLbl.CurrentStatus = StatusLabel.Status.Done; injectDetour(); }
public void StartProxy() { newEndPoint = new ExplicitProxyEndPoint(IPAddress.Loopback, _portNumber, true); SetRequestConfiguration(); //set actual blocking methods StartProxyWithEndPoint(); if (_isSystemProxy) { _proxyServer.SetAsSystemHttpProxy(explicitEndPoint); _proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); } 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); } ProxyRunning = _proxyServer.ProxyRunning; ProxyIsEnabled = _proxyServer.ProxyRunning; }
/// <summary> /// Set the given explicit end point as the default proxy server for current machine /// </summary> /// <param name="endPoint"></param> public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) { if (RunTime.IsRunningOnMono) { throw new Exception("Mono Runtime do not support system proxy settings."); } ValidateEndPointAsSystemProxy(endPoint); if (!endPoint.EnableSsl) { throw new Exception("Endpoint do not support Https connections"); } //clear any settings previously added ProxyEndPoints.OfType <ExplicitProxyEndPoint>() .ToList() .ForEach(x => x.IsSystemHttpsProxy = false); EnsureRootCertificate(); //If certificate was trusted by the machine if (CertificateManager.CertValidated) { systemProxySettingsManager.SetHttpsProxy( Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Loopback) ? "127.0.0.1" : endPoint.IpAddress.ToString(), endPoint.Port); } endPoint.IsSystemHttpsProxy = true; firefoxProxySettingsManager.UseSystemProxy(); Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTPS Proxy", endPoint.IpAddress, endPoint.Port); }
/// <summary> /// Fonction qui va démarrer le proxy. /// Elle va ajouter des évènement pour les requêtes et réponses HTTP /// Elle va ajouter des certificat pour le HTTPS /// </summary> public void StartProxy() { proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) { }; proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true) { GenericCertificateName = "google.com" }; proxyServer.AddEndPoint(transparentEndPoint); proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); }
public void StartProxy() { proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; //proxyServer.EnableWinAuth = true; explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) { //You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown //Use self-issued generic certificate on all https requests //Optimizes performance by not creating a certificate for each https-enabled domain //Useful when certificate trust is not required by proxy clients //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") }; //Fired when a CONNECT request is received explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect; explicitEndPoint.TunnelConnectRequest += OnTunnelConnectRequest; explicitEndPoint.TunnelConnectResponse += OnTunnelConnectResponse; //An explicit endpoint is where the client knows about the existence of a proxy //So client sends request in a proxy friendly manner proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); //Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy) //A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS //to send data to this endPoint //var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true) //{ // //Generic Certificate hostname to use // //When SNI is disabled by client // GenericCertificateName = "google.com" //}; //proxyServer.AddEndPoint(transparentEndPoint); //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; 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); } #if NETSTANDARD2_0 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) #endif { //Only explicit proxies can be set as system proxy! //proxyServer.SetAsSystemHttpProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); } }
static void Main(string[] args) { var proxyServer = new ProxyServer(); //locally trust root certificate used by this proxy proxyServer.TrustRootCertificate = true; proxyServer.BeforeRequest += OnRequest; proxyServer.BeforeResponse += OnResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) { //Exclude Https addresses you don't want to proxy //Usefull for clients that use certificate pinning //for example dropbox.com // ExcludedHttpsHostNameRegex = new List<string>() { "google.com", "dropbox.com" } //Use self-issued generic certificate on all https requests //Optimizes performance by not creating a certificate for each https-enabled domain //Usefull when certificate trust is not requiered by proxy clients // GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") }; //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 var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true) { GenericCertificateName = "google.com" }; proxyServer.AddEndPoint(transparentEndPoint); //proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; 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); } //Only explicit proxies can be set as system proxy! proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); //wait here (You can use something else as a wait function, I am using this as a demo) Console.Read(); //Unsubscribe & Quit proxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeResponse -= OnResponse; proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection; proxyServer.Stop(); }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); Task <TcpServerConnection>?prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; try { TunnelConnectSessionEventArgs?connectArgs = null; var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (method == KnownMethod.Connect) { // read the first line HTTP command var requestLine = await clientStream.ReadRequestLine(cancellationToken); if (requestLine.IsEmpty()) { return; } var connectRequest = new ConnectRequest(requestLine.RequestUri) { RequestUriString8 = requestLine.RequestUri, HttpVersion = requestLine.Version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, clientStream, cancellationTokenSource); clientStream.DataRead += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; bool sendRawData = !decryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(requestLine.Version); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStream.WriteResponseAsync(response, cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } bool isClientHello = clientHelloInfo != null; if (clientHelloInfo != null) { connectRequest.TunnelType = TunnelType.Https; connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && clientHelloInfo != null) { connectRequest.IsHttps = true; // todo: move this line to the previous "if" clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol; bool http2Supported = false; if (EnableHttp2) { var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support try { // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, cancellationToken); http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; // release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } catch (Exception) { // ignore } } } if (EnableTcpServerConnectionPrefetch) { IPAddress[]? ipAddresses = null; try { // make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { // don't pass cancellation token here // it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, false, CancellationToken.None); } } string connectHostname = requestLine.RequestUri.GetString(); int idx = connectHostname.IndexOf(":"); if (idx >= 0) { connectHostname = connectHostname.Substring(0, idx); } X509Certificate2?certificate = null; SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (EnableHttp2 && http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETSTANDARD2_1 clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count); } catch (Exception e) { sslStream?.Dispose(); var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); } method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } if (method == KnownMethod.Invalid) { sendRawData = true; await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } else if (clientHelloInfo == null) { method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (method == KnownMethod.Invalid) { sendRawData = true; } // Hostname is excluded or it is not an HTTPS connect if (sendRawData) { // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, true, cancellationToken); try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(); try { // clientStream.Available should be at most BufferSize because it is using the same buffer size int read = await clientStream.ReadAsync(data, 0, available, cancellationToken); if (read != available) { throw new Exception("Internal error."); } await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } if (!clientStream.IsClosed && !connection.Stream.IsClosed) { await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, null, null, connectArgs.CancellationTokenSource, ExceptionFunc); } } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && method == KnownMethod.Pri) { // todo string?httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { connectArgs.HttpClient.ConnectRequest !.TunnelType = TunnelType.Http2; // HTTP/2 Connection Preface string?line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, cancellationToken); try { #if NETSTANDARD2_1 var connectionPreface = new ReadOnlyMemory <byte>(Http2Helper.ConnectionPreface); await connection.Stream.WriteAsync(connectionPreface, cancellationToken); await Http2Helper.SendHttp2(clientStream, connection.Stream, () => new SessionEventArgs(this, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource) { UserData = connectArgs?.UserData }, async args => { await onBeforeRequest(args); }, async args => { await onBeforeResponse(args); }, connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } calledRequestHandler = true; // Now create the request await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } clientStream.Dispose(); } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); Task <TcpServerConnection> prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; SslStream sslStream = null; try { string connectHostname = null; TunnelConnectSessionEventArgs connectArgs = null; // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1) { // read the first line HTTP command string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (string.IsNullOrEmpty(httpCmd)) { return; } Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version); var httpRemoteUri = new Uri("http://" + httpUrl); connectHostname = httpRemoteUri.Host; var connectRequest = new ConnectRequest { RequestUri = httpRemoteUri, OriginalUrl = httpUrl, HttpVersion = version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, cancellationTokenSource); connectArgs.ProxyClient.Connection = clientConnection; connectArgs.ProxyClient.ClientStream = clientStream; await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(version); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isClientHello = clientHelloInfo != null; if (isClientHello) { connectRequest.TunnelType = TunnelType.Https; connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && isClientHello) { connectRequest.RequestUri = new Uri("https://" + httpUrl); bool http2Supported = false; var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support try { // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; //release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } catch (Exception) { // ignore } } if (EnableTcpServerConnectionPrefetch) { IPAddress[] ipAddresses = null; try { //make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { //don't pass cancellation token here //it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect: true, applicationProtocols: null, noCache: false, cancellationToken: CancellationToken.None); } } X509Certificate2 certificate = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (EnableHttp2 && http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETCOREAPP2_1 clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); } if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == -1) { decryptSsl = false; } if (!decryptSsl) { await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } // Hostname is excluded or it is not an HTTPS connect if (!decryptSsl || !isClientHello) { if (!isClientHello) { connectRequest.TunnelType = TunnelType.Websocket; } // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { await clientStream.ReadAsync(data, 0, available, cancellationToken); // clientStream.Available should be at most BufferSize because it is using the same buffer size await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, connectArgs.CancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1) { // todo string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { connectArgs.HttpClient.ConnectRequest.TunnelType = TunnelType.Http2; // HTTP/2 Connection Preface string line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); await connection.StreamWriter.WriteLineAsync("SM", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); #if NETCOREAPP2_1 await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, () => new SessionEventArgs(this, endPoint, cancellationTokenSource) { ProxyClient = { Connection = clientConnection }, HttpClient = { ConnectRequest = connectArgs?.HttpClient.ConnectRequest }, UserData = connectArgs?.UserData }, async args => { await invokeBeforeRequest(args); }, async args => { await invokeBeforeResponse(args); }, connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } calledRequestHandler = true; // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } sslStream?.Dispose(); clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
public void StartProxy() { proxyServer.BeforeRequest += onRequest; proxyServer.BeforeResponse += onResponse; proxyServer.AfterResponse += onAfterResponse; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; //proxyServer.EnableWinAuth = true; explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000); // Fired when a CONNECT request is received explicitEndPoint.BeforeTunnelConnectRequest += onBeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectResponse += onBeforeTunnelConnectResponse; // An explicit endpoint is where the client knows about the existence of a proxy // So client sends request in a proxy friendly manner proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); // Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy) // A transparent endpoint usually requires a network router port forwarding HTTP(S) packets // or by DNS to send data to this endPoint. //var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 443, true) //{ // // Generic Certificate hostname to use // // When SNI is disabled by client // GenericCertificateName = "localhost" //}; //proxyServer.AddEndPoint(transparentEndPoint); //proxyServer.UpStreamHttpProxy = new ExternalProxy("localhost", 8888); //proxyServer.UpStreamHttpsProxy = new ExternalProxy("localhost", 8888); // SOCKS proxy //proxyServer.UpStreamHttpProxy = new ExternalProxy("127.0.0.1", 1080) // { ProxyType = ExternalProxyType.Socks5, UserName = "******", Password = "******" }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy("127.0.0.1", 1080) // { ProxyType = ExternalProxyType.Socks5, UserName = "******", Password = "******" }; //var socksEndPoint = new SocksProxyEndPoint(IPAddress.Any, 1080, true) //{ // // Generic Certificate hostname to use // // When SNI is disabled by client // GenericCertificateName = "google.com" //}; //proxyServer.AddEndPoint(socksEndPoint); 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); } // Only explicit proxies can be set as system proxy! //proxyServer.SetAsSystemHttpProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); if (RunTime.IsWindows) { proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); } }
//This is called when client is aware of proxy //So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient) { Stream clientStream = tcpClient.GetStream(); clientStream.ReadTimeout = ConnectionTimeOutSeconds * 1000; clientStream.WriteTimeout = ConnectionTimeOutSeconds * 1000; var clientStreamReader = new CustomBinaryReader(clientStream); var clientStreamWriter = new StreamWriter(clientStream) { NewLine = ProxyConstants.NewLine }; Uri httpRemoteUri; try { //read the first line HTTP command var httpCmd = await clientStreamReader.ReadLineAsync(); if (string.IsNullOrEmpty(httpCmd)) { Dispose(clientStream, clientStreamReader, clientStreamWriter, null); return; } //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); //Find the request Verb var httpVerb = httpCmdSplit[0]; if (httpVerb.ToUpper() == "CONNECT") { httpRemoteUri = new Uri("http://" + httpCmdSplit[1]); } else { httpRemoteUri = new Uri(httpCmdSplit[1]); } //parse the HTTP version Version version = new Version(1, 1); if (httpCmdSplit.Length == 3) { string httpVersion = httpCmdSplit[2].Trim(); if (httpVersion == "http/1.0") { version = new Version(1, 0); } } //filter out excluded host names var excluded = endPoint.ExcludedHttpsHostNameRegex != null? endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false; List <HttpHeader> connectRequestHeaders = null; //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]); string tmpLine = null; connectRequestHeaders = new List <HttpHeader>(); while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync())) { var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); var newHeader = new HttpHeader(header[0], header[1]); connectRequestHeaders.Add(newHeader); } if (await CheckAuthorization(clientStreamWriter, connectRequestHeaders) == false) { Dispose(clientStream, clientStreamReader, clientStreamWriter, null); return; } await WriteConnectResponse(clientStreamWriter, version); SslStream sslStream = null; try { sslStream = new SslStream(clientStream, true); var certificate = certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); //Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); //HTTPS server created - we can now decrypt the client's traffic clientStream = sslStream; clientStreamReader = new CustomBinaryReader(sslStream); clientStreamWriter = new StreamWriter(sslStream) { NewLine = ProxyConstants.NewLine }; } catch { if (sslStream != null) { sslStream.Dispose(); } Dispose(clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now read the actual HTTPS request line httpCmd = await clientStreamReader.ReadLineAsync(); } //Sorry cannot do a HTTPS request decrypt to port 80 at this time else if (httpVerb.ToUpper() == "CONNECT") { //Cyphen out CONNECT request headers await clientStreamReader.ReadAllLinesAsync(); //write back successfull CONNECT response await WriteConnectResponse(clientStreamWriter, version); await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, version, null, false, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectClientCertificate), clientStream, tcpConnectionFactory, UpStreamEndPoint); Dispose(clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now create the request await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, httpRemoteUri.Scheme == Uri.UriSchemeHttps?httpRemoteUri.Host : null, endPoint, connectRequestHeaders, null, null); } catch (Exception) { Dispose(clientStream, clientStreamReader, clientStreamWriter, null); } }
//This is called when client is aware of proxy private async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient client) { Stream clientStream = client.GetStream(); var clientStreamReader = new CustomBinaryReader(clientStream); var clientStreamWriter = new StreamWriter(clientStream); Uri httpRemoteUri; try { //read the first line HTTP command var httpCmd = await clientStreamReader.ReadLineAsync(); 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(ProxyConstants.SpaceSplit, 3); //Find the request Verb var httpVerb = httpCmdSplit[0]; if (httpVerb.ToUpper() == "CONNECT") { httpRemoteUri = new Uri("http://" + httpCmdSplit[1]); } else { httpRemoteUri = new Uri(httpCmdSplit[1]); } //parse the HTTP version Version version = new Version(1, 1); if (httpCmdSplit.Length == 3) { string httpVersion = httpCmdSplit[2].Trim(); if (httpVersion == "http/1.0") { version = new Version(1, 0); } } //filter out excluded host names 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]); await clientStreamReader.ReadAllLinesAsync(); await WriteConnectResponse(clientStreamWriter, version); SslStream sslStream = null; try { //create the Tcp Connection to server and then release it to connection cache //Just doing what CONNECT request is asking as to do var tunnelClient = await tcpConnectionCacheManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version, UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectClientCertificate)); await tcpConnectionCacheManager.ReleaseClient(tunnelClient); sslStream = new SslStream(clientStream, true); var certificate = await certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); //Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); //HTTPS server created - we can now decrypt the client's traffic clientStream = sslStream; clientStreamReader = new CustomBinaryReader(sslStream); clientStreamWriter = new StreamWriter(sslStream); } catch { if (sslStream != null) { sslStream.Dispose(); } Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now read the actual HTTPS request line httpCmd = await clientStreamReader.ReadLineAsync(); } //Sorry cannot do a HTTPS request decrypt to port 80 at this time else if (httpVerb.ToUpper() == "CONNECT") { //Cyphen out CONNECT request headers await clientStreamReader.ReadAllLinesAsync(); //write back successfull CONNECT response await WriteConnectResponse(clientStreamWriter, version); //Just relay the request/response without decrypting it await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port, false, SupportedSslProtocols); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now create the request await HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter, httpRemoteUri.Scheme == Uri.UriSchemeHttps?true : false); } catch { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); } }
protected override void OnStart(string[] args) { // we do all this in here so we can reload settings with a simple restart _proxyServerInstance = new ProxyServer(false); if (Properties.Settings.Default.ListeningPort <= 0 || Properties.Settings.Default.ListeningPort > 65535) { throw new Exception("Invalid listening port"); } _proxyServerInstance.CheckCertificateRevocation = Properties.Settings.Default.CheckCertificateRevocation; _proxyServerInstance.ConnectionTimeOutSeconds = Properties.Settings.Default.ConnectionTimeOutSeconds; _proxyServerInstance.Enable100ContinueBehaviour = Properties.Settings.Default.Enable100ContinueBehaviour; _proxyServerInstance.EnableConnectionPool = Properties.Settings.Default.EnableConnectionPool; _proxyServerInstance.EnableTcpServerConnectionPrefetch = Properties.Settings.Default.EnableTcpServerConnectionPrefetch; _proxyServerInstance.EnableWinAuth = Properties.Settings.Default.EnableWinAuth; _proxyServerInstance.ForwardToUpstreamGateway = Properties.Settings.Default.ForwardToUpstreamGateway; _proxyServerInstance.MaxCachedConnections = Properties.Settings.Default.MaxCachedConnections; _proxyServerInstance.ReuseSocket = Properties.Settings.Default.ReuseSocket; _proxyServerInstance.TcpTimeWaitSeconds = Properties.Settings.Default.TcpTimeWaitSeconds; _proxyServerInstance.CertificateManager.SaveFakeCertificates = Properties.Settings.Default.SaveFakeCertificates; _proxyServerInstance.EnableHttp2 = Properties.Settings.Default.EnableHttp2; _proxyServerInstance.NoDelay = Properties.Settings.Default.NoDelay; if (Properties.Settings.Default.ThreadPoolWorkerThreads < 0) { _proxyServerInstance.ThreadPoolWorkerThread = Environment.ProcessorCount; } else { _proxyServerInstance.ThreadPoolWorkerThread = Properties.Settings.Default.ThreadPoolWorkerThreads; } if (Properties.Settings.Default.ThreadPoolWorkerThreads < Environment.ProcessorCount) { ProxyServiceEventLog.WriteEntry( $"Worker thread count of {Properties.Settings.Default.ThreadPoolWorkerThreads} is below the " + $"processor count of {Environment.ProcessorCount}. This may be on purpose.", System.Diagnostics.EventLogEntryType.Warning); } var explicitEndPointV4 = new ExplicitProxyEndPoint(IPAddress.Any, Properties.Settings.Default.ListeningPort, Properties.Settings.Default.DecryptSsl); _proxyServerInstance.AddEndPoint(explicitEndPointV4); if (Properties.Settings.Default.EnableIpV6) { var explicitEndPointV6 = new ExplicitProxyEndPoint(IPAddress.IPv6Any, Properties.Settings.Default.ListeningPort, Properties.Settings.Default.DecryptSsl); _proxyServerInstance.AddEndPoint(explicitEndPointV6); } if (Properties.Settings.Default.LogErrors) { _proxyServerInstance.ExceptionFunc = ProxyException; } _proxyServerInstance.Start(); ProxyServiceEventLog.WriteEntry($"Service Listening on port {Properties.Settings.Default.ListeningPort}", System.Diagnostics.EventLogEntryType.Information); }
/// <summary> /// Set the given explicit end point as the default proxy server for current machine /// </summary> /// <param name="endPoint"></param> /// <param name="protocolType"></param> public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType) { if (RunTime.IsRunningOnMono) { throw new Exception("Mono Runtime do not support system proxy settings."); } ValidateEndPointAsSystemProxy(endPoint); bool isHttp = (protocolType & ProxyProtocolType.Http) > 0; bool isHttps = (protocolType & ProxyProtocolType.Https) > 0; if (isHttps) { if (!endPoint.EnableSsl) { throw new Exception("Endpoint do not support Https connections"); } EnsureRootCertificate(); //If certificate was trusted by the machine if (!CertificateManager.CertValidated) { protocolType = protocolType & ~ProxyProtocolType.Https; isHttps = false; } } //clear any settings previously added if (isHttp) { ProxyEndPoints.OfType <ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false); } if (isHttps) { ProxyEndPoints.OfType <ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpsProxy = false); } systemProxySettingsManager.SetProxy( Equals(endPoint.IpAddress, IPAddress.Any) | Equals(endPoint.IpAddress, IPAddress.Loopback) ? "127.0.0.1" : endPoint.IpAddress.ToString(), endPoint.Port, protocolType); if (isHttp) { endPoint.IsSystemHttpsProxy = true; } if (isHttps) { endPoint.IsSystemHttpsProxy = true; } firefoxProxySettingsManager.UseSystemProxy(); string proxyType = null; switch (protocolType) { case ProxyProtocolType.Http: proxyType = "HTTP"; break; case ProxyProtocolType.Https: proxyType = "HTTPS"; break; case ProxyProtocolType.AllHttp: proxyType = "HTTP and HTTPS"; break; } if (protocolType != ProxyProtocolType.None) { Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System {2} Proxy", endPoint.IpAddress, endPoint.Port, proxyType); } }
/// <summary> /// Set the given explicit end point as the default proxy server for current machine /// </summary> /// <param name="endPoint"></param> public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) { SetAsSystemProxy(endPoint, ProxyProtocolType.Https); }
public MainWindow() { proxyServer = new ProxyServer(); //proxyServer.EnableHttp2 = true; //proxyServer.CertificateManager.CertificateEngine = CertificateEngine.DefaultWindows; ////Set a password for the .pfx file //proxyServer.CertificateManager.PfxPassword = "******"; ////Set Name(path) of the Root certificate file //proxyServer.CertificateManager.PfxFilePath = @"C:\NameFolder\rootCert.pfx"; ////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true //proxyServer.CertificateManager.OverwritePfxFile = true; ////save all fake certificates in folder "crts"(will be created in proxy dll directory) ////if create new Root certificate file(.pfx) ====> delete folder "crts" //proxyServer.CertificateManager.SaveFakeCertificates = true; proxyServer.ForwardToUpstreamGateway = true; //increase the ThreadPool (for server prod) //proxyServer.ThreadPoolWorkerThread = Environment.ProcessorCount * 6; ////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server //proxyServer.CertificateManager.EnsureRootCertificate(true); ////or load directly certificate(As Administrator if need this) ////and At the same time chose path and password ////if password is incorrect and (overwriteRootCert=true)(RootCertificate=null) ====> replace an existing .pfx file ////note : load now (if existed) //proxyServer.CertificateManager.LoadRootCertificate(@"C:\NameFolder\rootCert.pfx", "PfxPassword"); var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true); proxyServer.AddEndPoint(explicitEndPoint); //proxyServer.UpStreamHttpProxy = new ExternalProxy //{ // HostName = "158.69.115.45", // Port = 3128, // UserName = "******", // Password = "******", //}; proxyServer.BeforeRequest += ProxyServer_BeforeRequest; proxyServer.BeforeResponse += ProxyServer_BeforeResponse; proxyServer.AfterResponse += ProxyServer_AfterResponse; explicitEndPoint.BeforeTunnelConnectRequest += ProxyServer_BeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectResponse += ProxyServer_BeforeTunnelConnectResponse; proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); }; proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); }; proxyServer.Start(); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); InitializeComponent(); }