Aus Linux-Magazin 02/2005

Aus dem Nähkästchen geplaudert: Serverprozesse mit Inetd und Xinetd verwalten

Inetd und Xinetd verwalten Netzdienste und kümmern sich um die Kommunikation mit den Clients. So muss ein Programm weder Daemon- noch Netzwerk-Code enthalten, um als Internetserver zu arbeiten.

Typische Serverprozesse kümmern sich selbst um ihre Netzwerkkommunikation. Sie öffnen einen Socket, mit dem sie an einem TCP-Port lauschen und ihre Daten schicken und empfangen. Die Interaktion mit einem Socket ist zwar keine Geheimwissenschaft, aber lästig zu programmieren und fehlerträchtig. Zudem fällt es jedem Admin schwer, bei einer Schar von Serverprozessen den Überblick über die Konfigurationen zu behalten. Zentrale Sicherheitseinstellungen lassen sich nur mit viel Aufwand verwalten, wenn jeder Daemon seine eigenen Konfigurationsdateien unterhält.

Server zentral verwalten

Eine einfache Alternative zu den Daemons, die den gesamten Netzwerkcode selbst enthalten, sind die so genannten Superserver Inetd und Xinetd. Sie horchen an mehreren Netzwerkports gleichzeitig, starten für jede eingehende Verbindung den zuständigen Prozess und leiten ihm die Daten weiter (Abbildung 1). Die Server kommunizieren mit ihren Clients über Stdin und Stdout.

Die Inetd-Konfigurationsdatei enthält eine Tabelle mit den zu belegenden TCP- und UDP-Ports sowie den zuständigen Programmen. Der Superserver öffnet einen Socket für jeden Port und wartet auf Verbindungen. Listing 1 zeigt ein Beispiel: Die Felder einer Zeile beschreiben den jeweiligen Dienst.

Der symbolische Name, zum Beispiel »smtp«, bestimmt den Port. Aus »/etc/services« erfährt Inetd die Portnummer des Dienstes. Diese Datei dürfen Admins auch erweitern, doch sollten eigene Anwendungen nur Ports im Bereich von 49152 bis 65535 benutzen. Sie sind für private Anwendungen freigegeben. Eine komplette Liste der registrierten UDP- und TCP-Ports gibt es bei der IANA (Internet Assigned Numbers Authority,[1]).

Im zweiten Feld der Konfiguration steht der Socket-Typ (für TCP immer »stream«, bei UDP »dgram«), im dritten das Protokoll (etwa »tcp« oder »udp«). Die Option »nowait« in der nächsten Spalte weist Inetd an, sich nicht mehr um den gestarteten Prozess zu kümmern. Beim erneuten Verbindungsversuch an diesem Port startet der Daemon einen weiteren Prozess.

Mit »wait« wartet Inetd, bis der Prozess endet. Erst dann nimmt der Superserver wieder Verbindungen auf dem Port entgegen. Das ist vor allem bei Sockets vom Typ »dgram« sinnvoll, etwa bei UDP. Obwohl keine Verbindung besteht, gehören oft mehrere Datagramme zu einer Sitzung. Inetd lässt daher nur einen Prozess laufen und gibt ihm alle neuen UDP-Pakete.

Die letzten drei Argumente der Konfigurationszeile geben den User an, unter dessen Kennung der Server laufen soll, den Pfad zum Binary sowie eventuelle Argumente. Achtung Falle: Manche älteren Versionen von Inetd erlauben nur eine kleine Zahl von Argumenten, meist fünf oder 20. Alle weiteren Parameter ignoriert der Superserver.

Inetd kümmert sich nicht um Zugriffskontrolle und Sicherheit. Dafür sind separate Programme zuständig, etwa der TCP-Wrapper »tcpd«. Er wertet die Dateien »/etc/hosts.allow« und »/etc/hosts .deny« aus, um den Zugriff auf einzelne Ports detailliert zu kontrollieren.

Xinetd macht’s besser

Das Programm Xinetd ist eine stark verbesserte Version des originalen Inetd, mit modularer Konfiguration und Mechanismen wie Zugriffskontrolle und Abwehr von Denial-of-Service-Angriffen. Ein Beispiel für den Exim-Mailserver zeigt Listing 2.

Xinetd liest zwei Arten von Konfigurationsdateien: »/etc/xinetd.conf« enthält nur globale Einstellungen, die Dienste sind in je einer eigenen Datei beschrieben. Sie trägt üblicherweise den Namen ihres Dienstes und liegt im Verzeichnis »/etc/xinetd.d/«.

Abbildung 1: Der Internet-Superserver Inetd nimmt Serverprozessen die Netzwerkarbeit ab: Er verbindet Stdin und Stdout der Server mit ihren Clients.

Abbildung 1: Der Internet-Superserver Inetd nimmt Serverprozessen die Netzwerkarbeit ab: Er verbindet Stdin und Stdout der Server mit ihren Clients.

Über die Standardoptionen hinaus lassen sich zahlreiche Sicherheits- und Optimierungsvariablen festlegen. Etwa eine Liste der Rechner beziehungsweise IP-Adressen, die auf einen Port zugreifen dürfen. Praktisch: Der Admin kann Ausgaben in Dateien oder das Syslog protokollieren und die Ressourcen eines Programms beschränken.

Das Beispiel in Listing 3 erlaubt maximal zehn Instanzen jedes Servers. Xinetd ruft sie mit der niedrigen Priorität 5 auf (»nice = 5«). Ab einer Last von 2,5 starten keine weiteren Prozesse mehr (»max_load = 2.5«) und es sind höchstens 50 Verbindungen pro Sekunde gestattet. Nach Überschreiten dieses Limits sperrt Xinet den Dienst für 20 Sekunden (»cps = 50 20«). Den Anteil des Arbeitsspeichers, den sich ein Prozess einverleiben darf, beschränkt die Variable »rlimit _as«. Mit »no_access = 24.0.0.0« verbietet der Admin Verbindungen aus dem Subnetz 24/8.

Kann der gewünschte Server nicht starten, weil etwa seine Ressourcen erschöpft sind oder der anfragende Computer eine gesperrte IP-Adresse trägt, versucht Xinetd per Ident-Lookup den Benutzernamen des Clients zu ermitteln und protokolliert diesen gemeinsam mit der IP-Adresse (»log_on_failure = HOST USERID«). Hat der Superserver einen Prozess gestartet, weist ihn die Variable »log_on_success« per »HOST PID EXIT DURATION« dazu an, Hostnamen, Prozess-ID, Exit-Status und Länge der Sitzung zu speichern.

Ein eigener Server

Ein Serverprogramm fällt bei Verwendung von Inetd oder Xinetd sehr einfach aus. Es erhält die TCP-Verbindung auf seiner Standard-Ein- und -Ausgabe. Alle Ausgaben des Clients kommen beim Server auf Stdin an, Daten an den Client schreibt der Server auf Stdout. Das einfachste Beispiel für einen Inetd-Server besteht aus nur zwei Zeilen:

#!/bin/sh
echo This is me and I am called `uname -n`.

Um dieses Programm übers Netzwerk zugänglich zu machen, reicht folgende Zeile in »/etc/inetd.conf« aus:

sampleserver stream tcp nowait mas /usr/local/bin/sampleserver

Als symbolischer Servicename ist hier »sampleserver« gewählt. Ein Eintrag von »sampleserver 50000/tcp« in »/etc/services« macht Inetd den Port bekannt. Nach einer Änderung der Konfigurationsdatei ist der Superserver davon zu informieren. Das erledigt der Admin über den Aufruf »killall -HUP inetd«.

Danach steht der Server als TCP-Dienst bereit. Nach Eingabe von »telnet localhost 50000« erhält der User folgende Ausgabe, wobei die ersten drei sowie die letzte Zeile vom Telnet-Client kommen:

Trying 127.0.0.1...
Connected to anmen.
Escape character is '^]'.
This is me and I am called anmen.
Connection closed by foreign host.

Fallstricke

Da das Programmieren einer Serveranwendung mit einem Superserver so einfach von der Hand geht, hebt sich sogleich der mahnende Zeigefinger und erinnert an Sicherheitslücken: Egal ob er ein Programm in C, Java, Perl oder einer Shell schreibt, sollte der Entwickler mit großer Sorgfalt an die Sache herangehen. Nur zu leicht öffnet er versehentlich gefährliche Hintertüren. Worauf er besonders achten muss, erklärt ein eigener Artikel in diesem Heft.

Nicht unbedingt ein Sicherheitsproblem, aber trotzdem wichtig ist das Beachten der Zeilenende-Konvention. Während im Unix-Land das einzelne Newline-Zeichen »n« üblich ist, werden im Internet Zeilenenden durch die Kombination aus Linefeed und Newline »rn« übertragen. Inetd und Xinetd kümmern sich zwar um die Netzwerkfunktionalität, sie konvertieren aber keine Zeichensätze. Das überlassen sie dem Serverprozess, der sein Protokoll besser kennt.

Es ist nicht sinnvoll, sämtliche Dienste per Superserver zu starten. Jede Verbindung zu einem der Dienste verursacht einigen Overhead auf dem Server, da das entsprechende Programm immer von neuem anläuft.

Bei kleinen Daemons, die nicht sehr oft starten müssen, ist das kein Problem. Doch größere Dienste wie der Apache-Webserver oder ein SSH-Daemon brauchen zu lange fürs Starten, um effektiv per Inetd zu funktionieren. SSH generiert beispielsweise bei jedem Start mit hohem Rechenaufwand einen Server-Key für die Protokollversion 1.

Laufen so viele Dienste wie möglich per Superserver, bleibt die Prozesstabelle des Rechners schön übersichtlich und der Admin erspart sich unnötige Konfigurationsarbeit. (mwe)

Listing 1:
Inetd-Konfiguration

01 # Dienst Typ Protokoll Flags User Programm Argumente
02 
03 smtp    stream tcp nowait mail /usr/sbin/exim exim -bs
04 printer stream tcp nowait lp   /usr/lib/cups/daemon/cups-lpd cups-lpd
05 ftp     stream tcp nowait root /usr/sbin/tcpd /usr/sbin/proftpd

Listing 2:
»/etc/xinetd.d/exim«

01 service smtp
02 {
03         disable         = no
04         socket_type     = stream
05         wait            = no
06         user            = mail
07         server          = /usr/sbin/exim
08         server_args     = -bs
09         flags           = REUSE
10 }

Listing 3:
»/etc/xinetd.conf«

01 defaults
02 {
03         instances       = 10
04         cps             = 50 20
05         nice            = 5
06         max_load        = 2.5
07         rlimit_as       = 32M
08         no_access       = 24.0.0.0
09         log_type        = SYSLOG daemon
10         log_on_failure  = HOST USERID
11         log_on_success  = HOST PID EXIT DURATION
12 }

Infos

[1] IANA-Portliste: [http://www.iana.org/assignments/port-numbers]

[2] Xinetd: [http://www.xinetd.org]

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben