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

от автора

Данная статья посвящена организации СМС оповещения в очень бюджетном исполнении.
Такой метод подходит для домашнего использования или использования в 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

#!/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/,//g' | sed 's/ //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}. Она более чем информативна.

Послесловие

Как я и предупреждал в начале статьи, все очень примитивно и для «продакшена» не годится. Но метод позволяет за совсем скромные деньги получать чуть больше оперативной информации от вашей системы мониторинга. За сим разрешите откланяться.

ссылка на оригинал статьи http://habrahabr.ru/post/264949/