socket穿透代理代码(C++版)

48 篇文章 0 订阅
12 篇文章 1 订阅

写代码经常会遇到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;
}


评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值