基于SOCK4网络协议的代理服务器端代码示例

时间:2023-03-09 06:24:00
基于SOCK4网络协议的代理服务器端代码示例
//**********************************************************************
#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