zoukankan      html  css  js  c++  java
  • <转 >socket穿透代理代码(C++版)

    本文转自 http://blog.csdn.net/bodybo/article/details/7274865

    写代码经常会遇到socket要通过代理连接服务器的情况,代理类型通畅有三种:HTTP、SOCK4和SOCK5,通过学习和网上参考相关代码,写了个代理类来实现该功能,贴出来与大家共享

    才贴出来两天,刚在百度一搜竟然发现已被一字不改的转载到好几个网站去了,连转载的字样都没有,不反对转载分享,可能否注明出处?

    头文件

    #pragma once
    
    #include <WinSock2.h>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    enum ProxyStatus
    {
        SUCCESS,
        CONNECT_PROXY_FAIL,
        NOT_CONNECT_PROXY,
        CONNECT_SERVER_FAIL
    };
    
    class CProxy
    {
    public:
        CProxy(long type, string ip, u_short port, string username, string password)
            :m_proxyType(type), m_proxyIp(ip), m_proxyPort(port), m_proxyUserName(username), m_proxyUserPwd(password)
        {}
    
        ~CProxy(void){};
    
        ProxyStatus ConnectProxyServer(SOCKET socket);
        ProxyStatus ConnectServer(SOCKET socket, string ip, u_short port);
    
    private:
        ProxyStatus ConnectByHttp(SOCKET socket, string ip, u_short port);
        ProxyStatus ConnectBySock4(SOCKET socket, string ip, u_short port);
        ProxyStatus ConnectBySock5(SOCKET socket, string ip, u_short port);
    
        bool Send(SOCKET socket, const char* buf, int len);
        int Receive(SOCKET socket, char* buf, int bufLen);
    
    private:
        long m_proxyType;
        string m_proxyIp;
        u_short m_proxyPort;
        string m_proxyUserName;
        string m_proxyUserPwd;
    
        bool m_blnProxyServerOk;
    };
    
    struct TSock4req1 
    { 
        char VN; 
        char CD; 
        unsigned short Port; 
        unsigned long IPAddr; 
        char other; 
    }; 
    
    struct TSock4ans1 
    { 
        char VN; 
        char CD; 
    };
    
    struct TSock5req1 
    { 
        char Ver; 
        char nMethods; 
        char Methods; 
    }; 
    
    struct TSock5ans1 
    { 
        char Ver; 
        char Method; 
    }; 
    
    struct TSock5req2 
    { 
        char Ver; 
        char Cmd; 
        char Rsv; 
        char Atyp; 
        char other; 
    }; 
    
    struct TSock5ans2 
    { 
        char Ver; 
        char Rep; 
        char Rsv; 
        char Atyp; 
        char other; 
    }; 
    
    struct TAuthreq 
    { 
        char Ver; 
        char Ulen; 
        char Name; 
        char PLen; 
        char Pass; 
    }; 
    
    struct TAuthans 
    { 
        char Ver; 
        char Status; 
    }; 

    实现文件

    #include "StdAfx.h"
    #include "Proxy.h"
    #include "Base64.h"
    #include "log.h"
    
    #include <time.h>
    
    
    ProxyStatus CProxy::ConnectProxyServer(SOCKET socket)
    {
        int ret;
        struct timeval timeout ;
        fd_set r;
        string ip;
        u_short port;
    
        ip = m_proxyIp;
        port = m_proxyPort;
    
        sockaddr_in servAddr;
        servAddr.sin_family = AF_INET;
        servAddr.sin_addr.S_un.S_addr = inet_addr(ip.c_str());
        servAddr.sin_port = htons(port);
    
        //设置非阻塞方式连接
        unsigned long ul = 1;
        ret = ioctlsocket(socket, FIONBIO, (unsigned long*)&ul);
        if(ret == SOCKET_ERROR) 
        {
            return CONNECT_PROXY_FAIL;
        }
    
        connect(socket, (sockaddr*)&servAddr, sizeof(sockaddr));
    
        FD_ZERO(&r);
        FD_SET(socket, &r);
        timeout.tv_sec = 5; 
        timeout.tv_usec =0;
        ret = select(0, 0, &r, 0, &timeout);
    
        if (ret <= 0)
        {
            m_blnProxyServerOk = false;
            return CONNECT_PROXY_FAIL;
        }
        else
        {
            m_blnProxyServerOk = true;
            return SUCCESS;
        }
    }
    
    ProxyStatus CProxy::ConnectServer(SOCKET socket, string ip, u_short port)
    {
        int ret;
        int nTimeout;
    
        if (!m_blnProxyServerOk)
        {
            return NOT_CONNECT_PROXY;
        }
    
        nTimeout = 5000;
        setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));    //设置接收超时
    
        unsigned long ul = 0;
        ret = ioctlsocket(socket, FIONBIO, (unsigned long*)&ul);    //设置阻塞方式连接
    
        switch(m_proxyType)
        {
        case 0:    //HTTP
            return ConnectByHttp(socket, ip, port);
            break;
        case 1:    //SOCK4
            return ConnectBySock4(socket, ip, port);
            break;
        case 2:    //SOCK5
            return ConnectBySock5(socket, ip, port);
            break;
        default:
            break;
        }
    
        return CONNECT_SERVER_FAIL;
    }
    
    ProxyStatus CProxy::ConnectByHttp(SOCKET socket, string ip, u_short port)
    {
        char buf[512];
    
        if (m_proxyUserName != "")
        {
            string str;
            string strBase64;
            str = m_proxyUserName + ":" + m_proxyUserPwd;
            strBase64 = CBase64::Encode((unsigned char*)str.c_str(), str.length());
            sprintf_s(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1
    Host: %s:%d
    Authorization: Basic %s
    
    Proxy-Authorization: Basic %s
    
    ", 
                ip.c_str(), port, ip.c_str(), port, strBase64.c_str(), strBase64.c_str());
        }
        else
        {
            //sprintf_s(buf, 512, "CONNECT %s:%d HTTP/1.1
    Host: %s:%d
    
    ", ip.c_str(), port, ip.c_str(), port);
            sprintf_s(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1
    User-Agent: MyApp/0.1
    
    ", ip.c_str(), port);
        }
    
        Send(socket, buf, strlen(buf));
        Receive(socket, buf, sizeof(buf));
    
        if (strstr(buf, "HTTP/1.0 200 Connection established") != NULL)
        {
            return SUCCESS;
        }
        else
        {
            return CONNECT_SERVER_FAIL;
        }
    
    }
    
    ProxyStatus CProxy::ConnectBySock4(SOCKET socket, string ip, u_short port)
    {
        char buf[512];
    
        memset(buf, 0, sizeof(buf)); 
        struct TSock4req1 *proxyreq;
        proxyreq = (struct TSock4req1*)buf; 
        proxyreq->VN = 4; 
        proxyreq->CD = 1; 
        proxyreq->Port = ntohs(port); 
        proxyreq->IPAddr = inet_addr(ip.c_str()); 
    
        Send(socket, buf, 9);
    
        struct TSock4ans1 *proxyans; 
        proxyans = (struct TSock4ans1*)buf; 
        memset(buf, 0, sizeof(buf)); 
    
        Receive(socket, buf, sizeof(buf));
        if(proxyans->VN == 0 && proxyans->CD == 90) 
        { 
            return SUCCESS; 
        } 
        else
        {
            return CONNECT_SERVER_FAIL;
        }
    }
    
    ProxyStatus CProxy::ConnectBySock5(SOCKET socket, string ip, u_short port)
    {
        char buf[512];
    
        struct TSock5req1 *proxyreq1; 
        proxyreq1 = (struct TSock5req1 *)buf; 
        proxyreq1->Ver = 5; 
        proxyreq1->nMethods = 1; 
        proxyreq1->Methods = m_proxyUserName != "" ? 2 : 0;
    
        Send(socket, buf, 3); 
        
        struct TSock5ans1 *proxyans1; 
        proxyans1 = (struct TSock5ans1 *)buf; 
    
        memset(buf, 0, sizeof(buf));
        Receive(socket, buf, sizeof(buf));
        if(proxyans1->Ver != 5 || (proxyans1->Method != 0 && proxyans1->Method != 2)) 
        { 
            return CONNECT_SERVER_FAIL; 
        }
    
        if(proxyans1->Method == 2) 
        { 
            int nUserLen = m_proxyUserName.length();
            int nPassLen = m_proxyUserPwd.length();
            //struct TAuthreq *authreq; 
            //authreq = (struct TAuthreq *)buf; 
            //authreq->Ver = 1; 
            //authreq->Ulen = nUserLen; 
            //strcpy(authreq->Name, m_proxyUserName.c_str()); 
            //authreq->PLen = nPassLen; 
            //strcpy(authreq->Pass, m_proxyUserPwd.c_str()); 
    
            buf[0] = 1;
            buf[1] = nUserLen;
            memcpy(buf + 2, m_proxyUserName.c_str(), nUserLen);
            buf[2 + nUserLen] = nPassLen;
            memcpy(buf + 3 + nUserLen, m_proxyUserPwd.c_str(), nPassLen);
    
            Send(socket, buf, 3 + nUserLen + nPassLen);
    
            struct TAuthans *authans; 
            authans = (struct TAuthans *)buf; 
            memset(buf, 0, sizeof(buf)); 
    
            Receive(socket, buf, sizeof(buf));
            if(authans->Ver != 1 || authans->Status != 0) 
            { 
                return CONNECT_SERVER_FAIL;
            } 
        }
    
        memset(buf, 0, sizeof(buf));
        struct TSock5req2 *proxyreq2; 
        proxyreq2 = (struct TSock5req2 *)buf; 
        proxyreq2->Ver = 5; 
        proxyreq2->Cmd = 1; 
        proxyreq2->Rsv = 0; 
        proxyreq2->Atyp = 1; 
        unsigned long tmpLong = inet_addr(ip.c_str()); 
        unsigned short port1 = ntohs(port); 
        memcpy((char*)&proxyreq2->other, &tmpLong, 4); 
        memcpy((char*)(&proxyreq2->other) + 4, &port1, 2); 
    
        //Send(socket, buf, sizeof(struct TSock5req2) + 5); 
        Send(socket, buf, 10); 
        struct TSock5ans2 *proxyans2; 
        memset(buf ,0, sizeof(buf)); 
        proxyans2 = (struct TSock5ans2 *)buf; 
        
        Receive(socket, buf, sizeof(buf));
        if(proxyans2->Ver != 5 || proxyans2->Rep != 0) 
        { 
            return CONNECT_SERVER_FAIL; 
        }
    
        return SUCCESS;
    }
    
    int CProxy::Receive(SOCKET socket, char* buf, int bufLen)
    {
        return recv(socket, buf, bufLen, 0);
    }
    
    bool CProxy::Send(SOCKET socket, const char* buf, int len)
    {
        long ilen = len;
        int sendCnt = 0;
        int ret;
    
        while(sendCnt < ilen)
        {
            if((ret = send(socket, buf + sendCnt, ilen - sendCnt, 0)) == SOCKET_ERROR)
            {
                return false;
            }
            else
            {
                sendCnt += ret;
            }
        }
    
        return true;
    }

    proxy中用到的CBase64类

    头文件

    #pragma once
    
    #include <string>
    
    using namespace std;
    
    class CBase64
    {
    private:
        CBase64(void);
    public:
        ~CBase64(void);
    
        static string Encode(const unsigned char* Data,int DataByte);
        static string Decode(const char* Data,int DataByte,int& OutByte);
    };
    #include "StdAfx.h"
    #include "Base64.h"
    
    CBase64::CBase64(void)
    {
    }
    
    CBase64::~CBase64(void)
    {
    }
    
    string CBase64::Encode(const unsigned char* Data,int DataByte)
    {
        //编码表
        const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        //返回值
        string strEncode;
        unsigned char Tmp[4]={0};
        int LineLength=0;
        for(int i=0;i<(int)(DataByte / 3);i++)
        {
            Tmp[1] = *Data++;
            Tmp[2] = *Data++;
            Tmp[3] = *Data++;
            strEncode+= EncodeTable[Tmp[1] >> 2];
            strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
            strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
            strEncode+= EncodeTable[Tmp[3] & 0x3F];
            if(LineLength+=4,LineLength==76) {strEncode+="
    ";LineLength=0;}
        }
        //对剩余数据进行编码
        int Mod=DataByte % 3;
        if(Mod==1)
        {
            Tmp[1] = *Data++;
            strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
            strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];
            strEncode+= "==";
        }
        else if(Mod==2)
        {
            Tmp[1] = *Data++;
            Tmp[2] = *Data++;
            strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
            strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
            strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];
            strEncode+= "=";
        }
    
        return strEncode;
    }
    
    string CBase64::Decode(const char* Data,int DataByte,int& OutByte)
    {
        //解码表
        const char DecodeTable[] =
        {
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            62, // '+'
            0, 0, 0,
            63, // '/'
            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
            0, 0, 0, 0, 0, 0, 0,
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
            13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
            0, 0, 0, 0, 0, 0,
            26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
            39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
        };
        //返回值
        string strDecode;
        int nValue;
        int i= 0;
        while (i < DataByte)
        {
            if (*Data != '
    ' && *Data!='
    ')
            {
                nValue = DecodeTable[*Data++] << 18;
                nValue += DecodeTable[*Data++] << 12;
                strDecode+=(nValue & 0x00FF0000) >> 16;
                OutByte++;
                if (*Data != '=')
                {
                    nValue += DecodeTable[*Data++] << 6;
                    strDecode+=(nValue & 0x0000FF00) >> 8;
                    OutByte++;
                    if (*Data != '=')
                    {
                        nValue += DecodeTable[*Data++];
                        strDecode+=nValue & 0x000000FF;
                        OutByte++;
                    }
                }
                i += 4;
            }
            else// 回车换行,跳过
            {
                Data++;
                i++;
            }
        }
        return strDecode;
    }
  • 相关阅读:
    隐藏滚动条但可用滚动
    封装axios,带请求头和响应头
    文本超出显示...
    设置vue-quill-editor禁止输入或编辑
    element-ui select多选情况下获取label和value
    处理vue-quill-editor回显数据的时候没有空格问题
    Redis学习之路(二)Redis集群搭建
    redis requires Ruby version >= 2.2.2问题
    Redis学习之路(一)Redis简介
    Logstash学习之路(五)使用Logstash抽取mysql数据到kakfa
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/3425931.html
Copyright © 2011-2022 走看看