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; }