zoukankan      html  css  js  c++  java
  • 穿透代理服务器编程

    正文  
    在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问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);  
    }
  • 相关阅读:
    如何通过命令行窗口查看sqlite数据库文件
    eclipse自动补全的设置
    文本装饰
    注释和特殊符号
    文本装饰
    网页背景
    通过ArcGIS Server admin 查看和删除已注册的 Web Adaptor
    通过 ArcGIS Server Manager 查看已安装的 Web Adaptor
    通过 ArcGIS Server Manager 验证 DataStore
    Windows上安装ArcGIS Enterprise——以 Windows Server 2012 R2上安装 ArcGIS 10.8为例
  • 原文地址:https://www.cnblogs.com/simonhaninmelbourne/p/2700556.html
Copyright © 2011-2022 走看看