穿透代理服务器编程

正文  
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问Internet网上的服务器等等,一般代理服务器支持几种常见的代理协议标准,如Socks4,Socks5,Http代理,其中Socks5需要用户验证,代理相对复杂。我在查阅RFC文档和相关资料后,特总结一些TCP协议穿透代理服务器的程序片断,希望对大家有所帮助。  
//使用到的结构  
struct   sock4req1  
{  
char   VN;  
char   CD;  
unsigned   short   Port;  
unsigned   long   IPAddr;  
char   other[1];  
};  
struct   sock4ans1  
{  
char   VN;  
char   CD;  
};  
struct   sock5req1  
{  
char   Ver;  
char   nMethods;  
char   Methods[255];  
};  
struct   sock5ans1  
{  
char   Ver;  
char   Method;  
};  
struct   sock5req2  
{  
char   Ver;  
char   Cmd;  
char   Rsv;  
char   Atyp;  
char   other[1];  
};  
struct   sock5ans2  
{  
char   Ver;  
char   Rep;  
char   Rsv;  
char   Atyp;  
char   other[1];  
};  
struct   authreq  
{  
char   Ver;  
char   Ulen;  
char   Name[255];  
char   PLen;  
char   Pass[255];  
};  
struct   authans  
{  
char   Ver;  
char   Status;  
};  
//通过Socks4方式代理  
if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
{  
m_sError   =   _T( "不能连接到代理服务器! ");  
ClientSock.Close();  
return   FALSE;  
}  
char   buff[100];  
memset(buff,0,100);  
struct   sock4req1   *m_proxyreq;  
m_proxyreq   =   (struct   sock4req1   *)buff;  
m_proxyreq-> VN   =   4;  
m_proxyreq-> CD   =   1;  
m_proxyreq-> Port   =   ntohs(GetPort());  
m_proxyreq-> IPAddr   =   inet_addr(GetServerHostName());  
ClientSock.Send(buff,9);  
struct   sock4ans1   *m_proxyans;  
m_proxyans   =   (struct   sock4ans1   *)buff;  
memset(buff,0,100);  
ClientSock.Receive(buff,100);  
if(m_proxyans-> VN   !=   0   ||   m_proxyans-> CD   !=   90)  
{  
m_sError   =   _T( "通过代理连接主站不成功! ");  
ClientSock.Close();  
return   FALSE;  
}  
//通过Socks5方式代理  
if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
{  
m_sError   =   _T( "不能连接到代理服务器! ");  
ClientSock.Close();  
return   FALSE;  
}  
char   buff[600];  
struct   sock5req1   *m_proxyreq1;  
m_proxyreq1   =   (struct   sock5req1   *)buff;  
m_proxyreq1-> Ver   =   5;  
m_proxyreq1-> nMethods   =   2;  
m_proxyreq1-> Methods[0]   =   0;  
m_proxyreq1-> Methods[1]   =   2;  
ClientSock.Send(buff,4);  
struct   sock5ans1   *m_proxyans1;  
m_proxyans1   =   (struct   sock5ans1   *)buff;  
memset(buff,0,600);  
ClientSock.Receive(buff,600);  
if(m_proxyans1-> Ver   !=   5   ||   (m_proxyans1-> Method!=0   &&   m_proxyans1-> Method!=2))  
{  
m_sError   =   _T( "通过代理连接主站不成功! ");  
ClientSock.Close();  
return   FALSE;  
}  
if(m_proxyans1-> Method   ==   2)  
{  
int   nUserLen   =   strlen(g_ProxyInfo.m_strProxyUser);  
int   nPassLen   =   strlen(g_ProxyInfo.m_strProxyPass);  
struct   authreq   *m_authreq;  
m_authreq   =   (struct   authreq   *)buff;  
m_authreq-> Ver   =   1;  
m_authreq-> Ulen   =   nUserLen;  
strcpy(m_authreq-> Name,g_ProxyInfo.m_strProxyUser);  
m_authreq-> PLen   =   nPassLen;  
strcpy(m_authreq-> Pass,g_ProxyInfo.m_strProxyPass);  
ClientSock.Send(buff,513);  
struct   authans   *m_authans;  
m_authans   =   (struct   authans   *)buff;  
memset(buff,0,600);  
ClientSock.Receive(buff,600);  
if(m_authans-> Ver   !=   1   ||   m_authans-> Status   !=   0)  
{  
m_sError   =   _T( "代理服务器用户验证不成功! ");  
ClientSock.Close();  
return   FALSE;  
}  
}  
struct   sock5req2   *m_proxyreq2;  
m_proxyreq2   =   (struct   sock5req2   *)buff;  
m_proxyreq2-> Ver   =   5;  
m_proxyreq2-> Cmd   =   1;  
m_proxyreq2-> Rsv   =   0;  
m_proxyreq2-> Atyp   =   1;  
unsigned   long   tmpLong   =   inet_addr(GetServerHostName());  
unsigned   short   port   =   ntohs(GetPort());  
memcpy(m_proxyreq2-> other,&tmpLong,4);  
memcpy(m_proxyreq2-> other+4,&port,2);  
ClientSock.Send(buff,sizeof(struct   sock5req2)+5);  
struct   sock5ans2   *m_proxyans2;  
memset(buff,0,600);  
m_proxyans2   =   (struct   sock5ans2   *)buff;  
ClientSock.Receive(buff,600);  
if(m_proxyans2-> Ver   !=   5   ||   m_proxyans2-> Rep   !=   0)  
{  
m_sError   =   _T( "通过代理连接主站不成功! ");  
ClientSock.Close();  
return   FALSE;  
}  
//通过HTTP方式代理  
if(   !ClientSock.Connect(   g_ProxyInfo.m_strProxyIP,g_ProxyInfo.m_nProxyPort)   )  
{  
m_sError   =   _T( "不能连接到代理服务器! ");  
ClientSock.Close();  
return   FALSE;  
}  
char   buff[600];  
sprintf(   buff,   "%s%s:%d%s ", "CONNECT   ",GetServerHostName(),GetPort(), "   HTTP/1.1   User-Agent:   MyApp/0.1   ");  
ClientSock.Send(buff,strlen(buff));   //发送请求  
memset(buff,0,600);  
ClientSock.Receive(buff,600);  
if(strstr(buff,   "HTTP/1.0   200   Connection   established ")   ==   NULL)   //连接不成功  
{  
m_sError   =   _T( "通过代理连接主站不成功! ");  
ClientSock.Close();  
return   FALSE;  
}  
我们一般先与代理服务器连通,然后向代理服务器发送代理验证的用户名和密码(如果需要,如Socks5代理),验证成功后,再向代理服务器发送需要连接的目的地址和端口。以上代码仅用于TCP连接,如果在内部网侦听或通过UDP协议发送信息,可查阅RFC1829等文档资料。 
用socks5进行udp发送数据的过程:  
你的目的是要和服务器做UDP的数据传送。
步骤:  
1,和代理建立tcp联接,(你已经完成)。
2,向代理发送版本的请求信息,   我的实现:
void   CCommunicator::SendVer()
{
int   datasize   =   6;
char   tempbuf[6];
tempbuf[0]=5;
tempbuf[1]=4;//标示后面所根的字接数
tempbuf[2]=0;
tempbuf[3]=1;
tempbuf[4]=2;
tempbuf[5]=3;
int   senddatalen;  
senddatalen=send(m_sock,(char*)tempbuf,6,0);
}
这一步,你已经返回成功,是吗?如果失败,断开建立的tcp联接,如果成功,如果需要用户验证则进行步骤3,否则进行4.
3,如果需要用户验证,则类似:  
BOOL   CCommunicator::SendUserTest()  
{  
int   usernamelen=0;  
int   userpasslen=0;  
usernamelen=m_strTestUserName.GetLength();  
userpasslen=m_strTestUserPass.GetLength();  
char   tempbuf[100];  
tempbuf[0]=5;  
tempbuf[1]=usernamelen;//标示后面所根的字接数  
strcpy(&tempbuf[2],m_strTestUserName);  
tempbuf[2+usernamelen]=userpasslen;  
strcpy((char*)&tempbuf   [3+usernamelen],m_strTestUserPass);  
int   senddatalen;
int   len;  
len=usernamelen+userpasslen+3;  
senddatalen=send(m_sock,(char*)tempbuf,len,0);
}   如果失败,断开建立的tcp联接,   如果用户返回成功,步骤4.
4,发送请求的协议类似:  
void   CCommunicator::SendRequestUDP()  
{  
int   const   datasize=10;  
BYTE   tempbuf[datasize];   tempbuf[0]=5;  
tempbuf[1]=3;//标示UDP连接  
tempbuf[2]=0;  
tempbuf[3]=1;  
tempbuf[4]=0;  
tempbuf[5]=0;  
tempbuf[6]=0;  
tempbuf[7]=0;  
*((SHORT*)(&(tempbuf[8])))=m_uBindUDPPort;   //UDP在客户端绑定的端口,就是你本地机器的做udp数据传送的端口调用  
                                                                                      //socket函数后,再调用bind()来邦定一个端口。  
char   temp;  
temp=tempbuf[8];  
tempbuf[8]=tempbuf[9];  
tempbuf[9]=temp;  
int   senddatalen=send(m_sock,(char*)tempbuf,datasize,0);  
}
如果失败,断开建立的tcp联接,如果返回成功,验证完毕!步骤5  
5,真正的数据传送,用代理传送的时候,数据包的前面加上10个字节类似:  
void   CCommunicator::CopyDataHead(BYTE   *   ptempbuf)  
{  
struct   in_addr   addr;  
addr.s_addr=inet_addr(“202.220.33.333”);//这个ip是服务器端的ip  
ptempbuf[0]=0;  
ptempbuf[1]=0;  
ptempbuf[2]=0;  
ptempbuf[3]=1;  
ptempbuf[4]=(char)addr.S_un.S_un_b.s_b1;
ptempbuf[5]=(char)addr.S_un.S_un_b.s_b2;  
ptempbuf[6]=(char)addr.S_un.S_un_b.s_b3;
ptempbuf[7]=(char)addr.S_un.S_un_b.s_b4;  
*((SHORT*)(&(ptempbuf[8])))=m_uServerUDPPort;//服务器的端口,就是你最终要发到那个服务器的端口,也就是你的qq服务器。  
char   temp;  
temp=ptempbuf[8];  
ptempbuf[8]=ptempbuf[9];  
ptempbuf[9]=temp;  
}  
真正发送的时候类似:
int   CCommunicator::SendBufferUDP(LPBYTE   lpBuf,int   nLen)  
{  
BYTE   tempbuf[1000];  
int   iHeadData=0;  
struct   sockaddr_in   her;  
her.sin_family=AF_INET;  
her.sin_addr.s_addr=inet_addr(m_szProxyAddr);//代理服务器  
her.sin_port=htons(m_uSocksPort);//发送请求的时候返回的代理服务器端的端口,记住,这是最重要的。  
CopyDataHead(tempbuf);  
iHeadData=10;  
nLen=nLen+10;  
int   addr_len;  
addr_len=sizeof(struct   sockaddr);  
CopyMemory((char*)&tempbuf[iHeadData],lpBuf,nLen);  
int   returndatalen=sendto(m_socket,(char   *)tempbuf,nLen,0,(struct   sockaddr   *)&her,addr_len);  
}

你可能感兴趣的:(服务器编程)