Как известно, множество сетевых устройств могут использовать протокол syslog для оповещения о происходящих в них процессах. Соответственно, существует некоторое количество серверных программ, которые позволяют систематизировать информационные сообщения, передать их каким-либо способом для обработки обслуживающему персоналу, переслать дальше по цепочке серверов. Но зачастую такие системы представляют из себя комбайны по мониторингу, что может не подойти в какой-то конкретной ситуации. Таким образом, мне понадобился сервис, банально рассылающий сообщения syslog по группе пользователей icq. Ниже я предлагаю решение такой задачи.
Используемые инструменты:
1. Сервер на базе Debian Linux.
2. Интерпретатор языка Perl.
Первым делом нужно установить модуль Net::OSCAR, который обеспечит нам функциональность асечного клиента. Вариантов два, использовать CPAN, либо установить в ручном режиме.
В случае с CPAN выполняем:
cpan
install Net::OSCAR
exit
В случае ручного режима (после скачки и распаковки):
apt-get install libdigest-md5-file-perl
apt-get install libscalar-util-numeric-perl
apt-get install libxml-parser-perl
perl Makefile.PL
make test
make install
Будем писать perl-daemon, вечно висящий в памяти. Стоит обратить внимание, что сервис syslog слушает 514 порт, это значит, что он должен запускаться от root-а. Открываем любимый текстовый редактор и набираем следующий код.
#!/usr/bin/perl -w
#Чтобы не ошибаться в переменных
use strict;
#Используемые модули
use Net::OSCAR qw(:standard);
use POSIX qw(setsid);
use IO::Socket;
#Отсоединяемся от рабочей консоли
Daemonize();
#Настройки для соединения с сервером ICQ
my $icq_uin = _ICQ_UIN_HERE_;
my $icq_pass = "_ICQ_PASSWORD_HERE_";
#Здесь перечисляются получатели сообщения syslog
my @icq_users = (_ICQ_REC_UIN_HERE_,_ICQ_REC_UIN_HERE_);
#Готовимся к приему сообщений syslog на 514 порту
my $sock = IO::Socket::INET->new(LocalPort => '514', Proto => 'udp');
#Таймаут выполнения системной функции recv устанавливаем в 10 секунд
setsockopt($sock,SOL_SOCKET,SO_RCVTIMEO,pack('L!L!',+10,0));
#Сюда будем ловить сообщения от syslog-клиентов
my $buf;
#Инициализурем объект и соединяемся с ICQ
my $bot=Net::OSCAR->new();
$bot->signon($icq_uin,$icq_pass);
#Сделаемся видимыми
$bot->set_visibility(VISMODE_PERMITALL);
#Пока бот не online, топчемся здесь
while (!$bot->is_on) {
$bot->do_one_loop();
}
#Основной цикл
while (1) {
#Получаем сообщения от syslog-клиентов, с ожиданием в 10 секунд, раскладываем по переменным результат
$sock->recv($buf, 1524);
my ($port, $ipaddr) = sockaddr_in($sock->peername);
my $hn = gethostbyaddr($ipaddr, AF_INET);
$buf=~/< (\d+)>(.*?):(.*)/;
my $head=$2;
my $msg=$3;
#Если связь с ICQ прервалась, соединимся заново
if (!$bot->is_on) {
$bot->signon($icq_uin,$icq_pass);
$bot->set_visibility(VISMODE_PERMITALL);
sleep(5);
}
#Нужно, чтобы сервер нас не потерял
$bot->do_one_loop();
if ($buf) {
#Если к нам что-то пришло, отправим всей группе получателей
foreach my $i (@icq_users) {
$bot->send_im($i,"$head $msg (from $hn)");
}
}
}
#До этого места никогда не дойдет :-) В идеале нужен код обработки сигналов системы
$bot->signoff();
#Функция отсоединения, полностью copy&paste
sub Daemonize {
return if ($^O eq 'MSWin32');
chdir '/' or die "Can't chdir to /: $!";
umask 0;
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!\n";
}
Устанавливаем на файл 700 и запускаем:
chmod 700 ./icqBot.pl
./icqBot.pl
По мотивам:
1. Пишем icq-бот на perl
2. A simple Syslog daemon script written in Perl.
3. Архитектурно-независимый код для recv timeout
p.s. Всё, что нам легко досталось, так же легко и теряется. (c) (В данном случае распространяется обратно в интернет).