現在、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 文字列の知識を知っています - したがって、その時点でのコードは少し大雑把ですが、なぜそれが機能しないのか説明できません)
どんなアドバイスでも大歓迎です!