HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ПРОГРАММИРОВАНИЕ > С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

Socks-сервер WinSock
  #1  
Старый 13.06.2010, 20:59
Faost
Новичок
Регистрация: 11.07.2009
Сообщений: 20
С нами: 8860535

Репутация: 2
По умолчанию Socks-сервер WinSock

Т.к. в моей пред.теме о socks никто ничем помочь не смог, создаю еще одну.

Проблема заключается в некорректности работы сокс-сервера через соксификаторы.

Для наглядности, чтоб было максимально понятно написал простейший socks4 сервер с подробнейшими комментариями (Delphi, WinSock + WinApi).

Качаем соксификатор, настраиваем в нем socks4 (Сервер: 127.0.0.1, порт: 8080).


Качаем исходник socks4-сервера (залил для большей наглядности)

Компилируем, запускаем, заходим на mail.ru - страница грузится очень долго (конца загрузки дождаться мне так и не удалось), хотя тот же гугл, да и вконтакт (по крайней мере на "Поиске людей") работают норм.

Так вот, нужна подсказка, из-за чего это происходит и как это исправить.

Код:
Код:
program Socks4;
uses
  Windows,
  WinSock;

const IpToListen = '127.0.0.1';


 function OurBrowserListening(p: pointer): DWORD; stdcall;
  var BSock: TSocket;
      vn, cd, UserID: byte;
      answer: array[1..8] of byte;
      buf: pointer;
      addr: sockaddr_in;
      TargetSock: TSocket;
      fset: tfdset;
      i: integer;
      avail_bytes: integer;
      time_out: timeval;
      label 2, 3;
 begin
  BSock:= Cardinal(p); //BSock - браузер (подключеный клиент)


  TargetSock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  //TargetSock - таргет (цель, конечный хост)
  if TargetSock = INVALID_SOCKET then ExitThread(0);
  ZeroMemory(@addr, sizeof(addr));
  addr.sin_family:= PF_INET;

//Теперь нужно принять данные от браузера (клиента):
// +----+----+----+----+----+----+----+----+----+----+....+----+
// | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
// +----+----+----+----+----+----+----+----+----+----+....+----+
//   1    1      2              4           variable       1

  recv(BSock, vn, sizeof(vn), 0); //принимаем версию socks - 4
  recv(BSock, cd, sizeof(cd), 0); //принимаем команду - 1 (connect)
  if cd <> $01 then goto 2;  //если не connect, то перейти к метке 2
  recv(BSock, addr.sin_port, 2, 0); //принимаем порт таргета (цели)
  recv(BSock, addr.sin_addr.S_addr, 4, 0); //принимаем ip таргета (цели)
  repeat
  recv(BSock, UserID, sizeof(UserID), 0);
  until UserID = $00; //принимаем UserID, оканчивающийся NULL-байтом


  //пытаемся соединиться с таргетом
  if connect(TargetSock, addr, sizeof(addr)) <> 0 then
  begin //если не удалось, то:
2:ZeroMemory(@answer, sizeof(answer));
  answer[1]:= $00; //должен быть 0
  answer[2]:= $5B; //$5B - ошибка
  send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)
  goto 3;
  end;


//Теперь нужно послать ответ браузеру (клиенту)
//  +----+----+----+----+----+----+----+----+
//  | VN | CD | DSTPORT |      DSTIP        |
//  +----+----+----+----+----+----+----+----+
//     1    1      2              4
  ZeroMemory(@answer, sizeof(answer));
  answer[1]:= $00; //должен быть 0
  answer[2]:= $5A; //$5A - коннект к таргету успешен
  send(BSock, answer, sizeof(answer), 0); //посылаем ответ браузеру (клиенту)


//Теперь следует непосредственно перенаправление данных от браузера к
//таргету и наоборот
  while true do
  begin //while true do

   FD_ZERO(fset);
   FD_SET(BSock, fset);
   FD_SET(TargetSock, fset);
   time_out.tv_sec:= 8; //установим таймаут на select в 8 секунд
   time_out.tv_usec:= 0;


   if select(0, @fset, nil, nil, @time_out) <= 0 then
   goto 3;
   //если есть данные от браузера и/или таргета, то:




   if FD_IsSet(BSock, fset) then //если есть данные от браузера, то:
   begin
   avail_bytes:= 0;
   ioctlsocket(BSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
   buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
   i:= recv(BSock, buf^, avail_bytes, 0); //принимаем их от браузера
   if i <= 0 then //если ошибка/соединение закрыто, то:
   begin
   VirtualFree(buf, 0, MEM_RELEASE);
   goto 3;
   end;
   send(TargetSock, buf^, i, 0); //передаем клиенту
   VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
   end;


   if FD_IsSet(TargetSock, fset) then //если есть данные от таргета, то:
   begin
   avail_bytes:= 0;
   ioctlsocket(TargetSock, FIONREAD, avail_bytes); //читаем кол-во пришедших байт
   buf:= VirtualAlloc(nil, avail_bytes, MEM_COMMIT, PAGE_READWRITE); //освобождаем под них память
   i:= recv(TargetSock, buf^, avail_bytes, 0); //принимаем их от таргета
   if i <= 0 then //если ошибка/соединение закрыто, то:
   begin
   VirtualFree(buf, 0, MEM_RELEASE);
   goto 3;
   end;
   send(BSock, buf^, i, 0);
   VirtualFree(buf, 0, MEM_RELEASE); //освобождаем память
   end;



  end;  //while true do


  3:
     CloseSocket(BSock);       //закрываем сокет браузера
     CloseSocket(TargetSock); //закрываем сокет таргета

 Result:= 0;
 ExitThread(0); //выходим из потока
 end;




 var sock, ClientSock: TSocket;
     wdata: TWSAData;
     saddr: sockaddr_in;
     id: DWORD;
     label 1;
begin
if WSAStartup(MAKEWORD(1, 1), wdata) <> 0 then ExitProcess(0);
sock:= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if sock = INVALID_SOCKET then ExitProcess(0);

ZeroMemory(@saddr, sizeof(saddr));
saddr.sin_family:= PF_INET;
saddr.sin_port:= htons(8080); //будем слушать на 8080 порту
saddr.sin_addr.S_addr:= inet_addr(IpToListen); //127.0.0.1
if bind(sock, saddr, sizeof(sockaddr_in)) <> 0 then ExitProcess(0);
if listen(sock, SOMAXCONN) <> 0 then ExitProcess(0);

1:
ClientSock:= accept(sock, nil, nil);
CreateThread(nil, 0, @OurBrowserListening, pointer(ClientSock), 0, id);
goto 1; //Если подключился, ждем подключения снова.

WSACleanup();



end.
Я так думаю, что проблема зарыта где-то уже на этапе перенаправления данных от браузера к таргету и наоборот, но где именно - не могу найти никак, скоро на стену полезу. Надеюсь на вашу помощь.

Тому, кто поможет, скромное вознаграждение размером в 20$. Очень надеюсь на вас, а то я уже сломал мозг.
 
Ответить с цитированием

  #2  
Старый 14.06.2010, 18:37
Faost
Новичок
Регистрация: 11.07.2009
Сообщений: 20
С нами: 8860535

Репутация: 2
По умолчанию

Неужели на ачате совсем не осталось знающих людей? Может тогда посоветуете подходящий форум?
 
Ответить с цитированием

  #3  
Старый 14.06.2010, 18:56
Ra$cal
Постоянный
Регистрация: 16.08.2006
Сообщений: 640
С нами: 10386906

Репутация: 599


По умолчанию

попробуй на васме спросить. здесь мало кто таким программингом занимается. В основм хттпвебреквест, на делфе сделать проверку 20 радиобатонов через ифы, итп.
 
Ответить с цитированием

  #4  
Старый 14.06.2010, 19:10
fluffylion
Познающий
Регистрация: 22.02.2010
Сообщений: 30
С нами: 8534832

Репутация: 15
По умолчанию

Faost, как вариант можно разбить обработчик сессии на 2 потока, в одном передавать данные от браузера к таргету, в другом от таргета к браузеру
 
Ответить с цитированием

  #5  
Старый 14.06.2010, 19:23
Faost
Новичок
Регистрация: 11.07.2009
Сообщений: 20
С нами: 8860535

Репутация: 2
По умолчанию

Ra$cal, спасибо, попробую. Только не побьют ли меня там за делфийский код...)
А то билдер долго качать и устанавливать, чтоб проверить, так ли переписал на C.
fluffylion, я и так пробовал, проблема аналогичная.
 
Ответить с цитированием

  #6  
Старый 14.06.2010, 19:35
Ra$cal
Постоянный
Регистрация: 16.08.2006
Сообщений: 640
С нами: 10386906

Репутация: 599


По умолчанию

не побьют, но помогать будут медленнее =) накидай алгоритм словесный примерный лучше. я вот тоже даже не пытался смотретоь на код, ибо делфи.
 
Ответить с цитированием

  #7  
Старый 14.06.2010, 21:43
bons
Участник форума
Регистрация: 20.12.2007
Сообщений: 295
С нами: 9679872

Репутация: 347
По умолчанию

компилить и отлаживать код не пытался, так что просто опишу что я заметил, просматривая это:
- когда принимаешь заголовок socks не проверяешь количество принятых байт
- неправльная работа с select. Проблемы с mail.ru полагаю из-за этого. Ты не проверяешь возможность того что селект возвратил управление по таймауту. Ты не обновляешь набор сокетов перед использованием селекта. Короче, читай маны...
- зачем-то использованы одновременно потоки и select
- VirtualAlloc для выделения буфера памяти каждый раз при приеме данных очень круто и оптимально... вообще выделяемая этой функцией память округляется до страницы(64 кб). Почему бы не использовать буфер в стеке?
- когда таргет закрывает соединение, надо сначала отправить все данные в его буфере клиенту, а потом уже корректно завершить соединение с помощью shutdown а не обрывать его.

стиль:
- зачем goto? тут можно было бы и без него
- нет отступов адекватных


дополнительные советы:
если будут еще проблемы, попробуй использовать сниффер для отладки...

PS за такой код на васме точно побьют
 
Ответить с цитированием

  #8  
Старый 14.06.2010, 22:00
slesh
Познавший АНТИЧАТ
Регистрация: 05.03.2007
Сообщений: 1,985
С нами: 10097606

Репутация: 3349


По умолчанию

дажа разбиратсья влом, глядя на этот код.
Оформление нулевое и ужасный код.
 
Ответить с цитированием

  #9  
Старый 14.06.2010, 22:14
Faost
Новичок
Регистрация: 11.07.2009
Сообщений: 20
С нами: 8860535

Репутация: 2
По умолчанию

Цитата:
- когда принимаешь заголовок socks не проверяешь количество принятых байт
Ну это само собой, что нужно проверять, это все отлажено - тут проблем не возникает, поэтому для большей минимальности убрал проверку.
Цитата:
- неправльная работа с select. Проблемы с mail.ru полагаю из-за этого. Ты не проверяешь возможность того что селект возвратил управление по таймауту. Ты не обновляешь набор сокетов перед использованием селекта.
Насчет таймаута - я ставил даже на "бесконечное" ожидание - select(0, @fset, nil, nil, nil), проблема абсолютно идентична. Кроме того, маил.ру ну полюбасу ответит в течении 8сек на 1 запрос.
Цитата:
Ты не обновляешь набор сокетов перед использованием селекта
FD_ZERO(fset);
FD_SET(BSock, fset);
FD_SET(TargetSock, fset);
Цитата:
зачем-то использованы одновременно потоки и select
В главном потоке сервер слушает подключившихся клиентов, причем слушать след.клиента надо сразу после подключения первого.
Цитата:
VirtualAlloc для выделения буфера памяти каждый раз при приеме данных очень круто и оптимально... вообще выделяемая этой функцией память округляется до страницы(64 кб). Почему бы не использовать буфер в стеке?
Учту.
Цитата:
когда таргет закрывает соединение, надо сначала отправить все данные в его буфере клиенту, а потом уже корректно завершить соединение с помощью shutdown а не обрывать его.
А какие данные то отправлять, если они передаются ему по мере поступления от таргета? Как только таргет отправил данные, они отправились клиенту (браузеру). Если таргет вместо того, чтобы отправить данные, разрывает соединение, то что еще остается передать браузеру? Насчет shutdown - пробовал, результат тот же(

Цитата:
зачем goto? тут можно было бы и без него
можно было. Мне кажется, для форумчан использование goto очень-очень наглядно. Иначе, с множеством begin;end было бы жесть.
Цитата:
Оформление нулевое и ужасный код.
Насчет оформления - да тут и оформлять то собственно нечего, в коде нет и 200 строк. Насчет кода - поправь меня, скажи где что КРИТИЧЕСКИ криво (не учитывая goto, проверку того, в чем я уверен и что ошибочным в ходе ПРАВИЛЬНОГО теста быть не может - например, заголовков сокс. Также не считаю критически кривым кучу ExitProcess в начале, т.к. мне кажется, что это поспособствовало бы лучшему пониманию, чем множество begin;end). Ребята, вы же понимаете, что это не исходник на продажу/не для всеобщего использования в повседневной жизни, поэтому о каких программерских тонкостях типа goto может идти речь?
P.S.
Цитата:
Да, я злой и грубый, а что остается еще делать видя этот кривой код и радостные лица тех, кто его написал.
Лицо у меня далеко не радостное

Последний раз редактировалось Faost; 14.06.2010 в 22:33..
 
Ответить с цитированием
Ответ



Предыдущая тема Следующая тема

Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.