/// <summary>
        /// Read and execute request.
        /// </summary>
        /// <param name="request">
        /// A <see cref="Request"/>
        /// </param>
        public static void ProcessHttpConnect(Request request, Stream clientStream, CachedConnection remote)
        {
            request.Response = new Response (remote);
            request.Response.HttpVersion = "HTTP/1.1";
            request.Response.HttpCode = HttpStatusCode.OK;
            request.Response.HTTPMessage = HttpStatusCode.OK.ToString ();
            request.Response.KeepAlive = false;
            request.Response.Add ("Proxy-Agent: HitProxy");
            request.Response.SendHeaders (clientStream);

            Thread t = new Thread (() => {
                try {
                    request.Stream.PipeTo (request.Response.Stream);
                } catch (Exception) {
                    remote.Dispose ();
                } finally {
                }
            });
            t.Name = Thread.CurrentThread.Name + "ConnectOutput";
            t.Start ();
            try {
                request.Response.Stream.PipeTo (request.Stream);
            } catch (Exception e) {
                Console.WriteLine ("ConnectProxy " + e.GetType ().Name + " :" + e.Message);
                request.Stream.NullSafeDispose ();
            } finally {
                remote.Dispose ();
                clientStream.NullSafeDispose ();
            }
            t.Join ();

            request.Response.Dispose ();
            request.Response = null;
        }
Example #2
0
        /// <summary>
        /// Intercepts a HTTP CONNECT so we can filter the encrypted requests
        /// </summary>
        public static Stream InterceptConnect(Request request, Stream clientStream, CachedConnection remote)
        {
            //This code may work but it has not been tested yet.
            string certPath = Path.Combine (Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
                "HitProxy"), "server.pfx");
            if (File.Exists (certPath) == false)
                throw new FileNotFoundException ("Need a server certificate", certPath);

            X509Certificate cert = X509Certificate2.CreateFromCertFile (certPath);

            request.Response = new Response (remote);
            request.Response.HttpVersion = "HTTP/1.1";
            request.Response.HttpCode = HttpStatusCode.OK;
            request.Response.HTTPMessage = HttpStatusCode.OK.ToString ();
            request.Response.KeepAlive = false;
            request.Response.Add ("Proxy-Agent: HitProxy");
            request.Response.SendHeaders (clientStream);

            //Client
            SslStream ssl = new SslStream (clientStream, false, RemoteCertificateValidation, LocalCertValidation);
            try {
                ssl.AuthenticateAsServer (cert, false, System.Security.Authentication.SslProtocols.Tls, false);
            } catch (Exception e) {
                Console.WriteLine (e.Message);
                throw;
            }

            //Remote server
            SslStream remoteSsl = new SslStream (remote.Stream, false, RemoteCertificateValidation);
            remoteSsl.AuthenticateAsClient (request.Uri.Host);
            remote.Stream = remoteSsl;
            return ssl;
        }
Example #3
0
        //See http://tools.ietf.org/html/rfc1928 for details
        /// <summary>
        /// Given a new connection to a socks proxy we initate the handshake.
        /// </summary>
        void PrepareSocks(CachedConnection remoteConnection)
        {
            Socket socket = remoteConnection.remoteSocket;

            //Send Version identifier
            byte[] version = new byte[3];
            //Socks5
            version [0] = 5;
            //Numberof methods following
            version [1] = 1;
            //No authentication
            version [2] = 0;
            socket.Send (version);

            //Read Selection message
            byte[] selection = new byte[2];
            socket.Receive (selection);
            //Socks version
            if (selection [0] != 5)
                throw new HeaderException ("Socks5 not supported, got Socks" + selection [0], HttpStatusCode.MethodNotAllowed);
            if (selection [1] != 0)
                throw new HeaderException ("No authentication not supported: " + selection [0], HttpStatusCode.MethodNotAllowed);

            //Send request
            byte[] name = Encoding.ASCII.GetBytes (request.Uri.Host);
            byte[] sreq = new byte[7 + name.Length];
            sreq [0] = 5;
            //Connect
            sreq [1] = 1;
            //(Reserved)
            sreq [2] = 0;
            //Address type: DomainName = 3
            sreq [3] = 3;
            //Length of domain name
            sreq [4] = (byte)name.Length;
            //Domain Name
            name.CopyTo (sreq, 5);
            //Port
            sreq [5 + name.Length] = (byte)(request.Uri.Port >> 8);
            sreq [6 + name.Length] = (byte)(request.Uri.Port & 0xFF);
            socket.Send (sreq);

            //Read response
            byte[] resp = new byte[5];
            socket.Receive (resp);
            if (resp [0] != 5)
                throw new HeaderException ("Socks5 not supported, got Socks" + selection [0], HttpStatusCode.MethodNotAllowed);
            byte[] resp2;
            switch (resp [3]) {
            case 01:
                //IPv4
                resp2 = new byte[4 + 2];
                resp2 [0] = resp [4];
                socket.Receive (resp2, 1, 4 - 1 + 2, SocketFlags.None);
                break;
            case 03:
                //Domain name
                resp2 = new byte[resp [4] + 2];
                socket.Receive (resp2);
                break;
            case 04:
                //IPv6
                resp2 = new byte[16 + 2];
                resp2 [0] = resp [4];
                socket.Receive (resp2, 1, 16 - 1 + 2, SocketFlags.None);
                break;
            }

            switch (resp [1]) {
            case 0:
                break;
            case 1:
                throw new HeaderException ("Socks connect failed: general SOCKS server failure", HttpStatusCode.InternalServerError);
            case 2:
                throw new HeaderException ("Socks connect failed: Connection not allowed by ruleset", HttpStatusCode.InternalServerError);
            case 3:
                throw new HeaderException ("Socks connect failed: Network unrechable", HttpStatusCode.InternalServerError);
            case 4:
                throw new HeaderException ("Socks connect failed: Host unreachable", HttpStatusCode.InternalServerError);
            case 5:
                throw new HeaderException ("Socks connect failed: Connection refused", HttpStatusCode.InternalServerError);
            case 6:

                throw new HeaderException ("Socks connect failed: TTL expired", HttpStatusCode.InternalServerError);
            case 7:
                throw new HeaderException ("Socks connect failed: Command not supported", HttpStatusCode.InternalServerError);
            case 8:
                throw new HeaderException ("Socks connect failed: Address type not supported", HttpStatusCode.InternalServerError);
            default:
                throw new HeaderException ("Socks connect failed: " + resp [0], HttpStatusCode.InternalServerError);
            }

            return;
        }
Example #4
0
        /// <returns>
        /// True if Keep-alive
        /// </returns>
        bool ProcessRequest(CachedConnection remoteConnection)
        {
            try {
                //Begin connection communication

                //Prepare socks connection
                if (request.Proxy != null && request.Proxy.Scheme == "socks")
                    PrepareSocks (remoteConnection);

                //initiate HTTP CONNECT request
                if (request.Method == "CONNECT") {
                    Status = "Connecting Socket";
                    if (request.InterceptSSL) {
                        //Intercept SSL
                        this.ClientStream = ConnectProxy.InterceptConnect (request, ClientStream, remoteConnection);
                        this.sslConnect = remoteConnection;
                        return true;
                    } else {
                        //Pass connect stream unmodified
                        Status = "Connected";
                        ConnectProxy.ProcessHttpConnect (request, ClientStream, remoteConnection);
                        Status = "Connection closed";
                        return false;
                    }
                }

                //All done, send the traffic to the remote server
                ProcessHttp (remoteConnection);

                Status = "Request done";

            } catch (HeaderException e) {
                Console.Error.WriteLine (e.GetType () + ": " + e.Message);
                if (Status == "Sending response")
                    return false;
                request.Response = new Response (e);
                if (SendResponse () == false)
                    return false;
            } catch (SocketException e) {
                Console.Error.WriteLine (e.GetType () + ": " + e.Message + "\n" + e.StackTrace);
                if (Status == "Sending response")
                    return false;

                request.Response = new Response (e);
                if (SendResponse () == false)
                    return false;
            } catch (IOException e) {
                Console.Error.WriteLine (e.GetType () + ": " + e.Message + "\n" + e.StackTrace);
                if (Status == "Sending response")
                    return false;

                request.Response = new Response (e);
                if (SendResponse () == false)
                    return false;
            } catch (ObjectDisposedException e) {
                Console.Error.WriteLine (e.GetType () + ": " + e.Message + "\n" + e.StackTrace);
                if (Status == "Sending response")
                    return false;

                request.Response = new Response (e);
                if (SendResponse () == false)
                    return false;
            }

            //Close connection
            if (request.Response.Chunked == false && request.Response.HasBody == false)
                return false;
            if (request.Response.KeepAlive == false)
                return false;

            return request.KeepAlive;
        }
Example #5
0
 /// <summary>
 /// Remove a connection from the ServerCache
 /// This will trigger an event allowing pending connections to start.
 /// </summary>
 /// <param name="connection">
 /// The connection to remove
 /// </param>
 public void Remove(CachedConnection connection)
 {
     lock (connections) {
         connections.Remove (connection);
     }
     manager.releasedConnection.Set ();
 }
Example #6
0
 public CachedConnection GetUnlimitedNewConnection()
 {
     CachedConnection c = new CachedConnection (this);
     lock (connections) {
         connections.Add (c);
     }
     c.Connect ();
     return c;
 }
Example #7
0
 /// <summary>
 /// Creates and return a new connection.
 /// If the maximum number of connections to that server is reached,
 /// it will return null.
 /// </summary>
 public CachedConnection GetNewConnection()
 {
     CachedConnection c = new CachedConnection (this);
     lock (connections) {
         if (connections.Count >= max) {
             return null;
         }
         connections.Add (c);
     }
     c.Connect ();
     return c;
 }