Перед использованием данного руководства сделайте резервную копию настроек вашего роутера
Подбор правильного минимального решения требует для рассмотрения нескольких вариантов.
Первое решение, которое было в последствии отброшено по причине сложности и длительности реализации — arduino+ethernet shield/rapsberry PI + реле. Это тот случай, когда не нужно решать все задачи одним и тем же привычным способом, даже если очень хочется. Как минимум пришлось бы ждать либо ethernet shield, либо rapsberry PI. А ждать не хотелось. Далее логично было бы предположить, что раз нельзя сделать перезагрузку аппаратно, то может это можно сделать программно. Действительно, роутер подвисал не полностью, и предоставлял возможность без проблем войти в админку. 5 минут гугления.
curl -u 'login:password' 'http://192.168.1.1/setup.cgi?todo=reboot'
Ссылка замечательно работает в браузере, но через curl рецепт в упор не хотел работать и выдавал.
<HTML> <HEAD><TITLE>401 Unauthorized</TITLE></HEAD> <BODY BGCOLOR="#cc9999" TEXT="#000000" LINK="#2020ff" VLINK="#4040cc"> <H4>401 Unauthorized</H4> Authorization required. <HR> <ADDRESS><A HREF=""></A></ADDRESS> </BODY> </HTML>
Вариации с post параметрами, использование библиотеки request не дали положительного результата, ответ сервера всё тот же. Разбираться в тонкостях авторизации очень не хотелось. Виртуальная машина + скрипт на sikuli — с пушки по воробьям. Окончательное решение: использовать nodejs+coffeescript+phantomjs. Так уж сложилось исторически, что домашний linux дистрибутив «для поэкспериментировать» у меня gentoo. До последнего момента в gentoo был битый ebuild для phantomjs: сначала он просто не собирался, а потом таки стал собираться, но работать при этом всё-равно отказывался. Обидно, но попытка не пытка.
Создаем рабочее окружение для поделки и устанавливаем зависимости:
mkdir /opt/ext/router_reboot_tool cd /opt/ext/router_reboot_tool npm install -g coffeescript npm install phantomjs phpjs
И вот тут вскрывается интересный факт. При установке phantomjs он подтягивает готовый рабочий бинарник. Вот чудо, не надо будет плясать с бубном. Дальше уже дело техники.
check.coffee проверяет наличие интернета как умеет, и в случае падения вызывает reboot.sh:
#!/usr/bin/coffee fs = require('fs') exec= require('child_process').exec php = require('phpjs') _old_console_log = console.log console.log = (t)-> _old_console_log "[#{php.date('d.m.Y H:i:s')}] #{t}" check_internet = (get_result)-> exec 'ping -c1 8.8.8.8', (_skip,result)-> get_result /1 packets transmitted, 1 received/.test result if fs.existsSync 'marker' console.log 'marker detected' fs.unlinkSync 'marker' process.exit() fail_count = 0 max_fail_count = 10 check_count = 0 main_loop = setInterval ()-> check_count++ if check_count > 60*5-10 console.log "wiped (new will started by cron)" process.exit() check_internet (r)-> return if fail_count > max_fail_count # дополнительная проверка. Лень пока-что разбираться почему нужна # console.log r if r fail_count = 0 else fail_count++ console.log "fail #{fail_count}" if fail_count > max_fail_count console.log "reboot" clearInterval main_loop # как ни странно не срабатывает fs.writeFileSync 'marker', '' exec './reboot.sh', (_skip,result)-> console.log result setTimeout ()-> fs.unlinkSync 'phantom_marker' process.exit() , 10000 , 1000
Дополнительная запись файла marker нужна для того, что бы случайно не отправить 2 запроса перезагрузки подряд. Такое может быть если интернет пропал как раз перед концом 5-минутного интервала. А так мы гарантировано имеем промежуток как минимум 5 минут между перезагрузками роутера.
Сюрприз №1. clearInterval не захотел убивать интервал и reboot.sh вызывался в некоторых случаях по 4 раза из-за чего у меня слетели настройки на роутере. Внезапно две команды reboot подряд с интервалом в секунду вызывают hard reset. Решение-костыль так и осталось в готовом решении.
reboot.sh сильно логикой не отличается умом и сообразительностью. Прост и банален. Потом его придется поправить.
#!/bin/bash coffee -c ./phantom.coffee ./node_modules/phantomjs/bin/phantomjs ./phantom.js
phantom.coffee
console.log "start..." # fs = require('fs') # if fs.existsSync 'phantom_marker' # console.log "phantom_marker" # phantom.exit() # fs.writeFileSync 'phantom_marker', '' page = require('webpage').create() page.onConsoleMessage = (msg)-> console.log msg url = 'http://192.168.1.1/Reboot.htm' page.settings.userName = 'login' page.settings.password = 'password' page.open url, ()-> page.evaluate ()-> document.getElementsByName('mtenReboot')[0].click() console.log 'waiting...' setTimeout ()-> console.log 'exit' # fs.unlinkSync 'phantom_marker' phantom.exit() , 10000
В связи с тем, что хотелось добавить защиту от случайного запуска reboot.sh дважды, я добавил запись файла phantom_marker как индикатора того, что процесс уже запущен и не надо запускать еще один. Но тут меня ждал сюрприз №2.
Сюрприз №2. скрипты для phantomjs не поддерживают модули для nodejs (или просто модуль fs, или поддерживают, но какую-то старую версию модулей, подробно разбираться не имело смысла). Обидно, комментируем, вносим проверку в reboot.sh, которая менее красива, но работает.
Обновленный reboot.sh:
#!/bin/bash if [ -a 'phantom_marker' ] then echo "phantom_marker present" exit fi touch phantom_marker coffee -c ./phantom.coffee ./node_modules/phantomjs/bin/phantomjs ./phantom.js unlink phantom_marker
Финальные штрихи
chmod +x check.coffee chmod +x reboot.sh crontab -e */5 * * * * cd /opt/ext/router_reboot_tool && ./check.coffee 2>&1 >> ./log /etc/init.d/vixie-cron restart
Вносим правило уже ручками (я верю, что есть способ как это сделать из консоли, но у меня не было задачи автоматизировать установку данной поделки). После обновления crontab перезагружаем cron, иначе ничего работать не будет.
Пару тестов с ручным выключением WAN показали, что скрипт работает как нужно. В сумме на поиск решения и на решения сюрпризов было потрачено 2-4 часа, которых у кого-то может не быть, потому решил выложить решение на общее обозрение. Модифицировать скрипты под другой роутер — несложно, надо просто заменить путь к странице с кнопкой reboot и само нажатие на кнопку.
Что хотелось бы доделать, но не дошли руки: убрать костыль для лишней проверки fail_count.
ссылка на оригинал статьи http://habrahabr.ru/post/200328/
Добавить комментарий