Работа с цепочкой SOCKS-проксей. Не мне тебе объяснять, что значит анонимность для хакера. Ты, наверное, не раз задумывался о лучшем способе ее сохранения. Не самый лучший, но, безусловно, самый популярный – это использование цепочки SOCKS-серверов. Ведь если хотя бы одно звено-сервер из этой цепи не пишет логов, то у взломщика остаются неплохие шансы сохранить анонимность. Итак, как ты уже догадался сегодня мы познакомимся с работой по передаче данных в цепочке SOCKS-проксей. Для того чтобы Socks-сервер соединился с нужным нам сайтом необходимо указать адрес сайта и его порт. Но сначала придется поприветствовать сервер и пройти аутентификацию (она не обязательна, и на большинстве анонимных соксах отсутствует). [Приветствие] На этом этапе нужно отправить специальный пакет: 1 байт – номер версии 1 байт – количество методов (N) N байт – перечисление методов Т.к. мы будем работать с соксами 5 версии, то нужно послать $05, следующий байт – число поддерживаемых методов соединения / аутенфикации. За ним последовательность байт, описывающих эти самые методы. Мы не будем заморачиваться с аутенфикацией, поэтому напишем тут 00. На это приветствие сокс отвечает двумя байтами: номером своей версии и выбранным методом. Если соксу ничего не понравилось, то второй байт будет равняться $FF, если мы получим $00, то можно смело продолжить работу. [Соединение] на следующем этапе мы должны указать серверу с кем соединиться. Для этого нужно отправить такой пакет. 1 байт – номер версии 1 байт – команда 1 байт – зарезервировано до лучших времен 1 байт – тип адреса N байт – адрес 2 байта – порт Для заполнения этого пакета я создал специальную структуру: PHP: request = record version:byte; cmd:byte; null:byte; typeofaddr:byte; addr:integer; port:word; end; Байт команды у нас будет равен $01, это значит, что мы просто хотим соединиться (о других значениях следует прочитать в RFC). Следующий байт всегда равен нулю. Типом адреса может быть: $01 – ip v4 адрес, заданный 4 байтами $03 – Нерезолвленное имя хоста (всегда лучше резолвить удаленно, т.к. иначе ты можешь пропалить свой DNS-сервер). $04 –ip v6 адрес На это сокс-сервер вернет пакет той же структуры, но с другими значениями. Например. нерезолвленный хост станет ip-шником. Если все прошло нормально, то socks переходит в прозрачный режим и начинает передовать все данные по адресу. [Составляем цепочку] Теперь на практике разбирем, то о чем говорилось выше и реализуем минимальный функционал socks-клиента. Информацию о соксах будем хранить в следующей структуре. PHP: server = record ip:integer; port:word; end; Нужно заполнить структуру SockAddrIn, указав данные о первом соксе. PHP: SockAddrIn.sin_addr.S_addr:=socks[0].ip; SockAddrIn.sin_port:=Socks[0].port; Коннектимся к первому серверу PHP: connect(FSocket,SockAddrIn,SizeOf(SockAddrIn)); Затем в цикле запускаем коннект к следующем соксам. PHP: For i:=1 to sockcount do begin send(Fsocket,hello,SizeOf(hello),0); recv(FSocket,ans,Sizeof(ans),0); if (ans[0]<>$05) or (ans[1]<>$FF) then halt; //Заполняем структуру req req.version:=$05; req.cmd:=$01; req.null:=0; req.typeofaddr:=$01; req.addr:=socks[i].ip; req.port:=socks[i].port; send(Fsocket,req,sizeof(req),0); recv(Fsocket,req,sizeof(req),0); end; Вот мы и написали в общем-то нехитрый код для работы с SOCKS-проксями. Для более подробного изучения рекомендую прочитать RFC 1928, в котором описан протокол SOCKS 5. Напоследок, я выложу полный исходный код со всеми подробными комментариями. PHP: program Sock5clinet; uses Windows, WinSock; type server = record //Структура для описания адресов соксов ip:integer;//ip-адрес port:word; //порт end; request = record // Пакет для соединения с сервером version:byte; // номер версии cmd:byte; // команда null:byte; // зарезервировано до лучших времен typeofaddr:byte; // тип адреса addr:integer; // адрес port:word; // порт end; var socks:array [0..4] of server; FSocket:Tsocket; WSAData:TWSADATA; procedure connecttoSocks(sockcount:integer); var i:byte; ans:array[0..1] of byte; //Буфер для ответов сервера SockAddrIn: TSockAddrIn; hello:array [0..2]of char;//Буфер приветсвия req:request; //Структура в которой содержиться запрос на соединение begin hello:=#050100;//Последовательность байт 05, 01, 00 SockAddrIn.sin_addr.S_addr:=socks[0].ip; SockAddrIn.sin_port:=Socks[0].port; connect(FSocket,SockAddrIn,SizeOf(SockAddrIn)); For i:=1 to sockcount do begin send(Fsocket,hello,SizeOf(hello),0); recv(FSocket,ans,Sizeof(ans),0); if (ans[0]<>$05) or (ans[1]<>$FF) then halt; //Заполняем структуру req req.version:=$05; req.cmd:=$01; req.null:=0; req.typeofaddr:=$01; req.addr:=socks[i].ip; req.port:=socks[i].port; send(Fsocket,req,sizeof(req),0); recv(Fsocket,req,sizeof(req),0); end; end; begin //Первый сокс socks[0].ip:=inet_addr('127.0.0.1'); socks[0].port:=htons(80); //Второй сокс socks[1].ip:=inet_addr('127.0.0.1'); socks[1].port:=htons(81); //Третий сокс socks[2].ip:=inet_addr('127.0.0.1'); socks[2].port:=htons(82); //Четвертый сокс socks[3].ip:=inet_addr('127.0.0.1'); socks[3].port:=htons(83); //Хост куда нужно подключиться socks[4].ip:=inet_addr('127.0.0.1'); socks[4].port:=htons(110); //Инициализируем WinSock WSAStartUp($202,WSAData); //Подготавляиваем сокет FSocket:=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //Соединяемся по цепочке соксов с нужным хостом connecttoSocks(4); end.