Дистанционно наблюдение и управление на 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 хъб и да увеличите броя на портовете, но опитът показва, че това е тромаво и ненадеждно.

И така, опитах се да ви опиша моята типична ситуация: „някъде далеч, далеч има много важен, самотен и малък рутер, работещ с 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“ е файл на отдалечения рутер, където ще бъде записан отговорът на сървъра, например командата за рестартиране.

Бележка номер две: Аааа, защо използваме wget, а не curl, защото чрез curl можете да изпращате https заявки не с GET, а с POST? Аааа, защото, както в стария виц „NE се качва в буркана!“ curl включва библиотеки за криптиране с размер около 2MB и поради това е малко вероятно да успеете да сглобите изображение за малък TP-LINK ML3020, например. И с wget - моля.

2) От страната на сървъра (имам Ubuntu) ще използваме Zabbix. Защо: Искам да е красиво (с графики) и удобно (изпращане на команди чрез контекстното меню). Zabbix има такова прекрасно нещо като zabbix агента. Чрез агента ще извикаме PHP скрипт на сървъра, който ще върне информация дали нашият рутер се е регистрирал през необходимия период от време. За да съхранявам информация за времето за регистрация, команди за устройства, използвам MySQL, отделна таблица потребители с приблизително следните полета:

		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 потребителска парола” - извикан скрипт, указващ регистрационните данни на устройството.

Добавяне на диаграми: отворете уеб интерфейса на zabbix, изберете от менюто:
Настройки -> Мрежови възли -> Създаване на мрежов възел. Тук е достатъчно да посочите името на мрежовия хост, неговата група и интерфейса на агента по подразбиране:

Дистанционно наблюдение и управление на Lunix/OpenWrt/Lede базирани устройства през порт 80…

Сега трябва да добавим елемент от данни за този мрежов възел. Обърнете внимание на две полета: „ключ” - точно това е параметърът, който записахме във файла /etc/zabbix/zabbix_agentd.conf (в нашия случай е тест), и „интервал на актуализиране” - зададох го на 5 минути , защото и оборудването също се регистрира на сървъра веднъж на всеки пет минути.

Дистанционно наблюдение и управление на Lunix/OpenWrt/Lede базирани устройства през порт 80…

Е, нека добавим графика. Препоръчвам да изберете „Попълване“ като стил на изобразяване.

Дистанционно наблюдение и управление на Lunix/OpenWrt/Lede базирани устройства през порт 80…

Резултатът е нещо много лаконично, например като това:

Дистанционно наблюдение и управление на Lunix/OpenWrt/Lede базирани устройства през порт 80…

На разумния въпрос: „струваше ли си?“ Ще отговоря: добре, разбира се, вижте „причини за създаването на велосипед“ в началото на статията.

Ако първият ми графомански опит предизвика интереса на читателите, тогава в следващите статии искам да опиша как да изпращам команди до отдалечено оборудване. Успяхме да реализираме и цялата схема за устройства, базирани на RouterOS (Mikrotik).

Източник: www.habr.com

Добавяне на нов коментар