使用sock5代理连接tcp

 #ifndef EMS_PROXY_H 
  
#define EMS_PROXY_H
#pragma once

#include
#include
#include

using namespace std;

/*

sock代理工作原理大致如下:
1。[需要代理方]向服务器发出请求信息;
2。[代理方]应答;
3。[需要代理方]接到应答后发送向[代理方]发送目的ip和端口;
4。[代理方]与目的连接;
5。[代理方]将[需要代理方]发出的信息传到目的方,将目的方发出的信息传到[需要代理方];
6。代理完成。

sock5的TCP代理工作流程:
1。向服务器的代理端口建立tcp连接。一般为1080;
2。向服务器发送 05 02 00 02(此为16进制码,以下同),让代理服务器选择认证方式 ;
05
02 这里确认2种认证方式 无需认证和需要认证,只需要验证一种方式,可以直接发送05 01 00查询服务器是否支持无认证代理方式;
00 不需要认证;
02 需要认证;
3。如果接到 05 00 则是可以代理或则05 02需要认证,这里只需要判断第二字节就行;
如果需要认证,需要向服务器发送01 用户名长度(2字节)用户名 密码长度(2字节)密码,然后接收服务器返回数据,如果第二字节为 00,则认证通过,否则无法认证,则连接失败;
4。发送 05 01 00 01 + 目的地址(4字节)+ 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
例202.103.190.27 - 7201
则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)
5。接收代理服务器返回的数据,我们只要判断第二字节是否为00即表示代理连接完成;
6。以后操作和直接与目的方进行TCP连接相同。
*/
enum ProxyStatus
{
    SUCCESS,
    CONNECT_PROXY_FAIL,
    NOT_CONNECT_PROXY,
    CONNECT_SERVER_FAIL
};

class CProxy
{
public:
    CProxy():m_proxyType(0){
    
    };
    //构造函数的地址端口用户密码是代理服务器的
    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)
    {}

    void init(string ip, u_short port, string username, string password){
        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);//这里的ip,port是目标服务器

private:
    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 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;
};

#endif



#include "emsproxy.h"

#include
#include

//先连接代理服务器
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)
    {
        qDebug("ConnectProxyServer ioctlsocket failed.");
        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;
        qDebug("ConnectProxyServer CONNECT_PROXY_FAIL");
        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:    //SOCK5
        return ConnectBySock5(socket, ip, port);
        break;
    default:
        break;
    }

    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))
    {
        qDebug("ConnectBySock5 CONNECT_SERVER_FAIL1");
        return CONNECT_SERVER_FAIL;
    }
    //方式2为需要认证
    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)
        {
            qDebug("ConnectBySock5 CONNECT_SERVER_FAIL2");
            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)
    {
        qDebug("ConnectBySock5 CONNECT_SERVER_FAIL3");
        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;
}




你可能感兴趣的:(C++)