Вопрос или проблема
Я следовал учебнику по сетям на sock4 Toralizer, который реализовал протокол sock4 для выполнения HTTP-запросов. Поэтому я подумал, почему бы не улучшить реализацию и сделать это для sock5, как предложено в видео и комментариях.
Файл toralize.h
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define FREEPROXY "204.10.194.63"
#define FREEPROXYPORT 10087
// 103.174.178.131 : 1020 /* Все бесплатные прокси-серверы, которые я пробовал */
// 128.199.157.192 : 36838
// 208.102.51.6 : 58208
// 199.116.112.6 : 4145
// 188.165.249.131 : 9050
// 192.154.194.99 : 9000
// 67.149.165.201 : 9090
// 176.117.237.132 : 1080
// 192.252.215.5 : 16137
// 163.53.204.178 : 9813
// 68.71.252.38 : 4145
// 103.157.237.150 : 1080
// 46.105.105.223 : 51020
// 143.47.255.13 : 59900
// 162.240.146.101 : 31815
// 51.15.205.29 : 16379
// 204.10.194.63 : 10087
uint8_t supported_methods[] = {0x00};
#define nmethods sizeof(supported_methods) / sizeof(supported_methods[0])
#define hreqsize 2 + nmethods
#define hressize sizeof(struct sock_handshake_res)
#define reqsize sizeof(struct sock_connection_req)
#define ressize 22
struct sock_handshake_req
{
uint8_t version;
uint8_t n_methods;
uint8_t methods[];
};
struct sock_handshake_res
{
uint8_t version;
uint8_t method;
} ;
struct sock_connection_req
{
uint8_t version; // 5
uint8_t command; // 1 - connect , 2 - bind , 3 - udp
uint8_t reserved; // 0
uint8_t addr_type; // 1 - ipv4 , 3- domain , 4 - ipv6
uint32_t dst_addr; // Переменная
uint16_t dst_port;
};
struct sock_connection_res
{
uint8_t version; // 5
uint8_t reply;
uint8_t reserved; // 0
uint8_t addr_type; // 1 - ipv4 , 3- domain , 4 - ipv6
uint32_t bind_addr; // Переменная
uint16_t bind_port;
};
typedef struct sock_handshake_req Initial_Req;
typedef struct sock_handshake_res Initial_Res;
typedef struct sock_connection_req Req;
typedef struct sock_connection_res Res;
Req* request(const char* dstip, const int dstport);
и файл toralize.cpp
#include "toralize.h"
Initial_Req *hrequest()
{
Initial_Req *req;
req = malloc(hreqsize);
req->version = 5;
req->n_methods = nmethods;
memcpy(req->methods, supported_methods, sizeof(supported_methods));
return req;
}
Req *request(const char *dstip, const int dstport){
Req *req;
req = malloc(reqsize);
req->version = 5;
req->command = 1;
req->reserved = 0;
req->addr_type = 1;
req->dst_addr = inet_addr(dstip);
req->dst_port = htons(dstport);
return req;
}
int main(int argc, char *argv[])
{
char *host;
int port, s;
struct sockaddr_in sock;
Initial_Req *hreq;
Initial_Res *hres;
Req *req;
Res *res;
char hbuf[hressize];
char buf[ressize];
int success;
char tmp[512];
if (argc < 3)
{
fprintf(stderr, "Usage: %s <host> <port>\n", argv[0]);
return -1;
}
host = argv[1];
port = atoi(argv[2]);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s < 0)
{
perror("socket");
return -1;
}
sock.sin_family = AF_INET;
sock.sin_port = htons(FREEPROXYPORT);
sock.sin_addr.s_addr = inet_addr(FREEPROXY);
if (connect(s, (struct sockaddr*)&sock, sizeof(sock)))
{
perror("Connect");
return -1;
}
printf("Подключено к прокси\n");
hreq = hrequest();
write(s,hreq,hreqsize);
memset(hbuf, 0 ,hressize);
if(read(s,hbuf,hressize) < 1){
perror("read");
free(hreq);
close(s);
return -1;
}
hres = (Initial_Res *)hbuf;
success = (hres->method != 255);
printf("Ответ начального метода согласования: ");
for (int i = 0; i < hressize; i++)
{
printf("%x ", hbuf[i]);
}
printf("\n");
if (!success)
{
fprintf(stderr, "Ошибка\n");
free(hreq);
close(s);
return -1;
}
req = request(host,port);
write(s, req, reqsize);
memset(buf, 0, ressize);
if (read(s, buf, ressize) < 1)
{
perror("read");
free(hreq);
free(req);
close(s);
return -1;
}
// if(buf[3] != 1){
// perror("Другой IP-версия");
// free(hreq);
// free(req);
// close(s);
// return -1;
// }
printf("Ответ на установление соединения: ");
for (int i = 0; i < 10; i++)
{
printf("%x ", buf[i]);
}
printf("\n\n");
res = (Res *)buf;
struct in_addr paddr;
paddr.s_addr = res->bind_addr;
printf("Подключено к прокси "
"%s:%d\n\n",
inet_ntoa(paddr), ntohs(res->bind_port));
printf("Успешно подключено через прокси к "
"%s:%d\n\n\n",
host, port);
memset(tmp, 0, 512);
snprintf(tmp, 511,
"GET / HTTP/1.0\r\n"
"Host: www.example.com\r\n"
"User-Agent: CustomClient/1.0\r\n"
"Accept: */*\r\n"
"Connection: close\r\n"
"\r\n");
write(s,tmp,strlen(tmp));
memset(tmp, 0, 512);
read(s, tmp, 511);
printf("'%s'\n", tmp);
close(s);
free(hreq);
free(req);
return 0;
}
Я вызываю код с помощью makefile, сначала вызывая хост www.example.com и получая IP, затем вызываю программу с помощью makefile
all:
gcc toralize.c -o toralize && ./toralize <ip> 80
но результат, который я получаю, такой
Результат 1:
gcc toralize.c -o toralize && ./toralize <ip> 80
Подключено к прокси
Ответ начального метода согласования: 5 0
Ответ на установление соединения: 5 4 0 1 0 0 0 0 0 0
Подключено к прокси 0.0.0.0:0
Успешно подключено через прокси к <ip>:80
''
Метод согласования проходит корректно, но я получаю ответ на туннельное соединение правильно, однако затем нет вывода для HTTP-запроса. Также при попытке другого прокси-сервера я получаю другой ответ
Результат 2:
Подключено к прокси
Ответ начального метода согласования: 5 0
Ответ на установление соединения: 5 0 0 1 0 0 0 0 ffffff8f ffffffe6
Подключено к прокси 0.0.0.0:36838
Успешно подключено через прокси к <ip>:80
'HTTP/1.0 501 Not Implemented
Content-Type: text/html
Content-Length: 357
Connection: close
Date: Thu, 09 Jan 2025 07:44:25 GMT
Server: ECLF (lac/55F7)
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>501 - Not Implemented</title>
</head>
<body>
<h1>501 - Not Implemented</h1>
</body>
</h'
Я получаю ожидаемый результат, когда просто запускаю тот же запрос без sock5 с тем же заголовком, так что я не могу точно определить причину этого. Является ли проблема в том, что прокси-сервер, который я пытаюсь использовать, не поддерживает HTTP и поддерживает только HTTPS, или есть какая-то ошибка в моей реализации.
Я подключаюсь к бесплатному прокси-серверу, найденному на этом веб-сайте
Здесь
Некоторые завершают метод согласования, но когда я начинаю установку туннеля, они выдают
Результат 3: read: connection reset by peer
. В чем, кажется, проблема, я не могу точно определить. Постоянно получаю разные результаты.
.
Ответ или решение
Введение
При использовании прокси SOCKS5 для HTTP-запросов часто возникают сложности, когда результаты запросов могут варьироваться. Это может быть вызвано рядом факторов, начиная от конфигурации самого прокси-сервера до ошибок в реализации протокола. В этом ответе мы подробно рассмотрим возможные причины различий в результатах и поможем устранить проблемы в вашем коде.
Факторы, влияющие на различные результаты
1. Различия в прокси-серверах
Прокси-серверы, особенно бесплатные, могут работать по-разному. Некоторым серверам может потребоваться шифрование или другие методологии аутентификации, которых вы не поддерживаете в текущей реализации.
2. Поддержка и особенности прокси
Некоторые прокси-серверы поддерживают только HTTPS и могут не обрабатывать HTTP-запросы должным образом. Это может привести к неправильным ответам или отсутствию ответа.
3. Ошибки в реализации SOCKS5
Ваш код может содержать неточности в реализации протокола SOCKS5, такие как неправильная конструкция пакетов или неверное управление соединениями. Проверьте соответствие вашего кода с официальной спецификацией SOCKS5.
Анализ кода
Проблемные участки
-
Инициализация и анализ данных: Если в ответах сервера указывается
0.0.0.0:0
, это может указывать на проблемы в обработке адресной информации. -
Запросы и чтение ответов: Проблемы с чтением данных из сокета могут возникать из-за некорректной обработки доступных данных или неверного ожидания окончания данных.
Рекомендации
-
Проверка корректности пакетов: Убедитесь, что все посылаемые пакеты строго соответствуют спецификации SOCKS5. Неправильная длина или формат данных могут привести к неожиданным результатам.
-
Устойчивость к ошибкам: Введите механизмы обработки ошибок для каждой операции с сетью, чтобы улучшить отладку и стабилизацию процесса соединения.
-
Тестирование с различными прокси: Попробуйте несколько различных прокси-серверов, чтобы выявить закономерности в работе. Лучше использовать проверенные и стабильно работающие прокси.
Заключение
Проблемы с использованием SOCKS5-прокси могут варьироваться от конструкции сетевого кода до особенностей самих прокси-серверов. Персональная отладка и тестирование станут ключевыми этапами в достижении стабильного результата. Если продолжаете сталкиваться с проблемами, рассмотрите возможность использования более совершенных библиотек для работы с SOCKS5, чтобы минимизировать риск логических ошибок в реализации.