Lunix/OpenWrt/Lede-pohjaisten laitteiden etävalvonta ja ohjaus portin 80 kautta…

Hei kaikille, tämä on ensimmäinen kokemukseni Habresta. Haluan kirjoittaa kuinka hallita verkkolaitteita ulkoisessa verkossa epätyypillisellä tavalla. Mitä epästandardi tarkoittaa: useimmissa tapauksissa tarvitset ulkoisen verkon laitteiden hallintaan:

  • Julkinen IP-osoite. No, tai jos laite on jonkun NAT:n takana, niin julkinen IP ja "edelleen" portti.
  • Tunneli (PPTP/OpenVPN/L2TP+IPSec jne.) keskussolmuun, jonka kautta se olisi käytettävissä.

Siksi tarvitset "minun pyöräni", kun vakiomenetelmät eivät sovi sinulle, esimerkiksi:

  1. Laitteet sijaitsevat NAT:n takana ja tavallista http:tä (portti 80) lukuun ottamatta kaikki on kiinni. Tämä on täysin normaali tilanne suurille liittovaltion yritysverkostoille. He voivat rekisteröidä portteja, mutta eivät heti, eivät nopeasti eivätkä sinulle.
  2. Epävakaa ja/tai "kapea" viestintäkanava. Pieni nopeus, jatkuvat häviöt. Kipu ja turhautuminen tunnelin järjestämisessä.
  3. Kallis viestintäkanava, jossa kirjaimellisesti jokainen megatavu on tärkeä. Esimerkiksi satelliittiviestintä. Plus pitkät viiveet ja "kapea" kaista.
  4. Tilanne, jossa joudut "jonglöörimään" suuren määrän pieniä reitittimiä, joihin toisaalta on asennettu OpenWrt/Lede toimintojen laajentamiseksi, ja toisaalta reitittimen resurssit (muisti) eivät riitä kaikesta.

Huomaa numerot Mikä estää sinua asentamasta flash-asemaa reitittimen USB-porttiin ja laajentamasta reitittimen muistia?

Useimmiten vaatimukset koskevat ratkaisun kokonaiskustannuksia, mutta joskus myös muototekijällä on keskeinen rooli. Paikan päällä on esimerkiksi TP-Link ML3020, jonka ainoa USB-portti on 2G/3G-modeemilla, kaikki tämä on kääritty johonkin pieneen muovikoteloon ja sijoitettu jonnekin korkealle, korkealle (mastoon), kaukana, kaukana (pellolla, 30 km lähimmästä matkapuhelinoperaattorin tukiasemasta). Kyllä, voit kytkeä USB-keskittimen ja laajentaa porttien määrää, mutta kokemus osoittaa, että tämä on hankalaa ja epäluotettavaa.

Joten yritin kuvailla tyypillistä tilannettani: "jossain kaukana, kaukana, on erittäin tärkeä, yksinäinen ja pieni reititin, joka käyttää Linuxia. On tärkeää tietää vähintään kerran päivässä, että hän on "elossa" ja tarvittaessa hänelle lähetetään komentoja, esimerkiksi "kulta, käynnistä uudelleen!"

Siirrytään toteutukseen:

1) Reitittimen puolella, cronin kautta, 5/10/1440 minuutin välein tai milloin haluat, sinun on lähetettävä http-pyyntö palvelimelle wgetillä, tallennettava pyynnön tulos tiedostoon, tehtävä tiedosto suoritettavaksi , ja suorita se.

Oma cron line näyttää suunnilleen tältä:

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

, jossa:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai on palvelimeni verkkotunnus. Huomautan heti: kyllä, voit määrittää palvelimelle tietyn IP-osoitteen, teimme näin siihen asti, kunnes tilamme, vanhurskaan kamppailun impulssina, sanon, en tiedä, esti pääsyn leijonanosa DigitalOceanin ja Amazonin ”pilvistä”. Jos käytät symbolista toimialuetta, voit helposti nostaa varmuuskopiopilven, ohjata verkkotunnuksen siihen ja palauttaa laitteen valvonnan.

a.php on palvelinpuolen komentosarjan nimi. Kyllä, tiedän, että on väärin nimetä muuttujat ja tiedostonimet samalla kirjaimella... Ehdotan, että tällä tavalla säästämme muutaman tavun pyyntöä lähetettäessä :)
u - käyttäjätunnus, laitteiston sisäänkirjautuminen
p - salasana
"-O /tmp/wa.sh" on tiedosto etäreitittimessä, johon palvelimen vastaus, esimerkiksi reboot-komento, tallennetaan.

Huomautus numero kaksi: Ahhh, miksi käytämme wgetiä eikä curlia, koska curlin kautta voi lähettää https-pyyntöjä ei GET:llä vaan POSTilla? Ahhh koska, kuten vanhassa vitsissä "NE kiipeää purkkiin!" curl sisältää noin 2 Mt:n salauskirjastoja, ja tämän vuoksi on epätodennäköistä, että pystyt koomaan kuvan esimerkiksi pienelle TP-LINK ML3020:lle. Ja wgetillä - kiitos.

2) Palvelinpuolella (minulla on Ubuntu) käytämme Zabbixia. Miksi: Haluan sen olevan kaunis (kaavioiden kanssa) ja kätevä (lähetä komentoja kontekstivalikon kautta). Zabbixilla on niin ihana asia kuin zabbix-agentti. Agentin kautta kutsumme palvelimelle PHP-skriptin, joka palauttaa tiedon siitä, onko reitittimemme rekisteröitynyt vaaditun ajanjakson aikana. Tietojen tallentamiseen rekisteröintiajasta, komennoista laitteille, käytän MySQL:ää, erillistä taulukkoa käyttäjistä, jossa on suunnilleen seuraavat kentät:

		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;

Kaikki lähteet voidaan ladata Git-arkistosta osoitteesta: https://github.com/BazDen/iotnet.online.git
Nyt palvelinpuolelle sijoitetut PHP-skriptit (mukavuussyistä ne voidaan sijoittaa kansioon /usr/share/zabbix/):

a.php tiedosto:

<?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-tiedosto (tämä on zabbix-agentin komentosarja):

<?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, viimeinen vaihe: agentin rekisteröiminen ja aikataulujen lisääminen.

Jos et ole vielä asentanut zabbix-agenttia, toimi seuraavasti:

apt-get install zabbix-agent

Muokkaa tiedostoa /etc/zabbix/zabbix_agentd.conf.

Lisää rivi:

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

, jossa:
testi on edustajamme nimi
"php /usr/share/zabbix/agent.php käyttäjän salasana" - kutsuttu komentosarja, joka ilmaisee laitteen rekisteröintitiedot.

Kaavioiden lisääminen: avaa zabbix-verkkokäyttöliittymä, valitse valikosta:
Asetukset -> Verkkosolmut -> Luo verkkosolmu. Tässä riittää, kun määrität verkkoisännän nimen, sen ryhmän ja oletusagentin rajapinnan:

Lunix/OpenWrt/Lede-pohjaisten laitteiden etävalvonta ja ohjaus portin 80 kautta…

Nyt meidän on lisättävä dataelementti tälle verkkosolmulle. Kiinnitä huomiota kahteen kenttään: "avain" - tämä on juuri se parametri, jonka kirjoitimme /etc/zabbix/zabbix_agentd.conf-tiedostoon (tapauksessamme se on testi), ja "päivitysväli" - asetin sen 5 minuuttiin , koska ja laitteet rekisteröidään myös palvelimelle viiden minuutin välein.

Lunix/OpenWrt/Lede-pohjaisten laitteiden etävalvonta ja ohjaus portin 80 kautta…

No, lisätään kaavio. Suosittelen valitsemaan renderöintityyliksi "Täytä".

Lunix/OpenWrt/Lede-pohjaisten laitteiden etävalvonta ja ohjaus portin 80 kautta…

Tulos on jotain hyvin lakonista, esimerkiksi tällaista:

Lunix/OpenWrt/Lede-pohjaisten laitteiden etävalvonta ja ohjaus portin 80 kautta…

Kohtuulliseen kysymykseen: "oliko se sen arvoista?" Vastaan: no, tietysti, katso "syitä polkupyörän luomiseen" artikkelin alussa.

Jos ensimmäinen grafomaanikokemukseni herättää lukijoiden kiinnostuksen, niin seuraavissa artikkeleissa haluan kuvata, kuinka komentoja lähetetään etälaitteisiin. Onnistuimme myös toteuttamaan koko järjestelmän RouterOS:ään (Mikrotik) perustuville laitteille.

Lähde: will.com

Lisää kommentti