Thread: Socks5 protocol

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    12

    Socks5 protocol

    I need to make a server using this protocol,but my question is , how do I know how packets are sent from the client ? Using an array, a structure ? So i can test and sent the aproapite apcket back to the cleint. Thnaks in advanced

  2. #2
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    Sounds like you really haven't ever made a server before.

    If you are trying to write a proxy, I would first try to write a pure redirection proxy (no auth). This would get you most of your code so that you could easily transition into SOCKS5 authentication. SOCKS5 really is almost a pure redirection proxy except for the very first handshake, but past that data is just being forwarded.

  3. #3
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    I`ve written one before,but with a client and i knew how they were because,i wrote the cleint part:P . So can you tell how they are send. I made a simple server like this:

    Code:
    #include <iostream>
    #include <winsock2.h>
    using namespace std;
    
    
    
    
    class Server {
    	WSAData wsadata;
    	int desc;
    	int remoteSocket;
    	SOCKADDR_IN server;
    public:
    	Server()
    	{
    		if(WSAStartup( MAKEWORD( 1, 1 ), &wsadata ) != 0 )
    		{
    			cout << "Error creating socket" << endl;
    			exit(1);
    		}
    		wsadata.wVersion = 5;
    	}
    	void Initialize()
    	{
    		memset(&server, 0, sizeof(server));
    
    		server.sin_family = AF_INET;
    		server.sin_addr.s_addr = INADDR_ANY;
    		server.sin_port = htons(1080);
    	}
    	void Socket()
    	{
    		desc = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    		if(desc == -1)
    		{
    			cout << "Error in Socket()" << endl;
    		}
    	}
    	void Bind()
    	{
    		if((::bind(desc, (LPSOCKADDR)&server, sizeof(server))) == -1)
    		{
    			cout << "Error in Bind()" << endl;
    		}
    	}
    	void Listen()
    	{
    		if((::listen(desc, 5)) == -1)
    		{
    			cout << "Error in Listen()" << endl;
    		}
    	}
    	void Accept()
    	{
    		SOCKADDR_IN sock;
    		int intsock = sizeof(sock);
    		remoteSocket = ::accept(desc, (LPSOCKADDR)&sock,  &intsock);
    		if(remoteSocket == -1)
    		{
    			cout << "Error in Accept()" << endl;
    		}
    		HandleConnection();
    	}
    	void HandleConnection()
    	{
    		cout << "You are connected !!!" << endl;
    
    	}
    	void Send(const char* buffer, int size)
    	{
    		if((::send(remoteSocket, buffer, size, 0)) < 0)
    		{
    			cout << "Error in Send()" << endl;
    		}
    	}
    	void Recv(char* buffer, int size) {
    	    size_t n = 0;
    	    n = ::recv(remoteSocket, buffer, size, 0);
    	}
    	~Server()
    	{
    		WSACleanup();
    	}
    
    };
    
    int main()
    {
    	Server s;
    	s.Initialize();
    	s.Socket();
    	s.Bind();
    	s.Listen();
    	while(1)
    	{
    		s.Accept();
    	}
    }

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Maybe I'm not understanding your question. Why do you care whether the sender considers his data as part of an array or as a struct or as something else? For you, it's just bytes, right?

  5. #5
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    Yes,you are right,i didnt understand that part,that there are just bytes.
    i have a question about the packets i receive using this protocol: for example,lets say a packet contans first field 1 byte(the version) and field 2, 1 byte (lenght of the domain follow by domain name). Field 2 beeing 1 byte can i write: (for Google)

    Code:
    char* packet = new char[20];
    
    packet[0] = 5; // Version
    packet[1] = lenght(domain);
    packet[2] = w;
    packet[3] = w;
    packet[4] = w;
    packet[5] = .;
    packet[6] = g;
    ...........
    packet[12] = .;
    packet[13] = c
    packet[14] = o;
    packet[15] = m;
    Because when i hear that a packet has 2 fields of 1 byte each i think that the packet is an array of 2 (packet[2] ). So when i send this packet back to the client will it know how to check this packet corectly ? Or it just expects a array packet of 2 ? I hope i made myself understand. Thank you

  6. #6
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    Well, since the protocol is documented, you know that the client and server will be communicating back and forth initially for authentication. From the documentation, you can determine the length of each portion of the conversation.

    For example:
    The client will connect and send a short variable length packet
    * field 1: SOCKS version number (must be 0x05 for this version)
    * field 2: number of authentication methods supported, 1 byte
    * field 3: authentication methods, variable length, 1 byte per method supported

    So the length can be determined from reading even a partial packet. Here are a couple examples:
    Code:
    0x05 0x01 0x02
    or
    0x05 0x03 0x00 0x01 0x02
    Have your code read similar to this
    Code:
     /* pseudocode */
    greetinglength = 2 + secondbyte.length();
    You now know how much data you are waiting for and can act accordingly.
    So even if you only have 2 bytes out of the 3 or 5, you can still figure how much to wait for.

    The rest of the protocol is documented similarly and you can perform similar analysis on each packet. Note packets can be clumped, or fragmented, so you need to be sure to take this into account by either splitting data up if clumped, or waiting for the rest if fragmented.

  7. #7
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    Here is how i done until now.

    Code:
    void HandleConnection()
    	{
    		cout << "You are connected !!!" << endl;
    		char temp[30];
    		Recv(temp, sizeof(temp));
    		// Client sends 5,1,0 (version,nr of methods, the method(0 = no auth))
    		if(temp[0] == 5) // test for version
    		{
    			char* reply = new char[2];
    			reply[0] = 5; // version
    			reply[1] = 0; // method choosed (no auth required)
    			Send(reply, sizeof(reply)); // i send 5,0 (version,method choosed) i get warning that i send an unexpected answer
    			delete [] reply;
    			memset(temp, '\0', sizeof(temp));
    
    			Recv(temp, sizeof(temp));
    			// i receive 5,0,0,3,14,www.google.com,80 (version,command, reserved,type of address, dest adress, dest port)
    			int version = static_cast<int>(temp[0]);
    			int connectionType = static_cast<int>(temp[1]);
    			int adrressType = static_cast<int>(temp[3]);
    			int domainLen = static_cast<int>(temp[4]);
    			char* destinationAdrress = static_cast<char*>(&temp[5]);
    			int port1 = static_cast<int>(temp[19]);
    			int port2 = static_cast<int>(temp[20]);
    			int packetSize = sizeof(temp);
    			cout << "Size of packet: " << packetSize << endl;
    			cout << "Version: " << version << endl;
    			cout << "Conn type: " << connectionType << endl;
    			cout << "Adrr type: " << adrressType << endl;
    			cout << "Domain lenght: " << domainLen << endl;
    			cout << "Destination adrress: " << destinationAdrress << endl;
    			cout << "Destination port: " << port2 << endl;
    			if(version == 5) // test for version
    			{
    				char reply[21];
    				reply[0] = 5; // version
    
    				reply[1] = 0; // succed
    				reply[2] = 0; // reserved
    				reply[3] = 3; // its a domain
    				reply[4] = domainLen;; // lenght of domain
    				for(int j = 0; j < domainLen; ++j)
    				{
    					reply[j + 5] = destinationAdrress[j];
    				}
    				reply[5 + domainLen] = htons(port1);
    				reply[6 + domainLen] = htons(port2);
    				Send(reply, sizeof(reply));
    
    				Connect();
    			}
    		}
    
    
    	}
    But the client with i'm testing(Profixier) gives me this:
    Code:
    [25:23] Starting: Test 1: Connection to the Proxy Server
    [25:23] IP Address: 127.0.0.1
    [25:23] Connection established
    [25:23] Test passed.
    [25:23] Starting: Test 2: Connection through the Proxy Server
    [25:23] Authentication was successful.
    [25:24] Warning : the proxy server has returned an unexpected answer (0xFFFFFF84).
    [25:24] Connection to www.google.com:80 established through the proxy server.
    [25:24] Error : the reply that was recieved from the target host does not look like a usual Web Server reply.
    	Please make sure that the target host is a Web Server.
    	The error may also indicate that the proxy server is not operating properly.
    	Target host reply = www.google.c
    [25:24] Test failed.
    [25:24] Testing Finished.
    This is jut an example,to connect to google,and i dont use authorization.But cant get it to work.

  8. #8
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    You have some alarming things wrong with your code.

    You need to check the return result of recv and send, they both correspond to the amount of bytes received and sent, respectively.
    Code:
    Send(reply, sizeof(reply));
    Right here you are sending the entire pre-allocated buffer of 'reply', and there could be tons of garbage in there that the client can't understand.

    You need to read up on the documentation of send/recv so that you are using them properly. Things of sizeof need to be avoided. This is a binary protocol.

  9. #9
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    I change to see how much bytes i received and send,and i dont use sizeof() anymore,am sending the exactly size of the packet.
    Code:
    	void HandleConnection()
    	{
    		cout << "You are connected !!!" << endl;
    		char temp[30];
    		int bytes_recv = Recv(temp, sizeof(temp));
    		cout << "===Received=== " << bytes_recv << " bytes received" << endl;
    		// Client sends 5,1,0 (version,nr of methods, the method(0 = no auth))
    		if(temp[0] == 5) // test for version
    		{
    			char* reply = new char[2];
    			reply[0] = 5; // version
    			reply[1] = 0; // method choosed (no auth required)
    			int bytes_sent = Send(reply, 2); // i send 5,0 (version,method choosed) i get warning that i send an unexpected answer
    			cout << "---Sending-- " << bytes_sent << " bytes sent" << endl;
    			delete [] reply;
    			memset(temp, '\0', sizeof(temp));
    
    			bytes_recv = Recv(temp, sizeof(temp));
    			cout << "===Received=== " << bytes_recv << " bytes received" << endl;
    			// i receive 5,0,0,3,14,www.google.com,80 (version,command, reserved,type of address, dest adress, dest port)
    			int version = static_cast<int>(temp[0]);
    			int connectionType = static_cast<int>(temp[1]);
    			int adrressType = static_cast<int>(temp[3]);
    			int domainLen = static_cast<int>(temp[4]);
    			char* destinationAdrress = static_cast<char*>(&temp[5]);
    			int port1 = static_cast<int>(temp[19]);
    			int port2 = static_cast<int>(temp[20]);
    			int packetSize = bytes_recv;
    			cout << "Size of packet: " << packetSize << endl;
    			cout << "Version: " << version << endl;
    			cout << "Conn type: " << connectionType << endl;
    			cout << "Adrr type: " << adrressType << endl;
    			cout << "Domain lenght: " << domainLen << endl;
    			cout << "Destination adrress: " << destinationAdrress << endl;
    			cout << "Destination port: " << port2 << endl;
    			if(version == 5) // test for version
    			{
    				char reply[21];
    				reply[0] = 5; // version
    
    				reply[1] = 0; // succed
    				reply[2] = 0; // reserved
    				reply[3] = 3; // its a domain
    				reply[4] = domainLen;; // lenght of domain
    				for(int j = 0; j < domainLen; ++j)
    				{
    					reply[j + 5] = destinationAdrress[j];
    				}
    				reply[5 + domainLen] = htons(port1);
    				reply[6 + domainLen] = htons(port2);
    				bytes_sent = Send(reply, packetSize);
    				cout << "---Sending-- " << bytes_sent << " bytes sent" << endl;
    
    				//Connect();
    			}
    		}
    
    
    	}
    And in the client program i dont get anymore that error,but remains stuck here:
    Code:
    [57:16] Starting: Test 1: Connection to the Proxy Server
    [57:16] IP Address: 127.0.0.1
    [57:16] Connection established
    [57:16] Test passed.
    [57:16] Starting: Test 2: Connection through the Proxy Server
    [57:16] Authentication was successful.
    [57:16] Connection to www.google.com:80 established through the proxy server.
    Can you point what is the next stept i should do,or i i have errors in code ? Thanks for helping

  10. #10
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    Well no doubt that you still have problems in your code, not taking into account packet fragmentation, but I guess it kind of works now.

    Now you need to connect to the server that the client is requesting and either thread the two connections separately, or use some other method like select() to check the status of the sockets.

  11. #11
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    Sorry,i dont understand this: "thread the two connections separately". After the package exchange i called Connect("www.google.com", 80):
    Code:
    	void Connect(string address, unsigned short port)
    	{
    		memset(&server2, 0, sizeof(server2));
    		server2.sin_family = AF_INET;
    		server2.sin_addr.s_addr = inet_addr(address.c_str());
    		server2.sin_port = htons(port);
    
    		desc2 = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    		if((::connect(desc2, (LPSOCKADDR)&server2, sizeof(server2))) > 0)
    		{
    			cout << "Error in Connect()" << endl;
    		}
    		// code goes here
    	}
    The client(proxifier) has an option seted to: "Load a default webpage from the host".My server should retrieve that webpage or how ?

  12. #12
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    I am not familiar with your client at all, but that doesn't really matter.

    Once you are past the authentication stage, you now just forward data between the two connections. As tabstop said before, it's just bytes. No need to read them, just send them on their merry way.

    My suggestion of using threads or select() is a way for your program to handle two simultaneous connections. Depending on what type of traffic is being sent back and forth, you shouldn't assume that there will be any order of communication.

    The two methods I usually use when dealing with multiple sockets are the following:
    Multithread - keep the sockets blocking (synchronous) in their own thread
    Select() - change the sockets to be non-blocking (asynchronous) and have select() tell you when there is socket I/O

  13. #13
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    I am doing this for somebody and he told me this:
    Code:
    If you would like to test your socks5 server just start proxifier and start another program which connect anywhere in the internet. Proxifier will hook your network connection and will send the connection throw the socks5 server which is entered in the program.
    I guess i understand why i need threads,because I might start multiple aplications and that client will hook them and send them to my proxy server and i need to call connect for everyone of them one after the other.If I am corect,then whats next after this ? clients sends me packets and i just send them direclty to the server,whitout interesting me whats in the packet?

  14. #14
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by vbx_wx View Post
    clients sends me packets and i just send them direclty to the server,whitout interesting me whats in the packet?
    Once you get through the authenticate part, you're just a relay. You just get bytes and you send the bytes along.

  15. #15
    Registered User
    Join Date
    Jan 2011
    Posts
    12
    I thought i was past the authentification but now when i test it,the client hooked opera.exe,and when exchanged packets with it i got this:
    Code:
    You are connected !!!
    ===Received=== 3 bytes received
    ---Sending-- 2 bytes sent
    ===Received=== 10 bytes received
    Size of packet: 10
    Version: 5
    Conn type: 1
    Adrr type: 1
    Address lenght: 91
    510191-58-82-2408000000000000000000000-112-96420112-98420100000000000043-2340910001000100050002000641794010000-80-2340860000
    Destination adrress: Æ®è
    Destination port: 0
    Thoose numbers supossed to be the ip...how can i retrive the IP from that ? I used this to print it :
    Code:
    			for(int t = 0; t < domainLen; t++)
    			{
    				cout << static_cast<int>(temp[t]);
    			}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 10-04-2010, 10:09 AM
  2. FTP program
    By jakemott in forum Linux Programming
    Replies: 14
    Last Post: 10-06-2008, 01:58 PM
  3. Networking Protocol
    By Hunter2 in forum Networking/Device Communication
    Replies: 14
    Last Post: 12-11-2003, 04:51 PM
  4. help on protocol
    By Prasad kulkarni in forum C Programming
    Replies: 3
    Last Post: 10-20-2002, 08:54 AM
  5. HTTP Protocol :: Winsock
    By kuphryn in forum Windows Programming
    Replies: 9
    Last Post: 06-21-2002, 03:07 PM