FjÀrrövervakning och hantering av enheter baserade pÄ Lunix/OpenWrt/Lede genom port 80...

Hej alla, detta Àr min första erfarenhet pÄ Habra. Jag vill skriva om hur man pÄ ett icke-standardiserat sÀtt hanterar nÀtverksutrustning i ett externt nÀtverk. Vad betyder icke-standardiserat: i de flesta fall, för att hantera utrustning i ett externt nÀtverk behöver du:

  • En offentlig IP-adress. Eller om utrustningen Ă€r bakom nĂ„gons NAT, sĂ„ en offentlig IP och en 'forwardad' port.
  • En tunnel (PPTP/OpenVPN/L2TP+IPSec etc.) till en central nod, genom vilken den skulle vara tillgĂ€nglig.

DÀrför kommer 'min cykel' att behövas nÀr standardmetoderna inte passar dig, till exempel:

  1. Utrustningen ligger bakom NAT och förutom vanlig http (port 80) Àr allt stÀngt. En helt normal situation för stora federala företagsnÀtverk. Det kan ta tid att skriva in portar, och de gör det inte omedelbart, snabbt eller för dig.
  2. Instabil och/eller 'smal' kommunikationskanal. LÄg hastighet, stÀndiga förluster. SmÀrta och besvikelse vid försök att organisera en tunnel.
  3. Kostsam kommunikationskanal, dÀr varje megabyte bokstavligt talat rÀknas. Till exempel satellitkommunikation. Dessutom stora fördröjningar och en 'smal' bandbredd.
  4. En situation dÀr du behöver 'jonglera' med en stor mÀngd smÄ routrar, dÀr OpenWrt/Lede Àr installerat pÄ ena sidan för att utöka möjligheterna, medan tillgÄngen pÄ resurser (minne) pÄ routern lÄngt ifrÄn rÀcker till allt.

Notering nummer ett Vad hindrar dig frÄn att sÀtta in ett 'flashminne' i USB-porten pÄ routern för att utöka routerns minne?

Oftast handlar det om kostnadskrav pÄ lösningen som helhet, men ibland spelar formfaktorn ocksÄ en avgörande roll. Till exempel, pÄ platsen finns TP-Link ML3020, vars enda USB-port anvÀnds av en 2G/3G-modem, allt Àr inpackat i nÄgot litet plastfodral och placerat högt (pÄ en mast), lÄngt borta (pÄ fÀltet, 30 km frÄn den nÀrmaste mobiloperatörens basstation). Ja, du kan sÀtta in en USB-hub och öka antalet portar, men erfarenheten visar att detta Àr skrymmande och opÄlitligt.

SÄ jag har försökt beskriva min typiska situation: 'nÄgonstans lÄngt borta, finns en mycket viktig, ensam och liten router som kör Linux. Det Àr viktigt att veta minst en gÄng om dagen att den Àr "levande" och vid behov skicka kommandon till den, till exempel "sol, starta om!"

LÄt oss gÄ vidare till implementeringen:

1) PÄ routern, via cron var 5/10/1440 minut, eller nÀr som helst, behöver vi skicka en http-förfrÄgan till servern med hjÀlp av wget, spara resultatet av förfrÄgan i en fil, göra filen körbar och köra den.

Min rad i cron ser ungefÀr ut sÄ hÀr:

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

, dÀr:
xn--80abgfbdwanb2akugdrd3a2e5gsbj.xn--p1ai — domĂ€n för min server. Jag nĂ€mner direkt: ja, det gĂ„r att ange en specifik ip-adress till servern, vi gjorde sĂ„ tidigare, men vĂ„rt land, i en rĂ€ttfĂ€rdig strĂ€van att bekĂ€mpa nĂ„got jag inte vet vad, stĂ€ngde tillgĂ„ngen till en stor del av 'molnen' frĂ„n DigitalOcean och Amazon. Om du anvĂ€nder en symbolisk domĂ€n kan du, om en sĂ„dan situation uppstĂ„r, enkelt sĂ€tta upp ett reservmoln, omdirigera domĂ€nen dit och Ă„terupprĂ€tta övervakning av enheter.

a.php — namnet pĂ„ skriptet pĂ„ servern. Ja, jag vet att det Ă€r fel, att namnge variabler och filnamn med en bokstav
 lĂ„t oss sĂ€ga att vi sparar nĂ„gra byte för att skicka förfrĂ„gan 🙂
u — anvĂ€ndarnamn, inloggning för enheten
p — lösenord
‘-O /tmp/wa.sh’ — filen pĂ„ den avlĂ€gsna routern dĂ€r serverns svar kommer att sparas, som till exempel kommandot reboot.

Anteckning nummer tvĂ„: Aaaa, varför anvĂ€nder vi wget istĂ€llet för curl, eftersom man genom curl kan skicka https-förfrĂ„gningar och inte bara GET utan Ă€ven POST? Aaaa, dĂ€rför att, som i det gamla skĂ€mtet, ‘Det gĂ„r inte att fĂ„ ner det i krukan!’. Curl innehĂ„ller krypteringsbibliotek som Ă€r runt 2 MB stora, och dĂ€rför Ă€r det osannolikt att du kan skapa en bild för en liten TP-LINK ML3020 till exempel. Men med wget — absolut.

2) PÄ servern (i mitt fall Ubuntu) kommer vi att anvÀnda Zabbix. Varför: jag vill att det ska vara snyggt (med diagram) och bekvÀmt (skicka kommandon via kontextmenyn). Zabbix har en fin funktion kallad zabbix-agent. Via agenten kommer vi att anropa ett php-skript pÄ servern, som kommer att returnera information om huruvida vÄr router registrerades under den angivna tidsperioden. För att lagra information om registreringstider och kommandon för enheter anvÀnder jag MySQL, en separat tabell users med ungefÀr dessa fÀlt:

		SKAPA TABELL `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, // sista anslutningstid
		  `last_ip` varchar(20) NOT NULL, // sista anslutningens IP
		  `last_port` int(11) NOT NULL, // sista anslutningens port
		  `task` text NOT NULL, // uppgift som routern fÄr
		  `reg_task` varchar(150) NOT NULL, // "regelbundet" uppgift, om vi vill att uppgiften ska utföras alltid vid registrering
		  `last_task` text NOT NULL, // uppgiftslogg
		  `response` text NOT NULL, // hÀr skrivas svaret frÄn enheten
		  `seq` int(11) NOT NULL
		) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Alla kÀllor kan hÀmtas frÄn Git-repositoriet pÄ adressen: https://github.com/BazDen/iotnet.online.git
Nu PHP-skript som placeras pÄ serversidan (för bekvÀmlighet kan de lÀggas i mappen /usr/share/zabbix/):

Fil a.php:

set_charset("utf8");
	// HÀr söker vi efter vÄr router i databastabellen
	$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();
		// HĂ€r skickar vi routern dess uppgifter
		echo $task;
		echo "n";
		echo $reg_task;
		// HÀr skriver vi tidpunkten för svaret och sjÀlv svaret frÄn routern
		$response_history="[".date("Y-m-d H:i")."] ".$message;
		// Uppgiften har skickats, nu mÄste vi ta bort den, och efter att den har tagits bort markerar vi i loggen att uppgiften har slutförts
		$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();
		}
		// Nu mÄste vi spara tidpunkten för registreringen av anvÀndaren, dess ip och meddelandet frÄn dem. För nu bara meddelandet
		$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();
	}
	// Om vi inte hittade routern i vÄr databas, eller dess status Àr "inaktiv", kommer kommandot reboot... att skickas till den
	// Varför sÄ hÄrt? För eftersom routrar ibland försvinner, Àr det ett litet sÀtt att straffa "nya Àgare". 
	else
	{
	echo "reboot";
	}
	$sql_users->close();
	?>

Filen agent.php (detta Àr skriptet för den anropade zabbix-agenten):

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();
	// Datautbyte sker genom seq-fÀltet. Vid registrering stÀller utrustningen in detta fÀlt till "1"
	if (($sql_users->num_rows)==1){
		$sql_users->fetch();
		echo $seq;
	}
		
	// NollstÀller $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();
?>		

Och den sista etappen: registrera agenten och lÀgga till diagram.

Om du inte har installerat zabbix-agent Ànnu:

apt-get install zabbix-agent

Redigera filen /etc/zabbix/zabbix_agentd.conf.

LĂ€gg till raden:

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

, dÀr:
test — namnet pĂ„ vĂ„r agent
„php /usr/share/zabbix/agent.php user password“ — skriptet som anropas med autentiseringsuppgifterna för enheten.

LÀgga till diagram: öppna zabbix webgrÀnssnitt, vÀlj i menyn:
InstÀllning -> NÀtverksnoder -> Skapa nÀtverksnod. HÀr behöver du bara ange namnet pÄ nÀtverksnod, dess grupp och agentens standardgrÀnssnitt:

FjÀrrövervakning och hantering av enheter baserade pÄ Lunix/OpenWrt/Lede genom port 80...

Nu behöver vi för denna nĂ€tverksnod lĂ€gga till en datakomponent. Observera de tvĂ„ fĂ€lten: „nyckel“ — det Ă€r den parameter som vi angav i filen /etc/zabbix/zabbix_agentd.conf (i vĂ„rt fall test), och „uppdateringsintervall“ — jag sĂ€tter 5 minuter, eftersom utrustningen registreras pĂ„ servern ocksĂ„ en gĂ„ng var femte minut.

FjÀrrövervakning och hantering av enheter baserade pÄ Lunix/OpenWrt/Lede genom port 80...

Och sĂ„ lĂ€gger vi till diagrammet. Jag rekommenderar att vĂ€lja „Fyllning“ som ritstil.

FjÀrrövervakning och hantering av enheter baserade pÄ Lunix/OpenWrt/Lede genom port 80...

Resultatet blir nÄgot ganska minimalistiskt, till exempel sÄ hÀr:

FjÀrrövervakning och hantering av enheter baserade pÄ Lunix/OpenWrt/Lede genom port 80...

Till den rimliga frĂ„gan: „var det vĂ€rt det?“, svarar jag: sjĂ€lvklart, se „skĂ€len till att skapa cykeln“ i början av artikeln.

Om min första grafomana erfarenhet vÀcker intresse hos lÀsarna, vill jag i nÀsta artiklar beskriva hur man skickar kommandon till fjÀrrutrustningen. Jag har ocksÄ lyckats implementera hela systemet Àven för enheter baserade pÄ RouterOS (Mikrotik-enheter).

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster