Как известно, множество сетевых устройств могут использовать протокол 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-а. Открываем любимый текстовый редактор и набираем следующий код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #!/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) (В данном случае распространяется обратно в интернет).