понедельник, 13 июля 2015 г.

openwrt butler part2

Ранее, мы уже обучили роутер некоторым фишкам.
Каждый раз когда дворецкий волнуется и видит, что хозяина нет слишком долго, то он запускает протокол паники. Все бы ничего, но есть моменты которые хочется улучшить.
В предыдущих частях мы делали подготовку железа: выносили систему на флешь, и сделали удаленный доступ но https.
Ранее мы слали сообщение только одному адресату. При попытке слать сообщение сразу нескольким адресатам возникнут проблемы. После нескольких экспериментов работающий скрипт был найден.
#!/bin/sh

WORK_DIR="/home/mcgr0g"
MAIL_TO1="test@mcgrog.now.im, ping@mcgrog.now.im"
MAIL_TO2="test@mcgrog.now.im ping@mcgrog.now.im"
MAIL_FROM=server@mcgrog.now.im
MAIL_SUBJECT="panic"
MAIL_TEXT=$(cat ${WORK_DIR}/panic.txt)
MAIL_MESSAGE="To: ${MAIL_TO1}
\nFrom: ${MAIL_FROM}
\nSubject: ${MAIL_SUBJECT}
\nContent-Type: text/plain; charset=UTF-8
\n\n${MAIL_TEXT}"

echo -e ${MAIL_MESSAGE} | msmtp -C ${WORK_DIR}/.msmtprc -a server -t $MAIL_TO2
Да, появились избыточные строки, но это решение наименьшее из зол. Пойдем дальше. Ранее использовалось технология knockd, к сожалению это решение не отличалось надежностью и стабильностью. Так как наружу торчит http будем использовать uhttpd - у него есть возможность запуска cgi-bin скриптов. Ими и займемся
cd /www/cgi-bin
mkdir panic
touch test
touch delay
touch now
Начнем с тестового скрипта, он будет работать если корректно настроен веб сервер - просто покажет системные переменные.
#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "Sample CGI Output"
echo ""
echo ""
env
echo ""
echo ""
Если он корректно открывается из внешки, то идем дальше. Это для отмены паники.
#!/bin/sh
echo "Content-type: text/html"
echo ""
sh /home/mcgr0g/delay.sh
echo "delayed"
А это для немедленной паники.
#!/bin/sh
echo "Content-type: text/html"
echo ""
sh /home/mcgr0g/panic.sh
echo "panic now"
Как видно, они просто запускают подготовленные скрипты. Вот кстати немного модифицированный delay для откладывания паники.
#!/bin/sh

WORK_DIR="/home/mcgr0g/"
MAIL_TO=test@mcgrog.now.im
MAIL_FROM=server@mcgrog.now.im
MAIL_SUBJECT="panic"
MAIL_TEXT="delayed"
MAIL_MESSAGE="To: ${MAIL_TO}
\nFrom: ${MAIL_FROM}
\nSubject: ${MAIL_SUBJECT}
\nContent-Type: text/plain; charset=UTF-8
\n\n${MAIL_TEXT}"

touch ${WORK_DIR}/check_master.sh
echo "reset timer"
echo -e ${MAIL_MESSAGE} | msmtp -C ${WORK_DIR}.msmtprc -a server -t ${MAIL_TO}
Видно что в основном происходит 2 действия: меняется временная отметка файла проверки хозяина и отправка письма с предустановленными параметрами. По временной метке роутер как раз решает пора паниковать или еще нет. Решает он в каждый раз скриптом worry.
cat /home/mcgr0g/worry.sh
#!/bin/sh

WORK_DIR="/home/mcgr0g"
AT_HOME=$(${WORK_DIR}/check_master.sh)

if [ "${AT_HOME}" == 1 ]
then
    echo "master at home"
    touch ${WORK_DIR}/check_master.sh
else
    echo "how long?"
    date_last=$(date -r ${WORK_DIR}/check_master.sh +'%Y.%m.%d-%H:%M:%S')
    date_now=$(date +'%Y.%m.%d-%H:%M:%S')
    critic_delay=$(( 24*60*60 )) # 24 hours

    echo "last seen: ${date_last}"
    echo "sysdate is: ${date_now}"
    delta=$(( $(date -d "$date_now" +%s) - $(date -d "$date_last" +%s) ))

    if [[ $delta -lt $critic_delay ]]
        then echo "not too much"
    else
        echo "time to panic"
        ${WORK_DIR}/panic.sh
    fi

    if [[ $delta -lt 0 ]]
        then sign="-"; delta=${delta/^-/}
    else sign="+"
    fi
    ss=$(( $delta % 60 ))
    delta=$(( $delta / 60 ))
    mm=$(( $delta % 60 ))
    delta=$(( delta / 60 ))
    hh=$(( $delta % 24 ))
    dd=$(( $delta / 24 ))
    printf "$sign%d %.2d:%.2d:%.2d\n" $dd $hh $mm $ss
fi
В нем мы использовали подготовленный ранее скрипт check_master. Сначала им смотрим дома ли хозяин, потом когда был последний раз с помощью переменной $date_last. В переменной $delta хранится критическое время отсутствия хозяина. Все остальное безбожно украдено со stackoverflow. Этот скрипт дергается по крону и пишет лог:
crontab -l
*/10 * * * * /bin/sh /home/mcgr0g/upd_dns.sh
*/10 * * * * /bin/sh /home/mcgr0g/worry.sh >> /var/log/cron.log 2>&1

Хочу отметить, что перенос строки в кроне не случаен, без него он не запускался. Кстати, если он до этого не работал, то его еще надо активировать.
/etc/init.d/cron start
/etc/init.d/cron enable
Каждый раз когда дворецкий волнуется и видит, что хозяина нет слишком долго, то он запускает известный ранее скрипт паники, описанный в самом начале.
Те, кто были внимательны, заметили что у меня так же по крону запускается скрипт upd_dns. Он обновляет ip адерес на freedns. Его можно взять со страницы Dynamic DNS из примера cron example  и он просто работает, в отличие от этого корявого приложения luci. За сим все.