"А главное - никогда не подключайтесь телнетом к атакуемой машине!" - из одного хакерского мануала.
Думаю ты сам догадался почему - как-то неприятно оставлять в логах свой IP, от этого твоя безопасность может "чуть-чуть" пострадать :)) Ты
предложишь использовать SOCKS-сервера? Но во-первых их надо еще и найти, а во-вторых, даже если сервак является анонимным, то он все равно ведет логи, да к тому же может выполнять прямо противоположенную задачу - не обеспечивать анонимность, а служить для отлова хакеров, спаммеров и прочих социально опасных элементов 🙂 Поэтому самым верным с точки зрения человека со здоровой параноей будет поставить такой "прокси" лично для себя. Программа ставится на удаленную машину, например на заломанный тобой бесхозный сервак, или на какой-нить комп, стоящий во многочисленных Инет-центрах, инет-кафе/салонах/кабаках/борделях - добавить по вкусу :)) Правда в этом случае придется позаботиться о незаметности программы, но это уже совсем другая история. Пока же мы рассмотрим теорию и (самое главное :)) -- практику построения такой программы )
Для этого тебе понадобиться Дельфя (от 4-ой версии и выше), руки и голова
(очень желательно чтобы с мозгом :)) Запускаем Дельфю, затем File-New Application. На форму лепим два компонента из категории "Internet" - Client Socket и Server Socket - c которыми у нас и пойдет основная работа. Как следует из названий, эти элементы формы -
клиентский и серверный сокеты соответственно. Чем они хороши - что для КАЖДОГО события сокета можно задать свою процедуру, не нужно заморачиваться с WinAPI'шными функциями типа
WSAAsyncSelect, опеределяющими состояния сокета. А событий этих много - особенно для серверного сокета. Нам же, вследствие простоты ваяемой нами проги, будут нужны лишь некоторые из них.
Рассмотрим алгоритм. Нам нужно, чтобы сервак ждал когда к нему подключиться клиент, устанавливал
соединение с тем хостом, который будет нужен клиенту, и далее выполнять лишь сугубо
посреднические функции :)) В самом начале нужно сервак запустить - а он будет запускаться сразу, по активации формы - для этого в списке
объектов выберем Form1, в графе Events (cобытия) кликнем по пункту "OnActivate". Появится новая процедура, пока пустая, которая и будет запускать наш сервер.
procedure TForm1.FormActivate(Sender: TObject);
var hw:HWND;
begin
//этим мы определяем порт сервера.
ServerSocket1.Port:=8765;
// даем команду на старт работы
ServerSocket1.Active:=true;
//что ниже - для того, чтобы убрать окно, дабы оно не мозолило глаза
//hw - определитель окна. Мы считываем активное на данный момент окно
//GetActiveWindow, а окно проги будет активным, потому как запущено только
//что, а затем убираем его с экрана - функцией Windows.ShowWindow, где
//второй параметр(тот что SW_HIDE) показывает, что надо сделать с окном -
//показать, если оно спрятано, и соответственно
наоборот. Нам нужно второе
hw:=Windows.GetActiveWindow;
Windows.ShowWindow(hw,SW_HIDE);
end;
Теперь сервер запущен. Будем принимать данные от клиента, который собственно и будет использовать этот сервак. Прежде чем коннектиться к удаленному серваку, нужно передать программе IP
адрес и порт того сервака. А для этого наш "прокси" должен их принять. Донести столь важные
сведения до прокси можно очень простым способом, не прибегая ни к кому левому программному обеспечению, а воспользовавшись telnet'ом. Передается это просто -
набираешь сначала IPшник, а потом с новой строки - порт, и опять таки Enter, показывая что ввод окончен.
Рассмотрим механизм их приема. Для приема данных от клиента у серверного сокета есть процедура [SocketName]ClientRead. Опять - выбираешь среди объектов ServerSocket1, затем в событиях выбираешь OnClientRead и одним нажатием мыши создаешь новую процедуру.
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
q,t:boolean;
begin
//Принимаем данные от клиента.
ss:=Socket.ReceiveText;
//если еще не произошло подключение - тогда ждем ввода
адреса
if not(t) then begin
if not(q) then
if (byte(ss[1])=13) then begin
//если нажат Enter - пишем данные в строку адреса
и можем переходить
//к ожиданию ввода номера порта
q:=true;
end
else
//иначе - пишем принятые символы в строку адреса.
s1:=s1+ss;
//если уже введена строка адреса, ждем ввода номера порта
if (q) then
if (byte(ss[1])=13) then begin
// если ввели порт - идем дальше
t:=true;
//пишем, что прием данных для подключения выполнен.
//теперь нам нужно подключиться к удаленному серваку.
//присваиваем адрес
ClientSocket1.Address:=s1;
//присваеваем порт
ClientSocket1.Port:=StrToInt(s2);
//преобразовываем строку символов в целое число, являющиеся
//номером порта
//И - пытаемся подключиться.
//Примечание - удаленный сервак должен быть отпиногован и иметь открытый //порт, к которому идет коннект.
ClientSocket1.Active:=true;
end;
else
s2:=s2+ss;
//если нет - пишем символы в строку порта.
end else
//если все установлено -
//просто перенаправляем данные удаленному серваку от подключенного юзера
end;
Теперь нам нужно установить, удачно ли завершилась попытка подключения к удаленному серваку. Для этого просмотрим события клиентского сокета, в частности событие OnConnect - и
когда он будет выполнен - передадим клиенту, что соединение установлено - юзер примет эту строку телнетом.
procedure TForm1.ClientSocket1Connecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerSocket1.Socket.Connections[0].SendText('Connect OK');
//Connection[0] - выбираем, какое из соединений использовать, но так как
//у нас только один канал, то и будет использовано первое по списку
// соединение - с номером 0. СТрока 'Connect OK' функцией SendText будет
//послана клиенту
end;
Теперь, когда с подключением и передачей данных от клиента на удаленный сервак вроде разобрались, нужно разобраться с обратной задачей - приемом данных от удаленного сервака и передачи их клиенту. Для этого рассмотрим событие клиента OnRead:
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
begin
//читаем данные с удаленного сервака
ss:=Socket.ReceiveText;
//и посылаем их клиенту:
ServerSocket1.Socket.Connections[0].SendText(ss);
end;
А теперь рассмотрим, что делать при дисконнекте, если удаленный сервак отключил соединение - изредка такое бывает 🙂 - может ты его завалил.
За это отвечает событие клиентского сокета OnDisconnect:
procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
//мы просто посылаем извещение юзеру о том, что связь с удаленным серваком
//прервалась
ServerSocket1.Socket.Connections[0].SendText('Remote server disconnect');
//пишем, что соединение прервалось
t:=false;
//юзер должен будет опять вводить IP и порт.
// в принципе, можно сделать так, чтобы юзер тоже отключался если происходит
//разрыв с удаленным серваком, а потом снова подключался к проски - разрыв
//делается функцией Disconnect
end;
Теперь - о дисконнекте со стороны юзера. Ты же должен будешь подключаться несколько раз, и к разным сервакам, поэтому нужно грамотно отработать процедуру корректного отключения и возращения прокси в первоначальное состояние ожидания, а это сделать очень просто - достаточно присвоить переменной, отвечающей за установкой соединений, значение false.
Для этого рассмотрим событие серверного сокета OnClientDisconnect:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
// теперь сервак будет ждать нового подключения
t:=false;
// и вырубим старое подключение:
СlientSocket1.Active:=false;
end;
Пару слов о переменных - ss,s1 и s2 - строкового типа, и должны описываться глобально, чтобы могли использоваться во многих процедурах. Служебные переменные t и q - логические типа
boolean. Теперь ты видишь, что работа с сокетами в дельфях гораздо проще, чем обычными АПИшными функциями - каждое из состояний сокета у тебя как на ладони. И самое главное, хотя здесь это почти не упоминалось - возможность многоканальных подключений к серверу, и выделения под каждое из подключений своего сокета, уже готового для работы с данными, и даже своего потока. А теперь представь, сколько было бы хлопот с обычным описанием сокетов "ручками", не говоря уж о многоканальности. Так что прогресс не стоит на месте 🙂
И еще пара слов о самой программе - лучше выбирать порт прокси, к которому будет подключаться клиент, не стандартным типа
80 или 1080, а что-то вроде 8776 - т.е. такой, чтобы на него случайно не наткнулись какие-нить левые юзеры, сканящие сети в поисках прокси и прочего.
Можно конечно сделать процедуру авторизации, но я не захотел загромождать статью - потому как такая простая задача вполне тебе по силам.