Віддалений моніторинг та управління пристроїв на базі 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-й порт.

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

Віддалений моніторинг та управління пристроїв на базі Lunix/OpenWrt/Lede через 80-й порт.

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

Віддалений моніторинг та управління пристроїв на базі Lunix/OpenWrt/Lede через 80-й порт.

На виході виходить щось дуже лаконічне, наприклад:

Віддалений моніторинг та управління пристроїв на базі Lunix/OpenWrt/Lede через 80-й порт.

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

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

Джерело: habr.com

Додати коментар або відгук