Получение разных результатов для одного и того же запроса с использованием sock5 для выполнения HTTP-запроса [закрыто]

Вопрос или проблема

Я следовал учебнику по сетям на 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.

Анализ кода

Проблемные участки

  1. Инициализация и анализ данных: Если в ответах сервера указывается 0.0.0.0:0, это может указывать на проблемы в обработке адресной информации.

  2. Запросы и чтение ответов: Проблемы с чтением данных из сокета могут возникать из-за некорректной обработки доступных данных или неверного ожидания окончания данных.

Рекомендации

  1. Проверка корректности пакетов: Убедитесь, что все посылаемые пакеты строго соответствуют спецификации SOCKS5. Неправильная длина или формат данных могут привести к неожиданным результатам.

  2. Устойчивость к ошибкам: Введите механизмы обработки ошибок для каждой операции с сетью, чтобы улучшить отладку и стабилизацию процесса соединения.

  3. Тестирование с различными прокси: Попробуйте несколько различных прокси-серверов, чтобы выявить закономерности в работе. Лучше использовать проверенные и стабильно работающие прокси.

Заключение

Проблемы с использованием SOCKS5-прокси могут варьироваться от конструкции сетевого кода до особенностей самих прокси-серверов. Персональная отладка и тестирование станут ключевыми этапами в достижении стабильного результата. Если продолжаете сталкиваться с проблемами, рассмотрите возможность использования более совершенных библиотек для работы с SOCKS5, чтобы минимизировать риск логических ошибок в реализации.

Оцените материал
Добавить комментарий

Капча загружается...