Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #66, ИЮНЬ 2004 г.

Предохраняйся носками!

Докучаев Дмитрий aka Forb

Xakep, номер #066, стр. 066-118-2


Тонкости Perl

Как я уже сказал, первое, что требуется от нашего прокси-сервера - открытие главного порта. На него будут приниматься запросы для новых подключений. В самом начале скрипта идет определение значения порта. По умолчанию это 5190 (пусть все думают, что у тебя на шелле находится ICQ-сервер :)). Тут же отображается пароль на доступ к серверу. Я задал очень простой пасс - 123 (при желании можешь его поменять).

Код программы (без процедур) занимает всего несколько строк. В нем реализуется открытие порта и создание новых соединений.

Создаем новые соединения

unless (fork()) {

use IO::Socket;

use IO::Select;

use POSIX ":sys_wait_h";

$|++;

$bind=IO::Socket::INET->new(Listen=>10,Reuse=>1,LocalPort=>$startport)

|| die print "Can't bind MAIN socket on $startport: $!\n";

while(1) {

while($client=$bind->accept()) {

unless(fork()) {

new_client($client);

exit;

}}}}

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

Все начинается с вызова функции fork(). Ты знаешь, что форк создает идентичный подпроцесс. В данном случае мы описываем код, который выполняется в теле потомка (родитель завершает свое существование :)). По сути, я загнал процесс в бэкграунд. Ты сам в этом убедишься, когда запустишь скрипт - после старта вернется стандартное приглашение интерпретатора (будто ничего и не произошло).

Далее заюзываем Socket для создания сокетов и Select - для управления ими. Чуть ниже идет загрузка части модуля POSIX, которая отвечает за корректное завершение убитых потомков. Напоследок отрубим буферизацию ($|++ практически то же, что $|=1).

Теперь приступаем непосредственно к выполнению вышеописанного алгоритма. В переменной $bind будет храниться идентификатор сокета (или не будет - в случае если порт по каким-то причинам не открывается). Когда порт удачно засветился, впадаем в бесконечный цикл, в котором непрерывно анализируется состояние открытого сокета. Как только произошел коннект, сразу вызываем fork() и ответвляем процесс. Это делается для того, чтобы скрипт мог независимо обрабатывать сразу несколько подключений. Если процедура new_client() завершается, считаем соединение закрытым и выходим из подпроцесса.

Обслуживаем клиента

Тебе, несомненно, станет интересно, что же происходит в процедуре new_client(). Как я уже говорил, саба запускается в отдельном процессе, то есть не пересекается с остальными. И это правильно - клиенты не должны путаться друг у друга под ногами :). Итак, вот небольшая процедура, цель которой - аутентифицировать соединение и подготовиться к созданию необходимого туннеля.

Создание туннеля

sub new_client {

my ($sid)=@_;

$sid->recv($shake,1024);

Назад на стр. 066-118-1  Содержание  Вперед на стр. 066-118-3