[HELP] delphi+winsock+socks5

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by rikko, 13 Feb 2010.

  1. rikko

    rikko Member

    Joined:
    23 Nov 2009
    Messages:
    16
    Likes Received:
    7
    Reputations:
    0
    Приветствую, господа!
    вопрос относительно организации прокси соединения через socks5 на winsocks.
    реализовал алгоритм:
    1. шлю запрос на sock5 порт
    2. получаю ответ сервера (подтвержение соединения)
    3. шлю куда хочу коннектиться (например www.google.com:80)
    4. получаю ответ, что соединение установлено
    5. шлю данные серверу:

    GET / HTTP1.1+#13#10+
    Host: www.google.com+#13#10#13#10

    вот тут непонятки - очень редко когда приходит "200 OK", в основном приходит 400 ошибка, из 1к собранных socks5 примерно половина устанавливает соединение с сервером (остальные недоступны по таймауту), но не понятно как посылают данные ошибка 400 - очень часто приходит. 200 OK бывает очень редко - примерно 10 проксей из этих 1к.
    Собственно, что делаю неправильно? почему получается ошибка 400? и почему все же иногда получаю таки 200 ОК? уже запарился голову ломать.
     
    1 person likes this.
  2. AlexTheC0d3r

    AlexTheC0d3r Elder - Старейшина

    Joined:
    25 Jul 2008
    Messages:
    388
    Likes Received:
    179
    Reputations:
    18
    400 error код ошибки в протоколе HTTP, возникающей, когда запрос клиента не может быть понят

    не правильно формируешь запрос

    Сруктура GET запроса:

    Code:
    GET http://localhost/microtest.php HTTP/1.0
    Accept: */*
    Referer: http://localhost/1.php
    Accept-Language: ru
    Proxy-Connection: Keep-Alive
    User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.7 (build 01670); Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
    Host: localhost
    Cookie: PHPSESSID=rkp4kdodkh3190l8um92hl7oe1 
     
  3. rikko

    rikko Member

    Joined:
    23 Nov 2009
    Messages:
    16
    Likes Received:
    7
    Reputations:
    0
    AlexTheC0d3r, все тоже самое, что твой запрос, что мой... только попробовал.
    по-прежнему 98% ответов - 400 bad request
    не в этом дело видать.
     
  4. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    rikko, выложи часть кода.
     
  5. rikko

    rikko Member

    Joined:
    23 Nov 2009
    Messages:
    16
    Likes Received:
    7
    Reputations:
    0
    Code:
    procedure TProxyCheckThread.Execute;
    var
     sock:LongWord;
     block:u_long;
     SockAddrIn:TSockAddrIn;
     timeout:ttimeval;
     fds:TFDSet;
     rc,curr,len:integer;
     ws:TWSAData;
     send_buf, result:string;
     buf:array[0..4095] of char;
    
     socks5_req:record // привет
       ver:byte;
       nmet:byte;
       met:byte;
       end;
     socks5_resp:record //ответ на привет
       ver:byte;
       met:byte;
       end;
      socks5_req_TPC:record // куда подключаться
        ver:byte;
        cmd:byte;
        rsv:byte;
        atyp:byte;
        ip:u_long;
        port:u_short;
      end;
      socks5_resp_TPC:record // подключились
        ver:byte;
        cmd:byte;
        rsv:byte;
        atyp:byte;
        ip:u_long;
        port:u_short;
      end;
       
    
    begin
     //приветствие
     socks5_req.ver:=5;
     socks5_req.nmet:=1;
     socks5_req.met:=0;
     WsaStartup($202,ws);
     //запрос соединения
     socks5_req_TPC.ver:=5;
     socks5_req_TPC.cmd:=1;
     socks5_req_TPC.rsv:=0;
     socks5_req_TPC.atyp:=1;
     socks5_req_TPC.ip:=inet_addr(Pansichar(GetipAddress(form1.edit2.Text)));
     socks5_req_TPC.port:=htons(strtoint('80'));
    
    
     block:=1;
     sock:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if sock=LongWord(-1) then exit;
     SockAddrIn.sin_family := AF_INET;
     SockAddrIn.sin_port := htons(strtoint(PROXY_PORT));
     SockAddrIn.sin_addr.s_addr := inet_addr(Pansichar(PROXY_IP));
    
     ioctlsocket(sock, FIONBIO, block); // переводим сокет в неблокируемый режим
     if connect(sock, SockAddrIn, SizeOf(SockAddrIn))=SOCKET_ERROR then // пытаемся подключиться
      begin
       if WSAGetLastError=WSAEWOULDBLOCK then // проверяем что сокет перешел в неблокируемый режим
         begin
          FD_ZERO(fds);
          FD_SET(sock,fds);
          timeout.tv_sec:=strtoint(form1.Edit1.Text); // наш таймаут
          timeout.tv_usec:=0;
          rc:=select(0, nil, @fds, nil, @timeout); // ожидаем
         end;
       end;
     block:=0;
     ioctlsocket(sock, FIONBIO, block); // переводим сокет обратно в блокируемый режим
    if rc=0 then
     begin
       // сработал таймаут
    
       synchronize(showresultbad);
     end
    else
     begin
       // удачно соединились
      // запрос для http 
       send_buf:='GET http://'+form1.edit2.Text+'/ HTTP/1.1'#13#10+
                  'Host: '+form1.edit2.Text+#13#10+
                  'Accept: */*'+#13#10+
                  'Proxy-Connection: Keep-Alive'+#13#10+
                  'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.7 (build 01670); Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.50727)'#13#10#13#10; 
    
    
        send(sock,socks5_req, 3,0); // шлем привет
              len := recv(sock, socks5_resp, 2, 0); // считали данные
    
              if len > 0 then // если есть чтото
              begin
                //смотрим результат
                if (socks5_resp.ver=5) and(socks5_resp.met=0) then //успех
                  begin
    
                    send(sock, socks5_req_TPC, 14,0); // запрос на соединение с http сервом
                    len := recv(sock,  socks5_resp_TPC, 14, 0); // считали данные
                    if len > 0 then
                      if socks5_resp_TPC.cmd=0 then //успех
                        begin
    
                             send(sock, send_buf[1], length(send_buf),0); // шлем наднные http серву через прокси
                                 len := recv(sock,  buf, 4096, 0); // читаем ответ
                                 if len > 0 then
                                  begin
                                    result := copy(buf, 0, len);
                                    if pos('200 OK', result)<>0 then result:='GOOD';
                                  end;
                        end;
    
                  end;
    
              end;
         if result='GOOD' then synchronize(showresultgood);
    
     end;
      closesocket(sock);
      synchronize(dec_count);
    end;
    реализация для потоков.
    реализация таймаута для прокси - взял у Слэша.
    прокомментил отстальное.
    повторюсь - иногда работает. 200 ok получаю. Очень часто - ошибка 400
     
  6. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    У меня все работает стабильно, сервак возвращает код 200.
    Я кое-что поменял.

    Code:
    socks5_req_TPC.ip:=inet_addr(Pansichar(GetipAddress(form1.edit2.Text)));
    на
    Code:
    socks5_req_TPC.ip:=Integer(LookupName(form1.edit2.Text));
    Код функции LookupName:
    Code:
    function LookupName(str: String): TInAddr;
    var
      _hostEnt:PHostEnt;
      _inAddr:TInAddr;
    begin
      if (str[1] in ['a'..'z']) or
          (str[2] in ['a'..'z']) then
      begin
        _hostEnt := getHostByName(pchar(str));
        FillChar(_inAddr, sizeOf(_inAddr), 0);
        if _hostEnt<>nil then
        begin
          with _hostEnt^, _inAddr do
          begin
            s_un_b.s_b1 := h_addr^[0];
            s_un_b.s_b2 := h_addr^[1];
            s_un_b.s_b3 := h_addr^[2];
            s_un_b.s_b4 := h_addr^[3];
          end;
        end;
      end
      else
        _inAddr.s_addr := inet_addr(pchar(str));
      Result:= _inAddr;
    end;
    
    Также вот эту строку:
    Code:
    SockAddrIn.sin_addr.s_addr := inet_addr(Pansichar(PROXY_IP));
    изменил на:
    Code:
    SockAddrIn.sin_addr := LookupName(PROXY_IP);
     
  7. rikko

    rikko Member

    Joined:
    23 Nov 2009
    Messages:
    16
    Likes Received:
    7
    Reputations:
    0
    Chrome~, спасибо за совет, но у меня ничего не изменилось:
    из 100 заведомо работающих проксей 18 отдают 200 OK, 82 прокси 400 Bad request, странно как то...
     
  8. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    2 rikko
    socks5_req_TPC.port:=htons(strtoint('80')); - это жестоко.
    лучше уж socks5_req_TPC.port := htons(80);
    Вообще поподробнее попроверяй эти прокси.
    Могут быть следующие ошибки
    1) С коде проксей есть ошибка и запрос не полностью отправляется или хз что еще происходит. бывает всякое.
    2) попробуй найти прокси которые дывают ошибку постоянно и подконнектится куданить туда где можно проверить всё. Если у тя есть внешний IP то на него на какойнить порт или проверить логи сервака. Как вариант пробовать запрос на echo сервис. тогда он ответит темже что ты ему послал и таким образом сможеш увидеть запрос который идет уже от прокси.

    Также желательно проверять кол-во посланных данных с длинной буфера который ты посылал. просто хз почему но может быть такое что не до конца от тебя данные уходят.

    Еще иногда бывает что траф компов както хитро фильтруется. Такое у сотовых операторов часто бывает
    Это та часть по которой чтото может не пахать.

    А вот часть по которой скорее всего не пашет
    Code:
    send_buf:='GET http://'+form1.edit2.Text+'/ HTTP/1.1'#13#10+
                  'Host: '+form1.edit2.Text+#13#10+
                  'Accept: */*'+#13#10+
                  'Proxy-Connection: Keep-Alive'+#13#10+
                  'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MRA 4.7 (build 01670); Crazy Browser 1.0.5; .NET CLR 1.1.4322; .NET CLR 2.0.50727)'#13#10#13#10; 
    
    Ты же посылаешь запрос не на HTTP прокси.
    Ты посылаешь на HTTP сервер через socks5 прокси
    по этому он должен быть типа такой:
    Code:
    'GET / HTTP/1.0'#13#10+
    'Host: site.com'#13#10#13#10
    
    т.е. первый твой запрос был правильный, то там была ошибка на участке HTTP/1.0, а тот который тебе посоветывали - это запрос для HTTP прокси.

    P.S. 2 AlexTheC0d3r если не знаешь, то лучше не пиши, а то путаешь человека.
     
    #8 slesh, 17 Feb 2010
    Last edited: 17 Feb 2010
    1 person likes this.
  9. ADR-007

    ADR-007 Member

    Joined:
    12 Jul 2010
    Messages:
    218
    Likes Received:
    9
    Reputations:
    0
    так и не понял как реализовать WinSock + Proxy ...
    имею такой код WinSock (сделан в виде класса. если кому надо то могу выложить весь код)
    Code:
    { TPortScanner1 }
    
    procedure TPortScanner1.ApplicationEventsMessage(var Msg: tagMSG;
      var Handled: Boolean);
    begin
      if (Msg.message>=FPortStart+WM_USER)
                                    and (Msg.message<=FPortEnd+WM_USER)
      then
      if WSAGETSELECTERROR(Msg.lParam)=0
      then
        case WSAGETSELECTEVENT(msg.lParam) of
          FD_CONNECT:
            begin
              if Assigned(OnPortExists) then
                OnPortExists(Self,Msg.message - WM_USER);
              Application.ProcessMessages;
            end;
        end;
      Handled:=false;
    end;
    
    procedure TPortScanner1.Checking;
    var
     i: integer;
     buf: in_addr;
    begin
    
     FHost:=inet_addr(PAnsiChar(FIPAddress));
     if (FPortEnd<=FPortStart)or (FPortEnd>32768)
     then FHost:=SOCKET_ERROR;
     if FHost=SOCKET_ERROR
     then
      begin
       if Assigned(OnWorkEnd) then
        OnWorkEnd(self);
       Exit;
      end;
     buf.S_addr:=FHost;
     FPort:=FPortStart;
     for i:=0 to MaxOpenPort-1 do
      with FSocket[i] do
       begin
        TimeOut:=0;
        FData:=Socket(AF_INET, SOCK_STREAM, 0);
       end;
     //
     while not Terminated do
      begin
       Application.ProcessMessages;
       InitSockets;
       if FPort>=FPortEnd
       then break;
      end;
     //
     for i:=0 to MaxOpenPort-1 do
      CloseSocket(FSocket[i].FData);
     //
    end;
    
    constructor TPortScanner1.Create;
    var
     i: integer;
    begin
      inherited;
      SetLength(FSocket,MaxOpenPort);
      if WSAStartup(MAKEWORD(2, 0), FInfo)<>0
      then Halt;
      for i:=0 to MaxOpenPort-1 do
      with FSocket[i] do
        begin
          ATimeOut := 0;
          FData := Socket(AF_INET, SOCK_STREAM, 0);
          if FData = SOCKET_ERROR
          then
            begin
            WSACleanup;
            Halt;
          end;
        end;
      Application.OnMessage:=ApplicationEventsMessage;
    end;
    
    destructor TPortScanner1.Destroy;
    var
     i: integer;
    begin
      for i:=0 to MaxOpenPort-1 do
        CloseSocket(FSocket[i].FData);
      WSACleanup;
      inherited;
    end;
    
    procedure TPortScanner1.InitSockets;
    var
     i,time: word;
    begin
     for i:=0 to MaxOpenPort-1 do
      with FSocket[i] do
       if (FPort>=FPortEnd) or (FTerminated)
       then break
       else
        if (GetTickCount-ATimeOut>TimeOut)
        then
         begin
          sa.sin_family:=AF_INET;
          sa.sin_addr.S_addr:=FHost;
          sa.sin_port:=htons(FPort);
          //
          WSAAsyncSelect(FData, Application.Handle, WM_USER+FPort, FD_CONNECT);
          connect(FData, FSocket[i].sa, SizeOf(FSocket[i].sa));
          ATimeOut:=GetTickCount;
          inc(FPort);
          if Assigned(OnWork) then
            OnWork(Self,FPort);
          Application.ProcessMessages;
          //
          //Sleep(TimeOut div MaxOpenPort);
          time:=GetTickCount;
          while GetTickCount-time<TimeOut div MaxOpenPort do
            Application.ProcessMessages;
         end;
    end;
    
    procedure TPortScanner1.SetMaxOpenPort(const Value: Word);
    begin
      SetLength(FSocket,Value);
      FMaxOpenPort:=Value;
    end;
    
    procedure TPortScanner1.StartChecking;
    begin
      if not Working then
      begin
        FWorking:=true;
        if Assigned(OnWorkBegin) then
          OnWorkBegin(self,FPortStart,FPortEnd);
        try
          Checking;
          FWorking:=false;
        finally
          if Assigned(OnWorkEnd) then
            OnWorkEnd(self);
        end;
      end;
    end;
    
    вот и как сделать чтобы при значении переменной FUseProxy = true использовалось прокси?
     
    #9 ADR-007, 18 Feb 2011
    Last edited: 19 Feb 2011