不要心里老是想着只要拿到源代码就可以直接去用,因为对rfc1928、rfc1929研究是必要的,因为在调试程序的时候,你一定要知道协议才可以调,我现在给一些相关的文档给你,也许比那些代码对你更加有用处:用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);
    
}
希望对你有帮助!

解决方案 »

  1.   

    cococut(往事如屁!!!) 说的不错。另外,你应该首先精通SOCKET网络编程,至于SOCK5编程只是一个协议的问题。很容易搞定的。
      

  2.   

    你要得是一个类似wingate那样的源代码吗?
      

  3.   

    差不多,但我只是关心socks5部分。
      

  4.   

    to rovoboy(雪花满天):
    大哥,别开玩笑好不好。我早找过了,没有啊。
    ================================================================CSDN 论坛助手 Ver 1.0 B0402提供下载。 改进了很多,功能完备!★  浏览帖子速度极快![建议系统使用ie5.5以上]。 ★  多种帖子实现界面。 
    ★  保存帖子到本地[html格式]★  监视您关注帖子的回复更新。0D
    ★  可以直接发贴、回复帖子★  采用XML接口,可以一次性显示4页帖子,同时支持自定义每次显示帖子数量。可以浏览历史记录! 
    ★  支持在线检测程序升级情况,可及时获得程序更新的信息。
    0A
    ★★ 签名  ●  
         可以在您的每个帖子的后面自动加上一个自己设计的签名哟。Http://www.ChinaOK.net/csdn/csdn.zip
    Http://www.ChinaOK.net/csdn/csdn.rar
    Http://www.ChinaOK.net/csdn/csdn.exe    [自解压]
      

  5.   

    SOCKS 5协议详解 作者:李洪洲 发布时间:2000/12/13 
    文章摘要: 
      该文档描述了一个应用层的用于穿越IP网络防火墙的协议。这种穿越的安全性是高度依赖于正规的认证和正规执行方法提供的有效封装,以及在SOCKS客户端和SOCKS服务端所选择的安全性,还有管理员对认证方法选项所作的小心周密的考虑。  
             --------------------------------------------------------------------------------
     
    正文:    SOCKS 5协议详解     笔者在实际学习中,由于在有些软件用到了socks5(如oicq,icq等),对其原理不甚了解,相信很多朋友对其也不是很了解,于是仔细研读了一下rfc1928,觉得有必要译出来供大家参考。1.介绍:  防火墙的使用,有效的隔离了机构的内部网络和外部网络,这种类型的Internet架构变得越来越流行。这些防火墙系统大都充当着网络之间的应用层网关的角色,通常提供经过控制的Telnet,FTP,和SMTP访问。为了推动全球信息的交流,更多的新的应用层协议的推出。这就有必要提供一个总的架构使这些协议能够更明显和更安全的穿过防火墙。也就有必要在实际上为它们穿过防火墙提供一个更强的认证机制。这种需要源于客户机-服务器联系在不同组织网络之间的实现,而这种联系需要被控制和是很大程度上被认证的。
      该协议被描述为用来提供在TCP和UDP域下为客户机-服务器应用程序便利和安全的穿过防火墙的一个架构。该协议在概念上被描述为一个介于应用层和传输层之间的"隔离层",但是这类服务并不提供网络层网关服务,如ICMP报文的传输。2.现状:  SOCKS 4为基于TCP的客户机-服务器应用程序提供了一种不安全的穿越防火墙的机制,包括TELNET,FTP和当前最流行的信息发现协议如HTTP,WAIS和GOPHER.
      新协议为了包括UDP扩展了SOCKS 4,为了包括对总体上更强的认证机制的支持扩展了协议架构,为了包括域名和IPv6地址的支持扩展了地址集。
      SOCKS协议执行最具代表性的是包括了在SOCKS库中利用适当的封装程序来对基于TCP的客户程序进行重编译和重链结。注意:
      除非特别提及,封装在包格式中的十进制数表示的是通讯域的长度(用八位组octect表示)。一个给定的八位组必须具有指定的值,格式X'hh'被用来表示在该域中单个八位组的值。当单词"变量Variable"被使用时,它指出了通讯域拥有一个可变长度,这个可变长度要么由一个联合的(一个或两个八位组)长度域定义,要么由一个数据类型域所定义。3.基于TCP客户机的程序  当一台基于TCP的客户机希望和目标主机建立连接时,而这台目标主机只有经过防火墙才能到达(这种情况?一直持续到?它被执行时),它就必须在SOCKS服务器端的适当的SOCKS端口打开一个TCP连结。SOCKS服务按常例来说定位于TCP端口1080。如果连接请求成功,客户机为即将使用的认证方式进行一种协商,对所选的方式进行认证,然后发送一个转发请求。SOCKS服务器对该请求进行评估,并且决定是否建立所请求转发的连接。
      客户机连接到服务器,发送一个版本标识/方法选择报文:  +----+----------+----------+
      |VER | NMETHODS | METHODS |
      +----+----------+----------+
      | 1 |   1  | 1 to 255 |
      +----+----------+----------+  VER(版本)在这个协议版本中被设置为X'05'。NMETHODS(方法选择)中包含在METHODS(方法)中出现的方法标识八位组的数目。
      服务器从METHODS给出的方法中选出一种,发送一个METHOD selection(方法选择)报文:  +----+--------+
      |VER | METHOD |
      +----+--------+
      | 1 |  1  |
      +----+--------+  如果所选择的METHOD的值是X'FF',则客户机所列出的方法是没有可以被接受的,客户机就必须关闭连接。当前被定义的METHOD的值有:
      >> X'00' 无验证需求
      >> X'01' 通用安全服务应用程序接口(GSSAPI)
      >> X'02' 用户名/密码(USERNAME/PASSWORD)
      >> X'03' 至 X'7F' IANA 分配(IANA ASSIGNED) 
      >> X'80' 至 X'FE' 私人方法保留(RESERVED FOR PRIVATE METHODS)
      >> X'FF' 无可接受方法(NO ACCEPTABLE METHODS)
    ***IANA是负责全球INTERNET上的IP地址进行编号分配的机构(译者著)***
      于是客户机和服务器进入方法细节的子商议。方法选择子商议另外描述于独立的文档中。
      欲得到该协议新的METHOD支持的开发者可以和IANA联系以求得到METHOD号。已分配号码的文档需要参考METHOD号码的当前列表和它们的通讯协议。
      如果想顺利的执行则必须支持GSSAPI和支持用户名/密码(USERNAME/PASSWORD)认证方法。4.需求  一旦方法选择子商议结束,客户机就发送请求细节。如果商议方法包括了完整性检查的目的和/或机密性封装,则请求必然被封在方法选择的封装中。SOCKS请求如下表所示:  +----+-----+-------+------+----------+----------+
      |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 |  1 | X'00' |  1 | Variable |   2  |
      +----+-----+-------+------+----------+----------+其中:
    o VER protocol version:X'05'
    o CMD
     o CONNECT X'01'
     o BIND X'02'
     o UDP ASSOCIATE X'03'
    o RSV RESERVED
    o ATYP address type of following address
     o IP V4 address: X'01'
     o DOMAINNAME: X'03'
     o IP V6 address: X'04'
    o DST.ADDR desired destination address
    o DST.PORT desired destination port in network octet order5.地址  在地址域(DST.ADDR,BND.ADDR)中,ATYP域详细说明了包含在该域内部的地址类型:
        o X'01'  该地址是IPv4地址,长4个八位组。
        o X'03'  该地址包含一个完全的域名。第一个八位组包含了后面名称的八位组的数目,没有中止的空八位组。
        o X'04'  该地址是IPv6地址,长16个八位组。6.回应  到SOCKS服务器的连接一经建立,客户机即发送SOCKS请求信息,并且完成认证商议。服务器评估请求,返回一个回应如下表所示:
      +----+-----+-------+------+----------+----------+
      |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
      +----+-----+-------+------+----------+----------+
      | 1 | 1 | X'00' | 1  | Variable |   2  |
      +----+-----+-------+------+----------+----------+其中:o VER protocol version: X'05'
    o REP Reply field:
      o X'00' succeeded
      o X'01' general SOCKS server failure
      o X'02' connection not allowed by ruleset
      o X'03' Network unreachable
      o X'04' Host unreachable
      o X'05' Connection refused
      o X'06' TTL expired
      o X'07' Command not supported
      o X'08' Address type not supported
      o X'09' to X'FF' unassigned
    o RSV RESERVED
    o ATYP address type of following address
      o IP V4 address: X'01'
      o DOMAINNAME: X'03'
      o IP V6 address: X'04'
    o BND.ADDR server bound address
    o BND.PORT server bound port in network octet order
    标志RESERVED(RSV)的地方必须设置为X'00'。  如果被选中的方法包括有认证目的封装,完整性和/或机密性的检查,则回应就被封装在方法选择的封装套中。CONNECT  在CONNECT的回应中,BND.PORT包括了服务器分配的连接到目标主机的端口号,同时BND.ADDR包含了关联的IP地址。此处所提供的BND.ADDR通常情况不同于客户机连接到SOCKS服务器所用的IP地址,因为这些服务器提供的经常都是多址的(muti-homed)。都期望SOCKS主机能使用DST.ADDR和DST.PORT,连接请求评估中的客户端源地址和端口。BIND  BIND请求被用在那些需要客户机接受到服务器连接的协议中。FTP就是一个众所周知的例子,它通过使用命令和状态报告建立最基本的客户机-服务器连接,按照需要使用服务器-客户端连接来传输数据。(例如:ls,get,put)
    都期望在使用应用协议的客户端在使用CONNECT建立首次连接之后仅仅使用BIND请求建立第二次连接。都期望SOCKS主机在评估BIND请求时能够使用DST.ADDR和DST.PORT。
      有两次应答都是在BIND操作期间从SOCKS服务器发送到客户端的。第一次是发送在服务器创建和绑定一个新的socket之后。BIND.PORT域包含了SOCKS主机分配和侦听一个接入连接的端口号。BND.ADDR域包含了关联的IP地址。  客户端具有代表性的是使用这些信息来通报应用程序连接到指定地址的服务器。第二次应答只是发生在预期的接入连接成功或者失败之后。在第二次应答中,BND.PORT和BND.ADDR域包含了欲连接主机的地址和端口号。UDP ASSOCIATE(连接?)  UDP 连接请求用来建立一个在UDP延迟过程中操作UDP数据报的连接。DST.ADDR和DST.PORT域包含了客户机期望在这个连接上用来发送UDP数据报的地址和端口。服务器可以利用该信息来限制至这个连接的访问。如果客户端在UDP连接时不持有信息,则客户端必须使用一个全零的端口号和地址。  当一个含有UDP连接请求到达的TCP连接中断时,UDP连接中断。  在UDP连接请求的回应中,BND.PORT和BND.ADDR域指明了客户端需要被发送UDP请求消息的端口号/地址。回应过程  当一个回应(REP值非X'00')指明失败时,SOCKS主机必须在发送后马上中断该TCP连接。该过程时间必须为在侦测到引起失败的原因后不超过10秒。
      如果回应代码(REP值为X'00')时,则标志成功,请求或是BIND或是CONNECT,客户机现在就可以传送数据了。如果所选择的认证方法支持完整性、认证机制和/或机密性的封装,则数据被方法选择封装包来进行封装。类似,当数据从客户机到达SOCKS主机时,主机必须使用恰当的认证方法来封装数据。7.基于UDP客户机的程序
      

  6.   

    传透代理服务器的编程 
      
    关键字 代理服务器、Socks4、Socks5、Http代理
    原作者姓名 allfresh
    文章原始出处 http://www.allfresh.net/program/proxy.htm 
    正文
    在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问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\r\nUser-Agent: MyApp/0.1\r\n\r\n");
    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等文档资料。<正文完>
      

  7.   

    谢谢nne998(上上下下左右左右BABA) ,感谢你提供的socks5的中文资料.
      

  8.   

    找了一下,只有一个
    http://www.vckbase.com/code/listcode.asp?mclsid=9&sclsid=903&page=3
      

  9.   

    to  rovoboy(雪花满天) :
    我以前也找过,http://www.vckbase.com/code/listcode.asp?mclsid=9&sclsid=903&page=3
    只是个http代理,我要socks代理。
      

  10.   

    楼主,nne998(上上下下左右左右BABA)贴的回帖已经满足你的要求了。SOCKS的请求端口是1080。有它那段代码想干什么都可以了,访问数据库,远程通信都可以实现
      

  11.   

    punks(墙皮皮) 大哥看清楚,我要的代理服务器的实现,而不是客户端如何通过代理服务器连接
      

  12.   

    to solar(int argc,char**argv) :
    :)我也有啊,从nec上导来的。
    我决定自己照着协议写了,结帖。