18 August 2015

SMS из Bash или учим Zabbix новым трюкам

Configuring LinuxSystem administration
Данная статья посвящена организации СМС оповещения в очень бюджетном исполнении.
Такой метод подходит для домашнего использования или использования в SOHO. На что-то большее данная схема не способна, имейте это ввиду.
Ранее на Хабре уже были статьи на тему СМС информирования, но все сводилось к локальным USB-модемам или сервисам email2sms.
В этой статье будет рассмотрена иная схема взаимодействия. А именно: оборудование Mikrotik выступит в роли GSM шлюза, а Zabbix будет отправлять СМС через терминал.

Что понадобится:
1) Mikrotik 951 серии (активный USB-хаб крайне рекомендуется)
2) USB-модем с сим-картой
3) и развернутый Zabbix-сервер.

А работает это все согласно RFC2217.

Вся конфигурация разбита на 3 этапа:
A) Настройка Mikrotik
B) Работа со скриптом отправки
C) Настройка Zabbix

Наcтройка Mikrotik


К Mikrotik'у подключен USB-модем, произведены базовая настройка и проверка работоспособности модема.
Сразу выясните каналы для отправки СМС. В моем случае это было сделано экспериментально, каналы 1 и 2 отвечают за эту функцию.

В документации к ROS была найдена функция проброса COM-порта по TCP (RFC2217). Она позволяет обращаться к оборудованию за роутером через обычный терминал.
Настройка в Winbox
System -> Ports -> Remote Access


Все параметры интуитивно понятны. Каналы данных SMS Settings и Remote Port совпадать не должны!
Со стороны сетевого оборудования на этом настройка окончена.

Скрипт отправки СМС


В качестве гостевой системы ВМ в моем случае выступает Ubuntu 14.04.2. Так исторически сложилось, с этим приходится жить.
Вы же можете использовать как «железный» Zabbix, так и виртуальный.

Путем чтения тонны инструкций был написан скрипт отправки СМС на Bash сначала в текстовом формате, а следом и в формате PDU. PDU-формат позволяет отправлять СМС в Юникоде, т.е. латинские и кириллические символы (в данном случае только они нас интересуют).
Окончательный вариант скрипта, прилагаемый здесь, позволяет отправлять «многостраничные» СМС любого содержания, т.е. более 70 символов.
Для тех, кто хочет проникнуться, я оставлю несколько ссылок: тык и тык
Скрипт на Bash'е
Для работы скрипта требуется утилита Recode.
В случае, если вы хотите проверить работу скрипта из терминала, уберите "-e" у «echo».

#!/bin/bash
#Переменные
tel=$1
header=$2
mes=$3
ip=XXX.XXX.XXX.XXX                                          #IP шлюза
port=Y                                                 #Порт шлюза

#Служебные переменные !!! НЕ ТРОГАТЬ !!!
TP_MR0=0                                                #Начальный параметр TP-MR
IED31=1                                                 #Начальный параметр IED3 для блока UDH

#Начинается...
###########################################################################################################################################
#Переменные для обоих блоков

#Вычисление длины сообщения для определения использовать ли UDH
UDH=`echo $mes | recode ..U2/x2`                        #Преобразование тела сообщения в UCS2
UDH=`echo $UDH | sed 's/0x\|,\| //g' | sed 's/000A$//g'`
TP_UD=$UDH                                              #TP-UD - кодированное сообщение
UDH=`echo -n $UDH | wc -c | gawk '{print $1}'`
UDH=$(($UDH/4))                                         #Подсчет символов в сообщении - определяет какой типа отправки использовать

#Кодировка номера в нужный формат
tel="$tel"F""
i=`echo -n $tel | wc -c | gawk '{print $1}'`
i=$(($i/2))

while [ "$i" != "0" ]
do
R=`echo $tel | cut --complement -b '3-12' | rev`
TPTEL="$TPTEL$R"
tel=`echo $tel | cut --complement -b '1-2'`
i=$(($i-1))
done

###########################################################################################################################################
#Если символов 70 и менее!
if [ "$UDH" -le "70" ]; then

#Кодировка сообщения и длины сообщения в UCS2
TP_UDL=`echo -n $TP_UD | wc -c | gawk '{print $1}'`     #Вычисление длины сообщения в шестнадцатеричный формат вида XX
TP_UDL=$((($TP_UDL+1)/2))
TP_UDL=`printf '%02x' $TP_UDL | sed 's/[[:lower:]]/\u&/g'`      #Тут еще в верхний регистр загоняем для красоты


#Собираем строку для >
TPDU=""0011000B91"$TPTEL"0008AA"$TP_UDL$TP_UD"          #Собираем всю строку для >

#Подсчет байтов для AT+CMGS=
Byte=`echo -n $TPDU | cut --complement -b '1-2'`        #Убираем первые 2 символов, они не участвуют в подсчете
Byte=`echo -n $Byte | wc -c | gawk '{print $1}'`
Byte=$((($Byte)/2))

#Сама процедура отправки на шлюз. Вроде как поддерживается и RFC2217, и RAW
(
sleep 2
echo  "AT+CMGF=0"                                       #1 - Текстовый режим, 0 - PDU режим чтоб он сгорел!!!
sleep 1
echo "AT+CSCS=\"UCS2\""                                 #Кодировка
sleep 1
echo "AT+CMGS=$Byte"                                    #Передача байта в десятичном виде
sleep 1
echo -e "$TPDU\\032"                                       #Передача закодированной строки + Ctrl+Z
sleep 3                                                 #Спим долго, отчет идет долго
echo -e "\\033"                                            #ESC на всякий случай, чтоб модем не завис в случае ошибки
sleep 3
) | telnet $ip $port                                    #Telnet на шлюз, параметры в самом верху
exit 0

##################################################################################################################################
#Если символов более 70!
else

#Тут временные переменные, нужны для цилка
UDH=$((($UDH/67)+1))                                    #Превращаем UDH в количество циклов (на 1 больше, чем полных СМС по 67 символов)
IED2=$UDH                                               #Посчитаем количество частей СМСок - параметр для UDH
IED2=`printf '%02x' $IED2 | sed 's/[[:lower:]]/\u&/g'`

#Сама процедура отправки на шлюз. Вроде как поддерживается и RFC2217, и RAW
(
sleep 2
echo  "AT+CMGF=0"                                       #1 - Текстовый режим, 0 - PDU режим чтоб он сгорел!!!
sleep 1
echo "AT+CSCS=\"UCS2\""                                 #Кодировка
sleep 1

#Цикл отправки сообщений AT+CMGS=
while [ $UDH -ne 0 ];
do

#Кодировка сообщения и длины сообщения в UCS2
TPUD=`echo -n $TP_UD | cut --complement -b '269-100000000'`     #Отрезаем первые 67 символов для кодирования одного СМС
TP_UD=`echo -n $TP_UD | cut --complement -b '1-268'`    #Оставшееся сообщение без 67 символов, будет отрезано в следующем цикле

TP_MR=`printf '%02x' $TP_MR0 | sed 's/[[:lower:]]/\u&/g'`       #Преобразуем TP-MR (00, 01 и т.д.)
IED3=`printf '%02x' $IED31 | sed 's/[[:lower:]]/\u&/g'` #Текущая часть СМС - параметр для UDH

UDH_TP_UD=""050003FF"$IED2$IED3$TPUD"                   #Собираем строку для подсчета длины TP-UDL

TP_UDL=`echo -n $UDH_TP_UD | wc -c | gawk '{print $1}'` #Вычисление длины в шестнадцатеричный формат вида XX
TP_UDL=$(($TP_UDL/2))
TP_UDL=`printf '%02x' $TP_UDL | sed 's/[[:lower:]]/\u&/g'`      #Тут еще в верхний регистр загоняем для красоты

TPDU=""0041"$TP_MR"0B91"$TPTEL"0008"$TP_UDL$UDH_TP_UD"  #Собираем всю строку для >
TP_MR0=$(($TP_MR0+1))                                   #Увеличивает $TP-MR0 на 1 для следующего СМС
IED31=$(($IED31+1))                                     #Увеличиваем номер следующего СМС для UDH
UDH=$(($UDH-1))                                         #Уменьшаем номер для следующего цикл на один

#Подсчет байтов для AT+CMGS=
Byte=`echo -n $TPDU | cut --complement -b '1-2'`        #Убираем первые 2 символов, они не участвуют в подсчете
Byte=`echo -n $Byte | wc -c | gawk '{print $1}'`
Byte=$((($Byte)/2))

#Сама отправке нескольких сообщений на шлюз
echo "AT+CMGS=$Byte"                                    #Передача байта в десятичном виде
sleep 1
echo -e "$TPDU\\032"                                       #Передача закодированной строки + Ctrl+Z
sleep 3                                                 #Спим долго, отчет идет долго
echo -e "\\033"                                            #ESC на всякий случай, чтоб модем не завис в случае ошибки
sleep 3
done
) | telnet $ip $port                                    #Telnet на шлюз, параметры в самом верху

fi
exit 0
#В случае, если вы хотите проверить работу скрипта из терминала, уберите "-e" у "echo"


Вам в скрипте необходимо изменить две переменные на ваши — IP и Port.
В скрипт передаются 3 переменные по порядку: номер телефона, заголовок (не используется, просто Zabbix именно в такой последовательности передает данные в скрипт) и само сообщение. Дополнительно переменные экранировать не нужно, Zabbix это делает сам.
По умолчанию скрипт должен лежать в:
для версии 2.2 — /usr/local/share/zabbix/alertscripts
для версии 2.4 — /usr/lib/zabbix/alertscripts.
Не забывайте дать соответствующие права на файл скрипта!

Настройка Zabbix


На стороне Zabbix'а процедура настройки тривиальна, но я опишу ее еще раз для закрепления.
1) Указываете Способ оповещения
2) Указываете необходимый телефон в профиль пользователя
Телефон вводится в формате 11-значном формате, т.е. 7**********
3) Настраиваете действия на сработавший триггер
Картинки для закрепления






Не забывайте, что поле действия «Тема по умолчанию» не учитывается в скрипте, поэтому все необходимое выносите в «Сообщение по умолчанию». Я использую для этого следующую конструкцию: {TRIGGER.NAME} {TRIGGER.DESCRIPTION} {ITEM.NAME} — {ITEM.LASTVALUE}. Она более чем информативна.

Послесловие


Как я и предупреждал в начале статьи, все очень примитивно и для «продакшена» не годится. Но метод позволяет за совсем скромные деньги получать чуть больше оперативной информации от вашей системы мониторинга. За сим разрешите откланяться.
Tags:ZabbixUSBModemМониторингSMSMikrotikUbuntuPDU with UDH
Hubs: Configuring Linux System administration
+7
18.5k 177
Comments 38
Popular right now