Open Source im professionellen Einsatz
Linux-Magazin 11/2014
© Rainer Plendl, 123RF

© Rainer Plendl, 123RF

Das heimische Netz automatisiert überwachen

Auf der Wacht

Damit ein Anwender schnell über womöglich ungewollte Zu- und Abgänge in seinem Netzwerk informiert wird, speichert ein Perl-Daemon periodisch die Daten von Nmap-Scans und gibt sie über ein eingebautes Webinterface an Nagios weiter.

1166

Der praktische Netzwerkscanner »nmap« dient nicht nur regelbrechenden Akteuren in spannenden Thrillern zum Aufspüren von Einbruchszielen [1], sondern zeigt auch dem Hobby-Admin an, welche Geräte tatsächlich über sein Heimnetzwerk erreichbar sind. Wer in regelmäßigen Abständen einen Nmap-Lauf in seinen Subnetzen startet und die Ausgaben vergleicht, bleibt über neu hinzugekommene Geräte oder Abgänge auf dem Laufenden und baut bösen Überraschungen vor.

Dass »nmap« über eine Option »-oX« verfügt, die ihn zur Ergebnisausgabe im XML-Format veranlasst, erfuhr ich bei der Lektüre einer Nmap-Bedienungsanleitung, die kürzlich als Kindle-Buch erschienen ist [2]. Da ein Nmap-Scan über mehrere Netze schon mal einige Minuten dauern kann, kam mir die Idee, einen Daemon zu bauen, der einmal pro Stunde alle Endknoten findet, die Daten im Speicher behält und sie über einen eingebauten Webserver an anfragende Clients, etwa ein Nagios-Skript, ausgibt.

Schlankes Skript definiert den Suchraum

Das Skript in Listing 1 erledigt dies, allerdings hauptsächlich über das in Zeile 7 hereingezogene und weiter unten besprochene Modul »NmapServer« und dessen Methode »start()« . Vor dem Aufruf legt es im Konstruktor den IP-Bereich des Heimnetzwerks fest, den »nmap« scannen soll – in dem vorliegenden Beispiel sind das die Subnetze 192.168.14.x und 192.168.27.x.

Listing 1

nmap-server

01 #!/usr/local/bin/perl -w
02 ###########################################
03 # nmap-server - Nmap scanning daemon
04 # Mike Schilli, 2014 (m@perlmeister.com)
05 ###########################################
06 use strict;
07 use NmapServer;
08 use App::Daemon qw( daemonize );
09
10 daemonize();
11
12 my $nmap = NmapServer->new(
13   scan_range =>
14     [ "192.168.14.1/24",
15       "192.168.1.1/24" ] );
16
17 $nmap->start();
18
19 my $cv = AnyEvent->condvar();
20 $cv->recv();

Die Notation »/24« im Listing gibt an, dass die ersten drei Oktette (24 Bit) die Netzwerkmaske des zu scannenden Subnetzes definieren, die hinten angehängte 1 wird »nmap« durch alle Werte von 1 bis 254 ersetzen. Das CPAN-Modul App::Daemon sorgt mit der Methode »daemonize()« dafür, dass das Skript sich mit dem Parameter »start« starten lässt:

./nmap-server start

Alles, was im Skript unterhalb von »daemonize()« steht, läuft bis zum Sankt-Nimmerleins-Tag danach im Hintergrund weiter, selbst wenn das Skript sofort wieder zurückkehrt und die Shell dem User schon den nächsten Prompt zeigt. Auch wenn der Anwender sich ausloggt, läuft der Daemon unbeirrt weiter, weil das Modul App::Daemon hinter den Kulissen dafür gesorgt hat, dass das Skript sein eigener Session Leader ist und so auch nicht mehr von der aufrufenden Shell abhängt.

Um den Daemon wieder herunterzufahren, genügt das Kommando

./nmap-server stop

im selben Verzeichnis, denn das Modul App::Daemon speichert die Prozerss-ID (PID) des Daemon-Prozesses in der Datei »nmap-server.pid« ab.

Was der Daemon so alles treibt, steht in einer Logdatei namens »nmap-server.log« , und mit der Verbose-Option »-v« landen in derselben Datei auch die Debugmeldungen. Wer den Daemon im Vordergrund laufen lassen will, der ruft das Skript genau wie auch den Apache-Server mit der Option »-X« auf.

Ereignisse in Schleifen

Das Modul »NmapServer« ist mit dem Event-Framework »AnyEvent« vom CPAN implementiert, mit dem zwar Multitasking möglich ist, in dem aber zu jedem Zeitpunkt nur ein Thread und normalerweise nur ein Prozess läuft. Der Programmfluss ist asynchron, die verschiedenen Programmteile laufen nur quasi-parallel und generieren und konsumieren Ereignisse, die eine alles steuernde Eventschleife verwaltet.

Die letzten beiden Zeilen in Listing 1 sind deswegen ein »AnyEvent« -Unikum. Sie definieren mit »condvar()« eine Variable, die mit »recv()« auf Events wartet. Da der Variablen jedoch niemand ein Event schickt, wartet das Skript am Ende, verzweigt zur Eventschleife und verarbeitet dort eintreffende Events, bis jemand den Daemon herunterfährt. Fehlten die letzten zwei Zeilen in »nmap-server« , würde sich das Skript nach Zeile 13 verabschieden, wenn die Variable »$nmap« dem Garbage Collector zum Opfer fällt, weil sie das Ende ihres Gültigkeitsbereichs im Programm erreicht hat.

Das Modul »NmapServer.pm« in Listing 2 bringt nun das Kunststück fertig, mit Hilfe eines Timers vom Typ »AnyEvent::Timer« im Stundentakt das Programm »nmap« aufzurufen, dessen Ausgabe in eine mit »File::Temp« angelegte temporäre XML-Datei zu speichern und die Daten anschließend im Json-Format im Speicher abzulegen.

Listing 2

NmapServer.pm

001 ###########################################
002 package NmapServer;
003 ###########################################
004 # Daemon running nmap periodically and
005 # serving JSON data via a web interface
006 # Mike Schilli, 2014 (m@perlmeister.com)
007 ###########################################
008 use strict;
009 use warnings;
010 use Log::Log4perl qw(:easy);
011 use AnyEvent;
012 use AnyEvent::HTTPD;
013 use JSON qw( to_json );
014 use File::Temp qw( tempfile );
015 use XML::Simple;
016
017 ###########################################
018 sub new {
019 ###########################################
020   my( $class, %options ) = @_;
021
022   my( $fh, $tmp_file ) =
023      tempfile( UNLINK => 1 );
024
025   my $self = {
026     xml_file   => $tmp_file,
027     fork       => undef,
028     json       => "",
029     child      => undef,
030     scan_range => [],
031     %options,
032   };
033
034   bless $self, $class;
035 }
036
037 ###########################################
038 sub start {
039 ###########################################
040   my( $self ) = @_;
041
042   $self->{ timer } = AnyEvent->timer(
043     after    => 0,
044     interval => 3600,
045     cb => sub {
046       if( defined $self->{ fork } ) {
047           DEBUG "nmap already running";
048           return 1;
049       }
050       $self->nmap_spawn();
051     },
052   );
053
054   $self->httpd_spawn();
055 }
056
057 ###########################################
058 sub nmap_spawn {
059 ###########################################
060   my( $self ) = @_;
061
062   $self->{ fork } = fork();
063
064   if( !defined $self->{ fork } ) {
065     LOGDIE "Waaaah, failed to fork!";
066   }
067
068   if( $self->{ fork } ) {
069       # parent
070     $self->{ child } = AnyEvent->child(
071       pid => $self->{ fork },
072       cb  => sub {
073         my $data =
074           XMLin( $self->{ xml_file });
075         $self->{ json } =
076          to_json( $data, { pretty => 1 } );
077         $self->{ fork } = undef;
078       } );
079   } else {
080       # child
081     exec "nmap", "-oX",
082       $self->{ xml_file },
083       @{ $self->{ scan_range } },
084   }
085 }
086
087 ###########################################
088 sub httpd_spawn {
089 ###########################################
090   my( $self ) = @_;
091
092   $self->{ httpd } =
093     AnyEvent::HTTPD->new( port => 9090 );
094
095   $self->{ httpd }->reg_cb (
096     '/' => sub {
097       my ($httpd, $req) = @_;
098
099       $req->respond({ content =>
100         ['text/json', $self->{ json } ],
101       });
102     },
103   );
104 }
105
106 1;

Quasi gleichzeitig läuft im Code ein Webserver vom Type »AnyEvent::HTTPD« , der auf Port 9090 lauscht und anfragenden Clients die Json-Daten übermittelt. Abbildung 1 zeigt einen dort andockenden Browser, der die detaillierten Scandaten des letzten Nmap-Laufs im Json-Format anzeigt.

Abbildung 1: Die Json-Ausgabe des Nmap-Daemon.

Da das externe Programm »nmap« nicht mit der von »AnyEvent« benutzten Eventschleife kooperiert, sondern den Gesamtbetrieb des Servers aufhalten würde, muss Zeile 62 mit Hilfe der Anweisung »fork()« ein Prozesskind erzeugen, das »AnyEvent« mit der Methode »child()« in Zeile 70 verwaltet. Kommt der Childprozess zum Abschluss, wurde der »nmap« -Lauf also erfolgreich abgeschlossen, springt das Skript den ab Zeile 72 definierten Callback-Code an, verarbeitet das XML und wandelt es in Json um.

Für das Auffrischen des internen Cache muss der Code nicht einmal ein Lock setzen, denn es läuft immer nur ein Thread und eine Zuweisung ist auch dann atomar, wenn es sich um einen riesigen Datenwust handelt. Dank dieser Eventschleife kommt in der Zwischenzeit keine weitere AnyEvent-Task an die Reihe.

Andererseits führt das Prozesskind mit »exec()« in Zeile 81 lediglich das externe Nmap-Programm aus und beendet sich anschließend selbst. Definitionsgemäß kehrt der Prozess nie mehr aus seiner »exec()« -Anweisung zurück, es sei denn, beim Aufruf geht etwas schief.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Nmap 7 mit vollem IPv6-Support und neuen Skripten

    Dreineinhalb Jahre Arbeit stecken in der neuen Version 7 von Nmap. Das Projekt hat mittlerweile 18 Jahre auf dem Buckel, will aber auch weiterhin auf neueste Technologien setzen.

  • Leserbriefe

    Haben Sie Anregungen, Statements oder Kommentare? Dann schreiben Sie an redaktion@linux-magazin.de. Die Redaktion behält es sich vor, die Zuschriften und Leserbriefe zu kürzen. Sie veröffentlicht alle Beiträge mit Namen, sofern der Autor nicht ausdrücklich Anonymität wünscht.

  • Alles inklusive

    Viele kennen und nutzen Nmap. Nur wenige aber bedienen sich des mächtigen Werkzeugkastens, der im Laufe der Zeit rund um den eigentlichen Portscanner entstand.

  • Fyodors Diätprogramm

    Während viele Werkzeuge von Version zu Version bauchiger werden, kommt Nmap 4 als Diet Nmap verschlankt daher. Die jüngste Inkarnation 4.00 arbeitet daher schneller und verlangt weniger Hauptspeicher.

  • Schneller scannen mit Nmap 5.0

    Nmap ist schon seit langer Zeit das Netzwerktool der ersten Wahl, wenn es um die Administration und Analyse von Rechnern im Netz geht. Die neue Version verbessert Nmap nochmals erheblich.

comments powered by Disqus

Ausgabe 01/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.