1

現在、C++ プログラムに SOCKS 4/5 機能を実装しようとしています (つまり、任意のプロトコルとホストへの要求は、必要に応じて特定の SOCKS プロキシを介してリダイレクトできます)。私は純粋に Windows 用に開発しているので、Winsock 2 を使用しています。

私の問題は、単に「これはどのように機能するか」よりも少し抽象的ではありません。私は SOCKS 4 の RFC を読みました (SOCKS 4 は競合するリクエストのバイト数が少ないため、最初に SOCKS 4 を実装することにしました) が、send()に必要な C 文字列を作成するのに苦労しています。

現在、次のようなSocks4Msgという構造体が定義されています。

struct Socks4Msg {
const static uint8_t version = 0x04; //SOCKS version 4 (obviously)
const static uint8_t command = 0x01; //1 is TCP CONNECT command
const static uint8_t nullbyte = 0x00; //null byte sent at message end

uint16_t port; //16 bit/2 byte port (network order)
uint32_t ip; //32 bit/4 byte IP address (network order)
Socks4Msg(uint16_t p, uint32_t i) : port(p), ip(i) { }
};

実際のソケットを作成して作業を行う関数はここにあります (ここで、p と h は、プロキシを介してテストするポートとホストを保持します。p は、既に実装した HttpProxy との互換性を維持するための文字列です)。port と addr はクラスの一部であり、それぞれ int と string です。それらはプロキシサーバーの詳細です。

int Socks4Proxy::test(std::string p, std::string h) const {
uint16_t network_port = htons(str_to_numt<uint16_t>(p));
uint32_t network_ip = hostname_to_ip(h);
Socks4Msg msg_struct(network_port,network_ip);

SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
int last_error;
if(s == INVALID_SOCKET) {
              last_error = WSAGetLastError();
              std::cerr << "Failed to initialise socket! Error code: " << last_error << std::endl; 
              return 2;
}

sockaddr_in st_addr;
st_addr.sin_family = AF_INET;
st_addr.sin_port = htons(port);
ipaddr_t ip = inet_addr(addr.c_str());
st_addr.sin_addr.S_un.S_addr = ip;

if(connect(s,(sockaddr*)&st_addr,sizeof(st_addr))!=0) {
                                                      last_error = WSAGetLastError();
                                                      std::cerr << "Socket failed to connect. Error code: " << last_error << std::endl;
                                                      return 2;  
}

uint8_t message[13];
uint8_t* message_ptr;
memset(message, 0, 13);
message_ptr = message;
*message_ptr = msg_struct.version;
message_ptr++;
*message_ptr = msg_struct.command;
message_ptr++;
*message_ptr = msg_struct.port;
message_ptr += 2;
*message_ptr = msg_struct.ip;
message_ptr += 4;
*message_ptr = 'b'; message_ptr++; *message_ptr = 'o'; message_ptr++; *message_ptr = 'b'; message_ptr++;
*message_ptr = msg_struct.nullbyte;
message_ptr++;
*message_ptr = 0x00;
char smessage[13];
memcpy(smessage, message, 13);

int return_val;
while(return_val = send(s, smessage, strlen(smessage), 0)) {
                       if(return_val == SOCKET_ERROR) {
                                     last_error = WSAGetLastError();
                                     std::cerr << "Writing data failed. Error code: " << last_error << std::endl;
                                     return 2;
                       }
                       //implement return_val < strlen(message) here
                       else break;
}
//remainder of function

C 文字列操作を開始する前に、msg_struct のメンバーに正しいデータ (および正しいバイト順) が含まれていることをテストおよび検証しました。

割り当ての代わりにmemcpy() (例: memcpy(message_ptr, &msg_struct.port, 2))を使用して実行しようとしましたが、Wireshack が送信データのバイト長を常に 2 として引用する理由がわかりません (つまりバージョンとコマンド)、他には何もありません。(私は C 文字列の知識を知っています - したがって、その時点でのコードは少し大雑把ですが、なぜそれが機能しないのか説明できません)

どんなアドバイスでも大歓迎です!

4

1 に答える 1

1

まず第一に、message_ptr間違っuint8_t**message_ptr = msg_struct.ip;います。そうしないと、msg_struct.ipmessage_ptrがuint8_t に変換されてから割り当てられます。他の分野でも同じ問題があります。uint_32t** ((uint32_t*)message_ptr) = msg_struct.ip;

これを確認して、再び動作している場合はお知らせください:)

ところで。Wireshark ネットワーク トラフィック アナライザーは、このような問題の検索に大いに役立つと思います。

アップデート

おそらく、送信したいメッセージを表す構造体を作成し、message_ptrこの構造体のポインターにキャストすることをお勧めします。ただし、パディングを追加しないようにコンパイラに指示することを忘れないでください。

更新 2

ネットワークとホストのバイト順。

hton、ntoh、htonl、または ntohl 関数を使用してバイト順を変更する必要があることを忘れないでください。

于 2011-01-18T01:20:39.330 に答える