В настоящее время я пытаюсь реализовать функциональность SOCKS 4/5 в моей программе на C ++ (т.е. запросы к произвольным протоколам и хостам могут быть перенаправлены через данный прокси-сервер SOCKS, если это необходимо).Я занимаюсь разработкой исключительно для Windows, поэтому использую Winsock 2.
Моя проблема немного менее абстрактна, чем просто "как это работает".Я прочитал RFC для SOCKS 4 (я решил сначала внедрить SOCKS 4, поскольку в его запросах меньше байт), но я пытаюсь создать строку C, необходимую для send () .
В настоящее время у меня есть определенная структура с именем 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
Я проверил и проверил, что члены msg_struct содержат правильные данные (и в правильном порядке байтов) до начала манипуляции строкой C.
Я пытался сделать это, используя memcpy () (например, memcpy (message_ptr, & msg_struct.port, 2)) вместо назначений, но я просто не могу понять, почему Wireshack всегда цитируетдлина байта отправляемых данных как 2 (то есть версия и команда), но не более того.(Я знаю свои знания о строках C - и, следовательно, код на тот момент - немного грубовато, но я не могу объяснить, почему это не работает)
Любой совет будет принят с благодарностью!