• 穿透代理服务器编程


    正文  
    在网络程序设计过程中,我们经常要与各种类型的代理服务器打交道,比如在企业内部网通过代理去访问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);  
    }
  • 相关阅读:
    面试问题 集锦
    减少 lwip 消耗 的 RAM
    Blocking Master Example QT 自带 的 serial 即 串口 例子
    32位 的变量 用于表示 ms ,可以表示多少天那?
    centos 腾讯云 今天买了 18个月
    Linux BLE 基于 树莓派
    树莓派 4G模块 PPP 拨号 NDIS 拨号
    linux备份还原命令
    centos7中/tmp文件保存天数
    centos7查看可登陆用户
  • 原文地址:https://www.cnblogs.com/simonhaninmelbourne/p/2700556.html
Copyright © 2020-2023  润新知