Hallo zusammen, das ist meine erste Erfahrung auf Habré. Ich möchte darüber schreiben, wie man Netzwerkgeräte im externen Netzwerk unkonventionell verwaltet. Was unkonventionell bedeutet: In den meisten Fällen benötigen Sie zur Verwaltung von Geräten im externen Netzwerk:
- Eine öffentliche IP-Adresse. Oder, wenn das Gerät hinter einem NAT steht, dann die öffentliche IP und der 'durchgereichte' Port.
- Einen Tunnel (PPTP/OpenVPN/L2TP+IPSec usw.) zum zentralen Knoten, über den der Zugriff möglich wäre.
Deshalb wird 'mein Fahrrad' benötigt, wenn die Standardmethoden nicht funktionieren, zum Beispiel:
- Das Gerät befindet sich hinter einem NAT und neben dem üblichen http (Port 80) ist alles gesperrt. Eine ganz normale Situation für große föderale Unternehmensnetze. Ports zu öffnen – das können sie, aber nicht sofort, nicht schnell und nicht für Sie.
- Eine instabile und/oder 'schmale' Verbindung. Geringe Geschwindigkeit, ständige Paketverluste. Schmerz und Enttäuschung beim Versuch, einen Tunnel zu organisieren.
- Ein teurer Kommunikationskanal, wo buchstäblich jedes Megabyte zählt. Zum Beispiel Satellitenkommunikation. Dazu kommen große Verzögerungen und eine 'schmale' Bandbreite.
- Eine Situation, in der Sie mit einer großen Anzahl kleiner Router jonglieren müssen, auf denen einerseits OpenWrt/Lede zur Erweiterung der Möglichkeiten installiert ist, andererseits aber der Speicher des Routers bei weitem nicht ausreicht.
Hinweis Nummer eins Was hindert Sie daran, einen USB-Stick in den USB-Port des Routers zu stecken und den Speicher des Routers zu erweitern?
Häufig sind die Kosten für die Gesamtlösung entscheidend, aber manchmal spielt auch der Formfaktor eine Schlüsselrolle. Zum Beispiel gibt es am Standort einen TP-Link ML3020, dessen einziger USB-Port für ein 2G/3G-Modem verwendet wird, das alles ist in ein kleines Plast Gehäuse verpackt und irgendwo hoch (auf einem Mast) und weit weg (im Feld, 30 km von der nächstgelegenen Mobilfunkbasisstation) platziert. Ja, man könnte einen USB-Hub anschließen und die Anzahl der Ports erweitern, aber die Erfahrung zeigt, dass das unhandlich und unzuverlässig ist.
Also, ich habe versucht, Ihnen meine typische Situation zu beschreiben: 'irgendwo weit weg steht ein sehr wichtiger, einsamer und kleiner Router mit Linux. Es ist wichtig, mindestens einmal am Tag zu wissen, dass er "lebt" und bei Bedarf ihm Befehle zu senden, zum Beispiel "Sonnenstrahl, starte neu!"
Kommen wir zur Umsetzung:
1) Auf der Router-Seite sollte alle 5/10/1440 Minuten oder jederzeit ein HTTP-Request an den Server mittels wget gesendet werden. Das Ergebnis der Anfrage wird in einer Datei gespeichert, die Datei wird ausführbar gemacht und dann ausgeführt.
Meine Zeile im Cron sieht ungefähr 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 — das ist die Domain meines Servers. Ich merke gleich an: Ja, man kann auch eine spezifische IP-Adresse des Servers angeben. Das haben wir früher so gemacht, bis unser Staat, in einem heiligen Eifer gegen irgendetwas, das ich nicht kenne — den Zugang zu einem Großteil der „Clouds“ von DigitalOcean und Amazon gesperrt hat. Bei Verwendung einer symbolischen Domain können Sie im Falle eines solchen Vorfalls einfach eine Backup-Cloud erstellen, die Domain umleiten und das Monitoring der Geräte wiederherstellen.
a.php — das ist der Name des Skripts auf der Serverseite. Ja, ich weiß, dass es nicht richtig ist, Variablen und Dateinamen mit einem einzigen Buchstaben zu benennen... ich schlage vor, dass wir dies als ein Mittel betrachten, einige Bytes beim Senden der Anfrage zu sparen 🙂
u — der Benutzername, Login des Geräts
p — das Passwort
„-O /tmp/wa.sh“ — die Datei auf dem Remote-Router, in der die Antwort des Servers gespeichert wird, zum Beispiel der Befehl reboot.
Hinweis Nummer zwei: Aaaa, warum verwenden wir wget und nicht curl? Schließlich können mit curl HTTPS-Anfragen gesendet werden, und zwar nicht mit GET, sondern mit POST? Aaaa, weil es wie in dem alten Witz ist: „In die Krippe passt es nicht!“ In curl sind Verschlüsselungsbibliotheken von etwa 2 MB enthalten, und deshalb wird es Ihnen wahrscheinlich schwerfallen, ein Image für einen kleinen TP-LINK ML3020 zum Beispiel zu erstellen. Mit wget geht das allerdings problemlos.
2) Auf der Serverseite (bei mir ist das Ubuntu) verwenden wir Zabbix. Warum: Ich möchte, dass es schön (mit Grafiken) und praktisch (Befehle über das Kontextmenü senden) ist. Zabbix hat so eine wunderbare Funktion, wie den Zabbix-Agent. Über diesen Agenten werden wir ein PHP-Skript aufrufen, Server, welches Informationen darüber zurückgibt, ob unser Router sich im erforderlichen Zeitraum registriert hat. Zum Speichern der Registrierungsinformationen und der Befehle für die Geräte verwende ich MySQL, eine separate Tabelle users mit ungefähr diesen Feldern:
ERSTELLE TABELLE `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, // Zeit der letzten Verbindung
`last_ip` varchar(20) NOT NULL, // IP der letzten Verbindung
`last_port` int(11) NOT NULL, // Port der letzten Verbindung
`task` text NOT NULL, // Aufgabe, die der Router erhält
`reg_task` varchar(150) NOT NULL, // "regelmäßige" Aufgabe, wenn wir möchten, dass die Aufgabe immer bei der Registrierung ausgeführt wird
`last_task` text NOT NULL, // Log der Aufgaben
`response` text NOT NULL, // Hier wird die Antwort des Geräts geschrieben
`seq` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8; Alle Quellcodes können aus dem Git-Repository unter folgender Adresse abgerufen werden:
Jetzt die PHP-Skripte, die auf der Serverseite platziert werden (zur Vereinfachung können sie in den Ordner /usr/share/zabbix/ gelegt werden):
Datei a.php:
set_charset("utf8");
// hier suchen wir unseren Router in der Datenbanktabelle
$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();
// hier senden wir dem Router seine Aufgaben
echo $task;
echo "n";
echo $reg_task;
// hier schreiben wir die Antwortzeit und die Antwort des Routers
$response_history="[".date("Y-m-d H:i")."] ".$message;
// Die Aufgabe wurde gesendet, jetzt müssen wir sie löschen und in den Logs markieren, dass diese Aufgabe erledigt ist
$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();
}
// Jetzt müssen wir die Registrierungszeit des Benutzers, seine IP und seine Nachricht speichern. Vorerst nur die Nachricht
$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();
}
// Wenn wir den Router nicht in unserer Datenbank gefunden haben oder sein Status "inaktiv" ist, wird ihm ... der Befehl zum Neustart gesendet.
// Warum so rigoros? Weil Router manchmal verschwinden, und das ist ein kleiner Weg, um die "neuen Besitzer" zu erziehen.
else
{
echo "reboot";
}
$sql_users->close();
?>Die Datei agent.php (dies ist das Skript des aufgerufenen 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();
// Der Datenaustausch erfolgt über das Feld seq. Bei der Registrierung wird dieses Feld auf "1" gesetzt.
if (($sql_users->num_rows)==1){
$sql_users->fetch();
echo $seq;
}
// Setze $seq auf 0 zurück.
$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();
?> Und der letzte Schritt: Den Agenten konfigurieren und Grafiken hinzufügen.
Wenn Sie den Zabbix-Agenten noch nicht installiert haben, dann:
apt-get install zabbix-agentBearbeiten 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 – der Name unseres Agenten
„php /usr/share/zabbix/agent.php user password“ – das aufgerufene Skript mit den Anmeldedaten des Geräts.
Hinzufügen von Grafiken: Öffnen Sie die Weboberfläche von Zabbix, im Menü wählen Sie:
Einstellungen -> Netzwerkgeräte -> Netzwerkgerät erstellen. Hier müssen Sie nur den Namen des Netzwerkgeräts, seine Gruppe und den Standard-Agenten-Interface angeben:

Jetzt müssen wir für dieses Netzwerkgerät einen Datenelement hinzufügen. Achten Sie auf zwei Felder: „Schlüssel“ – das ist genau der Parameter, den wir in der Datei /etc/zabbix/zabbix_agentd.conf angegeben haben (in unserem Fall ist es test), und „Aktualisierungsintervall“ – ich setze es auf 5 Minuten, da das Gerät auch alle fünf Minuten auf dem Server registriert wird.

Und dann fügen wir die Grafik hinzu. Ich empfehle, als Zeichenstil „Füllung“ zu wählen.

Am Ende ergibt sich etwas sehr Prägnantes, zum Beispiel so:

Auf die berechtigte Frage: „Hat sich das gelohnt?“, antworte ich: Natürlich, siehe „Gründe für die Erstellung eines Fahrrads“ zu Beginn des Artikels.
Wenn mein erster grafomanischer Versuch das Interesse der Leser weckt, möchte ich in den nächsten Artikeln beschreiben, wie man Befehle an entfernte Geräte sendet. Es gelang mir auch, das gesamte Schema für Geräte auf Basis von RouterOS (Mikrotik) zu implementieren.
Quelle: habr.com
