вторник, 4 марта 2014 г.

OpenWrt: Интернет-панель управления питанием своими руками

Мечта родилась давным давно, когда линукс более-менее укоренился на моей домашней машине, я получил нормальный доступ в интернет и познал возможность рулить домашним компом удаленно, через ssh-интерфейс. Теперь, уезжая из дома, можно было оставив компьютер включенным, в любой момент получить к нему доступ, что иногда было жизненно необходимо.

Однако, каждый раз оставляя машину включенной, трезался мыслью - всё ли там в порядке: не остановился ли кулер на процессоре, ни прыгнуло ли напряжение, да мало ли ещё чего - с детства родители внушали, что нельзя оставлять электроприборы включенными.

Когда домашний "элеткроприбор" стал совсем не дешевым компом, а мощной машиной для сложных расчетов, когда парк домашних машин расширился за счет компа моей девушки и домашнего сервера, оставлять всё это хозяйство включенным стало не только страшновато, но и накладно для кармана - электричество не бесплатное.

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

На обдумывание деталей и постепенную реализацию ушло около месяца. И данная статья расскажет моему читателю, как сия задумка была претворена в жизнь. 


1. Как включать?


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

В экспериментах дома, проводимых на компьютерах под Arch Linux я использовал wol - отличная утилита, наличествующая в репозитории. В репозитории OpenWrt существует пакет wol, он устанавливается, но... заставить его стабильно работать мне так и не удалось. Поэтому выбор пал на другую утилиту - etherwake.

Идем в консоль роутера и устанавливаем эту утилиту

# opkg update
# opkg install etherwake

Теперь, для запуска машины напишем небольшой скриптик

Листинг 1. Скрипт включения питания

#!/bin/ash

etherwake 50:e5:49:3e:d3:2c -b -i eth1

В качестве параметра передается MAC-адрес включаемого компа, Ключ -b указывает на широковещательный характер отправляемого пакета, -i - интерфейс, ответственный в роутере за локальную сеть. MAC-адрес узнать не трудно, а имя интерфейса можно посмотреть в вот тут.

Внимание! OpenWrt по умолчанию использует командную оболочку ash а не bash, как обычные линуксы. Тут нет грамматической ошибки!

Листинг 2. Смотрим имя сетевого интерфейса в /etc/config/network

config interface 'lan'
       option ifname 'eth1'
       option type 'bridge'
       option proto 'static'
       option ipaddr '192.168.1.1'
       option netmask '255.255.255.0'
       option ip6assign '60'

Сохраняем скрипт, например под именем poweron, и обязательно делаем его исполняемым, а затем переностим в /bin

# chmod a+x poweron
# mv poweron /bin/

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

Итак, мы научили наш роутер включать компьютер.

2. Как выключать?


Это самое сложное из всего, что тут будет описано. Наберитесь терпения, букаф будет много.

Казалось бы, что может быть проще, в Arch Linux, недавно перешедшем на демон инициализации systemd, достаточно дать команду

$ sudo systemctl poweroff

а пользоветель, состоящий в группе power может сделать это и без sudo. Правда удаленно sudo всё равно придется использовать, саму команду можно завернуть в скрипт

Листинг 3. Скрипт для выключения питания

#!/bin/bash

systemctl poweroff

созранить его, скажем под именем poweroff в каталоге /usr/bin целевой машины (у арча все бинарники и системные скрипты теперь в этой директории, а для совместимости со старым ПО оставлен симлинк ~bin в корне системы).

# mv poweroff /usr/bin/
# chmod a+x /usr/bin/poweroff

Кроме того, надо разрешить sudo без пароля для этой команды, добавив в /etc/sudoers запись

<user> ALL=(ALL) NOPASSWD: /usr/bin/poweroff

Удаленно команду можно исполнить и через ssh-интерфейс, но.... Да-да, дорогие мои, правильно - для этого надо АВТОРИЗОВАТЬСЯ!!! Как же я об этом сразу не подумал, подумал я. Открытие суровым фейс-палмом легло на моё помрачневшее чело. Мечта ускользала...

Продвинутые пользователи *nix систем в целом и ssh в частности уже догадались о чем пойдет речь. Речь пойдет о беспарольной авторизации на удаленной машине через ssh с помощью ключа. Именно этим мы и займемся.

Для начала надо разрешить в настройках ssh-сервера на удаленной машине авторизацию с помощью ключа. В используемом в большинстве домашних OpenSSH эти настройки находятся в файлах /etc/ssh/ssh_config и /etc/sshd_config. Лезем в них и добавляем туда (или раскомментируем в дефолтном конфиге) параметр

RSAAuthentication yes

после чего, перезапускаем ssh-сервер

$ sudo systemctl restart sshd

Теперь заходим на роутер. Прошивка OpenWrt по умолчанию использует ssh-сервер dropbear - видимо он более легковесный чем OpenSSH, хотя последний о доступен в репозитории, будем использовать дефолтного "падающего медведя" )

Генерируем ключи - приватный и публичный

# cd /tmp
# dropbearkey -t rsa -f root_key | sed -n '/ssh/p' > root_key.pub

Эта команда сгенерирует два файла с ключами: root_key - приватный и root_key.pub - публичный. Скопируем их в место постоянного хранения.

# cp root_key* /root/.ssh

Внимание: приватный ключ нельзя никому показывать!!! При его утере или хищении генерацию ключей надо проделать заново!

Публичный ключ надо скопировать на целевую машину

# scp -P <порт> ~/.ssh/root_key.pub <user>@<host>:~

Под портом подразумевается порт на котором работает ssh на удаленной машине, user - имя пользователя, под которым мыслится авторизация на этой машине, host - адрес машины в сети.

Заходим на удаленную машину

# ssh <user>@<host> -p <порт>

Создаем в домашней директории каталог .ssh, а если он имеется, выставляем ему права

$ [ -d ~/.ssh ] || ( mkdir ~/.ssh ; chmod 711 ~/.ssh )

Добавляем наш ключ в список известных удаленному ssh-серверу ключей

$ cat root_key.pub >> ~/.ssh/authorized_keys

И ставим (если делаем это впервые) нужные права

$ chmod 600 ~/.ssh/authorized_keys

Верные права доступа тут важны - иначе при попытке авторизации ключ просто не будет принят. Прибираем мусор

$ rm root_key.pub

Всё! Теперь, находясь под root-ом в роутере, пробуем зайти на удаленный комп

# ssh <user>@<host> -p <порт>

Если прошел вход без ввода пароля - цель достигнута. Теперь роутер может авторизоваться на удаленной машине и выполнять на ней любые разрешенные команды.

Теперь пишем скрипт для роутера

Листинг 4. Скрипт, посылающий удаленной машине команду выключения питания

#!/bin/ash

ssh -i /root/.ssh/root_key <user>@<host> -p <порт> sudo poweroff

Скрипт выполняет авторизацию по RSA-ключу и запускает на удаленной машине скрипт выключения, написанный нами ранее. Сохраним его под именем, ну например my_comp_poweroff и скопируем в /bin/ дав права на исполнение

# mv my_comp_powroff /bin/
# chmod a+x /bin/my_comp_poweroff

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

3. Прикручиваем красивости


Подготовку почвы мы выполнили. Теперь бы добавить красивостей - какую-нибудь веб-панель с кнопочками.

Таковую можно написать и самому, для знатоков веб разработки не составит труда провернуть такое и прикрутить это к LuCI (сам планирую это сделать). Если же нет времени, желания и знаний на такой трюк, можно использовать плагин к LuCI - luci-app-commands. Установим его

# opkg install luci-app-commands

Перезагрузим роутер и в меню "Система" найдем пункт "Custom Commands". Там можно привязать наши скрипты к кнопкам. Чтобы долго не рассказывать об этом простом мероприятии, просто приведу скрин своей настройки, из которого осилившему изложенное выше всё станет понятно

Экран настройки кнопочных команд LuCI

 В итоге, получим такую вот панель
Пример панели управления питанием домашних машин
Жмем Run и наслаждаемся :)

Теперь, расшарив доступ к роутеру из внешней сети, например способом, описанным в предыдущей статье, можно рулить домашними машинами удаленно. Например можно, установив на смартфон с андроидом ftp-клиент и настроив ftp на домашней машине, с помощью браузера включить домашний компьютер, скачать нужное и... выключить его снова. Одним нажатием кнопки. Я уж не говорю о серьезной удаленной работе )

Заключение


Как видите, линукс, прямые руки и фантазия могут творить чудеса и делать нашу жизнь удобнее )