sock 5エージェントを使用してtcpに接続する
7823 ワード
#ifndef EMS_PROXY_H
#define EMS_PROXY_H
#pragma once
#include
#include
#include
using namespace std;
/*
sockエージェントの動作原理は大体以下の通りである.
1.[プロキシが必要]サーバに要求情報を送信する.
2.[エージェント]応答;
3.[需要エージェント]応答を受けて[エージェント]送信先ipとポートに送信する.
4.[エージェント]と目的の接続;
5.[エージェント]は[必要エージェント]から送信された情報を宛先に伝達し、宛先から送信された情報を[必要エージェント]に伝達する.
6.エージェントが完了しました.
sock 5のTCPエージェントワークフロー:
1.サーバのプロキシポートにtcp接続を確立します.一般的には1080です.
2.サーバに05 02 00 02(これは16進コードで、以下同じ)を送信し、エージェントサーバに認証方式を選択させる.
05
02ここでは、2つの認証方式が認証と認証を必要としないことを確認し、1つの方式を検証するだけで、05,100クエリーサーバが無認証エージェント方式をサポートしているかどうかを直接送信することができる.
00認証は必要ありません.
02認証が必要です.
3.05 00を受け取るとエージェント可能か05 02が認証を必要とし、ここでは2バイト目を判断すればよい.
認証が必要な場合は、01ユーザ名長(2バイト)ユーザ名パスワード長(2バイト)パスワードをサーバに送信し、サーバからデータを返す必要があります.2バイト目が00の場合、認証に合格します.そうしないと認証できません.接続に失敗します.
4.05,01,001+宛先アドレス(4バイト)+宛先ポート(2バイト)を送信し,宛先アドレスとポートはいずれも16進コード(文字列ではない)である.
例202.103.190.27 - 7201
送信されるメッセージは、05 01 00 01 CA 67 BE 1 B 1 C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)
5.プロキシサーバから返されるデータを受信し、2バイト目が00であるか否かを判断すると、プロキシ接続が完了したことを示す.
6.以降の操作は目的者と直接TCP接続を行うのと同じである.
*/
enum ProxyStatus
{
SUCCESS,
CONNECT_PROXY_FAIL,
NOT_CONNECT_PROXY,
CONNECT_SERVER_FAIL
};
class CProxy
{
public:
CProxy():m_proxyType(0){
};
//コンストラクション関数のアドレスポートユーザーパスワードはプロキシサーバの
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)
{}
void init(string ip, u_short port, string username, string password){
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);//ここのip、portはターゲットサーバです
private:
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 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;
};
#endif
#include"emsproxy.h"#include#include//プロキシサーバーに接続する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) { qDebug("ConnectProxyServer ioctlsocket failed."); 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; qDebug("ConnectProxyServer CONNECT_PROXY_FAIL"); 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_blnProxyServer Ok){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://Sock 5 return ConnectBySock 5(socket,ip,port);break;default:break; } return CONNECT_SERVER_FAIL; } ProxyStatus CProxy::ConnectBySock 5(SOCKET socket,string ip,u_short port){char buf[512];struct TSock 5 req 1*proxyreq 1;proxyreq 1=(struct TSock 5 req 1*)buf;proxyreq 1->Ver=5;proxyreq 1->nMethods=1;proxyreq 1->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)) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL1"); return CONNECT_SERVER_FAIL; }//方式2はif(proxyans 1->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) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL2"); 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) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL3"); 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; }
#define EMS_PROXY_H
#pragma once
#include
#include
#include
using namespace std;
/*
sockエージェントの動作原理は大体以下の通りである.
1.[プロキシが必要]サーバに要求情報を送信する.
2.[エージェント]応答;
3.[需要エージェント]応答を受けて[エージェント]送信先ipとポートに送信する.
4.[エージェント]と目的の接続;
5.[エージェント]は[必要エージェント]から送信された情報を宛先に伝達し、宛先から送信された情報を[必要エージェント]に伝達する.
6.エージェントが完了しました.
sock 5のTCPエージェントワークフロー:
1.サーバのプロキシポートにtcp接続を確立します.一般的には1080です.
2.サーバに05 02 00 02(これは16進コードで、以下同じ)を送信し、エージェントサーバに認証方式を選択させる.
05
02ここでは、2つの認証方式が認証と認証を必要としないことを確認し、1つの方式を検証するだけで、05,100クエリーサーバが無認証エージェント方式をサポートしているかどうかを直接送信することができる.
00認証は必要ありません.
02認証が必要です.
3.05 00を受け取るとエージェント可能か05 02が認証を必要とし、ここでは2バイト目を判断すればよい.
認証が必要な場合は、01ユーザ名長(2バイト)ユーザ名パスワード長(2バイト)パスワードをサーバに送信し、サーバからデータを返す必要があります.2バイト目が00の場合、認証に合格します.そうしないと認証できません.接続に失敗します.
4.05,01,001+宛先アドレス(4バイト)+宛先ポート(2バイト)を送信し,宛先アドレスとポートはいずれも16進コード(文字列ではない)である.
例202.103.190.27 - 7201
送信されるメッセージは、05 01 00 01 CA 67 BE 1 B 1 C 21
(CA=202 67=103 BE=190 1B=27 1C21=7201)
5.プロキシサーバから返されるデータを受信し、2バイト目が00であるか否かを判断すると、プロキシ接続が完了したことを示す.
6.以降の操作は目的者と直接TCP接続を行うのと同じである.
*/
enum ProxyStatus
{
SUCCESS,
CONNECT_PROXY_FAIL,
NOT_CONNECT_PROXY,
CONNECT_SERVER_FAIL
};
class CProxy
{
public:
CProxy():m_proxyType(0){
};
//コンストラクション関数のアドレスポートユーザーパスワードはプロキシサーバの
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)
{}
void init(string ip, u_short port, string username, string password){
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);//ここのip、portはターゲットサーバです
private:
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 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;
};
#endif
#include"emsproxy.h"#include#include//プロキシサーバーに接続する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) { qDebug("ConnectProxyServer ioctlsocket failed."); 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; qDebug("ConnectProxyServer CONNECT_PROXY_FAIL"); 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_blnProxyServer Ok){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://Sock 5 return ConnectBySock 5(socket,ip,port);break;default:break; } return CONNECT_SERVER_FAIL; } ProxyStatus CProxy::ConnectBySock 5(SOCKET socket,string ip,u_short port){char buf[512];struct TSock 5 req 1*proxyreq 1;proxyreq 1=(struct TSock 5 req 1*)buf;proxyreq 1->Ver=5;proxyreq 1->nMethods=1;proxyreq 1->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)) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL1"); return CONNECT_SERVER_FAIL; }//方式2はif(proxyans 1->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) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL2"); 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) { qDebug("ConnectBySock5 CONNECT_SERVER_FAIL3"); 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; }