NFS

Aus Foxwiki

Einführung

Das Network File System – abgekürzt NFS (auch: Network File Service) – ist ein von Sun Microsystems entwickeltes Protokoll, das den Zugriff auf Dateien über ein Netzwerk ermöglicht. Dabei werden die Dateien nicht wie z. B. bei FTP übertragen, sondern die Benutzer können auf Dateien, die sich auf einem entfernten Rechner befinden, so zugreifen, als ob sie auf ihrer lokalen Festplatte abgespeichert wären.

Bei diesem UNIX-Netzwerkprotokoll handelt es sich um einen Internet-Standard (RFC 1094, RFC 1813, RFC 3530), der auch als verteiltes Dateisystem (engl. Distributed File System) bezeichnet wird.

Die Entsprechung zu NFS heißt unter Windows- und OS/2-Umgebungen Server Message Block (SMB). Während sich bei SMB der Benutzer authentifiziert, authentifiziert das populärere NFS V3 den Client-Rechner, erst NFS V4 ermöglicht Benutzerauthentifikation. NFS-Dienste sind auch auf Microsoft-Windows-Servern verfügbar, wodurch UNIX-Workstations Zugang zu deren Dateien erhalten können, allerdings wird in gemischten Umgebungen meist SMB mit Samba auf Unixseite verwendet.

NFS arbeitet auf dem Netzwerk-Transportprotokoll TCP/IP. NFS ist ursprünglich ein zustandsloses UDP-Protokoll. Mittlerweile gibt es aber auch NFS über TCP. Die aktuelle Version 4 ist nicht mehr zustandslos, was die Programmierung und die Netzwerksicherung extrem erleichtert. Sie wurde maßgeblich durch die IETF entwickelt, nachdem SUN die Entwicklung abgegeben hatte.

NFS im OSI-Schichtenmodell

Anwendung NFS
Darstellung XDR
Sitzung (Sun-) RPC
Transport UDP TCP
Netzwerk IP
Netzzugang Ethernet TokenRing FDDI

Schematischer Ablauf der Datenübertragung

Im Folgenden ist der prinzipielle Ablauf einer NFS-Kommunikation des zustandslosen NFS beschrieben. Szenario: Ein Nutzer des Client-Rechners möchte ein entferntes Verzeichnis ("/directory") öffnen und eine darin befindliche Datei ("test") anzeigen lassen.

Damit ein Datenaustausch zwischen NFS-Server und Client stattfinden kann, muss der NFS-Server gestartet und beim Portmapper registriert sein.*

Client kontaktiert Portmapper und fragt nach dem Port des Mount-Daemons (mountd)
  • Portmapper gibt Portnummer für mountd heraus
  • Client kontaktiert mountd und fragt nach einem Filehandle für "/directory"
  • mountd gibt ein Filehandle 0 zurück
  • Client kontaktiert Portmapper und fragt nach dem Port für NFS (nfsd)
  • Portmapper gibt Portnummer für nfsd heraus
  • Client führt LOOKUP-Prozedur aus mit den Parametern Filehandle 0 und dem Dateinamen ("test")
  • nfsd gibt Filehandle 1 für Datei ("test") heraus
  • Client führt READ-Prozedur aus mit dem Parameter Filehandle 1
  • nfsd gibt Inhalt der Datei ("test") zurück (Daten)

Design der frühen Versionen des Systems

Ein Programm greift auf das Dateisystem über Systemaufrufe zu. Unter UNIX sind die wichtigsten Systemaufrufe:* open, close – Öffnen und Schließen einer Datei

  • read, write – Lesen und Schreiben
  • create, unlink – Erzeugen und Löschen
  • mkdir, rmdir – Erzeugen und Löschen eines Verzeichnisses
  • readdir – Lesen von Verzeichniseinträgen


Ein Netzwerkdateisystem muss diese Aufrufe in Netzwerkpakete verpacken und an einen Server senden. Dieser antwortet dann mit der entsprechenden Information oder einem Fehler.

Die Entwickler von Sun Microsystems entschieden sich zunächst für ein Remote Procedure Call-Modell. Das XDR setzt die Parameter in ein maschinenunabhängiges Format um, die Zugriffe werden dann über RPC wie ein normaler Unterprogrammaufruf behandelt.

Die Systemaufrufe werden aber nicht direkt in RPC-Aufrufe umgesetzt, da dann eine über open geöffnete Datei auch auf dem Server geöffnet werden müsste. Bei vielen Clients wären die Server dann schnell überlastet, da die Maschinen Mitte der 1980er Jahre noch relativ wenig Speicher hatten. Die Aufgaben des Servers wurden daher so einfach wie möglich gehalten, der Server merkt sich keine Dateiinformationen zwischen zwei RPC-Aufrufen. Er ist also zustandslos.

Statt open wird ein lookup-Aufruf implementiert. Dieser liefert ein Datei-"Handle", das die Inodenummer und die Gerätenummer des Massenspeichers auf dem Server enthält. Über dieses Handle kann eine Datei auf dem Server eindeutig identifiziert werden. Unter Unix steht über diese beiden Nummern die Dateiinformation effizient ohne Suche eindeutig zur Verfügung.

Die weiteren Aufrufe wie read oder write müssen stets ein Offset übergeben, so dass der Server auch hier ohne Kenntnis früherer Operation die gewünschte Information eindeutig liefern kann.

Weitere Eigenschaften des Protokolls sind* nur kurze Cachezeiten (wenige Sekunden) für Verzeichnisinformationen und Dateiattribute

  • kein Datencache
  • Verwendung des verbindungslosen User Datagram Protocols UDP
  • Lock- und Mount-Operationen über zusätzliche Hilfsprotokolle
  • Verwendung von Unix-Dateiattributen (zum Beispiel Benutzer-uid)


Wegen des einfachen Designs läuft NFS in normalen Umgebungen gut:* lokales Netzwerk mit kurzen Antwortzeiten

  • Ausführen von Programmen über das lokale Netzwerk
  • Normale Benutzeraktivitäten (Editieren, Programme übersetzen)
  • Server mit relativ wenig Arbeitsspeicher


Weniger gut ist das Verhalten bei* gemeinsamer Nutzung von Dateien

  • Verwendung über das Internet (lange Antwortzeiten, geringe Sicherheit)
  • Verwendung von Firewalls (UDP, kein fester Port wegen Portmapper)


Das Protokoll wurde Ende der 1980er Jahre entwickelt. Auch teure Workstations hatten zu dieser Zeit nur wenige Megabytes Arbeitsspeicher, typisch etwa 4 bis 8 MB. Ein NFS-Server kann auf solchen Maschinen aufgrund des Designs trotzdem effizient betrieben werden.

Wegen des zustandslosen Servers kann dieser ohne Datenverlust heruntergefahren und neu gestartet werden. Programme stürzen nicht ab und Benutzer müssen dann einfach warten, bis der Server wieder verfügbar ist.

Plattenlose Workstations

Workstations können über NFS ganz ohne Plattenlaufwerk betrieben werden. Das Betriebssystem und die Betriebsparameter können über Protokolle wie BOOTP und TFTP geladen werden. Ein spezieller Kernel kann dann über NFS bereits auf das Wurzel-Laufwerk unter Unix zugreifen. Spezielle plattenlose Workstations (diskless workstations) wurden von der Firma Sun in den 1990er Jahren angeboten.

Vorteil ist ein verringerter Wartungsaufwand, gemeinsame Nutzung von Plattenplatz sowie einfachere und preiswerte Client-Workstations (Thin-Clients). Bei vielen Clients wird der Server jedoch stark belastet, außerdem sind die Zugriffszeiten über Netzwerk in den meisten Fällen langsamer.

PC-NFS

Sun und andere Firmen boten in den 1990er Jahren auch NFS-Clientsoftware für PCs unter Windows an, das PC-NFS. Der Server musste weiterhin eine Unix-Workstation sein. Bis Windows für Workgroups war der Netzwerkzugriff unter Windows nicht Teil des Betriebssystems. In Unix-Umgebungen wurde der Einsatz von PCs dadurch wesentlich erleichtert.

PC-NFS musste mit den unterschiedlichen Konzepten des DOS/Windows-Systems kämpfen. Die damaligen Windows-Versionen erlaubten nur Dateinamen mit bis zu acht Zeichen sowie eine drei Zeichen lange Erweiterung, die durch einen Punkt getrennt wurde (z. B. AUTOEXEC.BAT), während Unix 255 Zeichen lange Pfadnamen erlaubte. Die Dateinamen unterschieden im Gegensatz zu DOS zwischen Groß- und Kleinschreibung. PC-NFS musste also zwischen den Dateinamenkonzepten übersetzen.

Ein Unix-Dateiname file.txt erschien als FILE.TXT unter Windows/DOS, während ein Dateiname Dokumentation.txt etwa in DOKU~123.TXT umgesetzt wurde.

NFS Version 4

Die NFS Version 4 stellt eine Neuimplementierung dar, die neuere Erfordernisse berücksichtigt. Sie ist in RFC 3530 standardisiert.

Die Unix-Lastigkeit der frühen Versionen wird soweit wie möglich verringert. Die UNIX-Benutzer- und Gruppennummern werden durch Zeichenketten, etwa Benutzername@Rechnername, ersetzt. Da manche Dateisysteme keine effiziente Implementierung von eindeutigen Dateihandles ermöglichen, werden flüchtige Handles eingeführt, die nur eine bestimmte Zeit zur Verfügung stehen. Unter Unix kann man Handles sehr einfach aus der Geräte- und Inodenummer konstruieren. Auch Dateisysteme, die nicht zwischen Groß- und Kleinschreibung unterscheiden sowie benutzerdefinierte Dateiattribute werden jetzt unterstützt.

Das Mount- und Lockprotokoll sind jetzt Bestandteil des Protokolls selbst, Hilfsprotokolle werden nicht mehr benötigt. Das Protokoll selbst läuft auf dem festen TCP-Port 2049, UDP wird nicht mehr unterstützt. Zwar liefen auch schon frühere Versionen auf diesem Port, die Hilfsprotokolle wurden vom RPC-Portmapper aber dynamisch zugeteilt. Die Verwendung von Firewalls bei NFS-Verbindungen wird durch diese Maßnahmen stark vereinfacht.

Mehrere Anfragen können gebündelt werden (combined request), sie werden dann vom Server ausgeführt und nur eine Antwort muss zurückgesendet werden. Das Protokoll kann damit effizient auch im Wide-Area-Bereich (WAN) eingesetzt werden, zum Beispiel zwischen verschiedenen Standorten einer Organisation.

Verschlüsselung ist jetzt Teil der Spezifikation. Zwar war früher schon über Secure-RPC eine Verschlüsselung möglich. Dies wurde nur selten genutzt, unter anderem, weil Secure-RPC nicht grundsätzlich zur Verfügung stand.

Der lookup-Aufruf wird durch open ersetzt, die Speicherung von Dateiinformationen wird dadurch möglich. Beispielsweise könnte die Schreib-/Leseposition auf dem Server verwaltet werden. Auch die gemeinsame Nutzung von Dateien wird besser unterstützt. Falls viele Clients eine Datei nur lesen, kann diese an alle Clients verliehen (leases) werden. Wenn ein Client eine Datei schreiben möchte, kann diese exklusiv verliehen werden.

Konfiguration in Unix-Systemen

Die NFS-Freigaben werden unter Unix serverseitig meist in der Datei /etc/exports festgelegt. Der Client kann eine Freigabe manuell mounten oder ggf. mit einem Eintrag in der Datei fstab automatisieren.

Vielen aktuellen Linux-Distributionen liegen grafische Hilfswerkzeuge bei, um die Einbindung von NFS-Freigaben ins System zu vereinfachen.

Sicherheit

NFS wurde geschaffen um in Unix-System-Netzen Dateisysteme über Rechnergrenzen hinweg zugänglich zu machen. Zur Zeit der Entwicklung von NFS waren solche Netze fast ausschließlich zentral verwaltet und die Rechner wurden zentral administriert, entsprechend wurde das Sicherheitskonzept gestaltet.

Die Entwickler von NFS bei Sun Microsystems hatten ursprünglich vorgesehen, die Sicherheit als Aufgabe der RPC-Schicht zu implementieren. Hierzu wird RPC durch Secure-RPC ersetzt. Die NFS-Protokolle selbst bleiben davon unberührt. Leider hat Secure-RPC keine weite Verbreitung gefunden, die Verwendung von Secure-RPC ist auch nicht bei allen Implementierungen möglich.

Ein NFS-Server ohne Secure-RPC exportiert Dateisysteme an bestimmte andere Rechner (von root durch IP-Adressen festgelegt), d. h. der root eines Clientrechners kann auf alle Dateien zugreifen, die der Server an den Client exportiert, unabhängig von deren Zugriffsrechten. Die Zugriffsrechte (der Benutzer) werden von NFS an den Client mitübertragen und vom Betriebssystem des jeweiligen Rechners ausgewertet und gegenüber den Benutzern durchgesetzt. Die Konsistenz der Benutzerdatenbank auf den beteiligten Rechnern wird dabei z. B. durch NIS erreicht.

Heutzutage sind Rechnernetze oftmals offen und nur bedingt zentral administriert, d. h. ein Angreifer kann relativ einfach entweder einen Rechner, dem der NFS-Server vertraut, übernehmen, indem er ihn z. B. mit einem Live-System neu bootet oder einen zusätzlichen Laptop in das Netz hängen und die IP eines gerade nicht laufenden NFS-Clients annehmen. In beiden Fällen kann der Angreifer, da er auf seinem System Rootrechte hat, auf alle an den Client exportierte Dateien, unabhängig von den Zugriffsrechten der Dateien, zugreifen. Somit ist NFS v3 immer nur so sicher, wie das Netz und die beteiligten Rechner.

NFS v4 löst dieses Problem indem z. B. mittels Kerberos eine Benutzeridentifizierung erfolgen kann.

Spezifikationen

  • RFC 1094 (NFS Version 2 Protocol Specification)
  • RFC 1813 (NFS Version 3 Protocol Specification)
  • RFC 3530 (NFS Version 4 Protocol Specification)

NFS Server

Übersicht

Dieser Abschnitt basiert auf Recherchen von Bernd Reimann. Herzlichen Dank an ihn für die Zusammenarbeit!

Bevor wir uns dem Schwerpunkt der Administration eines NFS-Servers zuwenden, sollen kurze Betrachtungen zur Vergangenheit, Gegenwart und Zukunft der NFS-Entwicklung unter Linux etwas Hintergrundwissen vermitteln...

Historie

Bereits 1984, also lange bevor Linus Torvalds auch nur annähernd an Linux dachte und die Computerwelt noch von den Mainframes regiert wurde, widmete sich das Unternehmen SUN Microsystems der Aufgabe, ein System zu entwickeln, das den transparenten Zugriff auf die auf entfernten Rechnern liegenden Daten und Programme ermöglichen konnte.

Nahezu ein Jahr nach dieser Ankündigung (1985) stellte SUN NFS Version 2 (NFS V2) der Öffentlichkeit vor. Das Herausragende dieser Präsentation waren jedoch nicht die technischen Finessen, die das System mit sich bringen würde, sondern die Veröffentlichung der Spezifikation an sich. SUN durchbrach zum ersten Mal die Heiligkeit der Geheimhaltung solcher Interna und ebnete damit auch unwillkürlich den Siegeszug von NFS.

SUN stellte allen interessierten Firmen die Entwicklungsergebnisse als Lizenz zur Verfügung und ermöglichte somit einen de-facto-Standard in der UNIX-Welt, der sich bis heute durchgesetzt hat und immer noch eine der erfolgreichsten UNIX-Technologien darstellt. Nach und nach wurde NFS auf weitere Plattformen wie System V, BSD, AIX, HP-UX und später auch Linux portiert, wo NFS zur Standardausstattung einer jeden Distribution gehört. Selbst viele Nicht-Unix-Systeme, die es zu einer gewissen Verbreitung gebracht haben, warten mit einer NFS-kompatiblen Implementierung auf.

Protokollkollegen

1991 veröffentlichte SUNSoft, eine Tochtergesellschaft von SUN, erstmals eine komplette Sammlung zusammenwirkender Protokolle namens ONC (Open Network Computing), in der alle Bestandteile der Netzwerkkommunikation vom Zugriff auf die Netzwerkhardware bis hin zu Netzwerkanwendungen integriert wurden. Der NFS-Dienst ist Teil dieser ONC-Protokoll-Suite (Abbildung 1) und vertritt dort die Anwendungsebene, d.h. mit dem NFS-Dienst wird direkt gearbeitet. Protokollsuiten

Abbildung 1: Vergleich verbreiteter Protokollstacks

Wie auch das OSI-Modell hat sich die ONC-Protokollsuite als Schema in der Praxis nicht durchgesetzt, auch wenn Protokolle wie XDR (External Data Representation) und der Remote Procedure Call (RPC) untrennbar mit dem NFS-Dienst einhergehen. XDR dient der Konvertierung der zu übermittelnden Daten in ein standardisiertes Format. Dies ist notwendig, da das NFS-Protokoll nicht auf ein System und eine Hardware-Plattform beschränkt ist und unterschiedliche Systeme und Hardware mitunter unterschiedliche Darstellungen der Daten praktizieren.

Hinter dem » Entferntem-Prozedur-Aufruf« (RPC) steckt die Idee, dass Programme auf Funktionen zurückgreifen, die nicht zwingend auf dem gleichen Rechner erbracht werden, wobei sich der Funktionsaufruf aus Sicht des Programms nicht von einem »normalen« lokalen Funktionsaufruf unterscheidet. Der interessierte Leser findet im Abschnitt Remote Procedure Call des Kapitels »Netzwerk-Grundlagen« eine umfassende Diskussion der Mechanismen und Probleme des RPCs.

Auf der Anwendungsebene tummelt sich nicht nur der NFS-Dienst selbst, sondern auch noch (verwandte) Protokolle wie das Mount-Protokoll, der Netzwerk-Lock-Manager (NLM) und der Netzwerk-Status-Monitor (NSM). Das Mount-Protokoll ist für den »Einhängevorgang« des Dateisystems zuständig, ein konkretes Beispiel des doch recht komplexen Vorgangs folgt zu einem späteren Zeitpunkt . NLM und NSM ermöglichen den exklusiven Zugriff auf Dateien über Rechnergrenzen hinweg. Beide Dienste sind für den Betrieb von NFS nicht zwingend erforderlich, ob Sie sie benötigen, erfahren Sie im Abschnitt Interna .

Kernel-NFS vs. Nutzeradressraum-NFS

Wer mit der Materie wenig vertraut ist, wird womöglich zum ersten Mal mit beiden Begriffen konfrontiert sein. Eigentlich erübrigt sich eine Diskussion über Vor- und Nachteile, hat sich doch der kernel-basierte Serverdienst gegenüber der alteingesessenen Implementierung als im Nutzeradressraum tätiger Serverprozess eindeutig durchgesetzt. Und dennoch verlangt eine umfassende Betrachtung einen tieferen Blick hinter die Kulissen.

Der so genannte User-Space NFS Server, wie er vor wenigen Jahren noch jeder Linux-Distribution beilag, zeichnet sich vor allem durch eine einfach zu realisierende Implementierung aus. Allein die Tatsache, dass ein Client dieselbe Sicht auf ein gemountetes Dateisystem hat, wie auch der Server, ermöglicht ein simples Mapping von lokalen Gruppen- und Benutzeridentifikationen (gid, uid) auf die vom importierten Dateisystem verwendeten Nummern. Dem User-Space-NFS-Server stand hierzu ein Rpc-Dienst (rpc.ugidd) zur Seite, der anhand einer Tabelle die Umsetzung der Benutzeridentifikationen vornahm. Nicht zuletzt aus Sicherheitsgründen unterstützt der neue Kernel-NFS-Server nur eine stark eingeschränkte Variante dieses Verfahrens (vergleiche Squashing ).

Wenn der kernel-basierte Server so aufwändig zu implementieren ist, warum hat man es nicht beim User-Space NFS Server belassen? Im Großen und Ganzen führen alle Überlegungen auf einen Grund zurück: Im Kernel arbeitet der Server entschieden schneller!. Der alte User-Space-NFS-Server kannte kein Threading (vereinfacht ausgedrückt, kann ein thread-basiertes Programm mehrere Aufgaben quasi gleichzeitig verrichten). Dieses Manko hätte eine Reimplementierung sicher noch behoben, aber auf Grund der strikten Schutzmechanismen im Betriebssystem bleiben dem Kernel-Server etliche Kopieroperationen erspart, da er bspw. die Berechtigung besitzt, Daten direkt in den Speicherbereich der Netzwerkkarte zu befördern. Ein Server im Nutzeradressraum müsste hierzu erst den Kernel bemühen, was allein schon einen Taskwechsel - und damit Zeit - bedingt. Weitere Unzulänglichkeiten sind die fehlende Unterstützung für NLM (Network Lock Manager) und NSM (Network Status Monitor) sowie die leidige Beschränkung der Dateigröße auf 2GB.

Die Vorteile des Kernel-Space NFS Servers liegen neben dem Geschwindigkeitsgewinn in dessen erweitertem Funktionsumfang. So beherrscht er mittels der NLM und NSM Protkolle das Setzen von Dateisperren auf exportierten Verzeichnissen. Und da die Überwachung der exports-Datei als Systemruf implementiert ist, müssen Server und Mountd nicht explizit über Änderungen unterrichtet werden. Die (theoretische) Beschränkung der Dateigröße liegt nun bei 263 Bits.

Leider besitzt auch die Kernelrealisierung noch eine Schwäche. So werden Dateisysteme, die sich unterhalb eines exportierten Verzeichnisses befinden, nicht automatisch exportiert (bis auf einen Fall; siehe später). Für diese wird ein extra Eintrag in der exports-Datei und damit clientseitig ein weiterer Mountvorgang notwendig.

So komplex obige Ausführungen auch anmuten mögen, aus Sicht des Administrators bestehen bez. der Einrichtung von NFS keinerlei Unterschiede zwischen User- und Kernel-Space NFS.

Ausblick

Im kurzen historischen Abriss war von NFS Version 2 die Rede. Version 3 ist seit Jahren existent und an Version 4 wird gestrickt. Die aktuellen NFS-Server (Kernelversionen ab 2.2.19) unterstützen alle Forderungen der Version 2 und bereits wesentliche Teile von Version 3. Die letzte »Hürde« (NFS via TCP) zur vollständigen Umsetzung von Version-3-Funktionalität ist als experimenteller Patch (ab Kernel 2.4.19) bereits genommen, die stabile Version ist somit nur noch eine Frage der Zeit. Auch Entwicklungen zur Umsetzung von NFS der 4. Version sind angelaufen.

Schritte zum Serverstart

Ports, Ports, Ports

Da eine Kommunikation zwischen zwei Rechnern über sogenannte Sockets läuft, also die IP-Adresse und die zugehörige Portnummer eines Dienstes, muss natürlich der Client, der seine Anfrage an den Server richtet, auch diese Portnummer kennen. Auf Grund der Fülle existenter RPC-Dienste werden Portnummern für diese nicht mehr strikt statisch vergeben, sondern über einen zusätzlichen Dienst - den Portmapper oder auch RPC-Bind (SUN) genannt - verwaltet. Der Portmapper selbst lauscht an einem festgelegten Port (111 sowohl über UDP als auch TCP ).

Dieser Portmapper ist in den meisten Distributionen standardmäßig installiert und wird oft durch ein Init-Skript in den Netzwerk-Runleveln beim Booten des Systems gestartet. Wird der Portmapper nur selten benötigt, spricht nichts gegen einen automatischen Start bei Bedarf durch den [x]inet-Daemonen .

Der Portmapper verwaltet eine Art kleine Datenbank, in der er verschiedene Informationen zu allen auf dem System aktiven RPC-Diensten hält. Ein RPC-Dienst muss sich deshalb beim Start beim Portmapper registrieren und ihm u.a. die von ihm verwendete Portnummer mitteilen. Bei Anfragen eines RPC-Clients an den Portmapper nach einem konkreten RPC-Dienst (PMAPPROC_GETPORT()), durchsucht dieser seine Datenbasis und übergibt, falls der Dienst verfügbar ist, dessen Portnummer. Alle Clientzugriffe erfolgen später direkt an diesen Port (also unter Umgehung des Portmappers; Abbildung 2). Kontaktaufnahme des Clients zum Server

Abbildung 2: Kontaktaufnahme des Clients zum Server

RPC-Dienste und Sicherheit

Der Zugang zu fast jedem RPC-Dienst unter Linux wird in aktuellen Programmversionen durch die Konfigurationen der Dateien /etc/hosts.allow und /etc/hosts.deny geregelt. Sie können leicht feststellen, ob die Dateien für ein Programm relevant sind:

# Wertet 'rpc.mountd' die Dateien hosts.allow und hosts.deny aus?
user@sonne> strings /usr/sbin/rpc.mountd | grep hosts
hosts_access_verbose
hosts_allow_table
hosts_deny_table
/etc/hosts.allow
/etc/hosts.deny
@(#) hosts_ctl.c 1.4 94/12/28 17:42:27
@(#) hosts_access.c 1.21 97/02/12 02:13:22

Insofern ein Dienst nicht in einer der Dateien »hosts.allow« bzw. »hosts.deny« aufgeführt ist, ist der Zugang zu diesem gewährt. In der Datei »hosts.allow« kann der Zugang explizit erlaubt und in »hosts.deny« verboten werden, wobei bei widersprüchlichen Einträgen in beiden Dateien die Angaben aus »hosts.allow« gelten.

In sicherheitskritischem Umfeld ist es nicht ungewöhnlich, zunächst pauschal sämtliche Dienste in »hosts.deny« zu sperren, um die wirklich benötigen in »hosts.allow« explizit für auserwählte Rechner zuzulassen. Bez. der auf einem NFS-Server notwendigen Dienste, wären folgende Einträge in die Dateien erforderlich, um den Zugriff für Rechner des lokalen Netzwerks (192.168.100.0) zuzulassen:

root@sonne> vi /etc/hosts.deny
# Alles verbieten
ALL : ALL
root@sonne> vi /etc/hosts.allow
# Alle für NFS notwendigen Dienste für die lokale Domain freigeben:
portmap    : 192.168.100.0/255.255.255.0
mountd     : 192.168.100.0/255.255.255.0
lockd      : 192.168.100.0/255.255.255.0
statd      : 192.168.100.0/255.255.255.0
rquotad  : 192.168.100.0/255.255.255.0

Die Namen der einzelnen Dienste könnten auf Ihrem System von denen im Beispiel abweichen. Im Zweifelsfall sollten Sie nach der Registrierung der RPC-Dienste beim Portmapper die Namen der Ausgabe von »/usr/sbin/rpcinfo -p« entnehmen (mehr Informationen dazu im weiteren Text). »lockd« und »statd« sind einzig erforderlich, wenn Programme auf dem Client mit Dateisperren arbeiten (vergleiche Anmerkungen in der Einleitung); der RPC-Dienst »rquotad« ist notwendig, wenn auf den exportierten Verzeichnissen Quotas Verwendung finden.

Registrierung

Vergewissern Sie sich zunächst, dass der Portmapper auf Ihrem System aktiv ist. Dies kann entweder über die Statusabfrage des Runlevelskripts (falls ein solches existiert) erfolgen oder durch Suche in der Ausgabe des Kommandos ps :

# Abfrage über Runlevelskript (dessen Name kann auf Ihrem System abweichend lauten!)
root@sonne> /etc/init.d/portmap status
Checking for RPC portmap daemon:                     running
# Abfrage mittels ps
user@sonne> ps ax | grep portmap
   399 ?        S      0:00 /sbin/portmap
1578 pts/3 S 0:00 grep portmap

Ist der Portmapper inaktiv, dann starten Sie ihn entweder über das Runlevelskript oder per Hand:

# Start über Runlevelskript (dessen Name kann auf Ihrem System abweichend lauten!)
root@sonne> /etc/init.d/portmap start
Starting RPC portmap daemon                          done
# Start per Hand
root@sonne> /sbin/portmap

In den aktuellen Distributionen erledigt den Start des NFS-Servers und aller weiteren notwendigen Dienste ein Skript, bei SuSE ist dies bspw. »/etc/init.d/nfsserver«:

# NFS-Serverstart bei SuSE
root@sonne> /etc/init.d/nfsserver start
Starting kernel based NFS server done

Existiert kein solches Skipt, müssen Sie die Dienste per Hand aktivieren:

root@sonne> /sbin/rpc.statd
root@sonne> /sbin/rpc.lockd
root@sonne> /usr/sbin/rpc.mountd
root@sonne> /usr/sbin/rpc.nfsd
root@sonne> /usr/sbin/rpc.rquotad

Die Dienste »/sbin/rpc.statd« und »/sbin/rpc.lockd« bzw. »/sbin/rpc.rquotad« sind nicht zwingend notwendig (siehe Anmerkungen in der Einleitung und unter Interna ).

Vom erfolgreichen Registrieren der RPC-Dienste beim Portmapper können Sie sich durch einen Aufruf von »rpcinfo« überzeugen. In Verbindung mit der Option »-p« erfahren Sie, welche Dienste mit welchen internen Daten aktuell verwaltet werden:

user@sonne> rpcinfo -p
   Program Vers Proto    Port
    100000    2   tcp     111  portmapper
    100000    2   udp     111  portmapper
    100021    1   udp    1024  nlockmgr
    100021    3   udp    1024  nlockmgr
    100024    1   udp    1025  status
    100024    1   tcp    1024  status
    100011    1   udp     969  rquotad
    100011    2   udp     969  rquotad
    100005    1   udp    1033  mountd
    100005    1   tcp    1025  mountd
    100005    2   udp    1033  mountd
    100005    2   tcp    1025  mountd
100003 2 udp 2049 nfs

Die Ausgaben könnten auf Ihrem System durchaus von obigem Beispiel abweichen, so sind abweichende Portnummern oder ähnliche Namen für die Dienste ebensowenig Besorgnis erregend, wie mehrfaches Auftauchen eines RPC-Dienstes in der Tabelle, da in vielen Konfigurationen aus Effizienzgründen gleich mehrere Instanzen eines Dienstes aktiviert werden.

Verzeichnisexport

Exportfs

Bevor ein Client ein Verzeichnis vom Server importieren kann, muss dieser dieses explizit mit den erforderlichen Rechten exportieren. Der Export eines Verzeichnisses erfolgt mit dem Kommando exportfs (das Kommando existiert nur in Zusammenhang mit dem Kernel-NFS):

/usr/sbin/exportfs [-avi] [-o Mountoptionen,..] [Client:/Pfad..]
/usr/sbin/exportfs [-av] -u [Client:/Pfad..]
/usr/sbin/exportfs -r [-v]

Der Export von Verzeichnissen mittels »exportfs« ist zumeist nur in der Testphase des NFS-Servers oder bei einmaliger Freigabe eines Verzeichnisses erforderlich. »exportfs« wird hauptsächlich genutzt, um nach Änderungen in der Datei »/etc/exports« den Server (genauer: rpc.nfsd und rpc.mountd) zu instruieren, seine Konfiguration neu einzulesen. Bei den Mountoptionen des Kommandos handelt es sich um eben diese, die anschließend in Zusammenhang mit der Datei »/etc/exports« vorgestellt werden; an dieser Stelle verzichten wir auf ihre Diskussion und veranlassen in einem ersten Beispiel den NFS-Server, das Verzeichnis »/home/user« für den Rechner »venus« freizugeben:

root@sonne> exportfs venus.galaxis.de:/home/user

Prinzipiell können Sie für die Rechnernamen dieselbe Syntax wie in »/etc/exports« verwenden; vergessen Sie jedoch nicht, enthaltene Sonderzeichen vor Interpretation durch die Shell zu schützen. Wird - wie im Beispiel - auf Mountoptionen verzichtet, gelten async, ro, root_squash, secure (Erklärung im Anschluss).

Um das Verzeichnis vom Export wieder auszuschließen, ist die Option »-u« dienlich:

root@sonne> exportfs -u venus.galaxis.de:/home/user

Die Option »-a« exportiert alle (auf der Kommandozeile und in /etc/exports angegebenen) Verzeichnisse; in Zusammenhang mit »-u« werden sämtliche exportierten Verzeichnisse vom Export ausgeschlossen. Um in solchen Fällen die Auswertung der Datei »/etc/exports« zu verhindern, dient »-i«. Schließlich synchronisiert die Option »-r« die aktuelle Datenbasis des NFS-Servers (/var/lib/nfs/xtab) mit den Einträgen der Datei »/etc/exports«.

Nach Änderungen in der Datei »/etc/exports« führt folgender exportfs-Aufruf zu einer Aktualisierung beim Server:

root@sonne> exportfs -ra

Anmerkung: Beim älteren User-Space-NFS-Server gelingt der Export von Verzeichnissen einzig über Einträge in der Datei »/etc/exports«. Anschließend muss dem Serverprozess das Signal SIGHUP gesendet werden (kill -HUP <Prozess-ID des Servers>).

Die Datei /etc/exports

Anstatt Dateisysteme einzeln via »exportfs« zu exportieren, wird die Konfiguration mittels der Datei »/etc/exports« bevorzugt (...und in Verbindung mit dem User-Space-NFS-Server ist dies die einzige Möglichkeit der Konfiguration).

Der Aufbau eines Eintrags in die Datei ist einfach:

Verzeichnis Client[(Mountoption,...)] [Client[(Mountoption,...)] ]

Verzeichnis bezeichnet das zu exportierende Verzeichnis. Es folgt eine Liste der Client-Rechner, die zum Importieren dieses Verzeichnisses befugt sind. Optional kann der Zugriff auf die Daten für einen Client gegenüber der Voreinstellung (async, ro, root_squash, secure) weiter eingeschränkt oder auch gelockert werden.

Die Syntax für Client ist etwas weiter gefasst. Hier sind nicht nur die Angabe starrer Rechnernamen gestattet, sondern ebenso die Bezeichnung von Netzgruppen (die in der Datei /etc/netgroup definiert sein müssen) oder die Verwendung von Wildcards zur Definition von Mustern. Damit ergeben sich folgende Varianten zur Angabe:

erde.galaxis.de Angabe eines konkreten Rechners (oder auch IP-Adresse)

@Gateways Bezug auf eine Netzgruppe, die der Datei [Linuxfibel - Netzwerk Server - NFS Server#Die Datei /etc/netgroup|/etc/netgroup]] definiert sein muss

*.galaxis.de Angabe von Mustern; hier: alle Rechner aus der Domäne »galaxis.de« 

192.168.100.0/255.255.255.0

192.168.100.0/22 Angabe von IP-Netwerken inklusive Subnetzmaske , welche für den Fall, dass allein führende Bits zur Maskenbildung herangezogen werden, auch als Anzahl der Bits (22 im Beispiel) spezifiziert werden kann

Jeder Angabe eines Clients kann eine Liste vom Optionen folgen, die den Zugriff auf die exportierten Daten steuern. Innerhalb der kommaseparierten Liste sind keine Leerzeichen statthaft! Mögliche Werte sind:

secure, insecure Client-Anfragen werden nur von vertrauenswürdigen Ports (Portnummern unterhalb 1024) akzeptiert (»secure«, Voreinstellung); mit »insecure« werden auf Anfragen an höhere Ports akzeptiert

ro, rw Das Verzeichnis wird schreibgeschützt (»read only«, Voreinstellung) bzw. mit vollen Lese- und Schreibrechten für den Client (»read/write«) exportiert

sync, async Der Server darf den Vollzug eines Schreibvorgang dem Client erst melden, wenn die Daten tatsächlich auf die Platte geschrieben wurden (Ausschalten des Plattencaches). Die Voreinstellung ist async.

wdelay, no_wdelay Die Option wird nur in Zusammenhang mit »sync« beachtet und erlaubt dem Server die Bestätigung eines Schreibvorgangs zu verzögern, falls mehrere Schreibvorgänge von einem Client zur gleichen Zeit im Gange sind. Anstatt jeden zu bestätigen, sendet der Server nur eine einzige Antwort nach Vollzug aller Schreiboperationen (betrifft »wdelay«, Voreinstellung).

hide, nohide Exportiert der Server ein Verzeichnis, in dem wiederum ein anderes Dateisystem gemeountet ist, so wird dieses nicht an einen Client exportiert (»hide«, Voreinstellung). Dies bedeutet allerdings, dass die Dateisysteme weiterhin alle einzelnd auf der Server-Seite exportiert werden müssen jedoch nicht alle expliziet auf der Client gemountet werden müssen. Die »nohide«-Option (also den impliziten Export) funktioniert jedoch nur, wenn es sich bei der Clientangabe um einen Rechnernamen (keine Wildcards, IP-Netzwerke und Netzgruppen!) handelt.

subtree_check, no_subtree_check Werden nur Teile eines Dateisystems vom Server exportiert, so muss der Server prüfen, dass Zugriffe nur auf Dateien erfolgen, die innerhalb dieses Teilbaums liegen (»subtree_check«, Voreinstellung). Dies erhöht zwar die Sicherheit allerdings auf Kosten der Geschwindigkeit, sodass die Prüfung mit »no_subtree_check« abgeschalten werden kann.

root_squash, no_root_squash Root erhält die UserID des Pseudobenutzers »nobody«, womit der Root-Benutzer des Client-Rechners keine Root-Rechte auf dem vom Server importierten Verzeichnis erhält (Voreinstellung); mit »no_root_squash« bleiben die Root-Rechte auf Clientseite auf dem Verzeichnis erhalten.

all_squash, no_all_squash Alle Zugreifenden erhalten die Nobody-UID; Voreinstellung ist »no_all_squash«, womit die Nutzerkennungen erhalten bleiben

anongid=gid Squashing der Gruppe; die Gruppen-ID wird auf »gid« gesetzt. Bei dieser Option kann Root entscheiden, mit welcher Server-GID die Client-Benutzer arbeiten sollen, sobald sie Zugriff auf den Server haben

anonuid=uid Squashing des Benutzers. Die zugreifenden Benutzer bekommen die UID »uid« verpasst

Die Optionen zum Verändern der Nutzerkennungen werden als »Squashing« bezeichnet und werden im folgenden Abschnitt detailliert diskutiert.

Die Datei /etc/exports - Ein Beispiel

Als reales Szenario nehmen wir an, dass unser NFS-Server (»sonne.galaxis.de«) als Datei- und als NIS-Server konfiguriert wurde. Die zentrale Aufgabe eines NIS-Servers ist immer noch die Bereitstellung einer zentralen Benutzerverwaltung, in Kombination mit einen NFS-Server werden meist auch die Heimatverzeichnisse der Benutzer zentral gehalten, sodass ein Benutzer sich an einen beliebigen Rechner eines Pools anmelden kann und überall seine gewohnte Umgebung vorfinden wird.

Des Weiteren gehen wir davon aus, dass die Clients nur über eine beschränkte Plattenkapazität verfügen, sodass sie etliche Daten, die nicht der Grundfunktionalität dienen, ebenso via NFS importieren (wir gehen jetzt nicht soweit, festplattenlose Clients in die Betrachtung einzubeziehen, die sogar ihr Root-Dateisystem und den Swap via NFS beziehen).

In der nachfolgenden Beispieldatei finden Sie weitere Anmerkungen in Form von Kommentaren, warum welche Option für welches Verzeichnis gesetzt wurde; die Überlegungen sollten auf etliche Rahmenbedingungen übertragbar sein.

root@sonne> vi /etc/exports
# Wir nehmen an, dass /home auf einer eigenen Partition liegt, sodass sich die Prüfung, ob eine Datei innerhalb des  exportierten Verzeichnisses liegt, erübrigt. Dass Benutzer innerhalb ihrer Heimatverzeichnisse auch Schreibrechte  erhalten sollten, ist verständlich. Da unsere Netzwerk als sichere Zone anzusehen ist, verzichten wir auf die  Einschränkung der zulässigen Portnummern:
/home           *.galaxis.de(rw,no_subtree_check,insecure)
# Wie der Name schon sagt, sind Daten unter /usr/share geeignet, um an zentraler Stelle für verschiedene Clients  bereit gestellt zu werden. Kein Client muss diese Daten veränern können, deshalb setzen wir gleich die Benutzerkennungen auf den sehr restriktiven Zugang »nobody«
/usr/share *.galaxis.de(ro,all_squash)

Abschließend sei darauf hingeweisen, dass auf Clientseite beim Import eines Verzeichnisses die Rechte weiter eingeschränkt werden können. Die Informationen dazu finden Sie im Abschnitt zum NFS-Client .

Squashing

Gerade wurde bei den Optionen und Parametern der Begriff »Squashing« eingeführt, doch was bedeutet er?

Lassen Sie es mich an einem Beispiel erklären: Auf dem System »sonne« (NFS-Server) existieren in einem exportierten Verzeichnis folgende Dateien:

user@sonne> ls -l

-rw-r-----    1  root     root    166 Apr 27 10:45 foo.bar
-rw-------    1  tux      users    16 Apr 27 10:45 testdaten.txt

Des weiteren existieren Benutzer mit folgender UID: root 0 tux 501

Auf System »venus« (unser NFS-Client) existieren Benutzer mit folgenden UIDs: root 0 alf 501 tux 502

Was passiert nun, wenn wir auf dem Client eine Serverfreigabe mounten?

Dazu muss man wissen, dass Unix die Zugriffsrechte nicht aufgrund der Benutzernamen verwaltet, sondern einzig anhand der zugrundeliegenden UIDs. In unserem Falle hat der Benutzer »alf« (auf dem Client) plötzlich Zugriff auf die Datei »testdaten.txt« von Benutzer «tux«, da beide dieselbe UID 501 besitzen. Gleiches gilt natürlich ebenso für den Benutzer »root«.

Um dies zu verhindern, gibt es das »Squashing«. Hierbei werden die UIDs und GIDs der auf die gemounteten Verzeichnisse zugreifenden Benutzer auf eine neutrale UID (der Pseudouser nobody mit UID -2) und GID (nogroup mit GID -2) gesetzt, wenn dieses mit der Option »all_squash« exportiert wurde. Die UID 0 (GID 0; also Root) wird in der Voreinstellung stets nach »nobody/nogroup« gemappt; erst die Option »no_root_squash» verhindert die Umsetzung.

Der alte User-Space-NFS-Server erlaubte das »Squashen« jeder UID auf jede beliege andere und ebenso konnte jede Gruppenkennung (GID) auf jede andere gemappt werden. Der neuer Kernel-NFS-Server arbeitet wesentlich restriktiver und gestattet einzig, anstatt dem Pseudobenutzer »nobody« bzw. der Pseudogruppe »nogroup« mittels »anonuid=<UID>« bzw. »anonguid=<GID>« andere Kennungen zu vergeben. Diese gelten dann jedoch für beliebige Gruppen oder Benutzer.

Bez. unserer oben angegebenen Benutzerstrukturen würde bei Export des Verzeichnisses mittels der Option »all_squash« der Client-Benutzer »alf« nur noch ein »Nobody« sein und hätte somit nur Lesezugriff auf die Datei »testdaten.txt« 

Etwas Statistik

Nicht zuletzt beim Aufspüren von Fehlkonfigurationen sind zwei Kommandos zur Diagnose des NFS-Servers nützlich. Zum einen erlaubt showmount einen Einblick sowohl auf die vom Server bereitgestellten Dateisysteme als auch auf die momentan aktiven Clients. Zum zweiten erlaubt nfsstat die Auswertung zahlreicher statistische Daten des Kernel-NFS-Servers.

showmount

/usr/sbin/showmount [ -adehv ] [ NFS-Server]

Ohne Argumente aufgerufen, listet das Kommando die Namen der NFS-Clients auf, die aktuell Verzeichnisse vom Server importiert haben; bei Verwendung der Option »-a« werden zusätzlich die Verzeichnisnamen aufgeführt:

user@sonne> /usr/sbin/showmount
All mount points on sonne:
venus.galaxis.de:/home/
venus.galaxis.de:/usr/share/
erde.galaxis.de:/home/

Um einzig die aktuell von Clients importierten Verzeichnisnamen anzuzeigen, nicht aber die Namen der Clientrechner selbst, dient die Option »-d«. »-h« schreibt eine Kurzhilfe aus; »-v« die Versionsnummer des Programms.

Vor allem für Clientrechner interessant ist die Option »-e«, mit der sie, wenn Sie auf der Kommandozeile noch den Namen eines NFS-Servers angeben, testen können, welche Verzeichnisse ein Server für welchen Client exportiert:

user@erde> /usr/sbin/showmount -e sonne.galaxis.de
Export list for sonne.galaxis.de:
/home      *.galaxis.de
/usr/share *.galaxis.de

nfsstat

/usr/sbin/nfsstat [-anrcs] [-o <Kategorie>

Der Zugang zu den Statistiken im Kernel trägt eher informativen Charakter und verdeutlichen, welche Anforderungen die Clients tatsächlich stellen. Die Unterscheidung nach NFS Version 2 und 3 zeigt, in welchem Verhältnis die Clients nach dem alten bzw. nach dem neuen Protokoll arbeiten; im nachfolgend dargestellten Beispiel habe ich der besseren Übersicht wegen die Tabelle für die Versionen 2 entfernt.

Die Optionen des Kommandos helfen, die Ausgaben auf einen konkreten Typ zu beschränken. So begnügt sich »nfsstat -s« auf die Ausschrift der Statsitik der Serverseite, während »nfsstat -c« nur die Client-Daten offenbahrt.

»nfsstat -r« beschränkt sich auf Angabe der RPC-relevanten Daten; »nfsstat -n« tut dasselbe für die NFS-spezifischen Informationen.

root@sonne> nfsstat
Server rpc stats:
calls      badcalls   badauth    badclnt    xdrcall
20860      0          0          0          0
Server nfs v3:
null       getattr    setattr    lookup     access     readlink
0       0% 264     1% 0       0% 1148    5% 14726  70% 32      0%
read       write      create     mkdir      symlink    mknod
4485   21% 0       0% 0       0% 0       0% 0       0% 0       0%
remove     rmdir      rename     link       readdir    readdirplus
0       0% 0       0% 0       0% 0       0% 188     0% 14      0%
fsstat     fsinfo     pathconf   commit
1       0% 2       0% 0       0% 0       0%
Client rpc stats:
calls      retrans    authrefrsh
775        0          0
Client nfs v3:
null       getattr    setattr    lookup     access     readlink
0       0% 263    33% 0       0% 0       0% 494    63% 2       0%
read       write      create     mkdir      symlink    mknod
1       0% 0       0% 0       0% 0       0% 0       0% 0       0%
remove     rmdir      rename     link       readdir    readdirplus
0       0% 0       0% 0       0% 0       0% 0       0% 14      1%
fsstat     fsinfo     pathconf   commit
0 0% 1 0% 0 0% 0 0%

Unter Kategorie können nochmals die Statistiken speziell für RPC (»nfsstat -o rpc«) und NFS (»nfsstat -o nfs«) abgerufen werden. Zusätzlich sind Informationen über Auslastung des Transportprotokolls (»nfsstat -o net«), des Dateihandle-Caches (»nfsstat -o fh«) und des Antwortcaches (»nfsstat -o rc«) abrufbar.

root@sonne> nfsstat -o net
Server packet stats:
packets    udp        tcp        tcpconn
0          20860      0          0
Client packet stats:
packets    udp        tcp        tcpconn
0 0 0 0

Der Mountvorgang intern

Die Abläufe eines vom NFS-Clients initiierten Dateiimports sind recht komplex. Die Verwendung des hierzu notwendigen Kommando mount finden Sie im Abschnitt zum NFS-Client . Hier schauen wir hinter die Kulissen, also auf das Zusammenspiel der einzelnen Komponenten bis letztlich das Dateihandle, eine vom Server vergebene eindeutige Kennziffer für das Verzeichnis, zum Client gelangt.

Ausgangspunkt sei folgender erstmaliger Mount-Aufruf:

root@venus> mount -t nfs sonne:/home /home

Anmerkung: Bei entsprechender Konfiguration kann ein Mountvorgang auch einem »normalen« Benutzer gestattet werden oder gar per Automounter automatisch bei Bedarf erfolgen.

Zum Zeitpunkt der ersten Kontaktaufnahme zum NFS-Server fehlt dem Client die Kenntnis der korrekten Portnummer, an dem dieser wartet. Deshalb geht die erste Anfrage an den Portmapper des Servers, an welchem Port der Mount-Daemon wartet. Mittels einer weiteren Anfrage beim Portmapper sollte der Client auch noch die Portnummer des NFS-Daemons in Erfahrung bringen (falls notwendig, erfragt der Client auch noch die Portnummern der RPC-Dienste NSM und NLM). Die Prinzipien des Verfahrens sollten Ihnen aus dem Abschnitt Schritte zum Serverstart bekannt sein. Einmal erfragte Portnummern werden solange lokal vorgehalten, bis ein Zugriff auf einen solchen Port einen Fehler meldet (oder der Client neu bootet;-).

Mit der Erkenntnis, an welchem Port der Mount-Daemon des Servers wartet, wendet sich der Client nun direkt an diesen. Der Mount-Daemon durchsucht nun die Datei »/var/lib/nfs/etab«, ob das erwünschte Verzeichnis zum Export freigegen ist und ob der Client zum Import berechtigt ist.

user@venus> cat /var/lib/nfs/etab
/usr/share *.galaxis.de(ro, async, wdelay, hide, secure, root_squash, all_squash,subtree_check, secure_locks,  mapping=identity, anonuid=-2, anongid=-2)
/home/ *galaxis.de(rw, async, wdelay, hide, secure, root_squash, no_all_squash, no_subtree_check, secure_locks, mapping=identity, anonuid=-2, anongid=-2)

Verlaufen die Überprüfungen erfolgreich, so wendet sich der Mount-Daemon an den NFS-Daemon (Funktion GETFH()), der ein eindeutiges Dateihandle, das das exportierte Verzeichnis referentiert, erzeugt. Dieses Handle ist ein Datenobjekt und enthält eine eindeutige Zufallszahl, die die Identifikation der Datei (ein Verzeichnis ist unter Unix letztlich auch nur eine Datei) gewährleisten soll und nur einmalig vergeben wird. Dieses Dateihandle übergibt der NFS-Daemon dem Mount-Daemon, der es zum Client sendet (Abbildung 3). Ablauf eines NFS-Mounts

Abbildung 3: Ablauf eines NFS-Mounts

Alle weiteren Zugriffe auf Dateien des importierten Verzeichnisses erfolgen durch direkten Kontakt zwischen NFS-Client und dem NFS-Daemon-Prozess. Der Client gibt jeweils das Dateihandle an, womit der Server das Verzeichnis kennt, von dem aus er nach angeforderten Dateien suchen muss. Was in der Abbildung nicht dargestellt wurde, ist die eventuell notwendige Interaktion zwischen Lock-Manager und Status-Monitor, falls beim Zugriff auf Dateien mit Sperren gearbeitet werden soll.

Interna

Rein informellen Charakter tragen die weiteren Ausführungen, die Apsekte ansprechen, die für die Administration von NFS selbst unerheblich sind.

Cachefs

Oftmals ist es wünschenswert, wenn es eine Art Zwischenspeicher für die Netzzugriffe gibt, um die Netzbelastung so gering wie möglich zu halten. Hierfür gibt es von SUN (mal wieder!) ein Dateisystem namens Cachefs, das genau dieses »Caching« übernimmt. Leider existiert noch keine Implementierung dieses Dateisystems für Linux, jedoch wird es unter anderen Unixen häufig verwendet. Bei Cachefs wird ein Puffer-Verzeichnis angelegt, das nach und nach mit den vom Server angeforderten Daten gefüllt wird. Bei jedem Datenzugriff wird nun zunächst geprüft, ob diese eventuell bereits im lokalen Puffer enthalten sind. Falls ja, muss die Datei nicht erst erneut übers Netz vom Server geladen werden, was einen mitunter erheblichen Geschwindigkeitsvorteil mit sich bringt, da lokale Bus- und Dateisysteme immer schneller sind als Netzleitungen (oder haben sie ein Gigabit-Ethernet zu Hause?).

CacheFS unter Linux = FS-Cache siehe : http://gentoo-wiki.com/HOWTO_FS-Cache http://en.wikipedia.org/wiki/CacheFS

Quota

Quotas dienen der Beschränkung des einem Benutzer zur Verfügung stehendem Plattenspeicherplatzes. Die Quotas selbst werden nur auf dem Server eingerichtet und ihre Einhaltung überwacht. Um Benutzern auf den Clients eine Abfrage ihres Quotastatus zu ermöglichen, ist auf dem NFS-Server der RPC-Dienst rpc.rquotad zu starten.

Network State Monitor (NSM) und Network Lock Manager (NLM)

Um gleichzeitige Zugriffe auf einunddieselben Dateien koordinieren zu können, behilft sich NFS eines Network-Lock-Managers (rpc.lockd) und eines Network-State-Monitors (rpc.statd). Das allein garantiert noch keine Dateisperren, denn diese müssen die auf NFS-importierte Dateien zugreifenden Programme auf Clientseite implementieren. Und dies tun bis heute die wenigsten Programme unter Linux. Daher ist es in den meisten Linuxnetzwerken gar nicht erforderlich, rpc.statd und rpc.lockd zu aktivieren.

Prinzipiell fordert ein entsprechend realisiertes Programm vom Kernel eine Dateisperre an. Der Kernel erkennt, dass die Datei auf einem via NFS gemountetem Dateisystem liegt und leitet die Anforderung an den lokalenLock-Manager weiter. Dieser sendet die Anforderung an den Lock-Daemon auf dem Server, welcher den Vorgang akzeptiert oder ablehnt. Das Ergebnis schickt er zum Lock-Daemon des Clients zurück, der es dem Kernel reicht.

Angenommen, während einer aktiven Dateisperre startet entweder der Client oder der Server neu, was passiert mit den Sperren? Jetzt kommt der Status-Monitor ins Spiel. Wenn auf Serverseite der Lock-Manager für einen Client eine Dateisperre anlegt, so unterrichtet er den Status-Monitor, welcher den Namen des Client-Rechners unter /var/lib/nfs/sm ablegt. Auf Clientseite erfährt der Status-Monitor die akzeptierte Sperre ebenso vom lokalen Lock-Manager, nur speichert er den Namen des Servers, von dem die Sperre gesetzt wurde.

Bootet nun ein Client neu, prüft der lokale rpc.statd sofort, ob irgendein Server zu unterrichten ist. Falls ja, kontaktiert er dessen Status-Monitor, der den Lock-Manager auf Serverseite unterrichtet, welcher wiederum alle Dateisperren des Clients aufhebt.

Fällt allerdings der Server aus, so unterrichtet nach einem Neustart dessen Status-Monitor die Kollegen auf allen Clients, die aktuelle Dateisperren besaßen. Die Lock-Manager auf den Clients versuchen nun zunächst die Dateisperren vom Server erneut anzufordern. Der Lock-Manager auf dem Server wird die durch den Neustart ungültigen Sperren noch »eine Zeit lang« reservieren und einzig dem »alten« Besitzer (also Client) gestatten, die Sperre unverzüglich anzufordern. So wird dem Client eine Chance erteilt, die verlorenen Sperren zu erneuern.

Unterschiede NFSV2 und NFSV3

Obwohl NFS V2 schon mehrere Jahre nach seiner Fertigstellung einen neuen großen Bruder erhielt (NFS V3), ist es trotzdem immer noch ein Standard und wird bei Linux weitestgehend eingesetzt. Langsam aber sicher findet der Umstieg auf NFS V3 statt, der aus Kompatibiltätsgründen fast alle alten Prozeduren übernimmt und neue Eigenschaften einbringt. So kann bei Version 3 nun zwischen den beiden Protokollen UDP und TCP ausgewählt werden, was bei Einsatz von TCP eine Entlastung des Dienstes bedeutet, da TCP nun die Fehlersicherung übernimmt und somit eine sichere Leitung gewährleistet - jedoch zum Preis einer erhöhten Netzbelastung (an der TCP-Unterstützung durch den Kernel-NFS-Daemon wird derzeit gearbeitet; vergleiche »Ausblick« in der Einleitung).

Die Größenlimits werden den heutigen Verhältnissen angemessener gestaltet bzw. ganz aufgehoben. Es wird ein asynchroner, zusätzlicher Schreib- und Lesemodus eingeführt, der die Geschwindigkeit deutlich erhöhen wird. Asynchrones Schreiben in NFS-3

Abbildung 7: Asynchrones Schreiben in NFS-3

Dabei wird nicht mehr wie beim synchronen Zugriff ein Arbeitsvorgang komplett abgeschlossen, sondern die gecachten Daten werden beim Server zwischengespeichert und »bei geeigneter Gelegenheit« auch gesammelt festgeschrieben. Erst auf die endgültige Bestätigung hin verwirft der Client seine Daten im Cache.

Auch bei den Lesezugriffen wurden neue Prozeduren eingeführt. So wurden beim Objektaufruf (bspw. ls -al) zuerst alle Daten übertragen (READDIR()) und danach jeweils die Attribute (GETATTR()) der Objekte. Dies wird in Version 3 durch eine vollständig neue Prozedur (READDIRPLUS()) ersetzt, die alles in einem Aufwasch erledigt und die erhoffte Steigerung der Geschwindigkeit nach sich zieht.

NFS nach Version 3 arbeitet anstatt mit 32 Bit mit 64 Bit langen Dateizeigern, sodass auch hier die insbesondere für Datenbankanwendungen schmerzlichen Schranken der Datei- und Dateisystemgrößenbeschränkung fallen.

Mittlerweile wird eine vierte Version (NFSV4) erstellt. Die Tests sind weitestgehend abgeschlossen und nun wird an einer Verabschiedung, die voraussichtlich 2002 erfolgen wird, gearbeitet.

NFS Clients

Das Network Filesystem ist die gebräuchlichste Methode unter Unix, um Verzeichnisse über Rechnergrenzen hinweg verfügbar zu machen. Einen kurzen Abriss zur Historie und Intention des NFS erhalten Sie im Abschnitt zum NFS-Server .

Voraussetzungen

Kernelunterstützung

Die Unterstützung des NFS-Dateisystems ist Aufgabe des Kernels. Vermutlich integriert der aktuelle Kernel bereits die erforderliche Eigenschaft; ein Blick in die Datei »/proc/filesystems« schafft Gewissheit:

user@sonne> cat /proc/filesystems
nodev   sockfs
nodev   tmpfs
nodev   pipefs
nodev   proc
        ext2
nodev   devpts
        reiserfs
nodev supermount

Im Beispiel fehlt offensichtlich ein entsprechender Eintrag für das NFS-Dateisystem. Bei aktuellen Kerneln, die heutigen Distributionen beiliegen, muss das noch nichts bedeuten... Eventuell ist die Unterstützung im Kernel nur als Modul kompiliert, und solange das Modul noch nicht geladen wurde, wird der Kernel das Dateisystem auch nicht kennen. Das Modul sollte nun von Hand geladen werden:

root@sonne> modprobe nfs

Eine Ausschrift der Art » modprobe: Can't locate module nfs « resultiert entweder aus einer falschen Konfiguration der Modulabhängigkeiten (unwahrscheinlich) oder aber aus einer fehlenden Unterstützung durch den Kernel. Die Generierung eines neuen Kernels wird notwendig sein...

Bei erfolgreichem »modprobe«-Aufruf erscheint folgende Zeile am Ende der Datei »/proc/filesystems«:

user@sonne> tail -2 /proc/filesystems
nodev   supermount
nodev nfs

Portmapper

Für die Grundfunktionalität eines NFS-Clients ist die Aktivierung des Portmappers nicht notwendig. Erst wenn Programme mit Dateisperren auf importierten NFS-Verzeichnissen arbeiten, werden auf Clientseite zwei RPC-Dienste (»rpc.lockd« und »rpc.statd«) und damit der Portmapper erforderlich.

Das Vorgehen zum Start des Portmappers und der beiden Dienste erfolgt analog zur Beschreibung im NFS-Server-Abschnitt . Beachten Sie auch die dortigen Hinweise zu ggf. erforderlichen Sicherheitseinstellungen in den Dateien »/etc/host.allow« und »/etc/hosts.deny«. Ebenfalls in der Abhandlung zum Server finden Sie eine Diskussion zur Arbeitsweise von Network-Lock-Manager (»rpc.lockd«) und Network-Status-Monitor (»rpc.statd«).

Bei aktuelleren RedHat- und SuSE-Distributionen finden Sie oft ein Skript /etc/init.d/nfs, über das Sie komfortabel den Client starten und beenden können (genau genommen startet das Skript auch nur die beiden RPC-Dienste und mountet alle in der Datei /etc/fstab erwähnten NFS-Dateisysteme).

Mounten eines NFS-Dateisystems

Welcher Server bietet was?

Für gewöhnlich wird der Administrator eines NFS-Servers die Verzeichnisse nur für konkrete Rechner exportieren und den Verantwortlichen dieser Clients alle notwendigen Informationen zum Zugriff zukommen lassen. Dennoch kann von einem Client leicht verifziert werden, ob ein Rechner als NFS-Server fungiert und welche Verzeichnisse er welchen Rechnern zur Verfügung stellt.

Das Kommando »showmount« dient zur Abfrage eines Servers. Werden, abgesehen vom Servernamen, keine weiteren Optionen angegeben, so werden die aktuell zum Server verbundenen Clients aufgelistet:

user@venus> showmount sonne.galaxis.de
All mount points on sonne.galaxis.de:
erde.galaxis.de
venus.galaxis.de

Aus Sicht eines NFS-Clients ist die Option »-e« nützlich, die dem Server Auskunft über die exportierten Verzeichnisse entlockt:

user@venus> showmount -e sonne.galaxis.de
Export list for sonne.galaxis.de:
/home      *.galaxis.de
/usr/share *.galaxis.de

Eine umfassende Beschreibung von »showmount« finden Sie im Abschnitt zum NFS-Server.

Das Mount-Kommando

Auch zum Mounten von NFS-Verzeichnissen dient das Kommando mount . Es gelten dieselben Voraussetzungen wie zum Einhängen lokaler Dateisysteme: Die notwendigen Rechte müssen gegeben sein (auch auf Serverseite) und der Mountpunkt - also das Zielverzeichnis - muss existieren .

Der Aufruf von mount folgt nun diesem Schema:

mount -t nfs [ -o <Optionen> ] <Servername>:<Verzeichnis auf Server> <lokaler Mountpunkt>

Anstatt des Servernamens ist auch die Angabe einer IP-Adresse zulässig. Neben den allgemein gültigen Optionen für das Mountkommando steuern NFS-spezifische Optionen vor allem das Verhalten des Kommandos im Fehlerfall. Wir widmen uns ihnen im folgenden Abschnitt.

Als konkretes Beispiel soll vom NFS-Server »sonne.galaxis.de« das dort freigegebene Verzeichnis »/home« importiert werden. Als Mountpunkt wurde lokal ein Verzeichnis »/mnt/home« erzeugt. Der Aufruf sieht wie folgt aus:

root@erde> mount -t nfs sonne.galaxis.de:/home/ /home

Etwas Komfort

Da Administratoren - allen voran »Unix-ler« - bekanntlich recht bequeme Menschen sind und nach Automatisierung streben, gibt es auch hier einen Weg, um den Mount-Aufruf zu vereinfachen. Die kürzere und elegantere Schreibweise wäre ein Eintrag in die Datei /etc/fstab , die statische Informationen über Dateisysteme, ihre Mountpunkte und Optionen enthält.

Eine typische fstab-Datei könnte wie folgt aussehen:

user@erde> cat /etc/fstab
/dev/hda3        /              ext3      defaults 1 2
/dev/hda1        /boot          ext3      defaults 1 2
/dev/cdrom       /media/cdrom   auto      ro,noauto,user,exec 0 0
/dev/fd0         /media/floppy  auto      noauto,user,sync 0 0
devpts           /dev/pts       devpts    defaults 0 0
proc             /proc          proc      defaults 0 0
usbdevfs         /proc/bus/usb  usbdevfs  noauto 0 0
/dev/hda2        swap           swap      pri=42 0 0
# NFS-Einträge
sonne:/home      /home          nfs       bg,soft,intr,retry=5 0 0
sonne:/usr/share /usr/share nfs defaults 0 0

Zur Bedeutung der einzelnen Felder finden Sie Erläuterungen im Abschnitt Dateisysteme, /etc/fstab des Kapitels »Systemadministration«. Wichtig für unser Beispiel sind die beiden letzten Einträge. Anstelle der Gerätedatei bei lokalen Dateinamen tritt nun das zu importierende Verzeichnis in der Form »Server:/Pfad«. Als Typ des Dateisystems muss »nfs« in die dritte Spalte eingetragen werden. Die beiden letzten Spalten sollten bei importierten Verzeichnissen stets »0« sein, da sowohl ein Backup als auch eine Überprüfung des Dateisystems Aufgabe des Servers (der Rechner, auf dem diese Dateisysteme lokal liegen) ist.

Und der Zweck solcher Einträge?

Zum einen genügt nun ein einziger Aufruf, um alle in der Datei benannten NFS-Verzeichnisse gleichzeitig zu importieren:

root@erde> mount -a -t nfs

Zum anderen sinkt selbst bei Import einzelner Einträge der Tippaufwand, da als Argument für das Kommando »mount« entweder die Angabe der Server-Pfad-Kombination oder auch nur die Angabe des lokalen Mountpunkts genügt. Mit jedem der beiden folgenden Aufrufe könnte das Verzeichnis »/home« vom Server »sonne« gemountet werden:

# Angabe des Servers+Pfads
root@erde> mount sonne:/home
# Angabe des lokalen Mountpunkts
root@erde> mount /home

Mount-Optionen

Durch gezielten Einsatz einiger Optionen des mount -Kommandos lassen sich die Zugriffe auf Daten eines NFS-Verzeichnisses mitunter erheblich beschleunigen. Auch kann das Verhalten im Fehlerfall über Argumente gesteuert werden. Selbstverständlich lassen sich solche Angaben auch in der /etc/fstab dauerhaft nieder schreiben.

Die das NFS betreffenden Optionen sind:


rw, ro Schreib- und Lesezugriff bzw. Nur-Lese-Zugriff. Beachten Sie, dass die Rechte höchstens weiter eingeschränkt werden können, d.h. ein vom Server nur-lesend-exportiertes Verzeichnis kann lokal nicht zum Schreiben freigegeben werden, umgekehrt kann die Schreibberechtigung lokal verboten werden, selbst wenn der Server diese zuließe
fg Jeder gescheiterte Mountvorgang wird eine Fehlermeldung erzeugen; der Vorgang läuft im Vordergrund (»foreground«).
bg Scheitert der Mountvorgang im ersten Versuch, wird er im Hintergrund (»background«) solange wiederholt, bis er erfolgreich war oder »retry« erreicht wurde.
retrans=zahl Anzahl der Wiederholungsversuche, um einen Mount durchzuführen. Der Default-Wert liegt bei 5
hard Ein Programm wird während des Zugriffs auf ein NFS-Verzeichnis hängen bleiben, falls der Server zusammenbricht. Nach Wiederanlaufen des Servers fährt das Programm mit seiner Arbeit fort. ein hängendes Programm, kann nur unterbrochen werden, wenn die Option »intr« angegeben wurde.
soft Der Kernel wird, falls der Server eine bestimmte Zeit lang (»retrans*timeo«) nicht antwortet, einen Fehler generieren und die auf den Server wartenden Prozesse informieren. Die Zeitdauer zwischen den Versuchen kann mit »timeo=Sekunden« eingestellt werden.
intr, nointr Möglichkeit des Abbruchs durch eine Tastenkombination (»interrupt«) bzw, das Verhindern derselben
remount Aushängen eines Verzeichnisses, um es sofort wieder (beispielsweise mit neuen Optionen) einzuhängen
suid, nosuid Möglichkeit zur Benutzung des SUID-Bits auf dem eingehängten Dateisystem
retry=zahl Anzahl der erfolglosen Mount-Versuche (Voreinstellung ist 10000), bis endgültig abgebrochen wird
wsize=zahl Setzt die Blockgröße beim Schreiben über NFS auf »Bytes« byte. Voreinstellung ist 1024, sollte aber auf 8192 gesetzt werden.
rsize=zahl Setzt die Blockgröße beim Lesen über NFS auf »Bytes« byte. Voreinstellung ist 1024, sollte aber auf 8192 gesetzt werden.
timeo=zahl Zeitspanne für Wiederholversuche, angegeben in Zehntelsekunden
proto=protokoll ab Version 3: Angabe des Protokolls (UDP oder TCP)