Startseite

Personenprofil

Projekte

Material zu Linux

"tcpserver"

Dieses Dokument befasst sich mit dem Einsatz von "tcpserver", ein von Dan J. Bernstein entwickelter TCP-Daemon der "inetd" ersetzt.

Dieses Dokument ist urheberrechtlich geschützt. Copyright (c) 2002 - 2012 Dirk Prösdorf
Es ist erlaubt, dieses Dokument unter den Bedingungen der GNU Free Documentation License (GNU FDL), Version 1.1 oder jeder späteren Version, die von der Free Software Foundation veröffentlicht wird, zu kopieren, verbreiten und/oder verändern.
Die Original-Version der GNU FDL http://www.gnu.org/copyleft/fdl.html und eine inoffizielle Übersetzung.

Die Webseiten von Dan J. Bernstein.


Warum "tcpserver" verwenden und nicht "inetd"?

Für den Einsatz von "tcpserver" anstelle von von "inetd" gibt es verschiedene Gründe:

  • "inetd" skaliert nicht besonders gut, hierdurch kann es bei vielen Anfragen in einem kurzem Zeitraum zu einer Überlastung dieses Dienstes kommen.
  • "tcpserver" bietet flexiblere Konfigurationsmöglichkeiten.

"tcpserver" installieren

"tcpserver" ist Bestandteil einer Toolsammlung "UNIX Client-Server Program Interface (UCSPI)". Bei der Installation wird die gesamte Toolsammlung installiert. Einzelne dieser Tools werden für die Konfiguration von "tcpserver" benötigt.

Als erstes muss die Software herunter geladen und entpackt werden:
$ tar -xzf ucspi-tcp-0.88.tar.gz
$ cd ucspi-tcp-0.88/

Danach muss die Software kompiliert werden:
$ make

Nun muss mit Root-Rechten die Software installiert werden:
# make setup check

Die Tools liegen nun unter /usr/local/bin/ und der Installationsprozess ist abgeschlossen.

"tcpserver" konfigurieren

Aufruf von "tcpserver"

An einigen Beispielen wird nun die Konfiguration von "tcpserver" erklärt.

Der Aufruf von "tcpserver" lautet:
tcpserver opts host port prog

Bei host handelt es sich um die um die IP-Adresse, auf der "tcpserver" Verbindungen annehmen soll. Alternativ kann auch der Rechnernamen angegeben werden, dann wird die erste IP-Adresse dieses Servers verwendet, oder 0, dann werden Verbindungen auf allen IP-Adressen des Servers angenommen.
Bei port kann entweder der Dienstname, wie er in /etc/services eingetragen ist, oder die Port-Nummer verwendet werden. Wenn als Port-Nummer 0 angegeben wird, wird von "tcpserver" der nächste freie Port verwendet.
prog ist da auszuführende Programm mit allen für die Ausführung notwendigen Parametern.
Mittels opts wird "tcpserver" gesteuert. Die vollständigen Aufrufoptionen können auf der "tcpserver"-Seite von Dan J. Bernstein nachgelesen werden. Die wichtigsten Aufrufoptionen werden in den nachfolgenden Beispielen vorgestellt.

Beispiele zur Nutzung von "tcpserver"

Für die von "tcpserver" benötigten Zugriffsregeln sollte eine eigenes Verzeichnis angelegt werden, welches Root gehört und 0755 Zugriffsrechte hat:
# mkdir /etc/tcpserver
# chmod 0755 /etc/tcpserver

Nun zum ersten Beispiel, ein Telnet-Zugang:

#!/bin/sh
/usr/local/bin/tcpserver 0 telnet /usr/sbin/in.telnetd

Dies ist die einfachste Form des Aufrufs von "tcpserver". Es wird hierbei der Dienst "telnet" (aufgerufen als /usr/sbin/in.telnetd, da in Skripten immer absolute Pfadangaben verwendet werden) an den Port "telnet" (also Port 23 in /etc/services) und allen IP-Adressen gebunden. Dies bedeutet aber auch, dass nun von überall aus, von wo aus der Rechner erreicht werden kann, dieser Dienst genutzt werden kann.

Im nächsten Beispiel soll dieser Telnet-Zugang auf einem Router nur an die interne Netzwerkkarte gebunden werden. Wir nehmen dafür an, dass 10.0.0.1 die Adresse der internen Netzwerkkarte ist. Es ist unter Sicherheitsgesichtspunkten nicht sinnvoll, einen Telnet-Dienst in einem Netzwerk zur Verfügung zu stellen, da alle Daten unverschlüsselt übertragen werden. Hier ist OpenSSH wesentlich besser geeignet (eigentlich sollte man dann gleich ganz auf Telnet verzichten, aber wir nehmen jetzt mal an, dass dies aus irgend welchen Gründen nicht möglich ist).

#!/bin/sh
/usr/local/bin/tcpserver 10.0.0.1 telnet /usr/sbin/in.telnetd

Nun werden nur noch Verbindungsanfragen auf der Netzwerkkarte, an die die IP-Adresse 10.0.0.1 gebunden ist, angenommen. Dort ist aber der "Telnet-Dienst" von allen Rechnern, die diese IP-Adresse erreichen können, aus nutzbar.

In einem nächsten Schritt soll nun der Zugriff auf den "Telnet-Dienst" für alle gesperrt und nur für einzelne Rechner anhand der IP-Adresse frei gegeben werden. Außerdem sollen nicht mehr als 3 Verbindungen zur gleichen Zeit angenommen werden.

#!/bin/sh
/usr/local/bin/tcpserver -x /etc/tcpserver/telnet.cdb -c 3 10.0.0.1 telnet /usr/sbin/in.telnetd

Nun kommen die Aufrufoptionen von "tcpserver" ins Spiel.
Mit der Option -c n kann die Anzahl der gleichzeitigen Zugriffe festgelegt werden. Weitere Zugriffe werden erst wieder angenommen, wenn eine Verbindung frei gegeben wird. Der Standardwert ist 40.
Mit der Option -x Dateiname werden Dateien mit Zugriffsregeln eingebunden. Wenn diese Datei nicht vorhanden ist werden Zugriffe standardmäßig zurück gewiesen. Dies lässt sich mit der zusätzlichen Option -X verhindern, wobei dann keine Zugriffsregeln gelten, wenn die Datei nicht vorhanden ist. Es sollte also mit der Option -X vorsichtig umgegangen werden.
Nun muss noch die benötigte Datei mit den Zugriffsregeln erstellt werden. Dafür wird das Tool "tcprules" benötigt, das Bestandteil von UCSPI ist und somit bei der Installation dieser Toolsammlung mit installiert wurde. Eine ausführliche Beschreibung zu diesem Tool gibt es auf der "tcprules"-Seite von Dan J. Bernstein.

Der Aufruf von "tcprules" lautet:
tcprules cdb-Datei tmp-datei,
wobei "tcprules" seine Eingabe von der Standardeingabe (STDIN) liest, die Regeln in die tmp-Datei schreibt und dann diese Datei über die cdb-Datei schreibt. Hier durch hat "tcpserver" immer die aktuellen Zugriffsregeln. Sinnvoll ist es, im Verzeichnis /etc/tcpserver eine Vorlage-Datei zu erstellen und diese dann dem Aufruf von "tcprules" auf der Standardeingabe zu übergeben.
Diese Vorschlage könnte wie folgt aussehen:

:deny
10.0.0.1-20:allow
10.0.1.:allow

In der Ersten Zeile wird jeglicher Zugriff verhindert. In der zweiten Zeile wird Zugriff für die IP-Adressen 10.0.0.1-10.0.0.20 gewährt und in der dritten Zeile wird Zugriff für die IP-Adressen 10.0.1.0-10.0.1.255 gewährt.
Nun muss nur noch mit dem folgenden Aufruf die cdb-Datei erstellt werden:

# tcprules telnet.cdb telnet.tmp < telnet.vorlage

Im nächsten Beispiel soll für den "Unix to Unix copy (UUCP) Dienst" Verbindungen angenommen werden. Im Gegensatz zu "Telnet" benötigt dieser Dienst keine Root-Rechte sondern kann mit seinen eigenen User- und Gruppen-IDs gestartet werden. Außerdem sollen alle Meldungen in eine Log-Datei geschrieben werden. Standardmäßig schreibt "tcpserver" seine entsprechenden Meldungen auf auf den Fehlerkanal (STDERR).

#!/bin/sh
/usr/local/bin/tcpserver -x /etc/tcpserver/uucp.cdb -v -c 10 -u 10 -g 14 0 uucp /usr/lib/uucp/uucico 2>> /var/log/tcpserver

Hier sind nun die folgenden Aufrufoptionen interessant:
Die Option -v erzeugt sowohl Fehlermeldungen als auch Statusmeldungen. Standard ist sind nur Fehlermeldungen (wofür es auch die redundante Option -Q gibt). Mit der Option -q würden überhaupt keine Meldungen aus gegeben.
Die Option -u uid übergibt die User-ID und die Option -g gid die Gruppen-ID.
Die jeweiligen nummerischen Werte lassen sich einfach mittels des folgenden Aufrufs ermitteln:
$ id uucp
uid=10(uucp) gid=14(uucp) groups=14(uucp)

Somit ruft hier, bei bis zu maximal 10 gleichzeitigen Verbindungsanfragen auf allen IP-Adressen, "tcpserver" den "UUCP file transfer daemon" mit der User- und Gruppen-Id von UUCP auf und schreibt alle Meldungen in sein Logfile.

Die obigen Skripte sind zwar in Lage, den jeweiligen Dienst zu starten, aber um diese Dienste auch bei einem Systemstart oder einen Wechsel des Runlevels zur Verfügung zu haben, muss daraus ein Start/Stopp-Skript gemacht werden. Eine Vorlage hierfür ist bei den meisten Distributionen unter /etc/rc.d/init.d/skeleton zu finden. Diese verwenden aber zum Beenden des jeweiligen Dienstes meistens den Befehl killproc. Dieser würde nun aber nicht nur den jeweiligen Dienst beenden, sondern alle mittels "tcpserver" gestarteten Dienste, da killproc über den absoluten Pfadnamen geht und der ist bei allen Diensten /usr/local/bin/tcpserver.
Eine Alternative ist das Beenden über die Prozess-ID des jeweiligen Dienstes. Ein einfaches Start/Stopp-Skript für den "Telnet-Dienst", welches dies gewährleisten würde, sähe wie folgt aus:

#!/bin/sh
# Start/Stopp-Script /etc/rc.d/init.d/telnet
case "$1" in
start)
echo -n "Starting telnet services: "
/usr/local/bin/tcpserver -x /etc/tcpserver/telnet.cdb -c 3 10.0.0.1 \
telnet /usr/sbin/in.telnetd 2>> /var/log/tcpserver || exit 1 &
echo $! > /var/run/telnet.pid
echo "done"
;;
stop)
echo "Stopping telnet services: "
kill -TERM `cat /var/run/telnet.pid` || exit 1
rm /var/run/telnet.pid
echo "done"
;;
restart)
$0 stop && $0 start || exit 1
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

Hier wird "tcpserver" als Hintergrundprozess gestartet, so dass das Skript weiter ablaufen kann. Dann wird mittels des Befehls echo $! die PID dieses Hintergrundprozesses in die Datei /var/run/telnet.pid geschrieben. Diese PID wird nun beim Beenden aus dieser Datei ausgelesen und kill beendet so den entsprechenden Dienst.
Nun müssen nur noch in den entsprechenden Runlevel-Verzeichnissen die Start- und Kill-Links auf dieses Skript angelegt werden und der entspreche Eintrag in der Datei /etc/inetd.conf auskommentiert werden. Falls alle Dienste umziehen kann der "inetd" auch komplett abgeschaltet werden.

Eine weitere Alternative wären die "daemontools"-Seite von Dan J. Bernstein.

Druckversion