Fernüberwachung und -steuerung von Lunix/OpenWrt/Lede-basierten Geräten über Port 80…

Hallo zusammen, das ist meine erste Erfahrung mit Habré. Ich möchte darüber schreiben, wie man Netzwerkgeräte in einem externen Netzwerk auf nicht standardmäßige Weise verwaltet. Was bedeutet „nicht standardisiert“: In den meisten Fällen benötigen Sie zum Verwalten von Geräten in einem externen Netzwerk Folgendes:

  • Öffentliche IP-Adresse. Nun, oder wenn sich die Ausrüstung hinter dem NAT von jemandem befindet, dann eine öffentliche IP und einen „weitergeleiteten“ Port.
  • Tunnel (PPTP/OpenVPN/L2TP+IPSec usw.) zum zentralen Knoten, über den darauf zugegriffen werden kann.

Daher benötigen Sie „mein Fahrrad“, wenn Standardmethoden nicht zu Ihnen passen, zum Beispiel:

  1. Die Geräte befinden sich hinter NAT und bis auf das übliche http (Port 80) ist alles geschlossen. Dies ist eine völlig normale Situation für große bundesstaatliche Unternehmensnetzwerke. Sie können Ports registrieren, aber nicht sofort, nicht schnell und nicht für Sie.
  2. Instabiler und/oder „enger“ Kommunikationskanal. Niedrige Geschwindigkeit, ständige Verluste. Schmerz und Frustration beim Versuch, einen Tunnel zu organisieren.
  3. Ein teurer Kommunikationskanal, bei dem buchstäblich jedes Megabyte zählt. Zum Beispiel Satellitenkommunikation. Plus lange Verzögerungen und ein „schmales“ Band.
  4. Eine Situation, in der Sie mit einer großen Anzahl kleiner Router „jonglieren“ müssen, auf denen einerseits OpenWrt/Lede zur Erweiterung der Fähigkeiten installiert ist und andererseits die Ressourcen (Speicher) des Routers nicht ausreichen für alles.

Anzahl mal notieren Was hindert Sie daran, ein Flash-Laufwerk im USB-Anschluss des Routers zu installieren und den Speicher des Routers zu erweitern?

Am häufigsten beziehen sich die Anforderungen auf die Kosten der Gesamtlösung, manchmal spielt aber auch der Formfaktor eine entscheidende Rolle. Zum Beispiel gibt es vor Ort einen TP-Link ML3020, dessen einziger USB-Anschluss für ein 2G/3G-Modem verwendet wird, das alles ist in eine Art kleines Plastikgehäuse eingewickelt und irgendwo hoch, hoch (auf dem Mast) platziert. weit, weit weg (im Feld, 30 km von der nächsten Basisstation des Mobilfunkanbieters entfernt). Ja, Sie können einen USB-Hub anschließen und die Anzahl der Anschlüsse erweitern, aber die Erfahrung zeigt, dass dies umständlich und unzuverlässig ist.

Deshalb habe ich versucht, Ihnen meine typische Situation zu beschreiben: „Irgendwo weit, weit weg steht ein sehr wichtiger, einsamer und kleiner Router, auf dem Linux läuft. Es ist wichtig, mindestens einmal am Tag zu wissen, dass er „am Leben“ ist und bei Bedarf Befehle an ihn gesendet werden, zum Beispiel „Schatz, neu starten!“

Kommen wir zur Umsetzung:

1) Auf der Router-Seite müssen Sie über cron alle 5 Minuten oder wann immer Sie möchten eine HTTP-Anfrage mit wget an den Server senden, das Ergebnis der Anfrage in einer Datei speichern und die Datei ausführbar machen , und führen Sie es aus.

Meine Cron-Zeile sieht in etwa so aus:

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

, wo:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai ist die Domäne meines Servers. Lassen Sie mich gleich anmerken: Ja, Sie können eine bestimmte IP-Adresse des Servers angeben, das haben wir früher gemacht, bis unser Staat in einem gerechten Kampfimpuls, ich werde sagen, ich weiß nicht, den Zugang zum Löwen blockierte Anteil der DigitalOcean- und Amazon-„Clouds“. Wenn Sie eine symbolische Domäne verwenden und ein solcher Vorfall auftritt, können Sie problemlos eine Backup-Cloud erstellen, die Domäne dorthin umleiten und die Geräteüberwachung wiederherstellen.

a.php ist der Name des serverseitigen Skripts. Ja, ich weiß, dass es falsch ist, Variablen und Dateinamen mit demselben Buchstaben zu benennen ... Ich schlage vor, dass wir auf diese Weise beim Senden einer Anfrage ein paar Bytes sparen :)
u – Benutzername, Hardware-Login
p - Passwort
„-O /tmp/wa.sh“ ist eine Datei auf dem Remote-Router, in der die Serverantwort, beispielsweise der Neustartbefehl, gespeichert wird.

Anmerkung Nummer zwei: Ahhh, warum verwenden wir wget und nicht Curl, weil man über Curl https-Anfragen nicht mit GET, sondern mit POST senden kann? Ahhh, weil, wie im alten Witz „NE klettert ins Glas!“ Curl enthält Verschlüsselungsbibliotheken mit einer Größe von etwa 2 MB. Aus diesem Grund ist es unwahrscheinlich, dass Sie beispielsweise ein Image für einen kleinen TP-LINK ML3020 zusammenstellen können. Und mit wget – bitte.

2) Auf der Serverseite (ich habe Ubuntu) werden wir Zabbix verwenden. Warum: Ich möchte, dass es schön (mit Grafiken) und praktisch ist (Befehle über das Kontextmenü senden). Zabbix hat so etwas Wunderbares wie den Zabbix-Agenten. Über den Agenten rufen wir ein PHP-Skript auf dem Server auf, das Informationen darüber zurückgibt, ob sich unser Router im erforderlichen Zeitraum registriert hat. Um Informationen über Registrierungszeit und Befehle für Geräte zu speichern, verwende ich MySQL, eine separate Benutzertabelle mit ungefähr den folgenden Feldern:

		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;

Alle Quellen können aus dem Git-Repository heruntergeladen werden unter: https://github.com/BazDen/iotnet.online.git
Jetzt werden PHP-Skripte auf der Serverseite platziert (der Einfachheit halber können sie im Ordner /usr/share/zabbix/ abgelegt werden):

a.php-Datei:

<?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-Datei (dies ist das Skript des Zabbix-Agenten mit dem Namen):

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

Nun, der letzte Schritt: Registrieren eines Agenten und Hinzufügen von Zeitplänen.

Wenn Sie den Zabbix-Agenten noch nicht installiert haben, dann:

apt-get install zabbix-agent

Bearbeiten Sie die Datei /etc/zabbix/zabbix_agentd.conf.

Fügen Sie die Zeile hinzu:

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

, wo:
test ist der Name unseres Agenten
„php /usr/share/zabbix/agent.php Benutzerpasswort“ – ein aufgerufenes Skript, das die Geräteregistrierungsdaten angibt.

Diagramme hinzufügen: Öffnen Sie die Zabbix-Weboberfläche und wählen Sie aus dem Menü:
Einstellungen -> Netzwerkknoten -> Netzwerkknoten erstellen. Hier reicht es aus, den Namen des Netzwerkhosts, seiner Gruppe und die Standard-Agentenschnittstelle anzugeben:

Fernüberwachung und -steuerung von Lunix/OpenWrt/Lede-basierten Geräten über Port 80…

Jetzt müssen wir ein Datenelement für diesen Netzwerkknoten hinzufügen. Achten Sie auf zwei Felder: „Schlüssel“ – das ist genau der Parameter, den wir in die Datei /etc/zabbix/zabbix_agentd.conf geschrieben haben (in unserem Fall ist es test), und „Aktualisierungsintervall“ – ich habe ihn auf 5 Minuten eingestellt , denn und das Gerät wird auch alle fünf Minuten auf dem Server registriert.

Fernüberwachung und -steuerung von Lunix/OpenWrt/Lede-basierten Geräten über Port 80…

Nun, fügen wir ein Diagramm hinzu. Ich empfehle, als Rendering-Stil „Füllen“ zu wählen.

Fernüberwachung und -steuerung von Lunix/OpenWrt/Lede-basierten Geräten über Port 80…

Die Ausgabe ist etwas sehr Lakonisches, zum Beispiel so:

Fernüberwachung und -steuerung von Lunix/OpenWrt/Lede-basierten Geräten über Port 80…

Auf die berechtigte Frage „Hat es sich gelohnt?“ antworte ich: Na ja, siehe natürlich „Gründe für die Entwicklung eines Fahrrads“ am Anfang des Artikels.

Wenn meine erste graphomanische Erfahrung das Interesse der Leser weckt, dann möchte ich in den folgenden Artikeln beschreiben, wie man Befehle an entfernte Geräte sendet. Es ist uns auch gelungen, das gesamte Schema für Geräte basierend auf RouterOS (Mikrotik) umzusetzen.

Source: habr.com

Kommentar hinzufügen