Zdalne monitorowanie i sterowanie urządzeniami opartymi na Lunix/OpenWrt/Lede poprzez port 80…

Witam wszystkich, to moje pierwsze doświadczenie z Habré. Chcę napisać o tym jak w niestandardowy sposób zarządzać sprzętem sieciowym w sieci zewnętrznej. Co oznacza niestandardowy: w większości przypadków do zarządzania sprzętem w sieci zewnętrznej potrzebujesz:

  • Publiczny adres IP. Cóż, albo jeśli sprzęt jest za czyimś NAT-em, to publiczny adres IP i „przekazany” port.
  • Tunel (PPTP/OpenVPN/L2TP+IPSec itp.) do węzła centralnego, przez który będzie dostępny.

Dlatego „mój rower” będzie Ci potrzebny, gdy standardowe metody Ci nie odpowiadają, na przykład:

  1. Sprzęt znajduje się za NAT-em i poza zwykłym http (port 80) wszystko jest zamknięte. Jest to całkowicie normalna sytuacja w przypadku dużych federalnych sieci korporacyjnych. Mogą zarejestrować porty, ale nie od razu, nie szybko i nie za Ciebie.
  2. Niestabilny i/lub „wąski” kanał komunikacji. Niska prędkość, ciągłe straty. Ból i frustracja podczas próby zorganizowania tunelu.
  3. Drogi kanał komunikacji, w którym liczy się dosłownie każdy megabajt. Na przykład łączność satelitarna. Do tego długie opóźnienia i „wąskie” pasmo.
  4. Sytuacja, gdy trzeba „żonglować” dużą liczbą małych routerów, na których z jednej strony zainstalowany jest OpenWrt/Lede w celu rozszerzenia możliwości, a z drugiej strony zasoby (pamięć) routera są niewystarczające za wszystko.

Zanotuj liczbę razy Co stoi na przeszkodzie zainstalowaniu pendrive'a w porcie USB routera i rozszerzeniu pamięci routera?

Najczęściej wymagania dotyczą kosztu rozwiązania jako całości, ale czasami kluczową rolę odgrywa również współczynnik kształtu. Np. na miejscu stoi TP-Link ML3020, jego jedyny port USB służy do podłączenia modemu 2G/3G, to wszystko jest opakowane w jakąś małą plastikową obudowę i umieszczone gdzieś wysoko, wysoko (na maszcie), daleko, daleko (w terenie, 30 km od najbliższej stacji bazowej operatora komórkowego). Tak, można podłączyć koncentrator USB i zwiększyć liczbę portów, ale doświadczenie pokazuje, że jest to uciążliwe i zawodne.

Próbowałem więc opisać moją typową sytuację: „gdzieś daleko, daleko, jest bardzo ważny, samotny i mały router, na którym działa Linux. Ważne jest, aby przynajmniej raz dziennie wiedzieć, że „żyje” i, jeśli to konieczne, wysyłane są do niego polecenia, na przykład „kochanie, uruchom ponownie!”

Przejdźmy do realizacji:

1) Po stronie routera, przez cron, co 5/10/1440 minut lub kiedy chcesz, musisz wysłać żądanie http do serwera za pomocą wget, zapisać wynik żądania do pliku, uczynić plik wykonywalnym i wykonaj go.

Moja linia cron wygląda mniej więcej tak:

Plik /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

, gdzie:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai to domena mojego serwera. Od razu zaznaczę: tak, można podać konkretny adres IP serwera, robiliśmy to do czasu, aż nasze państwo w słusznym impulsie walki, powiem, nie wiem, zablokowało dostęp do lwa udział „chmur” DigitalOcean i Amazon. Jeśli korzystasz z domeny symbolicznej, jeśli zdarzy się takie zdarzenie, możesz łatwo podnieść chmurę zapasową, przekierować do niej domenę i przywrócić monitorowanie urządzenia.

a.php to nazwa skryptu po stronie serwera. Tak, wiem, że błędnym jest nazywanie zmiennych i plików tą samą literą... Sugeruję, żeby w ten sposób zaoszczędzić kilka bajtów przy wysyłaniu żądania :)
u - nazwa użytkownika, login sprzętowy
p - hasło
„-O /tmp/wa.sh” to plik na zdalnym routerze, w którym zostanie zapisana odpowiedź serwera, na przykład polecenie ponownego uruchomienia.

Uwaga numer dwa: Ahhh, dlaczego używamy wget, a nie curl, ponieważ za pomocą curl możesz wysyłać żądania https nie za pomocą GET, ale za pomocą POST? Ahhh, bo jak w starym dowcipie „NE wchodzi do słoika!” curl zawiera biblioteki szyfrujące o rozmiarze około 2 MB i z tego powodu jest mało prawdopodobne, że będziesz w stanie złożyć obraz na przykład dla małego TP-LINK ML3020. I z wget - proszę.

2) Po stronie serwera (mam Ubuntu) będziemy używać Zabbix. Dlaczego: Chcę, żeby było pięknie (z wykresami) i wygodnie (wysyłaj polecenia poprzez menu kontekstowe). Zabbix ma tak cudowną rzecz jak agent Zabbix. Za pośrednictwem agenta wywołamy na serwerze skrypt PHP, który zwróci informację o tym, czy nasz router zarejestrował się w wymaganym okresie czasu. Do przechowywania informacji o czasie rejestracji, komendach dla urządzeń używam MySQL, osobnej tabeli użytkowników zawierającej w przybliżeniu następujące pola:

		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;

Wszystkie źródła można pobrać z repozytorium Git pod adresem: https://github.com/BazDen/iotnet.online.git
Teraz skrypty PHP umieszczone po stronie serwera (dla wygody można je umieścić w folderze /usr/share/zabbix/):

plik.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();
	?>

Plik Agent.php (jest to skrypt agenta Zabbix o nazwie):

<?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();
?>		

No cóż, ostatni etap: rejestracja agenta i dodanie harmonogramów.

Jeśli jeszcze nie zainstalowałeś agenta Zabbix, to:

apt-get install zabbix-agent

Edytuj plik /etc/zabbix/zabbix_agentd.conf.

Dodaj linię:

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

, gdzie:
test to nazwa naszego agenta
„php /usr/share/zabbix/agent.php user hasło” - wywoływany skrypt wskazujący dane rejestracyjne urządzenia.

Dodawanie wykresów: otwórz interfejs WWW Zabbix, wybierz z menu:
Ustawienia -> Węzły sieciowe -> Utwórz węzeł sieciowy. Tutaj wystarczy podać nazwę hosta sieciowego, jego grupę i domyślny interfejs agenta:

Zdalne monitorowanie i sterowanie urządzeniami opartymi na Lunix/OpenWrt/Lede poprzez port 80…

Teraz musimy dodać element danych dla tego węzła sieci. Zwróć uwagę na dwa pola: „key” – to jest dokładnie parametr, który zapisaliśmy w pliku /etc/zabbix/zabbix_agentd.conf (w naszym przypadku jest to test) oraz „updateinterwał” – ustawiam go na 5 minut , ponieważ i sprzęt jest również rejestrowany na serwerze raz na pięć minut.

Zdalne monitorowanie i sterowanie urządzeniami opartymi na Lunix/OpenWrt/Lede poprzez port 80…

Cóż, dodajmy wykres. Zalecam wybranie „Wypełnienie” jako stylu renderowania.

Zdalne monitorowanie i sterowanie urządzeniami opartymi na Lunix/OpenWrt/Lede poprzez port 80…

Wynik jest bardzo lakoniczny, na przykład taki:

Zdalne monitorowanie i sterowanie urządzeniami opartymi na Lunix/OpenWrt/Lede poprzez port 80…

Na rozsądne pytanie: „czy było warto?”, odpowiem: no cóż, oczywiście, patrz „powody stworzenia roweru” na początku artykułu.

Jeśli moje pierwsze doświadczenia z grafomanem wzbudzą zainteresowanie czytelników, to w kolejnych artykułach chcę opisać, jak wysyłać polecenia do zdalnego sprzętu. Udało nam się również wdrożyć cały schemat dla urządzeń opartych na RouterOS (Mikrotik).

Źródło: www.habr.com

Dodaj komentarz