Вве­де­ние

Доста­точно про­дол­жи­тель­ное время я зани­ма­юсь уда­лен­ным адми­ни­стри­ро­ва­нием сер­ве­ров. В этом нелег­ком труде мне помо­гает цен­тра­ли­зо­ван­ная система мони­то­ринга состо­я­ния сер­ве­ров с воз­мож­но­стью опо­ве­ще­ния о кри­ти­че­ских ситу­а­циях через 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}\nAlphabet: ${ALPHABET}\nUDH: false\n" >${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}\nDate: ${DATE}\n\n${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\r' >/dev/ttyUSB0

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

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