<转 >socket穿透代理代码(C++版)

简介: 本文转自 http://blog.csdn.net/bodybo/article/details/7274865 写代码经常会遇到socket要通过代理连接服务器的情况,代理类型通畅有三种:HTTP、SOCK4和SOCK5,通过学习和网上参考相关代码,写了个代理类来实现该功能,贴出来与大家共享 ...

本文转自 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\r\nHost: %s:%d\r\nAuthorization: Basic %s\r\n\r\nProxy-Authorization: Basic %s\r\n\r\n", 
            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\r\nHost: %s:%d\r\n\r\n", ip.c_str(), port, ip.c_str(), port);
        sprintf_s(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: MyApp/0.1\r\n\r\n", 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+="\r\n";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 != '\r' && *Data!='\n')
        {
            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;
}

 

相关文章
|
4天前
|
数据采集 安全 大数据
使用代理IP时有哪些小技巧?
代理IP工具在大数据和跨境行业广泛使用,能隐藏真实IP并提升数据采集效率。选择时考虑代理IP的质量、速度、稳定性和价格,确保服务商信誉安全。测试多个代理IP以满足不同需求,设置正确请求头信息避免被目标服务器屏蔽。避免频繁更换地区,定期更新代理IP,并保护个人信息。根据业务需求制定使用计划,提前学习相关技巧,可避免后期问题。
|
3月前
|
网络协议
服务器端口被占用怎么解决
服务器端口被占用怎么解决
|
8月前
|
缓存 安全 生物认证
什么是代理ip?代理ip的工作原理?代理ip有哪些类型?
当您在互联网上浏览或访问网站时,您的IP地址是您的设备在网络上的唯一标识。通过IP地址,网站和其他在线服务可以追踪您的位置、活动和访问历史。但是,使用IP代理可以帮助您代理本地IP地址,从而增加您的在线隐私和安全。
什么是代理ip?代理ip的工作原理?代理ip有哪些类型?
|
7月前
|
数据采集 前端开发 网络协议
socks5代理是什么意思?它跟http代理有什么不同点?它有什么应用场景?
socks5代理是什么意思?它跟http代理有什么不同点?它有什么应用场景?
socks5代理是什么意思?它跟http代理有什么不同点?它有什么应用场景?
|
应用服务中间件 网络安全 nginx
如果发现一个IP一直在大量的请求服务器,如何解决这个问题?底层原理是什么?
如果发现一个IP一直在大量的请求服务器,如何解决这个问题?底层原理是什么?
725 0
|
网络协议 网络安全
服务器端口是干什么的?底层原理是什么?
服务器端口是干什么的?底层原理是什么?
266 0
|
存储 缓存 应用服务中间件
Nginx代理服务 - 代理缓冲区、代理重新定义请求头、代理连接超时
1. 代理缓冲区 代理服务器可以缓存一些响应数据,来减少I/O损耗,数据默认存储在内存中,当内存不够时,会存储到硬盘上。
|
Web App开发 Dart 负载均衡
MASQUE 中 IP 和 UDP 代理的传输注意事项
HTTP Connect 方法使用往返代理的背靠背 TCP 连接。这种解决方案处理了许多传输方面以及与 IP 流相关的问题。另一方面,对于 UDP 和 IP 代理,需要考虑多个按数据包和按流的方面以保留端到端 IP/UDP 流的属性。本文档的目的是突出显示与 UDP 和 IP 代理相关的这些问题并提供解决方案。
504 0
MASQUE 中 IP 和 UDP 代理的传输注意事项
|
存储 缓存 监控
代理缓存 | 学习笔记
快速学习代理缓存,介绍了代理缓存系统机制, 以及在实际应用过程中如何使用。
87 0
代理缓存 | 学习笔记
|
Java
【Java 网络编程】服务器端 ServerSocket 配置 ( 端口复用 | 缓冲区设置 | 超时时间 | 性能权重 | 端口绑定 )
【Java 网络编程】服务器端 ServerSocket 配置 ( 端口复用 | 缓冲区设置 | 超时时间 | 性能权重 | 端口绑定 )
751 0