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
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
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.
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(); } }
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?
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)
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 youCode: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;
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:
Have your code read similar to thisCode:0x05 0x01 0x02 or 0x05 0x03 0x00 0x01 0x02
You now know how much data you are waiting for and can act accordingly.Code:/* pseudocode */ greetinglength = 2 + secondbyte.length();
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.
Here is how i done until now.
But the client with i'm testing(Profixier) gives me this: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(); } } }
This is jut an example,to connect to google,and i dont use authorization.But cant get it to work.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.
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.
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.Code:Send(reply, sizeof(reply));
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.
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.
And in the client program i dont get anymore that error,but remains stuck here: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(); } } }
Can you point what is the next stept i should do,or i i have errors in code ? Thanks for helpingCode:[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.
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.
Sorry,i dont understand this: "thread the two connections separately". After the package exchange i called Connect("www.google.com", 80):
The client(proxifier) has an option seted to: "Load a default webpage from the host".My server should retrieve that webpage or how ?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 }
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
I am doing this for somebody and he told me this:
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?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 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:
Thoose numbers supossed to be the ip...how can i retrive the IP from that ? I used this to print it :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
Code:for(int t = 0; t < domainLen; t++) { cout << static_cast<int>(temp[t]); }