穿透代理服务器编程

摘要:
在网络编程过程中,我们经常要处理各种类型的代理服务器,例如通过企业内部网中的代理访问Internet上的服务器。通常,代理服务器支持几种常见的代理协议标准,如Socks4、Socks5和Http代理。Socks5需要用户身份验证,代理相对复杂。在查阅了RFC文档和相关资料后,我在此总结了穿透代理服务器的TCP协议的一些程序片段,希望能帮助您//使用structsock4req1{charVN;charCD;unsigned shortPort;unsignedlongIPAddr;other[1];};结构sock4ans1{charVN;charCD;};structsock5req1{charVer;charnMethods;charMethods[255];};structsock5ans1{charVer;charMethod;};structsock5req2{charVer;charCmd;charRsv;charAtyp;charother[1];};结构代码2{charVer;charRep;charRsv;charAtyp;charother[1];};结构验证请求{charVer;charUlen;charName[255];charPLen;charPass[255];};结构验证{charVer;charStatus;};//如果(!ClientSock.Connect){m_sError=_T(“无法连接到代理服务器!”);ClientSock。Close();returnFALSE;}//如果(!=0){m_sError=_T(“代理用户身份验证失败!
正文  
在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问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);  
}

免责声明:文章转载自《穿透代理服务器编程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇深度学习Tensorflow生产环境部署(下·模型部署篇)egret 自动播放音乐问题:ios 自动播放音乐失效下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python pymysql连接数据库并创建表

之前看菜鸟教程 #!/usr/bin/python3 import pymysql # 打开数据库连接 db = pymysql.connect("localhost","testuser","test123","TESTDB" ) # 使用 cursor() 方法创建一个游标对象 cursor cursor = db.cursor() #...

Crypto++入门学习笔记(DES、AES、RSA、SHA-256)

最先附上下载地址 背景(只是个人感想,技术上不对后面的内容构成知识性障碍,可以skip): 最近,基于某些原因和需要,笔者需要去了解一下Crypto++库,然后对一些数据进行一些加密解密的操作。 笔者之前没接触过任何加密解密方面的知识(当然,把每个字符的ASCII值加1之流对明文进行加密的“趣事”还是干过的,当时还很乐在其中。),甚至一开始连Crypto+...

goahead3.6.3就基本使用(后台上传信息到html页面),高手请忽略

声明:这里面的代码均为网上找的然后有小小的改动,并非原创。但文章为原创 一、.编译 1.1,、下载:进入http://embedthis.com/goahead/下载goahead3.6.3(2017年9月12日还是这版本) 1.2、解压 , 然后进入goahead-3.6.3-rc目录,进入后为这样 , 然后在进入goahead-3.6.3 然后在终端...

Jmeter代理服务器设置

(一)设置Jmeter之web代理,操作步骤这里就直接用动图代替了。 第一步:设置Jmeter的代理,添加Http代理服务器 第二步:添加一个线程组 第三步:设置代理服务器的各项参数,启动代理服务器 第四步:设置浏览器的代理设置,要跟代理服务保持一致的参数 第五步:在浏览器操作,检查Jmeter是否有录制相关操作脚本 第六步:打开浏览器设置浏览器的代理,...

C#.NET 中的类型转换

C# 出来也有些日子了,最近由于编程的需要,对 C# 的类型转换做了一些研究,其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 Unicode 码、数值字符串和数值之间的转换、字符串和字符数组/字节数组之间的转换、各种数值类型和字节数组之间的转换、十六进制数输出以及日期型数据的一些转换处理,在这里与大家分享—— 1. 装箱...

C语言:字符数组 + 字符串指针

字符数组 C语言中没有特定的字符串类型,通常是将字符串放在一个字符数组中。 字符串指针 除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串。 char *str = "leetcode"; char *str; str = "leetcode"; 字符串中的所有字符在内存中是连续存放的,str指向的是字符串的第0个字符,即...