通过连接socks5代理上网(与服务端通讯)

下面是C++通过socks5进行与服务端进行简单通讯的代码,希望能提供部分帮助

proxy.h文件

#pragma once

#include  
#include
#include

enum ProxyStatus
{
    SUCCESS,
    CONNECT_PROXY_FAIL,
    NOT_CONNECT_PROXY,
    CONNECT_SERVER_FAIL
};

class CProxy
{
public:
    CProxy() :m_proxyType(0){

    };
    //构造函数的地址端口用户密码是代理服务器的
    CProxy(long type, std::string ip, u_short port, std::string username, std::string password)
        :m_proxyType(type), m_proxyIp(ip), m_proxyPort(port), m_proxyUserName(username), m_proxyUserPwd(password)
    {}

    void init(std::string ip, u_short port, std::string username, std::string password){
        m_proxyIp = ip;
        m_proxyPort = port;
        m_proxyUserName = username;
        m_proxyUserPwd = password;
    };
    ~CProxy(void){};

    ProxyStatus ConnectProxyServer(SOCKET socket);//先连接代理服务器
    ProxyStatus ConnectServer(SOCKET socket, std::string ip, u_short port);//这里的ip,port是目标服务器

    bool Send(SOCKET socket, const char* buf, int len);
    int Receive(SOCKET socket, char* buf, int bufLen);

private:
    ProxyStatus ConnectBySock5(SOCKET socket, std::string ip, u_short port);

private:
    long m_proxyType;
    std::string m_proxyIp;
    u_short m_proxyPort;
    std::string m_proxyUserName;
    std::string m_proxyUserPwd;
    bool m_blnProxyServerOk;
};

struct TSock5req1
{
    char Ver;        //协议版本号,SOCKS是0x05.
    char nMethods;  //方式
    char Methods;    //0表示不需要,1表示GSSAPI,2表示需要账号密码验证,3...
};

struct TSock5ans1
{
    char Ver;        //协议版本号,SOCKS是0x05.
    char Method;    //服务端返回选中的方法
};

struct TSock5req2 //req请求
{
    char Ver;    //协议版本号,SOCKS是0x05.
    char Cmd;    //0x01:表示CONNECT请求,0x02:表示BIND请求,0x03:表示UDP转发
    char Rsv;    //0x00:保留,无实际作用
    char Atyp;    //0x01:表示IPV4地,0x03:表示域名格式,0x04:表示IPV6地址
    char other; //拼接ip(unsigned long)和端口(short)
};

struct TSock5ans2 //answer返回
{
    char Ver;    //协议版本号,SOCKS是0x05.
    char Rep;    //0x00:succeeded,0x00:succeeded,0x01:general SOCKS server failure,0x02:connection not allowed by ruleset,0x03:Network unreachable,
                //0x04:Host unreachable,0x05:Connection refused,0x06:TTL expired,0x07:Command not supported,0x08: Address type not supported,0x09:to X’FF’unassigned
    char Rsv;    //0x00:保留,无实际作用
    char Atyp;    //0x01:表示IPV4地址 0x03:表示域名格式 0x04:表示IPV6地址
    char other;    //
};

struct TAuthans
{
    char Ver; //协议版本号,SOCKS是0x05.
    char Status;//0成功 1失败
};

proxy.cpp文件

#include "proxy.h"
#include

using namespace std;

//先连接代理服务器
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:    //SOCK5
    {
        ProxyStatus status = ConnectBySock5(socket, ip, port);
        return status;
    }
    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;
    //请求认证方式
    bool nRet = 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();

        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);

    struct TSock5ans2 *proxyans2;
    memset(buf, 0, sizeof(buf));
    proxyans2 = (struct TSock5ans2 *)buf;
    //接收返回
    int nResqqet = 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;
}

main.cpp文件

#include "proxy.h"

#include
#include
#include
#include
#include

using namespace std;
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996) //如果你有inet_addr函数的报错,加上这个就解决了


int main()
{
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA data;
    if (WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }
    while (true){
        SOCKET sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sockClient == INVALID_SOCKET)
        {
            printf("invalid socket!");
            return 0;
        }

        sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(1081);
        serAddr.sin_addr.S_un.S_addr = inet_addr("192.168.101.202");//如果你有inet_addr函数的报错,看上文
        if (connect(sockClient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
        {
            printf("connect error !");
            closesocket(sockClient);
            return 0;
        }

        CProxy proxy(0,"192.168.101.202",1081,"","");
        ProxyStatus status1 = proxy.ConnectProxyServer(sockClient);
        ProxyStatus status2 = proxy.ConnectServer(sockClient, "192.168.101.93", 8888);
        
        string data = "123456";
        const char * sendData;
        sendData = data.c_str();
        proxy.Send(sockClient, sendData, strlen(sendData));
        
        char recData[255];
        int ret = proxy.Receive(sockClient, recData, 255);
        if (ret>0){
            recData[ret] = 0x00;
            printf(recData);
        }
        closesocket(sockClient);
        WSACleanup();
    }
    WSACleanup();
    return 0;
}

 

你可能感兴趣的:(C++,socks代理,socks5)