小型的http代理程序的详细介绍
小型的http代理程序的详细介绍
http代理程序网上有很多,公布源代码的也有一些,但是很多我测试的都不是很满意,于是就借鉴了那些代码,我自己动手打造了这个。
没有很多注释,其实每个函数名都可以顾名思义。
我自己测试没什么问题的,有心的可以帮忙测试下,附件中有源码和已编译压缩的程序
其实协议的很多细节我没去弄清楚,只是知道修改下请求包再转发包,就写了这个东西
glacier前辈有空可以看下吗,http代理这样实现还有什么不足
// Author: LZX
// E-mail: LZX@qq.com
// Version: V1.0 beta
// Purpose: A HTTP Proxy Supports GET && POST && CONNECT Methods
// Test PlatForm: WinXP SP2
// Compiled On: VC++ 6.0
#i nclude <windows.h>
#i nclude <stdio.h>
#i nclude <wininet.h>
#i nclude <errno.h>
#pragma comment(lib,"Ws2_32.lib")
#define MAX_HOSTNAME 256
#define DEFAULTPORT 80
#define LISTENPORT 8000
#define DEFLISNUM 500
#define HEADLEN 7
#define TIMEOUT 10000
#define MAXSIZE 20480
char ErrorMsg[]="Http/1.1 403 Forbidden/r/n/r/n<body><h1>403 Forbidden</h1></body>";
char ConnectionEstablished[]="HTTP/1.0 200 OK/r/n/r/n";
DWORD WINAPI ZXHTTPProxyThread(SOCKET* CSsocket);
int CheckRequest(char *ReceiveBuf,int *MethodLength);
char *GetURLRootPoint(char * ReceiveBuf,int DataLen,int *HostNaneLen);
void GetHostNameAndPort(char *ReceiveBuf,int datalen,char *HostName,UINT *RemotePort);
int ModifyRequest(char *SenderBuf,char *ReceiveBuf,int DataLen,int MethodLength);
char *DNS(char *HostName);
BOOL ConnectToRemoteHost(SOCKET *ServerSocket,char *HostName,const UINT RemotePort);
BOOL SendRequest(SOCKET* CSsocket, char *SenderBuf, char *ReceiveBuf, int DataLen);
void TransferData(SOCKET* CSsocket);
char *DNS(char *HostName)
{
HOSTENT *hostent = NULL;
IN_ADDR iaddr;
hostent = gethostbyname(HostName);
if (hostent == NULL)
{
return NULL;
}
iaddr = *((LPIN_ADDR)*hostent->h_addr_list);
return inet_ntoa(iaddr);
}
BOOL ConnectToRemoteHost(SOCKET *ServerSocket,char *HostName,const UINT RemotePort)
{
struct sockaddr_in Server;
memset(&Server, 0, sizeof(Server));
Server.sin_family = AF_INET;
Server.sin_port = htons(RemotePort);
if (inet_addr(HostName) != INADDR_NONE)
{
Server.sin_addr.s_addr = inet_addr(HostName);
}
else
{
if (DNS(HostName) != NULL)
{
Server.sin_addr.s_addr = inet_addr(DNS(HostName));
}
else
{
//printf("Invalid Host Name/n");
return FALSE;
}
}
// Create Socket
*ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (*ServerSocket == INVALID_SOCKET)
{
//printf("Fail To Create Server Socket/n");
return FALSE;
}
// Set Socket Time To 10 Seconds
UINT TimeOut = TIMEOUT;
setsockopt(*ServerSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut));
// Connect To The Remote Host
if (connect(*ServerSocket, (const SOCKADDR *)&Server,sizeof(Server)) == SOCKET_ERROR)
{
//printf("Fail To Connect To Remote Host/n");
closesocket(*ServerSocket);
return FALSE;
}
return TRUE;
}// End Of ConnectToRemoteHost()
//---------------------------------------------------------------------------
void GetHostNameAndPort(char *ReceiveBuf,int datalen,char *HostName,UINT *RemotePort)
{
char *fp = ReceiveBuf;
for(int i = 0;i < datalen && *fp != ':' && *fp != '/0' && *fp != '/r' && *fp != '/';i++)
{
HostName[i]=*fp++;
if(*fp == ':')
*RemotePort=atoi(fp+1);
else *RemotePort=DEFAULTPORT;
}
}
//---------------------------------------------------------------------------
char * GetURLRootPoint(char * ReceiveBuf,int DataLen,int *HostNaneLen)
{
for(int i = 0;i < DataLen; i++)
{
if(ReceiveBuf[i] == '/')
{
*HostNaneLen = i;
return &ReceiveBuf[i];
}
}
return NULL;
}
//---------------------------------------------------------------------------
int CheckRequest(char *ReceiveBuf,int *MethodLength)
{
if(!strnicmp(ReceiveBuf,"GET ",4))
{
*MethodLength = 4;
return 1;
}
else if(!strnicmp(ReceiveBuf,"HEAD ",5)) //Looks like the same with GET
{
*MethodLength = 5;
return 2;
}
else if(!strnicmp(ReceiveBuf,"POST ",5))
{
*MethodLength = 5;
return 3;
}
else if(!strnicmp(ReceiveBuf,"CONNECT ",8))
{
*MethodLength = 8;
return 4;
}
else
{
return 0;
}
}
int ModifyRequest(char *SenderBuf,char *ReceiveBuf,int DataLen,int MethodLength)
{
strncpy(SenderBuf,ReceiveBuf,MethodLength);
int HedLen = 0;
if(strncmp(ReceiveBuf+MethodLength,"http://",HEADLEN))
return 0;
char * Getrootfp = GetURLRootPoint(ReceiveBuf+MethodLength+HEADLEN,DataLen-MethodLength-HEADLEN,&HedLen);
if(Getrootfp == NULL)
return 0;
memcpy(SenderBuf+MethodLength,Getrootfp,DataLen-MethodLength-HEADLEN-HedLen);
return DataLen-HEADLEN-HedLen;
}
////////////////////////////////////////////////////////
void TransferData(SOCKET* CSsocket)
{
SOCKET ClientSocket = CSsocket[0];
SOCKET ServerSocket = CSsocket[1];
struct timeval timeset;
fd_set readfd,writefd;
int result,i=0;
char read_in1[MAXSIZE],send_out1[MAXSIZE];
char read_in2[MAXSIZE],send_out2[MAXSIZE],SenderBuf[MAXSIZE];
int read1=0,totalread1=0,send1=0;
int read2=0,totalread2=0,send2=0;
int sendcount1,sendcount2;
int maxfd;
maxfd=max(ClientSocket,ServerSocket)+1;
memset(read_in1,0,MAXSIZE);
memset(read_in2,0,MAXSIZE);
memset(send_out1,0,MAXSIZE);
memset(send_out2,0,MAXSIZE);
timeset.tv_sec=TIMEOUT;
timeset.tv_usec=0;
while(1)
{
FD_ZERO(&readfd);
FD_ZERO(&writefd);
FD_SET((UINT)ClientSocket, &readfd);
FD_SET((UINT)ClientSocket, &writefd);
FD_SET((UINT)ServerSocket, &writefd);
FD_SET((UINT)ServerSocket, &readfd);
result=Select(maxfd,&readfd,&writefd,NULL,×et);
if((result<0) && (errno!=EINTR))
{
//printf("[-] Select error./r/n");
break;
}
else if(result==0)
{
//printf("[-] Socket time out./r/n");
break;
}
if(FD_ISSET(ServerSocket, &readfd))
{
if(totalread2<MAXSIZE)
{
read2=recv(ServerSocket,read_in2,MAXSIZE-totalread2, 0);
if(read2==0)break;
if((read2<0) && (errno!=EINTR))
{
//printf("[-] Read ServerSocket data error,maybe close?/r/n/r/n");
break;
}
memcpy(send_out2+totalread2,read_in2,read2);
totalread2+=read2;
memset(read_in2,0,MAXSIZE);
}
//printf("Read from WebServer:/n%s/n",send_out2);
}
if(FD_ISSET(ClientSocket, &writefd))
{
int err2=0;
sendcount2=0;
while(totalread2>0)
{
send2=send(ClientSocket, send_out2+sendcount2, totalread2, 0);
if(send2==0)break;
if((send2<0) && (errno!=EINTR))
{
//printf("[-] Send to ClientSocket unknow error./r/n");
err2=1;
break;
}
if((send2<0) && (errno==ENOSPC)) break;
sendcount2+=send2;
totalread2-=send2;
}
if(err2==1) break;
if((totalread2>0) && (sendcount2 > 0))
{
/* move not sended data to start addr */
memcpy(send_out2, send_out2+sendcount2, totalread2);
memset(send_out2+totalread2, 0, MAXSIZE-totalread2);
}
else
memset(send_out2,0,MAXSIZE);
}
if(FD_ISSET(ClientSocket, &readfd))
{
/* must < MAXSIZE-totalread1, otherwise send_out1 will flow */
if(totalread1<MAXSIZE)
{
read1=recv(ClientSocket, read_in1, MAXSIZE-totalread1, 0);
if((read1==SOCKET_ERROR) || (read1==0))
{
//printf("[-] Read ClientSocket data error,maybe close?/r/n");
break;
}
memcpy(send_out1+totalread1,read_in1,read1);
totalread1+=read1;
memset(read_in1,0,MAXSIZE);
}
if(SendRequest(CSsocket,SenderBuf,send_out1,totalread1))
totalread1=0;
}
if(FD_ISSET(ServerSocket, &writefd))
{
int err=0;
sendcount1=0;
while(totalread1>0)
{
send1=send(ServerSocket, send_out1+sendcount1, totalread1, 0);
if(send1==0)break;
if((send1<0) && (errno!=EINTR))
{
//printf("[-] Send to ServerSocket unknow error./r/n");
err=1;
break;
}
if((send1<0) && (errno==ENOSPC)) break;
sendcount1+=send1;
totalread1-=send1;
}
if(err==1) break;
if((totalread1>0) && (sendcount1>0))
{
memcpy(send_out1,send_out1+sendcount1,totalread1);
memset(send_out1+totalread1,0,MAXSIZE-totalread1);
}
else
memset(send_out1,0,MAXSIZE);
}
Sleep(5);
}
closesocket(ClientSocket);
closesocket(ServerSocket);
//printf("/r/nClosed The Two Socket./r/n");
}
BOOL SendRequest(SOCKET* CSsocket, char *SenderBuf, char *ReceiveBuf, int DataLen)
{
//CSsocket[0] ClientSocket
//CSsocket[1] ServerSocket
DWORD dwThreadID;
char HostName[MAX_HOSTNAME] = {0};
UINT RemotePort = 0;
int Flag=0, MethodLength=0, SendLength=0;
Flag = CheckRequest(ReceiveBuf,&MethodLength);
if(Flag==0) return 0;
if(Flag==1 || Flag==2 || Flag==3)
{
SendLength=ModifyRequest(SenderBuf,ReceiveBuf,DataLen,MethodLength);
if(!SendLength)
return 0;
GetHostNameAndPort(ReceiveBuf+MethodLength+HEADLEN,DataLen-MethodLength-HEADLEN,HostName,&RemotePort);
//printf("%s:%d/n",HostName,RemotePort);
if(!ConnectToRemoteHost(&CSsocket[1],HostName,RemotePort))
return 0;
//printf("%s/n",SenderBuf);
if(send(CSsocket[1],SenderBuf,SendLength,0) == SOCKET_ERROR)
return 0;
}else if(Flag==4)
{
GetHostNameAndPort(ReceiveBuf+MethodLength,DataLen-MethodLength,HostName,&RemotePort);
//printf("%s:%d/n",HostName,RemotePort);
if(!ConnectToRemoteHost(&CSsocket[1],HostName,RemotePort))
return 0;
send(CSsocket[0], ConnectionEstablished, strlen(ConnectionEstablished),0);
}
if(CSsocket[0] && CSsocket[1])
{
HANDLE ThreadHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)TransferData,(LPVOID)CSsocket,0,&dwThreadID);
if (ThreadHandle != NULL)
{
WaitForSingleObject(ThreadHandle, INFINITE);
}
}else
return 0;
return 1;
}
DWORD WINAPI ZXHTTPProxyThread(SOCKET* CSsocket)
{
char *ReceiveBuf = (char*)malloc(sizeof(char)*MAXSIZE);
char *SenderBuf = (char*)malloc(sizeof(char)*MAXSIZE);
memset(ReceiveBuf,0,MAXSIZE);
memset( SenderBuf,0,MAXSIZE);
int DataLen = 0;
DataLen = recv(CSsocket[0],ReceiveBuf,MAXSIZE,0);
if(DataLen == SOCKET_ERROR || DataLen == 0)
{
goto error;
}
if(!SendRequest(CSsocket, SenderBuf, ReceiveBuf, DataLen))
goto error;
error:
send(CSsocket[0],ErrorMsg,strlen(ErrorMsg),0);
closesocket(CSsocket[0]);
closesocket(CSsocket[1]);
free(CSsocket);
free(ReceiveBuf);
free(SenderBuf);
return 0;
}
int main(int argc, char* argv[])
{
int LisPort=LISTENPORT;
if(argc>1)
LisPort=atoi(argv[1]);
printf("Http Proxy V1.0 By LZX./r/nUsage: %s ProxyPort/r/n",argv[0]);
WSADATA WSAData;
if(WSAStartup(MAKEWORD(2,2), &WSAData))
return 1;
SOCKET ProxyServer= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(ProxyServer == SOCKET_ERROR)
return 1;
struct sockaddr_in Server={0};
Server.sin_family = AF_INET;
Server.sin_port = htons(LisPort);
Server.sin_addr.S_un.S_addr = INADDR_ANY;
if(bind(ProxyServer, (LPSOCKADDR)&Server, sizeof(Server)) == SOCKET_ERROR)
return 1;
if(listen(ProxyServer, DEFLISNUM) == SOCKET_ERROR)
return 1;
SOCKET AcceptSocket = INVALID_SOCKET;
SOCKET *CSsocket;
DWORD dwThreadID;
printf("Now listening on port: %d/r/n",LisPort);
while(1)
{
AcceptSocket = accept(ProxyServer, NULL, NULL);
//printf("Accepting New Requests/n");
CSsocket = (SOCKET*)malloc(sizeof(SOCKET)*2);
if (CSsocket == NULL)
{
//printf("Fail To Allocate Ram/n");
continue;
}
CSsocket[0] = AcceptSocket;
HANDLE hThread = CreateThread (NULL,0, (LPTHREAD_START_ROUTINE)ZXHTTPProxyThread,CSsocket,0, &dwThreadID); // Create Thread To Handle Request
if (hThread == NULL) // Fail To Create Socket
{
//printf("Fail To Create Thread.Probably Too Many Threads Have Been Created/n");
Sleep(1000);
}
else
{
CloseHandle(hThread);
}
}
}