Удаленный мониторинг и управление устройств на базе Lunix-OpenWrt-Lede через 80-ый порт…

Всем привет, это мой первый опыт на Хабре. Хочу написать о том, как нестандартно управлять сетевым оборудованием во внешней сети. Что значит нестандартно: в большинстве случаев, для управления оборудованием во внешней сети Вам необходимо:

  • Публичный IP-адрес. Ну, или если оборудование находится за чьим-то NAT-ом, то публичный IP и «проброшенный» порт.
  • Туннель (PPTP/OpenVPN/L2TP+IPSec и т.д.) до центрального узла, через который была бы доступна.

Поэтому «мой велосипед» потребуется Вам, когда стандартные методы Вам не подходят, например:

  1. Оборудование находится за NAT-ом и кроме обычного http (80-го порта) — все закрыто. Вполне нормальная ситуация для крупных федеральных корпоративных сетей. Прописать порты — могут, но не сразу, не быстро и не Вам.
  2. Нестабильный и/или «узкий» канал связи. Маленькая скорость, постоянные потери. Боль и разочарование при попытке организовать туннель.
  3. Дорогой канал связи, где буквально каждый мегабайт на счету. Например спутниковая связь. Плюс большие задержки и «узкая» полоса.
  4. Ситуация, когда Вам надо «жонглировать» большим количеством маленьких роутеров, на которых с одной стороны установлена OpenWrt/Lede для расширения возможностей, а с другой стороны ресурсов (памяти) роутера хватает далеко не на все.
Примечание номер раз

А что мешает в USB-порт роутера установить «флэшку» и расширить память роутера?

Чаще всего требования к стоимости решения в целом, но иногда ключевую роль играет и форм-фактор. Например, на объекте стоит TP-Link ML3020, его единственный USB-порт используется под 2G/3G модем, все это завернуто в какой-нить небольшой пластиковый корпус и размещено где-то высоко-высоко (на мачте), далеко-далеко (в поле, в 30 км. от ближайшей базовой станции мобильного оператора). Да, можно воткнуть USB-hub и расширить число портов, но опыт показывает что это громоздко и ненадежно.

Итак, я постарался описать Вам мою типовую ситуацию: «где-то далеко-далеко, стоит очень важный, одинокий и маленький роутер под управлением Linux. Важно знать хотя бы раз в день, что он „жив“ и при необходимости отсылась ему команды, например „солнышко, перезагрузись!“

Перейдем к реализации:

1) На стороне роутера по cron-у каждые 5/10/1440 минут, или когда угодно необходимо отсылать http-запрос на сервер с помощью wget, результат запроса сохранять в файл, файл делать исполняемым, и исполнять его.

У меня строчка в cron-е выглядит примерно так:

Файл /etc/crontabs/root:

 */5 * * * * wget "http://xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai/a.php?u=user&p=password" -O /tmp/wa.sh && chmod 777 /tmp/wa.sh && /tmp/wa.sh

, где:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai — домен моего сервера. Сразу замечу: да, можно указать и конкретный ip-адрес сервера, мы так раньше делали, пока наше государство, в праведном порыве борьбы нескажусчемнезнаю — не закрыло доступ к львиной доле „облаков“ DigitalOcean и Amazon. В случае использования символьного домена, при возникновении подобного казуса, вы спокойно сможете поднять резервное облако, перенаправить на него домен и восстановить мониторинг устройств.

a.php — имя скрипта на стороне сервера. Да, я знаю, что это неправильно, называть переменные и имена файлов одной буквой… предлагаю считать, что так мы экономим несколько байт при отправке запроса 🙂
u — имя пользователя, логин железки
p — пароль
„-O /tmp/wa.sh“ — файл на удаленном роутере, куда будет сохранятся ответ сервера, например команда reboot.

Примечание номер два:

Аааа, почему мы используем wget, а не curl, ведь через curl можно отправлять https запросы и не GET-ом, а POST-ом? Аааа потому, что как в старом анекдоте „В крынку нЭ лезет!“. В состав curl входят библиотеки шифрования размером около 2МБ и в силу этого врятли Вам удастся собрать образ для маленького TP-LINK ML3020 к примеру. А с wget — пожалуйста.

2) На стороне сервера (у меня это Ubuntu) мы будем использовать Zabbix. Почему: хочу чтобы было красиво (с графиками) и удобно (отправлять команды через контекстное меню). У Заббикса есть такая прелестная вещь, как zabbix-агент. Через агента мы будем вызывать php-скрипт на сервере, который будет возвращать информацию о том, регистрировался ли наш роутер в требуемый период времени. Для хранения информации о времени регистрации, командах для устройств, я использую MySQL, отдельную таблицу users примерно с такими полями:

 CREATE TABLE `users` ( `id` varchar(25) NOT NULL, `passwd` varchar(25) NOT NULL, `description` varchar(150) NOT NULL, `category` varchar(30) NOT NULL, `status` varchar(10) NOT NULL, `last_time` varchar(20) NOT NULL, // время последнего соединения `last_ip` varchar(20) NOT NULL, // IP последнего соединения `last_port` int(11) NOT NULL, // порт последнего соединения `task` text NOT NULL, // задача которую получает роутер `reg_task` varchar(150) NOT NULL, // "регулярная" задача, если мы захотим чтобы задача выполнялась всегда при регистрации `last_task` text NOT NULL, // лог задач `response` text NOT NULL, // сюда пишется ответ устройства `seq` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Все исходники можно забрать с Git-репозитория, по адресу: https://github.com/BazDen/iotnet.online.git
Теперь PHP-скрипты, размещаемые на стороне сервера(для удобства их можно положить в папку /usr/share/zabbix/):

Файл a.php:

<?php
// Получаем входные параметры: имя пользователя, пароль и сообщение от удаленного роутера
// Зачем нужен message ? Это способ ответа роутера, например если вы захотите посмотреть содержимое файла роутера $user=$_REQUEST['u']; $password=$_REQUEST['p']; $message=$_REQUEST['m']; // Подключаемся к нашей базе данных (MySQL) $conn=new mysqli("localhost","db_login","db_password","DB_name"); if (mysqli_connect_errno()) { exit(); } $conn->set_charset("utf8"); // здесь ищем наш роутер в таблице базы данных $sql_users=$conn->prepare("SELECT task, reg_task, response, last_time FROM users WHERE id=? AND passwd=? AND status='active';"); $sql_users->bind_param('ss', $user, $password); $sql_users->bind_result($task, $reg_task, $response, $last_time); $sql_users->execute(); $sql_users->store_result(); if (($sql_users->num_rows)==1){ $sql_users->fetch(); // здесь мы роутеру отправляем его задачи echo $task; echo "n"; echo $reg_task; // вот здесь мы пишем время ответа и сам ответ роутера $response_history="[".date("Y-m-d H:i")."] ".$message; // задачу отправили, теперь надо ее удалить,а после удаления отметить в логах, что такая-то задача выполнена $last_ip=$_SERVER["REMOTE_ADDR"]; $last_port=$_SERVER["REMOTE_PORT"]; $ts_last_conn_time=$last_time; $sql_users=$conn->prepare("UPDATE users SET task='', seq=1 WHERE (id=?);"); $sql_users->bind_param('s', $user); $sql_users->execute(); if (strlen($message)>1){ $sql_users=$conn->prepare("UPDATE users SET response=?, seq=1 WHERE (id=?);"); $sql_users->bind_param('ss', $response_history, $user); $sql_users->execute(); } // теперь надо сохранить время регистрации пользователя, его айпи и сообщение от него. Пока только сообщение $ts_now=time(); $sql_users=$conn->prepare("UPDATE users SET last_time=?, last_ip=?, last_port=? WHERE (id=?);"); $sql_users->bind_param('ssss', $ts_now, $last_ip, $last_port, $user); $sql_users->execute(); } // если мы не нашли роутер в нашей базе данных, или его статус "неактивный", то ему ... будет отправлена команда reboot.... // Почему так жестоко ? Потому что роутеры иногда пропадают, а это маленький способ проучить "новых владельцев". else { echo "reboot"; } $sql_users->close(); ?>

Файл agent.php (это скрипт вызываемого zabbix-агента):

<?php // файл агента Zabbix. Данный скрипт обращается к таблице users и получает "1" если устройство регистрировалось с момента последнего обращения // user и password - учетные данные оборудования $user = $argv[1]; $password = $argv[2]; // подключаемся к нашей базе данных $conn=new mysqli("localhost","db_user","db_password","db_name"); if (mysqli_connect_errno()) { exit(); } $conn->set_charset("utf8"); $sql_users=$conn->prepare("SELECT seq FROM users WHERE id=? AND passwd=? AND status='active';"); $sql_users->bind_param('ss', $user, $password); $sql_users->bind_result($seq); $sql_users->execute(); $sql_users->store_result(); // обмен данными происходит через поле seq. При регистрации железка ставит данное поле в "1" if (($sql_users->num_rows)==1){ $sql_users->fetch(); echo $seq; } // обнуляем $seq. $sql_users=$conn->prepare("UPDATE users SET seq=0 WHERE id=? AND passwd=? AND status='active';"); $sql_users->bind_param('ss', $user, $password); $sql_users->execute(); $sql_users->close();
?> 

Ну и заключительный этап: прописание агента и добавление графиков.

Если у Вас еще не установлен zabbix-агент, то:

apt-get install zabbix-agent

Редактируем файл /etc/zabbix/zabbix_agentd.conf.

Добавляем строку:

UserParameter=test,php /usr/share/zabbix/agent.php user password

, где:
test — имя нашего агента
„php /usr/share/zabbix/agent.php user password“ — вызываемый скрипт с указанием регистрационных данных устройства.

Добавление графиков: открываем web-интерфейс zabbix, в меню выбираем:
Настройка -> Узлы сети -> Создать узел сети. Здесь достаточно указать имя узла сети, его группу, интерфейс агента по умолчанию:

Удаленный мониторинг и управление устройств на базе Lunix-OpenWrt-Lede через 80-ый порт… - 1

Теперь нам для данного узла сети надо добавить элемент данных. Обратите внимание на два поля: „ключ“ — это как раз тот параметр, что мы прописывали в файле /etc/zabbix/zabbix_agentd.conf (в нашем случае это test), и „интервал обновления“ — я ставлю 5 минут, потому как и оборудование регистрируется на сервере тоже один раз в пять минут.

Удаленный мониторинг и управление устройств на базе Lunix-OpenWrt-Lede через 80-ый порт… - 2

Ну и добавляем график. Рекомендую в качестве стиля отрисовки выбрать „Заполнение“.

Удаленный мониторинг и управление устройств на базе Lunix-OpenWrt-Lede через 80-ый порт… - 3

На выходе получается нечто очень лаконичное, например вот так:

Удаленный мониторинг и управление устройств на базе Lunix-OpenWrt-Lede через 80-ый порт… - 4

На резонный вопрос: „и это того стоило?“, отвечу: ну конечно, смотрите „причины создания велосипеда“ в начале статьи.

Если мой первый графоманский опыт вызовет интерес читателей, то в следующих статьях я хочу описать как отправлять команды на удаленное оборудование. Также удалось реализовать всю схему и для устройств на базе RouterOS (Mikrotik-ов).

Автор: bazden

Источник

Комментарии:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *