Приветствую, господа! вопрос относительно организации прокси соединения через 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 ОК? уже запарился голову ломать.
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
AlexTheC0d3r, все тоже самое, что твой запрос, что мой... только попробовал. по-прежнему 98% ответов - 400 bad request не в этом дело видать.
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
У меня все работает стабильно, сервак возвращает код 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);
Chrome~, спасибо за совет, но у меня ничего не изменилось: из 100 заведомо работающих проксей 18 отдают 200 OK, 82 прокси 400 Bad request, странно как то...
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 если не знаешь, то лучше не пиши, а то путаешь человека.
так и не понял как реализовать 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 использовалось прокси?