Click here to Skip to main content
Click here to Skip to main content

Golabi Proxy Server

, 20 Sep 2011
Rate this:
Please Sign up or sign in to vote.
This is a proxy server with a client that can encrypt your browser request.
softwareuut

Introduction

Golabi proxy is a kind of reserved proxy. This proxy has encryption in requests of browsers for passing through filterings of internet.

Background

In some countries, the ISPs of that country have some kind of request checking to block unauthorized requests to websites. For example, Facebook is one of those websites that is blocked!

These request checkings have a big weakness! They cannot check encrypted request and responses. Because of that, we encrypt requests with AES algorithm. The keys of AES algorithm can be sent with some secret IP and secret ports. But in this project, we use one key as secret.

Using the Code

In this project, we have 2 sides - server side and client side.

First, we receive the requests from browser in the client computer with client Golabi proxy. Next, we encrypt the request. After that, the server side receives the encrypted request and decrypts it. In the server side, our application (server Golabi proxy) has unlimited access to internet. It makes a request and receives a response. Then response returns back to client and browser.

This project is the start of an idea! It has a few problems, but it can be fixed by some improvements.

client.png

Server.png

Client Side Handler

private void Handler()
        {
            bool recvRequest = true;
            string EOL = "\r\n";

            string requestPayload = "";
            List<string> requestLines = new List<string>();
            byte[] requestBuffer = new byte[1];
            byte[] responseBuffer = new byte[1];

            requestLines.Clear();

            try
            {
                //State 0: Handle Request from Client
                while (recvRequest && _ContinueRecive)
                {
                    if (this.clientSocket.Receive(requestBuffer) == 0)
                    {
                        break;
                    }
                    string fromByte = UTF8Encoding.UTF8.GetString(requestBuffer);
                    requestPayload += fromByte;
                    if (requestPayload.EndsWith(EOL + EOL))
                    {
                        recvRequest = false;
                    }
                }

                //State 1: Creating a new socket to connect to server
                Socket destServerSocket = new Socket
		(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                destServerSocket.Connect(this._Info.ServerIP,this._Info.ServerPort);
                destServerSocket.ReceiveTimeout = 12000;
                destServerSocket.SendTimeout = 12000;

                //State 2: Sending New Request Information to Destination Server 
                //and Relay Response to Client
                if (this._Info.EncryptionEnabled)
                {
                    destServerSocket.Send(ASCIIEncoding.ASCII.GetBytes
			(Encryption.Encrypt(requestPayload, this._Info.Key) + 
			"farhadserverfinish"));
                }
                else
                {
                    destServerSocket.Send(ASCIIEncoding.ASCII.GetBytes
			(requestPayload + "farhadserverfinish"));
                }

                if (false)
                {
                    while (destServerSocket.Receive(responseBuffer) != 0)
                    {
                        int tmp = responseBuffer[0];
                        tmp -= 2;
                        if (tmp < 0)
                        {
                            tmp += 256;
                        }
                        responseBuffer[0] = (byte)tmp;
                        this.clientSocket.Send(responseBuffer);
                    }
                }
                else
                {
                    while (destServerSocket.Receive(responseBuffer) != 0)
                    {
                        this.clientSocket.Send(responseBuffer);
                    }
                }
                destServerSocket.Disconnect(false);
                this.clientSocket.Disconnect(false);
            }
            catch (Exception ex)
            {
                this._Info.MessageCenter.setMessage(ex.Message);
            }
        }

Server Side Handler

private void Handler()
        {
            bool recvRequest = true;
            string EOL = "\r\n";

            string requestPayload = "";
            string requestTempLine = "";
            List<string> requestLines = new List<string>();
            byte[] requestBuffer = new byte[1];
            byte[] responseBuffer = new byte[1];

            requestLines.Clear();

            try
            {
                while (recvRequest)
                {
                    this.clientSocket.Receive(requestBuffer);
                    string fromByte = UTF8Encoding.UTF8.GetString(requestBuffer);
                    requestPayload += fromByte;
                    requestTempLine += fromByte;

                    if (requestPayload.EndsWith("farhadserverfinish"))
                    {
                        recvRequest = false;
                    }
                }

                string recivedDec;

                if (this._Info.EncryptionEnabled)
                {
                    recivedDec = Encryption.Decrypt(requestPayload.Replace
				("farhadserverfinish", ""), this._Info.Key);
                }
                else
                {
                    recivedDec = requestPayload.Replace("farhadserverfinish", "");
                }

                requestPayload = "";
                requestTempLine = "";

                int counter = 0;
                //State 0: Handle Request from Client
                while (counter < recivedDec.Length)
                {
                    string fromByte = recivedDec[counter].ToString();
                    counter++;
                    requestPayload += fromByte;
                    requestTempLine += fromByte;

                    if (requestTempLine.EndsWith(EOL))
                    {
                        requestLines.Add(requestTempLine.Trim());
                        requestTempLine = "";
                    }

                    if (requestPayload.EndsWith(EOL + EOL))
                    {
                        break;
                    }

                }
                //State 1: Rebuilding Request Information and Create Connection 
                //to Destination Server
                if (requestLines.Count == 0)
                {
                    return;
                }

                string remoteHost = requestLines[0].Split(' ')[1].Replace
					("http://", "").Split('/')[0];
                string requestFile = requestLines[0].Replace("http://", "").Replace
					(remoteHost, "");
                requestLines[0] = requestFile;

                this._Info.MessageCenter.setMessage(string.Format("Request to {0}", 
					remoteHost));

                requestPayload = "";
                foreach (string line in requestLines)
                {
                    requestPayload += line;
                    requestPayload += EOL;
                }

                Socket destServerSocket = new Socket(AddressFamily.InterNetwork, 
					SocketType.Stream, ProtocolType.Tcp);
                destServerSocket.Connect(remoteHost, 80);
                destServerSocket.ReceiveTimeout = 12000;
                destServerSocket.SendTimeout = 12000;

                //State 2: Sending New Request Information to Destination Server 
                //and Relay Response to Client
                destServerSocket.Send(ASCIIEncoding.ASCII.GetBytes(requestPayload));

                if(false)
                while (destServerSocket.Receive(responseBuffer) != 0)
                {
                    int tmp = responseBuffer[0];
                    tmp += 2;
                    if (tmp > 255)
                    {
                        tmp -= 256;
                    }
                    responseBuffer[0] = (byte)tmp;
                    this.clientSocket.Send(responseBuffer);
                }

                while (destServerSocket.Receive(responseBuffer) != 0)
                {
                    this.clientSocket.Send(responseBuffer);
                }

                destServerSocket.Disconnect(false);
                this.clientSocket.Disconnect(false);
            }
            catch (Exception ex)
            {
                this._Info.MessageCenter.setMessage(ex.Message);
            }
        }

Inside the Code

This project uses multiple TCP connections and opens many clients and sends requests to the server. Then the server waits for accepting the connection.

There is a thread in the server side that is ready to accept connection on a specific port. The connection between server and client establishes throw socket connection, sockets send and receive information with binary format. These binaries would be sent byte after byte.

private void startAcc()
        {
            ConnectionInfo info = new ConnectionInfo
		(ServerIP.Text, ServerPort.Text, ListenIP.Text, 
		ListenPort.Text,KeyInput.Text,this,Encrypt.Checked);

            proxyListener = new ProxyTCPListener(info);

            proxyListener.StartServer();

            while (true)
            {
                proxyListener.AcceptConnection();
            }
        }

We can add some delay:

private void startAcc()
        {
            ConnectionInfo info = new ConnectionInfo
		(ServerIP.Text, ServerPort.Text, ListenIP.Text, 
		ListenPort.Text,KeyInput.Text,this,Encrypt.Checked);

            proxyListener = new ProxyTCPListener(info);

            proxyListener.StartServer();

            while (true)
            {
                proxyListener.AcceptConnection();
            }
            Thread.Sleep(50);
        }

Sockets

Sockets have a big problem. You don't know when to stop. It has just a reading method. We made a con that after sending information, we send this string: "farhadserverend". After that, the client knows that sending information is finished. Now, stop client and dispose it!

destServerSocket.Send(ASCIIEncoding.ASCII.GetBytes
	(Encryption.Encrypt(requestPayload, this._Info.Key) + "farhadserverfinish"));

Queue for the Countries that have Low Speed Internet (Like IRAN)

In some countries because of low speed internet, we have network problems. So in this class, we made a queue for browser requests. These requests will be checked every time from client application. They have 5 seconds for response timeout. If the connection does not respond in 5 seconds, it will be disposed!

class ProxyTCPListener : IDisposable
    {
        private TcpListener _Listener;
        private ConnectionInfo _Info;
        private List<clientconnection> _Clients;

        public ProxyTCPListener(ConnectionInfo info)
        {
            this._Info = info;
            
            this._Listener = new TcpListener(this._Info.LocalIP, this._Info.LocalPort);

            this._Clients = new List<clientconnection>();
        }

        public void StartServer()
        {
            this._Listener.Start();
        }

        public void AcceptConnection()
        {
            if (this._Listener.Pending())
            {
                Socket newClient = this._Listener.AcceptSocket();
                this._Info.MessageCenter.setMessage("ClientQueued...");
                ClientConnection _Client = new ClientConnection(newClient, this._Info);
                _Clients.Add(_Client);
            }
            Thread.Sleep(200);
        }

        public void QueueCheck()
        {
            if (_Clients.Count > 0)
            {
                if (_Clients[0]._ContinueRecive == false && 
				_Clients[0]._finished == true)
                {
                    _Clients.RemoveAt(0);
                }
            }
            if (_Clients.Count > 0)
            {
                if (_Clients[0]._ContinueRecive == false && 
				_Clients[0]._finished == false)
                {
                    this._Info.MessageCenter.setMessage("ClientAccepted...");
                    _Clients[0].StartHandling();
                }
            }
        }

        public void Dispose()
        {
            foreach (ClientConnection client in _Clients)
            {
                client.StopHandling();
            }
            _Listener.Stop();
        }

Encryption

We encrypt the request with AES algorithm:

public static string Encrypt(string clearText, string Password)
        {
            // First we need to turn the input string into a byte array.
            byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);

            // Then, we need to turn the password into Key and IV
            // We are using salt to make it harder to guess our key
            // using a dictionary attack -
            // trying to guess a password by enumerating all possible words.
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
                0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});

            // Now get the key/IV and do the encryption using the
            // function that accepts byte arrays.
            // Using PasswordDeriveBytes object we are first getting
            // 32 bytes for the Key
            // (the default Rijndael key length is 256bit = 32bytes)
            // and then 16 bytes for the IV.
            // IV should always be the block size, which is by default
            // 16 bytes (128 bit) for Rijndael.
            // If you are using DES/TripleDES/RC2 the block size is
            // 8 bytes and so should be the IV size.
            // You can also read KeySize/BlockSize properties off
            // the algorithm to find out the sizes.
            byte[] encryptedData = Encrypt(clearBytes,
                     pdb.GetBytes(32), pdb.GetBytes(16));

            // Now we need to turn the resulting byte array into a string.
            // A common mistake would be to use an Encoding class for that.
            //It does not work because not all byte values can be
            // represented by characters.
            // We are going to be using Base64 encoding that is designed
            //exactly for what we are trying to do.
            return Convert.ToBase64String(encryptedData);
        }

Decryption

public static string Decrypt(string cipherText, string Password)
        {
            // First we need to turn the input string into a byte array.
            // We presume that Base64 encoding was used
            byte[] cipherBytes = Convert.FromBase64String(cipherText);

            // Then, we need to turn the password into Key and IV
            // We are using salt to make it harder to guess our key
            // using a dictionary attack -
            // trying to guess a password by enumerating all possible words.
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
                new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65,
                0x64, 0x76, 0x65, 0x64, 0x65, 0x76});

            // Now get the key/IV and do the decryption using
            // the function that accepts byte arrays.
            // Using PasswordDeriveBytes object we are first
            // getting 32 bytes for the Key
            // (the default Rijndael key length is 256bit = 32bytes)
            // and then 16 bytes for the IV.
            // IV should always be the block size, which is by
            // default 16 bytes (128 bit) for Rijndael.
            // If you are using DES/TripleDES/RC2 the block size is
            // 8 bytes and so should be the IV size.
            // You can also read KeySize/BlockSize properties off
            // the algorithm to find out the sizes.
            byte[] decryptedData = Decrypt(cipherBytes, pdb.GetBytes(32), 
					pdb.GetBytes(16));

            // Now we need to turn the resulting byte array into a string.
            // A common mistake would be to use an Encoding class for that.
            // It does not work
            // because not all byte values can be represented by characters.
            // We are going to be using Base64 encoding that is
            // designed exactly for what we are trying to do.
            return System.Text.Encoding.Unicode.GetString(decryptedData);
        }

History

  • 15th September, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Farhad Hazraty Eini
Software Developer رایان پایا داده محاسب
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Bachelor of computer software engineer at Urmia University of Technology,
 
Masters of computer software engineer at Shahid Beheshti University,
 
Microsoft Certified Solution Developer : Web Applications,
 
Microsoft Specialist : HTML5 , CSS3 , javascript,
 
MCTS at Mojtame Fanni Tehran (MFT)
 

My Server Solution Blog
Follow on   Google+

Comments and Discussions

 
Questionسوال Pinmemberomid-hh6-Jun-13 4:54 
AnswerRe: سوال PinmemberFarhad Hazraty Eini6-Jun-13 17:33 
GeneralMessage Removed Pinmemberomid-hh6-Jun-13 21:00 
GeneralRe: سوال PinmemberFarhad Hazraty Eini6-Jun-13 22:05 
Questionquestion2 PinmemberMember 100617653-Jun-13 1:48 
AnswerRe: question2 PinmemberFarhad Hazraty Eini3-Jun-13 18:12 
Questionquestion PinmemberMember 1006176531-May-13 22:31 
AnswerRe: question PinmemberFarhad Hazraty Eini1-Jun-13 0:49 
GeneralRe: question PinmemberMember 100617651-Jun-13 19:31 
QuestionHow to implement for https PinmemberMember 877285016-Apr-13 23:20 
AnswerRe: How to implement for https PinmemberFarhad Hazraty Eini17-Apr-13 5:16 
Questionnasb dar server PinmemberMember 99632363-Apr-13 9:37 
AnswerRe: nasb dar server PinmemberFarhad Hazraty Eini3-Apr-13 17:59 
GeneralRe: nasb dar server PinmemberMember 99632364-Apr-13 21:55 
GeneralRe: nasb dar server PinmemberMember 99632364-Apr-13 22:32 
GeneralRe: nasb dar server PinmemberFarhad Hazraty Eini4-Apr-13 22:59 
QuestionServer Installation Pinmemberhadi_aghasi23-Dec-11 22:46 
Please, provide more information about running your code on the server. Should I run it on the web hosts? If yes, please explain how.
 
In addition, please for better understanding, describe the differences between server code on your program and on other ip changer programs like JONDO .
AnswerRe: Server Installation PinmemberFarhad Hazraty Eini24-Dec-11 2:25 
GeneralMy vote of 5 PinmemberMember 432084427-Sep-11 7:56 
SuggestionWhat about content Encrypting ? PinmemberRabinDl17-Sep-11 3:34 
GeneralRe: What about content Encrypting ? PinmemberFarhad Hazraty Eini17-Sep-11 18:27 
GeneralRe: What about content Encrypting ? PinmemberFarhad Hazraty Eini17-Sep-11 20:48 
GeneralRe: What about content Encrypting ? PinmemberFarhad Hazraty Eini20-Sep-11 3:28 
GeneralRe: What about content Encrypting ? PinmemberRabinDl20-Sep-11 10:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 20 Sep 2011
Article Copyright 2011 by Farhad Hazraty Eini
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid