517 lines
15 KiB
C++
517 lines
15 KiB
C++
//#include "stdafx.h"
|
|
#include "socksproxyclient.h"
|
|
|
|
|
|
using namespace std;
|
|
|
|
CSocksProxyClient::CSocksProxyClient(void)
|
|
: m_nProxyPort(0)
|
|
{
|
|
m_sv = SOCKS_V4;
|
|
memset(&m_proxyaddress,0,sizeof(m_proxyaddress));
|
|
m_sockDescriptor = 0;
|
|
m_szProxyServer = new char[512];
|
|
m_szErrorMsg = new char[512];
|
|
m_szUserName = new char[512];
|
|
m_szPassword = new char[512];
|
|
}
|
|
|
|
CSocksProxyClient::~CSocksProxyClient(void)
|
|
{
|
|
if (m_szErrorMsg != nullptr)
|
|
{
|
|
delete m_szErrorMsg;
|
|
}
|
|
if (m_szUserName != nullptr)
|
|
{
|
|
delete m_szUserName;
|
|
}
|
|
if (m_szPassword != nullptr)
|
|
{
|
|
delete m_szPassword;
|
|
}
|
|
|
|
CloseSocket();
|
|
|
|
}
|
|
|
|
void CSocksProxyClient::SetSocksVersion(SOCKS_VERSION sv)
|
|
{
|
|
m_sv = sv;
|
|
}
|
|
|
|
|
|
// Sets the proxy server and port to use in subsequent calls
|
|
bool CSocksProxyClient::SetProxy(char* szProxy, int nProxyPort/*=1080*/)
|
|
{
|
|
strcpy(m_szProxyServer, szProxy);
|
|
|
|
m_nProxyPort = nProxyPort;
|
|
struct hostent *he;
|
|
//attempt to resolve the proxy
|
|
if( !( he = gethostbyname( m_szProxyServer ) ) ){
|
|
strcpy(m_szErrorMsg, "Could not resolve proxy");
|
|
return false;
|
|
}
|
|
//store proxy info to avoid lookup later
|
|
m_proxyaddress.sin_family = AF_INET;
|
|
m_proxyaddress.sin_port = htons(static_cast<uint16_t>(m_nProxyPort));
|
|
m_proxyaddress.sin_addr = *( reinterpret_cast<struct in_addr *>( he->h_addr ) );
|
|
memset(&(m_proxyaddress.sin_zero ), '\0', 8 ); //clear the struct
|
|
|
|
std::cout << "ip of server: " << inet_ntoa( m_proxyaddress.sin_addr ) << std::endl;
|
|
|
|
strcpy(m_szErrorMsg,"Success");
|
|
return true;
|
|
}
|
|
|
|
// returns the socket descriptor to use for send / recv calls
|
|
#ifdef Windows
|
|
SOCKET CSocksProxyClient::GetSocket(void)
|
|
#else
|
|
int CSocksProxyClient::GetSocket(void)
|
|
#endif
|
|
{
|
|
return m_sockDescriptor;
|
|
}
|
|
|
|
// sets the username to use for authorization
|
|
void CSocksProxyClient::SetUserName(char* szUserName)
|
|
{
|
|
strcpy(m_szUserName,szUserName);
|
|
}
|
|
|
|
// sets the password to use for V5 Authorization
|
|
void CSocksProxyClient::SetPassword(char* szPassword)
|
|
{
|
|
strcpy(m_szPassword,szPassword);
|
|
}
|
|
|
|
// returns the error message
|
|
char* CSocksProxyClient::GetErrorMessage(void)
|
|
{
|
|
return m_szErrorMsg;
|
|
}
|
|
|
|
// closes the socket
|
|
void CSocksProxyClient::CloseSocket(void)
|
|
{
|
|
#ifdef Windows
|
|
if (m_sockDescriptor != 0 ) {
|
|
closesocket(m_sockDescriptor);
|
|
m_sockDescriptor = 0;
|
|
strcpy(m_szErrorMsg,"Success");
|
|
}
|
|
#else
|
|
if (m_sockDescriptor != 0 ) {
|
|
close(m_sockDescriptor);
|
|
m_sockDescriptor = 0;
|
|
strcpy(m_szErrorMsg,"Success");
|
|
}
|
|
#endif
|
|
else
|
|
strcpy(m_szErrorMsg,"Invalid Socket");
|
|
}
|
|
|
|
char *strlwr(char *str)
|
|
{
|
|
unsigned char *p = reinterpret_cast<unsigned char*>(str);
|
|
|
|
while (*p) {
|
|
*p = static_cast<unsigned char>(tolower(static_cast<unsigned char>(*p)));
|
|
p++;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*
|
|
in_addr_t make_inaddr(
|
|
unsigned char a1,
|
|
unsigned char a2,
|
|
unsigned char a3,
|
|
unsigned char a4)
|
|
{
|
|
in_addr_t result;
|
|
|
|
result = htonl(((uint32_t)a1 << 24)
|
|
| ((uint32_t)a2 << 16)
|
|
| ((uint32_t)a3 << 8)
|
|
| a4);
|
|
return result;
|
|
}*/
|
|
|
|
// connects to the specified domain at the given port
|
|
bool CSocksProxyClient::Connect(char* szDomain/*=nullptr*/, int nDomainPort/*=80*/)
|
|
{
|
|
if((m_sockDescriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg, "Could not establish socket connection.");
|
|
return false;
|
|
}
|
|
std::cout << "Socket created" << std::endl;
|
|
|
|
if (m_proxyaddress.sin_port == 0x00)
|
|
{
|
|
strcpy(m_szErrorMsg,"Proxy Information not set");
|
|
return false;
|
|
}
|
|
if ((szDomain == nullptr) || (strcmp(szDomain,"") == 0))
|
|
{
|
|
strcpy(m_szErrorMsg,"Invalid domain string");
|
|
return false;
|
|
}
|
|
|
|
std::cout << "connect..." << std::endl;
|
|
|
|
// Code for proxy authentication if allowed by proxy server:
|
|
if(connect(m_sockDescriptor, reinterpret_cast<struct sockaddr *>(&m_proxyaddress), sizeof(struct sockaddr)) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg,"Could not connect to proxy.");
|
|
return false;
|
|
}
|
|
std::cout << "Connected." << std::endl;
|
|
|
|
|
|
unsigned char msg[512];//generally we don't need a big array but domains names can be long some times.
|
|
|
|
szDomain = strlwr(szDomain);
|
|
size_t nlen = 0;
|
|
if (m_sv == SOCKS_V4)
|
|
{
|
|
struct hostent *he;
|
|
short dw = static_cast<short>( nDomainPort );
|
|
|
|
msg[0] = 0x04;
|
|
msg[1] = 0x01;
|
|
msg[2] = static_cast<unsigned char>(dw>>8);
|
|
msg[3] = static_cast<unsigned char>(dw);
|
|
if( !( he = gethostbyname( szDomain ) ) ){
|
|
strcpy(m_szErrorMsg,"Could not resolve domain");
|
|
return false;
|
|
}
|
|
|
|
#ifdef Windows1
|
|
struct sockaddr_in dest;
|
|
memcpy(&(dest.sin_addr), he->h_addr_list[0], he->h_length);
|
|
msg[4] = dest.sin_addr.S_un.S_un_b.s_b1;
|
|
msg[5] = dest.sin_addr.S_un.S_un_b.s_b2;
|
|
msg[6] = dest.sin_addr.S_un.S_un_b.s_b3;
|
|
msg[7] = dest.sin_addr.S_un.S_un_b.s_b4;
|
|
#else
|
|
std::string ip = szDomain + std::string(".");
|
|
size_t pos = 0;
|
|
int arrayPos = 3;
|
|
std::cout << ip << std::endl;
|
|
for (pos = ip.find("."); pos != std::string::npos; pos = ip.find(".")) {
|
|
arrayPos++;
|
|
if(arrayPos == 8)
|
|
break;
|
|
msg[arrayPos] = static_cast<unsigned char>(atoi(ip.substr(0, pos).c_str()));
|
|
std::cout << "[" << arrayPos << "]: " << std::hex << static_cast<int>( msg[arrayPos] ) << std::dec <<"==" << atoi(ip.substr(0, pos).c_str()) << std::endl;
|
|
ip.erase(0, pos +1);
|
|
}
|
|
|
|
#endif
|
|
|
|
if (m_szUserName != nullptr) {
|
|
strcpy(reinterpret_cast<char*>(&msg[8]), m_szUserName);
|
|
msg[8+strlen(m_szUserName)] = 0x00;
|
|
nlen = 8 + strlen(m_szUserName) +1 ;
|
|
|
|
} else {
|
|
msg[8] = 0x00;
|
|
nlen = 9;
|
|
}
|
|
if (send(m_sockDescriptor, reinterpret_cast<char*>( msg ), nlen, 0) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
if(recv(m_sockDescriptor, reinterpret_cast<char*>( msg ), 8, 0) <= 0)
|
|
std::cout << "recv failed in socks4" << std::endl;
|
|
|
|
if (msg[1] == 0x5a)
|
|
{
|
|
strcpy(m_szErrorMsg,"request granted");
|
|
return true;
|
|
}
|
|
else if (msg[1] == 0x5b)
|
|
{
|
|
strcpy(m_szErrorMsg,"request rejected or failed");
|
|
return false;
|
|
}
|
|
else if (msg[1] == 0x5c)
|
|
{
|
|
strcpy(m_szErrorMsg,"failed: client is not running identd");
|
|
return false;
|
|
}
|
|
else if (msg[1] == 0x5d)
|
|
{
|
|
strcpy(m_szErrorMsg,"failed: could not confirm the user id string in the request");
|
|
return false;
|
|
}
|
|
}
|
|
else if (m_sv == SOCKS_V4A)
|
|
{
|
|
msg[0] = 0x04;
|
|
msg[1] = 0x01;
|
|
short dw = static_cast<short>(nDomainPort);
|
|
msg[2] = static_cast<unsigned char>(dw>>8);
|
|
msg[3] = static_cast<unsigned char>(dw);
|
|
msg[4] = 0x00;
|
|
msg[5] = 0x00;
|
|
msg[6] = 0x00;
|
|
msg[7] = 0xFF;
|
|
if (m_szUserName != nullptr)
|
|
{
|
|
strcpy(reinterpret_cast<char*>(&msg[8]), m_szUserName);
|
|
msg[ 8 + strlen(m_szUserName) ] = 0x00;
|
|
nlen = 9 + strlen(m_szUserName);
|
|
if (send(m_sockDescriptor,(char*)msg,nlen,0) == -1) {
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
strcpy(reinterpret_cast<char*>(msg), szDomain);
|
|
msg[strlen(szDomain)] = 0x00;
|
|
nlen = strlen(szDomain) + 1;
|
|
}
|
|
else
|
|
{
|
|
msg[8] = 0x0;
|
|
nlen = 9;
|
|
if (send(m_sockDescriptor,reinterpret_cast<char*>( msg ),nlen,0) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
strcpy(reinterpret_cast<char*>( msg ), szDomain);
|
|
msg[strlen(szDomain)] = 0x00;
|
|
nlen = strlen(szDomain) + 1;
|
|
}
|
|
|
|
if (send(m_sockDescriptor,reinterpret_cast<char*>( msg ), nlen, 0) == -1) {
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
|
|
} else if(recv(m_sockDescriptor,reinterpret_cast<char*>( msg ), 8, 0) <= 0 ) {
|
|
perror("recv failed");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x5a) {
|
|
strcpy(m_szErrorMsg,"request granted");
|
|
return true;
|
|
|
|
} else if (msg[1] == 0x5b) {
|
|
strcpy(m_szErrorMsg,"request rejected or failed");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x5c) {
|
|
strcpy(m_szErrorMsg,"failed: client is not running identd");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x5d) {
|
|
strcpy(m_szErrorMsg,"failed: could not confirm the user id string in the request");
|
|
return false;
|
|
}
|
|
}
|
|
else if (m_sv == SOCKS_V5)
|
|
{
|
|
msg[0] = 0x05;
|
|
msg[1] = 0x02;
|
|
msg[2] = 0x00;
|
|
msg[3] = 0x02;
|
|
std::cout << "send to proxy msg..." << std::endl;
|
|
|
|
if (send(m_sockDescriptor,reinterpret_cast<char*>( msg ), 4, 0) == -1) {
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
|
|
std::cout << "OK\nRecv from Proxy..." << std::endl;
|
|
|
|
if( recv(m_sockDescriptor,reinterpret_cast<char*>( msg ), 2, 0) <= 0) {
|
|
std::cout << "Recv failed" << std::endl;
|
|
}
|
|
|
|
std::cout << "OK" << std::endl;
|
|
|
|
if (msg[1] == 0x00) { //no authentication
|
|
std::cout << "No Autentifikation" << std::endl;
|
|
msg[0] = 0x04;
|
|
msg[1] = 0x01;
|
|
msg[2] = 0x00;
|
|
msg[3] = 0x03;
|
|
msg[4] = static_cast<unsigned char>(strlen(szDomain));
|
|
strcpy(reinterpret_cast<char*>( &msg[5] ), szDomain);
|
|
nlen = strlen(szDomain) + 5;
|
|
short dw = static_cast<short>( nDomainPort );
|
|
msg[nlen++] = static_cast<unsigned char>(dw>>8);
|
|
msg[nlen++] = static_cast<unsigned char>(dw);
|
|
}
|
|
else if (msg[1] == 0x02)//username/password authentication
|
|
{
|
|
std::cout << "need Autentifikation" << std::endl;
|
|
|
|
msg[0] = 0x01;
|
|
msg[1] = (unsigned char)(int)strlen(m_szUserName);
|
|
strcpy(reinterpret_cast<char*>( &msg[2]), m_szUserName);
|
|
nlen = 2+msg[1];
|
|
msg[nlen++] = static_cast<unsigned char>(strlen(m_szPassword));
|
|
strcpy(reinterpret_cast<char*>(&msg[nlen]), m_szPassword);
|
|
nlen += strlen(m_szPassword);
|
|
|
|
std::cout << "send in autentifk..." << std::endl;
|
|
|
|
if (send(m_sockDescriptor,(char*)msg,nlen,0) == -1) {
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
|
|
std::cout << "recv in autentifk..." << std::endl;
|
|
|
|
if(recv(m_sockDescriptor,(char*)msg,8,0) <= 0) {
|
|
std::cout << "recv in autentifk. failed" << std::endl;
|
|
}
|
|
|
|
if (msg[1] == 0x00) {//status ok so send message
|
|
msg[0] = 0x04;
|
|
msg[1] = 0x01;
|
|
msg[2] = 0x00;
|
|
msg[3] = 0x03;
|
|
msg[4] = static_cast<unsigned char>(strlen(szDomain));
|
|
strcpy(reinterpret_cast<char*>(&msg[5]),szDomain);
|
|
nlen = strlen(szDomain)+5;
|
|
short dw = static_cast<short>(nDomainPort);
|
|
msg[nlen++] = static_cast<unsigned char>(dw>>8);
|
|
msg[nlen++] = static_cast<unsigned char>(dw);
|
|
|
|
} else {
|
|
#ifdef Windows
|
|
closesocket(m_sockDescriptor);
|
|
#else
|
|
close(m_sockDescriptor);
|
|
#endif
|
|
strcpy(m_szErrorMsg,"Error Authenticating User");
|
|
return false;
|
|
}
|
|
|
|
} else {
|
|
strcpy(m_szErrorMsg,"Authentication Method not supported");
|
|
return false;
|
|
}
|
|
|
|
if (send(m_sockDescriptor,reinterpret_cast<char*>( msg ), nlen,0) == -1) {
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
|
|
} else if( recv(m_sockDescriptor,(char*)msg,8,0) <= 0 ) {
|
|
std::cout << "recv 2 failed" << std::endl;
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x00) {
|
|
strcpy(m_szErrorMsg,"request granted");
|
|
return true;
|
|
|
|
} else if (msg[1] == 0x01) {
|
|
strcpy(m_szErrorMsg,"request rejected or failed");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x02) {
|
|
strcpy(m_szErrorMsg,"failed: connection not allowed by ruleset");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x03) {
|
|
strcpy(m_szErrorMsg,"failed: network unreachable");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x04) {
|
|
strcpy(m_szErrorMsg,"failed: host unreachable");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x05) {
|
|
strcpy(m_szErrorMsg,"failed: connection refused by destination host");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x06) {
|
|
strcpy(m_szErrorMsg,"failed: TTL expired");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x07) {
|
|
strcpy(m_szErrorMsg,"failed: command not supported / protocol error");
|
|
return false;
|
|
|
|
} else if (msg[1] == 0x08){
|
|
strcpy(m_szErrorMsg,"failed: address type not supported");
|
|
return false;
|
|
|
|
}
|
|
}
|
|
strcpy(m_szErrorMsg,"Success");
|
|
return true;
|
|
}
|
|
|
|
// receives a message from the server
|
|
bool CSocksProxyClient::Recv(char* szBuffer, size_t nLen, int nTimeout/*=0*/)
|
|
{
|
|
if (recv(m_sockDescriptor,szBuffer,nLen,nTimeout) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg,"Error receiving message");
|
|
return false;
|
|
}
|
|
strcpy(m_szErrorMsg,"Success");
|
|
return true;
|
|
}
|
|
|
|
// sends a message to the socks proxy
|
|
bool CSocksProxyClient::Send(char* szBuffer, size_t nLength, int nFlags/*=0*/)
|
|
{
|
|
if (send(m_sockDescriptor,szBuffer,nLength,nFlags) == -1)
|
|
{
|
|
strcpy(m_szErrorMsg,"Error sending message");
|
|
return false;
|
|
}
|
|
strcpy(m_szErrorMsg,"Success");
|
|
return true;
|
|
}
|
|
|
|
// Reads a line of text from the servers response
|
|
char *CSocksProxyClient::ReadLine()
|
|
{
|
|
if (m_sockDescriptor <= 0)
|
|
{
|
|
strcpy(m_szErrorMsg,"Invalid Socket");
|
|
return nullptr;
|
|
}
|
|
vector<char> vText;
|
|
char buffer[1];
|
|
//int unsigned charsReceived;
|
|
|
|
while (true) {
|
|
|
|
ssize_t charsReceived = recv(m_sockDescriptor, buffer, 1, 0);
|
|
|
|
if( charsReceived <= 0)
|
|
{
|
|
strcpy(m_szErrorMsg,"No Message To Recieve");
|
|
return nullptr;
|
|
}
|
|
|
|
if(buffer[0] == '\n') {
|
|
|
|
char *pChar = new char[vText.size() + 1];
|
|
memset(pChar, 0, vText.size() + 1);
|
|
|
|
for (int f = 0; f < static_cast<int>(vText.size()); f++)
|
|
pChar[f] = vText[static_cast<std::vector<char>::size_type>(f)];
|
|
|
|
strcpy(m_szErrorMsg,"Success");
|
|
return pChar;
|
|
|
|
}
|
|
else
|
|
{
|
|
vText.push_back(buffer[0]);
|
|
}
|
|
}
|
|
}
|