下面是C++通过socks5进行与服务端进行简单通讯的代码,希望能提供部分帮助
proxy.h文件
#pragma once
#include
#include
#includeenum 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"
#includeusing 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
#includeusing 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;
}