Некоторое время назад был рассмотрен вопрос использования модема SENSE GM02 в частности для отправки SMS. Сейчас немного усложним задачу: попробуем "расшарить" модем по сети, чтобы его можно было использовать одновременно с нескольких компьютеров.
Зачем это нужно? Ну например если есть несколько серверов мониторинга, каждый из которых должен иметь возможность отправлять SMS, а модем у нас только один и подключен к одному из серверов.
Немного конкретизируем задачу: есть Zabbix-сервер, работающий под управлением FreeBSD и сервер под управлением Ubuntu 11.04 с подключенным к нему модемом и имеющий IP-адрес 1.1.1.1.
Приступаем к решению задачи. Общая идея заключается в том что zabbix-сервер для отправки оповещений будет использовать внешний скрипт, который будет по сети передавать данные серверу и тот уже будет отправлять SMS. Автору этих строк не удалось найти готовых решений и потому пришлось создавать своё.
Начнём работу с создания сервера. Полноценную работу с GSM-модемом делать долго, потому в качестве промежуточного звена используем smstools. Установим их:
apt-get install smstools
Приведём файл /etc/smsd.conf к следующему виду:
devices = GSM1 outgoing = /var/spool/sms/outgoing checked = /var/spool/sms/checked incoming = /var/spool/sms/incoming logfile = /var/log/smstools/smsd.log infofile = /var/run/smstools/smsd.working pidfile = /var/run/smstools/smsd.pid outgoing = /var/spool/sms/outgoing checked = /var/spool/sms/checked failed = /var/spool/sms/failed incoming = /var/spool/sms/incoming sent = /var/spool/sms/sent stats = /var/log/smstools/smsd_stats receive_before_send = no autosplit = 3 [GSM1] device = /dev/ttyACM0 incoming = yes baudrate = 19200 decode_unicode_text = yes
Перезапускаем сервис:
invoke-rc.d smstools restart
Теперь для отправки SMS достаточно создать файл определённого формата в директории "/var/spool/sms/outgoing", чем мы и воспользуемся при создании сервера. Описание формата есть в документации smstools.
Собственно код сервера (на Perl):
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use POSIX;
use IO::Socket;
use XML::Simple;
use Text::Iconv;
use Data::Dumper;
# Права, с которыми будет работать скрипт
# Важно понимать что файлы он так же будет создавать с этими правами
# Так что эти настройки должны учитывать аналогичные настройки для smsd
my $settings = {
'user' => "smsd",
'group' => "smsd",
'port' => 32767,
'outgoing_dir' => '/var/spool/sms/outgoing/',
'logfile' => '/var/log/smstools/zabbix_smsd.log',
};
# Резолвим идентификаторы пользователя и группы
my $d_uid = getpwnam($settings->{'user'});
my $d_gid = getgrnam($settings->{'group'});
# Урезаем права
setuid($d_uid);
setgid($d_gid);
# Создаём сокет
my $sock = new IO::Socket::INET (
LocalPort => $settings->{'port'},
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);
# Обрабатываем входящие соединения
while (my $client = $sock->accept()) {
# IP-адрес клиента
my $client_ip = $client->peerhost;
# Считываем данные с клиента
my $xml_data = "";
while (<$client>) {
$xml_data .= $_;
}
# Пытаемся распарсить данные
eval {
my $data = XMLin($xml_data);
# Если данные указаны
if (defined($data->{'number'}) && defined($data->{'message'})) {
# Имя файла для записи SMS
my $uniq_name = time();
my $sms_file_name = $settings->{'outgoing_dir'} . $uniq_name;
# Перекодируем сообщение
my $converter = Text::Iconv->new('UTF-8', 'UCS-2BE');
my $message = $converter->convert($data->{'message'});
# Извлекаем номер
my $number = $data->{'number'};
# Формируем SMS-сообщение
my $sms_data = "To: $number\nAlphabet: UCS2\n\n$message";
# Печатаем сообщение в файл
open SMSFILE, '>', $sms_file_name;
print SMSFILE $sms_data;
close SMSFILE;
# Формируем сообщение для записи в лог
my $logtime = strftime("%Y-%m-%d %H:%M:%S", localtime());
my $logline = "$logtime $client_ip $number $uniq_name\n";
# Пишем в лог
open LOGFILE, '>>', $settings->{'logfile'};
flock LOGFILE, 2;
print LOGFILE $logline;
close LOGFILE;
}
};
# Если произошла ошибка то не расстраиваемся
if (my $error = $@) {
}
}
# Закрываем сокет
close($sock);
Сохраним скрипт под именем "/usr/local/scripts/smsd.pl" и запустим его командой:
/usr/local/scripts/smsd.pl &
Эту же команду нужно добавить в файл "/etc/rc.local" для автоматического запуска сервера при загрузке. Поскольку скрипт не содержит средств авторизации нужно ограничить с помощью файрволла доступ к порту, который прослушивает сервер.
Переходим к написанию клиента. Поскольку в первую очередь он будет "заточен" для использования совместно с zabbix он должен принимать параметры командной строки в совместимом с zabbix-формате. А именно:
| Параметр | Значение |
|---|---|
| 1 | Адресат |
| 2 | Тема сообщения |
| 3 | Тело сообщения |
Поскольку SMS характеризуется только адресатом (номер телефона) и телом сообщения - тему мы будем просто отбрасывать. Листинг клиента:
#!/usr/bin/perl
use strict;
use warnings;
use warnings;
use IO::Socket;
use XML::Simple;
use Data::Dumper;
# Настройки
my $settings = {
'host' => '1.1.1.1',
'port' => 32767,
};
# Если количество аргументов не равняется трём:
exit 1 if @ARGV != 3;
# Извлекаем данные
my $number = shift @ARGV;
my $subject = shift @ARGV;
my $body = shift @ARGV;
# Создаём структуру данных
my $data = {
'number' => $number,
'message' => $body,
};
# Создаём строку данных
my $data_line = XMLout(
$data,
'RootName' => 'xml',
'NoAttr' => 1
);
# Создаём сокет
my $sock = new IO::Socket::INET (
PeerAddr => $settings->{'host'},
PeerPort => $settings->{'port'},
Proto => 'tcp',
);
# Пишем строку данных в сокет
print $sock $data_line;
# Закрываем сокет
close $sock;
Скрипт сохраним на сервере мониторинга под именем "zabbix_smsc.pl" в директорию, указанную параметров "AlertScriptsPath" в файле "/usr/local/etc/zabbix/zabbix_server.conf". Затем заходим в веб-интерфейс zabbix-сервера, выбираем в меню "Администрирование" -> "Способы оповещений" -> "Создать способ оповещения" и заполняем таблица следующим образом:
| Параметр | Значение |
|---|---|
| Описание | Remote SMS |
| Тип | Скрипт |
| Название скрипта | zabbix_smsc.pl |
Результат будет выглядеть примерно так:

Теперь можно в настройках пользовательских аккаунтов использовать новый способ оповещений - "Remote SMS".
Разумеется клиентскую часть системы можно использовать и с другими системами мониторинга. А так же, поскольку клиент с сервером обмениваются данными в формате XML и используют весьма примитивный протокол, к серверной части можно подключить многие другие программные продукты с минимальной доработкой.
На этом всё. Приятной работы!

Anonymous 2011-09-13 22:50:32 (#)
Так же можно через scp класть файл в папку /var/spool/sms/outgoing/ на сервере.
С авторизацией по ключам.