//********************************************************************** #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <winsock.h> #define BufferSize 1024*8 // 8k Buffer #define SOCKS4_GRANT 90 #define SOCKS4_REJECT 91 #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"wsock32.lib") // Some Structures To Define typedef struct { SOCKET ClientSocket; }TSocks4Info; typedef struct { BYTE VN; // Version Number BYTE CD; // Code Of Command WORD wPort; // Remote Port DWORD dwIP; // Remote IP }Socks4Info; // End Of Structure static CRITICAL_SECTION cs; // Function ProtoType Declaration //------------------------------------------------------------------------------------------------------ DWORD GetRemoteAddressAndPort(char *HTTPBuffer, WORD *wPort); BOOL SendSock4ID(SOCKET sSocket, BYTE Socks4RequestID); DWORD WINAPI Socks4Thread(TSocks4Info *Sock4Info); BOOL StartSocks4Proxy(unsigned int Sock4Port); BOOL Init(); BOOL IsDigits(const char *String); //------------------------------------------------------------------------------------------------------ // End Of Fucntion ProtoType Declaration // Main Function int main(int argc,char *argv[]) { unsigned int Sock4Port; // Define Sock4 Listening Port if (argc != 2) // Require Two Arguments { printf("Usage: %s Port\n",argv[0]); // Display Usage return -1; // Quit The Program } if (!IsDigits(argv[1])) // Invalid Port Number { printf("Invalid Port\n"); // Display Error Message return -1; // Quit The Program } Sock4Port = atoi(argv[1]); // Convert String Into Unsigned Int Format,And Store Into Sock4Port if (Sock4Port <= 0 || Sock4Port > 65535) // The Port Out Of Bound { printf("The Port Out Of Bound\n"); // Display Error Message return -1; // Quit The Program } if (!Init()) // Socket StartUP Fails { printf("Fail To StartUp\n"); // Display Error Message return -1; // Quit The Program } StartSocks4Proxy(Sock4Port); // Start The Proxy WSACleanup(); // Clean UP DeleteCriticalSection(&cs); // Delete Critical Section return 0; // Quit The Program }// End Of Main Method //------------------------------------------------------------------------------------ // Purpose: To Get The Remote IP And Port From The Buffer // Return Type: DWORD // Parameters: // In: char *HTTPBuffer --> The HTTP Buffer Containing Remote IP And Port // Out: DWORD *wPort --> Store The Remote Port And Returen To The Caller //------------------------------------------------------------------------------------ DWORD GetRemoteAddressAndPort(char *HTTPBuffer, WORD *wPort) { // All Variable Stuff DWORD dwIP, Socks4InfoSize = sizeof(Socks4Info); struct hostent* pHostEnt; DWORD dwIndex = 0; char ServerAddress[BufferSize] = {0}; Socks4Info Socks4Request; memcpy(&Socks4Request, HTTPBuffer, Socks4InfoSize); // Get The Sock4 Structure if ((Socks4Request.VN != 4) || (Socks4Request.CD != 1)) // Invalid Sock4 Request { EnterCriticalSection(&cs); // Enter Critical Section printf("Invalid Socks 4 Request\n"); // Display Error Message LeaveCriticalSection(&cs); // Leave Critical Section return INADDR_NONE; // Return NULL Address } *wPort = ntohs(Socks4Request.wPort); // Get The Remote Port if ((Socks4Request.dwIP >> 8) == 0) // Some Shift Operation { strcpy(ServerAddress, &HTTPBuffer[Socks4InfoSize + strlen(&HTTPBuffer[Socks4InfoSize]) + 1]); // Get The Remote Address dwIP = inet_addr(ServerAddress); // Is In Dot Form if (dwIP == INADDR_NONE) // The Remote Address Is Not In Dot Form { pHostEnt = gethostbyname(ServerAddress); // Get The Dot Form if (pHostEnt == NULL) // Fail To Get The IP { EnterCriticalSection(&cs); // Enter Critical Section printf("Fail To Get Host By Name\n"); // Display Errory Message LeaveCriticalSection(&cs); // Leave Critical Section return INADDR_NONE; // Return NULL Address } dwIP = *((unsigned long *)pHostEnt->h_addr); // Get The Remote IP } return dwIP; // Return The Remote IP } return Socks4Request.dwIP; // We Already Get The Remote IP In The Sock4 Structure,Return It Then }// End Of GetRemoteAddressAndPort() Method //------------------------------------------------------------------------------------ // Purpose: To Send The Sock4 Request // Return Type: Boolean // Parameters: // 1.SOCKET sSocket --> The Socket That That ID Will Send To // 2.BYTE SocketsRequestID --> Either Grand Or Reject //------------------------------------------------------------------------------------ BOOL SendSock4ID(SOCKET sSocket, BYTE Socks4RequestID) { Socks4Info Socks4Request; // Define Variable memset(&Socks4Request, 0, sizeof(Socks4Info)); // Reset Variable Socks4Request.CD = Socks4RequestID; return (send(sSocket, (char *)&Socks4Request, sizeof(Socks4Info), 0) != SOCKET_ERROR); // Return Send Success Or Failure }// End Of SendSock4ID() Method //------------------------------------------------------------------------------------ // Purpose: To Handle All Sock4 Traffic // Return Type: DWORD // Parameters: // 1.TSocks4Info *Sock4Info --> Sock4 Info //------------------------------------------------------------------------------------ DWORD WINAPI Socks4Thread(TSocks4Info *Sock4Info) { // Variables Define And Reset int iRet; struct sockaddr_in SockAddrIn; SOCKET MySocket, ClientSocket = Sock4Info->ClientSocket; BOOL ClientFlag = FALSE, ServerFlag = FALSE; int iClientLen = 0, iServerLen = 0; BYTE byClientBuf[BufferSize], byServerBuf[BufferSize]; fd_set readfds; DWORD dwRemoteIP; WORD wRemotePort; memset(byClientBuf, 0, BufferSize); iRet = recv(Sock4Info->ClientSocket, (char *)byClientBuf, BufferSize, 0); // Receive Data if ((iRet == SOCKET_ERROR) || (iRet == 0)) // Fail To Receive Data { closesocket(Sock4Info->ClientSocket); // Close Socket free(Sock4Info); // Free The Allocated Ram return 1; // Return To The Caller } byClientBuf[iRet] = 0; if ((dwRemoteIP = GetRemoteAddressAndPort((char *)byClientBuf, &wRemotePort)) == INADDR_NONE) // Fail To Get Remote IP And Port { SendSock4ID(ClientSocket, SOCKS4_REJECT); // Send The Reject ID closesocket(Sock4Info->ClientSocket); // Close Socket free(Sock4Info); // Free The Allocated Ram return 1; // Return To The Caller } MySocket = socket(AF_INET, SOCK_STREAM, 0); // Create A New Socket if (MySocket == INVALID_SOCKET) // Fail To Create A New Socket { EnterCriticalSection(&cs); // Enter Critical Section printf("Fail To Create Socket\n"); // Display Error Message LeaveCriticalSection(&cs); // Leave Critical Section SendSock4ID(ClientSocket, SOCKS4_REJECT); // Send The Reject ID closesocket(Sock4Info->ClientSocket); // Close Socket free(Sock4Info); // Free The Allowed Ram return 1; // Return To The Caller } BOOL Val = 1; if (setsockopt(MySocket, SOL_SOCKET, SO_KEEPALIVE, (char *)(&Val), sizeof(BOOL)) != 0) // Set Socket Option(KeepAlive) Fail { EnterCriticalSection(&cs); // Enter Critical Section printf("Fail To Set Socket Option\n"); // Display Error Message LeaveCriticalSection(&cs); // Leave Critical Section SendSock4ID(ClientSocket, SOCKS4_REJECT); // Send Reject ID closesocket(Sock4Info->ClientSocket); // Close Socket closesocket(MySocket); // Close Socket free(Sock4Info); // Free Allocated Ram return 1; // Return To The Caller } // All Socket Stuff SockAddrIn.sin_family = AF_INET; SockAddrIn.sin_port = htons(wRemotePort); SockAddrIn.sin_addr.s_addr = dwRemoteIP; iRet = connect(MySocket, (struct sockaddr *) &SockAddrIn, sizeof(SockAddrIn)); // Connect To The Remote IP if (iRet == SOCKET_ERROR) // Fail To Connect { EnterCriticalSection(&cs); // Enter Critical Section printf("Fail To Connect To %s\n",inet_ntoa(SockAddrIn.sin_addr)); // Display Error Message LeaveCriticalSection(&cs); // Leave Critical Section SendSock4ID(ClientSocket, SOCKS4_REJECT); // Send Reject ID closesocket(ClientSocket); // Close Socket closesocket(MySocket); // Close Socket free(Sock4Info); // Free Allocated Ram return 1; // Return To The Caller } if (!SendSock4ID(ClientSocket, SOCKS4_GRANT)) // We Fail To Send The Grant ID { EnterCriticalSection(&cs); // Enter Critical Section printf("Fail To Send Grant ID\n"); // Display Error Message LeaveCriticalSection(&cs); // Leave Critical Section closesocket(Sock4Info->ClientSocket); // Close Socket closesocket(MySocket); // Close Socket free(Sock4Info); // Free Allocated Ram return 1; // Return To The Caller } EnterCriticalSection(&cs); // Enter Critical Section printf("Connected to: %s:%d ThreadID:%X\n",inet_ntoa(SockAddrIn.sin_addr), wRemotePort, GetCurrentThreadId()); // Display Successful Message LeaveCriticalSection(&cs); // Leave Critical Section while(TRUE) // Sock4 Traffic Starts { FD_ZERO(&readfds); // Reset The Readable Socket Flag FD_SET(MySocket, &readfds); // Set MySocket As Readable FD_SET(ClientSocket, &readfds); //Send ClientSocket As Readable iRet = select(0, &readfds, NULL, NULL, NULL); // Select Any Readable Socket if (iRet == SOCKET_ERROR) // We Fail To Get Any Readable Socket { break; // Leave The Loop } // Below Are All About Send And Receive Stuff,Pretty Tedious To Explain.Read It YouSelf if (iClientLen < BufferSize) { if ((FD_ISSET(ClientSocket, &readfds)) && (!ClientFlag)) { iRet = recv(ClientSocket, (char *)&byClientBuf[iClientLen], BufferSize-iClientLen, 0); if (iRet == 0 || iRet == SOCKET_ERROR) { break; } ClientFlag = TRUE; iClientLen += iRet; } } if (ClientFlag) { iRet = send(MySocket, (char *)byClientBuf, iClientLen, 0); if (iRet == SOCKET_ERROR) { break; } ClientFlag = FALSE; iClientLen = 0; } if (iServerLen < BufferSize) { if ((FD_ISSET(MySocket, &readfds)) && (!ServerFlag)) { iRet = recv(MySocket, (char *)&byServerBuf[iServerLen], BufferSize-iServerLen, 0); if (iRet == 0 || iRet == SOCKET_ERROR) { break; } ServerFlag = TRUE; iServerLen += iRet; } } if (ServerFlag) { iRet = send(ClientSocket, (char *)byServerBuf, iServerLen, 0); if (iRet == SOCKET_ERROR) { break; } ServerFlag = FALSE; iServerLen = 0; } } closesocket(MySocket); // Close Socket closesocket(ClientSocket); // Close Socket free(Sock4Info); // Free Allocated Ram return 0; // Return To The Caller }// End Of Socks4Thread() Method //------------------------------------------------------------------------------------ // Purpose: To Start The Socks4 Proxy // Return Type: Boolean // Parameters: // 1.unsigned int Sock4Port --> The Port Listening On //------------------------------------------------------------------------------------ BOOL StartSocks4Proxy(unsigned int Sock4Port) { // All Variables Define SOCKADDR_IN saServer; int iRet; SOCKET ListenSocket; // socket to listen SOCKET ClientSocket; // Client socket DWORD dwThreadID; TSocks4Info *Sock4Info; saServer.sin_family = AF_INET; // Address Family(Internet) saServer.sin_addr.s_addr = INADDR_ANY; // Let WinSock Assign Address saServer.sin_port = htons(Sock4Port); // Port Number ListenSocket = socket( AF_INET, SOCK_STREAM,IPPROTO_TCP); // Create A New Socket if (ListenSocket == INVALID_SOCKET) // Fail To Create A New Socket { printf("Fail To Create Listening Socket\n"); // Display Error Message return FALSE; // Return False } iRet = bind(ListenSocket, (LPSOCKADDR)&saServer, sizeof(struct sockaddr)); // Bind The Socket if (iRet == SOCKET_ERROR) // Fail To Bind { printf("Fail To Bind Socket\n"); // Display Error Message closesocket(ListenSocket); // Close Socket return FALSE; // Return False } iRet = listen(ListenSocket, SOMAXCONN); // Listen On The Socket if (iRet == SOCKET_ERROR) // Fail To Listen { printf("Fail To Listen On The Socket\n"); // Display ErrorMessage closesocket(ListenSocket); // Close Socket return FALSE; // Return False } printf("Socks 4 Server Started On Port %d\n",Sock4Port); // The Sock4 Proxy Is Started Successfully while(TRUE) { ClientSocket = accept(ListenSocket, NULL, NULL); // Accept Incoming Connection if (ClientSocket == SOCKET_ERROR) // Fail To Accept Connection { break; // Leave The Loop } BOOL Val = 1; if (setsockopt(ClientSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)(&Val), sizeof(BOOL)) != 0) // Set The Socket As Keepalive Fail { closesocket(ClientSocket); // Close The Socket continue; // Begin A New Loop } if ((Sock4Info = (TSocks4Info *)malloc(sizeof(TSocks4Info))) == NULL) // Allocate Ram Fail { closesocket(ClientSocket); // Close Socket closesocket(ListenSocket); // Close Socket return FALSE; // Return False } Sock4Info->ClientSocket = ClientSocket; // Get The Socket if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Socks4Thread, (LPVOID)Sock4Info, 0, &dwThreadID) == NULL) // Fail To Create A New Thread { closesocket(ClientSocket); // Close Socket continue; // Begin A New Loop } } closesocket(ListenSocket); // Close Socket return TRUE; // Return To The Caller }// End Of StartSocks4Proxy() Method //------------------------------------------------------------------------- // Purpose: To Initize Socket // Return Type: Boolean // Parameters: NULL // This Is Too Simple,I Won't Comment It //------------------------------------------------------------------------- BOOL Init() { WSADATA data; WORD ver; ver = MAKEWORD(2,2); if (WSAStartup( ver, &data ) != 0 ) { return FALSE; } InitializeCriticalSection(&cs); return TRUE; }// End Of Init() Method //------------------------------------------------------------------------- // Purpose: To Check Whether A String Is All Digits // Return Type: Boolean // Parameters: cosnt char *String --> The String To Be Checked //------------------------------------------------------------------------- BOOL IsDigits(const char *String) { unsigned int i = 0; unsigned int StringLength = strlen(String); // Get The Length Of The String //One By One To Check Every Character for (i = 0;i < StringLength;i++) { if (String[i] < 48 || String[i] > 57) // The Character Is Not One Of 0 To 9 { return FALSE; // Return False } } return TRUE; // Return True }// End Of IsDigits() Method // End Of File