Предохраняйся носками! Докучаев Дмитрий aka Forb Xakep, номер #066, стр. 066-118-1 (forb@real.xakep.ru) Создаем приватный прокси-сервер Ты не раз задумывался о собственной безопасности, правда? Порой ведь приходится проделывать различные штуковины: например, зацепиться по ssh под чужим логином, снять мыло какого-нибудь ламера и т.п. Для этого необходимо прибегнуть к помощи анонимного проксика, который мы сейчас и напишем. Зачем тебе сокс? Прежде чем что-либо кодить, подумаем, зачем вообще может пригодиться прокси? Ведь в огромных проектах (наподобие squid) сервер включает в себя возможности кэширования, управления потоками, аутентификации по хостам, паролям и прочие возможности. Разумеется, подобные вещи используются не для хакерских проделок. Для нас с тобой приватный прокси должен выполнять всего одну задачу - мутить безопасный туннель до точки назначения. Причем безопасность не будет включать шифрование данных (при острой необходимости ты реализуешь это самостоятельно), а только скроет твой IP-адрес. В принципе, в инете полно различных проксиков, и совсем не обязательно изобретать еще один. Но уже существующие проекты нередко требуют рута либо написаны на Си. Такие проги могут быть заюзаны лишь на *nix-системах. Я поставил задачу - написать прокси-сервер на Perl и убить двух зайцев сразу. Во-первых, сценарий будет работать под непривилегированным аккаунтом, а во-вторых, исправно сотрудничать с виндовым ActivePerl. Создание алгоритма Общие черты прокси-сервера я обдумал. Теперь приступим к составлению алгоритма этого проекта. Прежде всего, скрипт должен светиться порту не ниже 1025 (что допустимо для обычного пользователя). При новом подключении проксик создает туннель с удаленным сервером. Вот тут возникла первая проблема: нужно либо подстраиваться под уже известный протокол (Socks4, к примеру), либо придумывать что-то свое. Мне не хотелось реализовывать отдельный протокол по одной простой причине: я желал, чтобы любой клиент мог юзать прокси-соединение, не зная, что трафик туннелируется. Непонятно? Объясню еще раз. Обычный HTTPS-прокси ждет от клиента команды «CONNECT server:port PROTOCOL». После этого происходит соединение с необходимой машиной. Однако при этом клиент должен уметь коннектиться через HTTPS. В моем случае это совсем не обязательно. Но ты спросишь: как тогда скрипт узнает, с каким сервером ему соединяться? На самом деле все очень просто. Прежде чем использовать прокси-сервер по прямому назначению, ему необходимо заслать специальную команду. Она будет содержать три параметра: пароль для доступа к прокси, удаленный сервер и удаленный порт. Приняв эти опции, скрипт проверит пароль, и, если он совпадает, замутит необходимое соединение на другом порту. Значение порта вернется в ответ на пользовательский запрос. Помимо этого, необходимо позаботиться о своевременном закрытии соединения, в случае если на порт никто не приконнектился (зачем нам дохлые сокеты?). Разумеется, проксик будет многопоточным, с корректным завершением «мертвых» сессий. И, наконец, нужно осуществить логинг всех входящих запросов и трафика. Несмотря на всю сложность алгоритма, код проксика довольно прост и не содержит никаких изощрений. Для работы с сокетами я использовал модули IO::Socket, IO::Select, а также POSIX (для корректного завершения потомков). Помимо этого, в коде юзается перехват двух сигналов (CHLD и ALRM) - об их назначении я расскажу немного позже. |