AllInfo
Main: Info Blog Temp Mail


unix 2010-11-21 08-54-16

Обработка SMS-сообщений на сервере


Введение

Достаточно продолжительное время я занимаюсь удаленным администрированием серверов. В этом нелегком труде мне помогает централизованная система мониторинга состояния серверов с возможностью оповещения о критических ситуациях через SMS-сообщения, передаваемые через подключенный к серверу мобильный телефон. Поэтому, уходя надолго от рабочего компьютера, достаточно просто иметь коммуникатор с выходом в интернет, чтобы быстро разрешать критические ситуации на серверах, если поступит SMS-сообщение от системы мониторинга.

Я расскажу как обеспечить отправку, прием и обработку SMS-сообщений, а так же обработку входящих звонков, на сервере под управлением «Gentoo GNU/Linux» с использованием пакета «app-mobilephone/smstools».

Благодаря возможности обрабатывать SMS-сообшения, пакет «smstools» дает безграничные возможности по управлению серверами посредством команд, переданных в SMS-сообщениях, если нет возможности получить доступ к серверу через другие источники.

Выполнение команд, переданных в SMS-сообщениях, влечет за собой ослабление уровня безопасности системы. При обработке SMS-сообщений обязательно делайте проверку номера телефона отправителя!

Попробуйте использовать для передачи команд в SMS-сообщениях различные методы шифрования, например воспользоваться пакетом «GnuPG». Это даст дополнительный уровень защиты при передаче данных в незащищенных сетях.
Проверка возможностей мобильного телефона

Я буду подключать мобильный телефон к серверу через usb-кабель, поэтому в моей системе появится устройство «/dev/ttyUSB0». Телефон можно подключить и через «bluetooth» с использованием какого-либо usb-брелка, тогда в системе после настройки появится устройство «/dev/rfcomm0», которое можно так же использовать.

При подключении через «bluetooth» есть некоторые тонкости. После выполнения поиска телефона через команду «hcitool scan», получаем MAC-адрес телефона.
# hcitool scan
Scanning ...
00:21:08:D3:38:F5 Nokia

Выполняем просмотр возможностей телефона. Нас будет интересовать секция с названием «Dial-Up Networking» или аналогичным.
# sdptool browse 00:21:08:D3:38:F5
...
Service Name: Dial-Up Networking
Service RecHandle: 0x10050
Service Class ID List:
"Dialup Networking" (0x1103)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 4
Language Base Attr List:
code_ISO639: 0x454e
encoding: 0x6a
base_offset: 0x100
Profile Descriptor List:
"Dialup Networking" (0x1103)
Version: 0x0100
...

В выводе команды интересна строка с номером канала «Channel: 4».

Далее настраиваем файл «/etc/bluetooth/rfcomm.conf» как показано ниже. Здесь как раз и нужно указать номер канала.
/etc/bluetooth/rfcomm.confrfcomm0 {
bind yes;
device 00:21:08:D3:38:F5;
channel 4;
comment "Nokia Modem";
}

Перезапускаем службу «bluetooth» и можно использовать устройство «/dev/rfcomm0» в дальнейшем точно так же, как «/dev/ttyUSB0».
# /etc/init.d/bluetooth restart

Для нашей цели необходимо чтобы мобильный телефон позволял читать входящие SMS-сообщения из своей памяти. Не все телефоны это позволяют с помощью AT-команд. Например, современные телефоны «Nokia» блокируют эту возможность. Проверим наш телефон. Для этого выполним к нему подключение с помощью программы «minicom». Если не удается подключиться к телефону, попробуйте уменьшить скорость подключения, используя опцию «-b».

# minicom -b 19200 -D /dev/ttyUSB0

Если подключение произошло и мобильный телефон ответил «OK», то проверим, сможем ли мы читать полученные SMS-сообщения из памяти телефона. В моем случае вывод команды «AT+CPMS?» следующий.
AT+CPMS?
+CPMS: "SM",0,15,"SM",0,15,"SM",0,15

OK

Но может быть и такой результат.
AT+CPMS?
+CPMS: ,,,,,,,,

OK

В этом случае возможно только отправлять SMS-сообщения, но читать из памяти телефона полученные SMS-сообщения не выйдет. В современных телефонах такая функция заблокирована производителем в целях безопасности и как ее обойти я пока что не знаю.

Следующим шагом проверим возможность получать ответы на USSD-запросы. Выполним команду «AT+CUSD?». Если ответ «OK», то все в порядке, если «ERROR», то мобильный телефон слишком древний и USSD-запросы в нем возможно выполнять только с помощью команд набора номера.

Например, для проверки баланса используется набор «*100#». В современном телефоне для просмотра баланса можно выполнить следующее:
AT+CUSD=1,"*100#",15

В более древнем телефоне для проверки баланса выполняется следующее:
ATDT*100#

Обработчик USSD-запросов в пакете «smstools», работает только с современным форматом запросов через команду «AT+CUSD». Выполнение USSD-запросов через конструкцию вида «ATDT*100#» будет приводить к ошибке в логах «Unexpected input: …» и обработчик, заданный в опции «eventhandler_ussd» срабатывать не будет! Но сами USSD-запросы будут выполняться.

Осталось настроить мобильный телефон так, чтобы он не издавал никаких звуков при своей работе и обеспечить ему бесперебойное питание.
Установка и настройка «smstools»

Самую последнюю версию пакета «smstools» для «Gentoo GNU/Linux» всегда можно получить из моего оверлея или получить исходные тексты на официальном сайте в разделе загрузки.

Перед установкой, обратите внимание на USE-флаг «examples». При его использовании установиться масса примеров и скриптов, идущих в комплекте с пакетом «smstools».
# emerge smstools

Сообщения о поступлении входящих звонков будем сохранять в «/var/spool/sms/calls», а все отправленные SMS-сообщения будем складывать в «/var/spool/sms/sent». Создадим необходимые директории и назначим им соответствующие права.
# mkdir -p /var/spool/sms/{calls,sent,fail}
# chown sms:sms /var/spool/sms/{calls,sent,fail}

Теперь приведем файл конфигурации «/etc/smsd.conf» к следующему виду.
/etc/smsd.confdevices = mobile
loglevel = 5
logfile = /var/log/smsd/smsd.log
infofile = /var/run/smsd/smsd.running
pidfile = /var/run/smsd/smsd.pid
autosplit = 3
user = sms
group = sms
incoming_utf8 = yes
decode_unicode_text = yes
phonecalls = /var/spool/sms/calls
sent = /var/spool/sms/sent
failed = /var/spool/sms/fail

[mobile]
device = /dev/ttyUSB0
baudrate = 19200
incoming = high
report = yes
send_delay = 5
hangup_incoming_call = yes
phonecalls = clip
phonecalls_purge = yes
detect_unexpected_input = yes
ussd_convert = 1
eventhandler = /usr/local/sbin/smshandler
eventhandler_ussd = /usr/local/sbin/smshandler

Описание всех опций файла конфигурации можно найти на официальном сайте пакета «smstools» в разделе описания конфигурации.

Файл конфигурации разделен на две части. Сначала идут глобальные опции, а потом секция с опциями для мобильного телефона.

Обратите внимание на опцию «baudrate» в секции телефона. В ней задается скорость работы порта.

Если не удается подключится к телефону, то попробуйте уменьшить скорость работы порта.

Наиболее интересны две последние строки файла конфигурации в секции для телефона. В строке «eventhandler» задается обработчик входящих SMS-сообщений и входящих звонков, а в строке «eventhandler_ussd» - обработчик ответов на USSD-запросы. В моем случае это один и тот же скрипт «smshandler», о котором будет рассказано ниже.
Отправка SMS-сообщений

Для отправки используется скрипт «sendsms». Скрипт, идущий в комплекте пакета «smstools», мне не очень понравился, поэтому я написал свой. Скрипт поддерживает прием текста сообщения на «stdin» и может быть использован следующим образом.
# echo "Проверка" | sendsms +79161234567

Скопируйте скрипт, приведенный ниже в «/usr/local/sbin/sendsms».
/usr/local/sbin/sendsms#!/bin/bash

set -e
set -u

SPOOLDIR="/var/spool/sms/outgoing/"
ALPHABET="UTF-8"
USER="sms"
GROUP="sms"

# Show usage
usage() {
cat << USAGE
Send SMS messages via mobile phone
Usage:
echo "Text" | $(basename $0) [OPTIONS] phonenumber

Options:
-h, --help This help output
-e, --encode Set message encoding to UCS2. Input the default must be UTF-8
-V, --version Show version

Examples:
cat /etc/gentoo-release | $(basename $0) +79161234567
echo "Проверка" | $(basename $0) -e +79161234567

Report bugs to mrcat@mrcat.ru
Homepage: <http://mrcat.ru>
USAGE
if [ -n "$*" ]; then
echo 1>&2
echo "Error: $*" 1>&2
exit 1
else
exit 0
fi
}

# Parse parameters
while [ "${1+isset}" ]; do
case "$1" in
-h|--help)
usage
;;
-e|--encode)
ALPHABET="UCS2"
;;
-V|--version)
echo "$(basename $0)-0.01"
exit 0
;;
--)
break
;;
-*)
usage "Unknown option '$*'"
;;
*)
break
;;
esac
shift
done

# If empty parameters - show usage
[ -z "$*" ] && usage

PHONE="$1"
shift

# Check phone number
[ -z "${PHONE}" ] && usage "No destination phone number"
[ -z $(echo "${PHONE}"|sed -n "/^+[0-9]/p") ] && usage "Phone number must be international format"

SMSFILENAME=$(mktemp /tmp/sms_XXXXXXX)
chown ${USER}:${GROUP} ${SMSFILENAME}

# Read STDIN
STDIN=$(cat <&0)

echo -e "To: ${PHONE}
Alphabet: ${ALPHABET}
UDH: false
" >${SMSFILENAME}

if [ "${ALPHABET}" == "UCS2" ]; then
echo "${STDIN}" | iconv -f UTF-8 -t UCS-2BE >>${SMSFILENAME}
else
echo "${STDIN}" >>${SMSFILENAME}
fi

mv ${SMSFILENAME} ${SPOOLDIR}

Не забудьте назначить скрипту права на выполнение.
# chmod 755 /usr/local/sbin/sendsms

Теперь можно попробовать отправить тестовое сообщение.
# echo "Проверка" | sendsms +79161234567

По умолчанию скрипт отправляет SMS-сообщения в кодировке «UTF-8», но если принимающий телефон ее не поддерживает, то можно отправить SMS-сообщение в кодировке «UCS2», поддерживаемой большинством телефонов, используя опцию «-e».
Прием и обработка SMS-сообщений

Рассмотрим скрипт «smshandler» для обработки событий, заданный в файле конфигурации в опциях «eventhandler» и «eventhandler_ussd». Скрипт обрабатывает только два переданных параметра. Первый - это тип события. Может принимать значения «CALL, RECEIVED, USSD, SENT, FAILED, REPORT». Второй параметр - это имя файла с SMS-сообщением. В качестве примера ниже приведен сам скрипт «smshandler» с комментариями. Скопируйте скрипт в директорию «/usr/local/sbin» и внесите свои изменения.
/usr/local/sbin/smshandler#!/bin/bash

# Зададим глобальные переменные.
ADMINPHONE="79161234567"
ADMINMAIL="admin@mydomain.cxm"

# Обработаем только входящие звонки и SMS-сообщения.
# Разделим данные на заголовок и тело сообщения.
if [[ "$1" =~ (CALL|RECEIVED) ]]; then
MESSAGE=$(cat "$2")
FROM=$(echo "${MESSAGE}"|grep -e '^From:'|cut -d' ' -f2)
DATE=$(echo "${MESSAGE}"|grep -e '^Received:'|cut -d' ' -f2,3)
BODY=$(echo "${MESSAGE}"|sed -e '1,/^$/d')
fi

case "$1" in
# События при входящем звонке.
CALL)
# Проверка номера входящего звонка.
if [ "${FROM}" == "${ADMINPHONE}" ]; then
# Блокировка/разблокировка 22-го порта.
# Не забудьте задать следующую строку в файле /etc/sudoers
#
# sms ALL= NOPASSWD: /sbin/iptables
#
if [ "$(sudo /sbin/iptables -S INPUT|grep -e '--dport 22.*ACCEPT')" ]; then
sudo /sbin/iptables -D INPUT -p tcp --dport 22 -j ACCEPT
else
sudo /sbin/iptables -A INPUT -p tcp --dport 22 -j ACCEPT
fi
fi
;;

# События при получении ответа на USSD-запрос.
USSD)
;;

# События при поступлении SMS-сообщения.
RECEIVED)
# Проверка номера и тела входящего SMS-сообщения.
# Если номер совпадает с содержанием переменной ADMINPHONE и тело
# SMS-сообщения совпадает со словом "REBOOT", то выполняется перезагрузка.
if [[ "${FROM}" == "${ADMINPHONE}" && "$BODY" == "REBOOT" ]]; then
# Не забудьте задать следующую строку в файле /etc/sudoers
#
# sms ALL= NOPASSWD: /sbin/reboot
#
sudo /sbin/reboot
exit
fi
# Перенаправление остальных SMS-сообщений на почтовый ящик.
echo -e "From: ${FROM}
Date: ${DATE}

${BODY}" |
/usr/bin/mail -s "SMS Received" ${ADMINMAIL} >/dev/null
;;

# События при отправке SMS-сообщения.
SENT)
;;

# Прочие события, не определенные выше.
*)
echo "$*" >>/var/log/smsd/others.log
;;
esac

Не забудьте назначить скрипту права на выполнение.
# chmod 755 /usr/local/sbin/smshandler

Рассмотрим работу скрипта.
При поступлении входящего звонка открывается 22-ой порт, а при следующем звонке - закрывается. Получается такой себе «call-knocking» для открытия доступа к серверу по «ssh» в удобное время.

Так же, в качестве примера, при входящем SMS-сообщении с определенного номера с текстом «REBOOT» выполняется перезагрузка сервера. Все остальные входящие SMS-сообщения перенаправляются на почтовый ящик администратора, заданный в переменной «ADMINMAIL».

Подгоняя под свои нужды скрипт «smshandler», можно добиться необходимой функциональности.
Дополнительные возможности

Используя опции «regular_run», «regular_run_cmd» и «regular_run_cmdfile» в файле конфигурации в секции телефона, можно организовать, например, проверку оставшихся средств на счету телефона.
/etc/smsd.conf[mobile]
regular_run_cmd = AT+CUSD=1,"*100#",15;
regular_run_interval = 604800

Результатом работы данных опций будет еженедельная проверка баланса. Извлечь результат можно в скрипте «smshandler» в секции обработки USSD-запросов.

Можно и вручную выполнить проверку баланса. Достаточно послать в порт телефона соответствующую команду. Например, если телефон подключем к порту «/dev/ttyUSB0», то можно выполнить следующее:
echo -e 'AT+CUSD=1,"*100#",15 ' >/dev/ttyUSB0

Или тоже самое для древних моделей телефонов без поддержки команды «AT+CUSD»:
echo -e "ATDT*100#; " >/dev/ttyUSB0

В статье я рассмотрел только пример организации мониторинга и управления сервером с помощью SMS-сообщений, но пакет «smstools» имеет гораздо большие возможности. Если рассмотреть идущие в комплекте примеры скриптов, то можно найти еще очень много полезных и интересных применений пакету «smstools».

http://mrcat.ru/sms-send-receive

18.116.15.124 / 2024-12-22_20-28-41 UTC.