//**********************************************************************
#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 

 

 

posted on 2013-07-21 17:34  5t4rk  阅读(1474)  评论(0编辑  收藏  举报