Monitoraggio e controllo remoto di dispositivi basati su Lunix/OpenWrt/Lede tramite la porta 80...

Ciao a tutti, questa è la mia prima esperienza su Habré. Voglio scrivere su come gestire le apparecchiature di rete su una rete esterna in modo non standard. Cosa significa non standard: nella maggior parte dei casi, per gestire apparecchiature su una rete esterna è necessario:

  • Indirizzo IP pubblico. Bene, o se l'attrezzatura si trova dietro il NAT di qualcuno, allora un IP pubblico e una porta "inoltrata".
  • Tunnel (PPTP/OpenVPN/L2TP+IPSec, ecc.) al nodo centrale attraverso il quale sarebbe accessibile.

Pertanto, avrai bisogno della “mia bici” quando i metodi standard non ti si addicono, ad esempio:

  1. L'attrezzatura si trova dietro NAT e, ad eccezione del solito http (porta 80), tutto è chiuso. Questa è una situazione del tutto normale per le grandi reti aziendali federali. Possono registrare i porti, ma non subito, non rapidamente e non per te.
  2. Canale di comunicazione instabile e/o “stretto”. Bassa velocità, perdite costanti. Dolore e frustrazione quando si tenta di organizzare un tunnel.
  3. Un canale di comunicazione costoso, dove conta letteralmente ogni megabyte. Ad esempio, le comunicazioni satellitari. Inoltre lunghi ritardi e una banda “stretta”.
  4. Una situazione in cui è necessario "destreggiarsi" tra un gran numero di piccoli router, sui quali, da un lato, è installato OpenWrt/Lede per espandere le capacità e, dall'altro, le risorse (memoria) del router non sono sufficienti per tutto.

Annota il numero di volte Cosa ti impedisce di installare un'unità flash nella porta USB del router ed espandere la memoria del router?

Molto spesso i requisiti riguardano il costo della soluzione nel suo insieme, ma a volte anche il fattore forma gioca un ruolo chiave. Ad esempio, sul sito c'è un TP-Link ML3020, la sua unica porta USB è utilizzata per un modem 2G/3G, tutto questo è avvolto in una sorta di piccola custodia di plastica e posizionato da qualche parte in alto, in alto (sull'albero), molto, molto lontano (sul campo, a 30 km dalla stazione base dell'operatore di telefonia mobile più vicina). Sì, puoi collegare un hub USB ed espandere il numero di porte, ma l'esperienza dimostra che è complicato e inaffidabile.

Quindi, ho provato a descriverti la mia situazione tipica: “da qualche parte molto, molto lontano, c'è un router molto importante, solitario e piccolo che esegue Linux. È importante sapere almeno una volta al giorno che è "vivo" e, se necessario, gli vengono inviati dei comandi, ad esempio "tesoro, riavvia!"

Passiamo alla realizzazione:

1) Lato router, tramite cron, ogni 5/10/1440 minuti, o quando si vuole, bisogna inviare una richiesta http al server utilizzando wget, salvare il risultato della richiesta su un file, rendere eseguibile il file ed eseguirlo.

La mia linea cron è simile a questa:

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

, dove:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai è il dominio del mio server. Faccio subito notare: sì, puoi specificare un indirizzo IP specifico del server, lo facevamo finché il nostro stato, in un giusto impulso di lotta, dirò, non lo so, ha bloccato l'accesso al leone quota delle “nuvole” DigitalOcean e Amazon. Se utilizzi un dominio simbolico, se si verifica un incidente del genere, puoi facilmente creare un cloud di backup, reindirizzare il dominio ad esso e ripristinare il monitoraggio del dispositivo.

a.php è il nome dello script lato server. Sì, lo so che è sbagliato nominare variabili e nomi di file con la stessa lettera... suggerisco di risparmiare qualche byte in questo modo quando si invia una richiesta :)
u - nome utente, accesso hardware
p - parola d'ordine
"-O /tmp/wa.sh" è un file sul router remoto in cui verrà salvata la risposta del server, ad esempio il comando di riavvio.

Nota numero due: Ahhh, perché usiamo wget e non curl, perché tramite curl puoi inviare richieste https non con GET, ma con POST? Ahhh perché, come nella vecchia battuta “NE si arrampica nel barattolo!” curl include librerie di crittografia di circa 2 MB di dimensione e per questo motivo è improbabile che tu possa assemblare un'immagine per un piccolo TP-LINK ML3020, ad esempio. E con wget, per favore.

2) Sul lato server (ho Ubuntu) useremo Zabbix. Perché: voglio che sia bello (con i grafici) e comodo (inviare comandi tramite il menu contestuale). Zabbix ha una cosa meravigliosa come l'agente Zabbix. Attraverso l'agente, chiameremo uno script PHP sul server, che restituirà informazioni sulla registrazione del nostro router durante il periodo di tempo richiesto. Per memorizzare informazioni sul tempo di registrazione e sui comandi per i dispositivi, utilizzo MySQL, una tabella utente separata con approssimativamente i seguenti campi:

		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;

Tutti i sorgenti possono essere scaricati dal repository Git all'indirizzo: https://github.com/BazDen/iotnet.online.git
Ora gli script PHP vengono posizionati sul lato server (per comodità, possono essere posizionati nella cartella /usr/share/zabbix/):

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

File Agent.php (questo è lo script dell'agente zabbix chiamato):

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

Bene, la fase finale: registrare un agente e aggiungere orari.

Se non hai ancora installato l'agente zabbix, allora:

apt-get install zabbix-agent

Modifica il file /etc/zabbix/zabbix_agentd.conf.

Aggiungi la riga:

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

, dove:
test è il nome del nostro agente
"php /usr/share/zabbix/agent.php password utente" - uno script chiamato che indica i dati di registrazione del dispositivo.

Aggiunta di grafici: aprire l'interfaccia web di zabbix, selezionare dal menu:
Impostazioni -> Nodi di rete -> Crea un nodo di rete. Qui è sufficiente specificare il nome dell'host di rete, il suo gruppo e l'interfaccia dell'agente predefinita:

Monitoraggio e controllo remoto di dispositivi basati su Lunix/OpenWrt/Lede tramite la porta 80...

Ora dobbiamo aggiungere un elemento dati per questo nodo di rete. Presta attenzione a due campi: "chiave" - ​​questo è esattamente il parametro che abbiamo scritto nel file /etc/zabbix/zabbix_agentd.conf (nel nostro caso è test) e "intervallo di aggiornamento" - l'ho impostato su 5 minuti , perché e anche l'apparecchiatura viene registrata sul server una volta ogni cinque minuti.

Monitoraggio e controllo remoto di dispositivi basati su Lunix/OpenWrt/Lede tramite la porta 80...

Bene, aggiungiamo un grafico. Consiglio di scegliere "Riempi" come stile di rendering.

Monitoraggio e controllo remoto di dispositivi basati su Lunix/OpenWrt/Lede tramite la porta 80...

L'output è qualcosa di molto laconico, ad esempio come questo:

Monitoraggio e controllo remoto di dispositivi basati su Lunix/OpenWrt/Lede tramite la porta 80...

Alla domanda ragionevole: "ne è valsa la pena?", Risponderò: beh, ovviamente, vedi "motivi per creare una bicicletta" all'inizio dell'articolo.

Se la mia prima esperienza grafomane suscita l'interesse dei lettori, nei seguenti articoli voglio descrivere come inviare comandi ad apparecchiature remote. Siamo anche riusciti a implementare l'intero schema per i dispositivi basati su RouterOS (Mikrotik).

Fonte: habr.com

Aggiungi un commento