Artikel mit ‘centos’ getagged

FTP und NFS Mounts

Mittwoch, 16. Februar 2011

Vorsicht: Rant

Ich hasse FTP — die Warze unter den Dateiübertragungsprotokollen. Ich hasse es wirklich, leidenschaftlich und abgrundtief. Es ist ein veraltetes, unsicheres, umständliches, schlecht designtes Protokoll und es gibt so gut wie keine vernünftigen Implementierungen. Die Clients haben fast alle grauenvolle User Interfaces, sind langsam und gelegentlich auch noch instabil. Auf der Serverseite sieht es auch nicht viel besser aus, das meiste was es da gibt ist weder schnell noch schlank und selbst wenn es das ist ist es fast immer unsicher. (Wir verwenden als FTP-Server-Software übrigens vsftpd, der wenigstens in dem Ruf steht sicher zu sein und den man sich auch nicht so leicht unsicher konfigurieren kann. Lieber wäre uns aber, wenn wir einfach darauf verzichten könnten. Das beste FTP ist kein FTP.)

FTP überträgt alle Passwörter im Klartext, die etwas besser gesicherte Erweiterung FTPS (FTP mit SSL) gibt es zwar schon seit einer halben Ewigkeit, wird aber immer noch längst nicht von jedem genutzt und den meisten Clients kann man auch nicht oder nur schwer beibiegen, daß sie auf gar keinen Fall Passwörter im Klartext übermitteln sollen. Selbst wenn FTPS die Passwörter (oder genauer gesagt den gesamten Kommandokanal) verschlüsselt, verschlüsselt es dann aber nicht die übertragenen Dateien (den Datenkanal), die bei sehr vielen Webanwendungen aber wiederum Klartextpasswörter z.B. für MySQL-Datenbanken enthalten. „Secure“ FTP hat den gleichen Fehler, nur daß es statt SSL halt SSH benutzt um den Kommandokanal zu verschlüsseln, in jedem Fall verschlüsselt es nicht die übertragenen Dateien. Und über das Firewalling von FTP möchte ich gar nicht schreiben, da würde ich mir die Tastatur unter den Fingern zerlegen vor lauter in den Tastenanschlag einfließendem Ärger.

Ich kann auch nicht verstehen, wieso FTP immer noch eingesetzt wird. Ich weiß, daß viele Leute nur so auf die Dokumente auf ihren Webservern zugreifen können, aber ich weiß halt auch, daß enorm viele Programme auch Support für das SSH File Transfer Protocol (SFTP, nicht zu verwechseln mit „Secure“ FTP) oder sogar Secure CoPy (SCP) mitbringen und ich weiß auch daß es mit Putty und sshfs und noch ein paar anderen Programmen (deren Namen mir gerade nicht mehr einfallen) wirklich bequeme Methoden gibt Daten sicher zu übertragen. Es gibt auch haufenweise Anleitungen dazu, die Hälfte davon offenbar von entnervten Admins geschrieben, die sich große Mühe geben die Leute dazu zu bewegen doch bitte endlich kein FTP mehr zu benutzen. Und Webhostinganbieter die kein SSH anbieten, sondern nur FTP… gut ich arbeite bei einem Webhostinganbieter der genau das aus gutem Grund nicht tut, insofern ist es naheliegend, daß ich davon nichts halte, trotzdem: FTP ist sowas von alt und überholt, wenn ein Anbieter nichts neueres zu bieten hat, dann ist sein Angebot es einfach nicht wert. Einen Zahnarzt der außer Zähne ziehen keine neueren Lösungen zu bieten hat, würde man bei Zahnschmerzen ja auch nicht bevorzugt aufsuchen.

Warum FTP immer noch so weit verbreitet ist, will mir einfach nicht in den Kopf. Ich finde das schlimm. Es ärgert mich, daß ich mich mit dem Mist auseinandersetzen muß, es ärgert mich das ich dafür Support leisten muß. (Was nicht heißt, daß ich mich im Ungang mit solchen Supportanfragen dann nicht zusammenreiße und trotzdem schnell und freundlich weiterzuhelfen versuche. Den Ärger spare ich mir dann für Momente wie diesen hier auf.) Es ärgert mich, daß unsere Kunden sich damit rumquälen müssen. FTP soll endlich verschwinden. Telnet ist doch auch weitgehend verschwunden, warum dann nicht FTP?

So, nachdem ich mir nun Luft gemacht habe, kommen wir zum eigentlichen Thema:

Mein Kollege Matthias sprach mich neulich an, weil bei einem Kunden ein Problem mit einem Backup aufgetreten war. Offenbar dauerte das Runterladen der Backups per FTP sehr lange. Matthias hat das Problem auch sofort reproduzieren können und so wußten wir gleich, daß die Downloads nicht einfach lange dauerten, sondern im Gegenteil ganz normal funktionierten, aber vor Beginn jedes einzelnen Downloads eine Wartezeit von 30 Sekunden eingelegt wurde.

Kurze Erklärung des Setups: Die Backups liegen auf einem Backupserver, von wo aus wir sie per NFS auf dem Webserver den der Kunde nutzt einbinden, wobei NFS das Verzeichnis mit den Backups nur im Read-Only-Modus holt. Schreibzugriffe aufs Backup sind also vom Webserver aus nicht möglich.

Deswegen dachte ich auch im ersten Moment, daß die Verzögerung wohl eher daher rühren wird, daß entweder NFS irgendwie gestört ist oder der Backupserver zum Zeitpunkt der Downloads zu viel zu tun hatte. Der Backupserver hatte aber zu dem Zeitpunkt an dem mein Kollege und ich das testeten gerade nichts zu tun und NFS hat auch durchaus funktioniert. Wenn ich dieselben Dateien per SCP runtergeladen habe, dann gab es keine Verzögerung.

Ich habe also etwas in den Logs gestöbert und schließlich diese Einträge in /var/log/messages gefunden:


Feb 14 10:01:59 helium kernel: statd: server localhost not responding, timed out
Feb 14 10:01:59 helium kernel: lockd: cannot monitor 82.98.87.73
Feb 14 10:01:59 helium kernel: lockd: failed to monitor 82.98.87.73

(Am Rande sei hier mal angemerkt, daß das Deuten der Logausgaben von NFS eine arkane Kunst ist die ich — wie 99% der Nutzer und Entwickler von NFS — nicht beherrsche. In der Regel kann ein und diesselbe Logausgabe von NFS für mindestens ein Dutzend verschiedene Fehlerursachen stehen und in beinahe allen Fällen enthält der genaue Text der im Log landet inhaltlich keine sachdienlichen Hinweise zur Problemlokalisierung. Obendrein muß man bei NFS schon dankbar sein, wenn es überhaupt Logausgaben gibt. Mit anderen Worten ist das Logging von NFS das absolut allerletzte, wie wohl jeder der schonmal NFS Fehler debuggt hat und dazu im Internet nach Lösungen suchen mußte sofort bestätigen wird. Diese Logausgabe hier verdient besondere Erwähnung, weil sie ausnahmsweise in der Tat direkt etwas mit dem Problem zu tun hat und vergleichsweise leicht zu deuten ist. Genießt es, sowas sieht man nicht allzu oft.)

Davon auf die Spur gebracht hatte ich bald die Ursache des Problems ausgemacht und gelöst: FTP versucht hier einen Lock auf die Datei zu legen und da dies nicht funktioniert, wartet es auf einen Timeout und kopiert die Datei dann trotzdem. — Warum auch immer. Ich hätte ja ein anderes Verhalten erwartet, aber gut. Bleibt nur noch die Frage, warum FTP hier versucht einen Lock zu erlangen, denn es handelt sich ja um ein Read-Only gemountetes Verzeichnis. Eine ohnehin nur lesbare, aber nicht schreibbare Datei zu locken ist weitgehend sinnfrei. Wie auch immer, die Lösung war recht einfach:

chkconfig nfslock on; service nfslock start

Ich gestehe gerne ein, daß ich nfslock von Anfang an hätte laufen lassen sollen, da es prinzipiell für einen geordneten NFS-Betrieb schon dazu gehört. Mea culpa. Aber ich weigere mich zu begreifen, warum FTP hier einen Lock erreichen will. Ein Lock ist dafür gedacht, damit niemand anderes schreibend auf die Datei zugreift, für Lesezugriffe ist das gar nicht gedacht. Ich möchte an der Stelle nocheinmal darauf hinweisen, daß dieses Problem nicht auftritt, wenn ich diesselbe Datei lokal kopiere oder per SSH oder HTTP runterlade. Im Grunde hat mich FTP hier auf einen Konfigurationsfehler den ich bei NFS gemacht hatte hingewiesen und ich bin dafür auch dankbar — nur bin ich halt auch mittlerweile unfähig etwas über FTP zu sagen ohne mich erstmal ausgiebig über FTP an sich aufzuregen.

Gut, da ich es jetzt eh schonmal nachrecherchiert habe, kann ich mein Wissen hier ja nochmal teilen: Wenn man ein CentOS 5 nur als NFS Client benutzen möchte, dann sollte man den Dienst nfslock laufen lassen (geht aber in vielen Fällen auch ohne). Wenn man NFSv4 verwendet und auf’s ID Mapping wert legt, sollte man zusätzlich rpcidmapd laufen lassen. Wenn man NFSv4 verwendet und authentifizieren oder verschlüsseln möchte, dann sollte man zusätzlich rpcgssd laufen lassen. Wenn man mit CentOS 5 einen NFS Server betreiben möchte, dann muß man die Dienste portmap und nfs laufen lassen (die in dieser Reihenfolge zu starten sind). Auch hier brauch man bei NFSv4 für ID Mapping rpcidmapd, für Authentifikation und Verschlüsselung braucht man aber rpcsvcgssd statt rpcgssd.

Zum Abschluß noch ein weiterer Seitenhieb auf NFS. Beim Lesen der Manpage von rpc.lockd bin ich vor Lachen fast vom Stuhl gefallen, sowas schwammiges und uninformatives ist mir lange nicht mehr untergekommen:

The rpc.lockd program starts the NFS lock manager (NLM) on kernels that don’t start it automatically. However, since most kernels do start it automatically, rpc.lockd is usually not required. Even so, running it anyway is harmless.

Na dann ist ja alles klar.

Zum Stand von Maildir-Support bei CentOS 5

Montag, 14. Februar 2011

Wir setzen auf den meisten unserer Server qmail bzw. netqmail als MTA ein und erfreuen uns dabei an den vielen Vorzügen, die das Maildir-Format bietet. Zwar kommt dabei meistens ein zusätzliches Tool wie vpopmail oder vmailmgr zum Tragen, was virtualisierte Mailuser bietet; auf unserer Hosting-Plattform Uberspace.de bieten wir aber ganz offiziellen Support für ein “echtes” Maildir des betreffenden Systemusers. Die netqmail-Dokumentation erläutert dazu in INSTALL.maildir:

The system administrator can set up Maildir as the default for everybody by creating a maildir in the new-user template directory and replacing ./Mailbox with ./Maildir/ in /var/qmail/rc.

Und so sieht das Setup bei uns dann auch aus: Ein /var/qmail/bin/maildirmake /etc/skel/Maildir legt ein Standard-Maildir an, was beim Anlegen eines neuen Users automatisch in dessen Home-Verzeichnis übertragen wird, und qmail-local stellt Mails, die an den Systemuser adressiert sind, dorthin zu.

Nicht völlig überraschend zeigt sich aber, dass traditionelle Mailboxen in einem zentralen Verzeichnis wie z.B. /var/spool/mail derart fest im Betriebssystem verankert sind, dass es mehr als einen Klimmzug braucht, das System sauber an Maildirs anzupassen. Das fängt schon ganz vorne an:

useradd

Beim Anlegen von Benutzern wird standardmäßig eine (leere) Mailbox in /var/spool/mail/$USER angelegt, bzw. in dem Verzeichnis, das in der /etc/login.defs (siehe dort) via MAIL_DIR angegeben ist. Maildirs werden aber nicht unterstützt; genausowenig Mailboxen, die nicht in einem zentralen Verzeichnis liegen, sondern im Home-Verzeichnis des Benutzers. Dieses Anlegen lässt sich nur über die Einstellung CREATE_MAIL_SPOOL=no in der /etc/default/useradd abschalten – was hier ja durchaus Sinn ergibt, denn durch das Anlegen eines Maildirs in /etc/skel haben wir diesen Punkt ohnehin erledigt. (Mit herkömmlichen Mailboxen funktionierte das nicht, da /etc/skel ja die Vorlage für das Home-Verzeichnis des Users ist, die herkömmlichen Mailboxen aber zentralisiert und damit außerhalb des Home-Verzeichnisses liegen.)

$MAIL

Diese Umgebungsvariable wird von verschiedenen Programmen benutzt, um zu identifizieren, wo denn die Mails eines Users liegen. Hier fackelt CentOS 5 nicht lange – in /etc/profile steht hart kodiert:

if [ -x /usr/bin/id ]; then
        USER="`id -un`"
        LOGNAME=$USER
        MAIL="/var/spool/mail/$USER"
fi

Das ist für unsere Zwecke ergo völlig unbrauchbar. Die /etc/profile selbst anzupassen, empfiehlt sich nicht, weil die Änderungen sonst bei jedem Update des setup-RPMs (zu dem diese Datei gehört) hinfällig wären. Stattdessen bietet sich ein Einzeiler in /etc/profile.d an:

# cat /etc/profile.d/maildir.sh
export MAIL=~/Maildir/

/etc/login.defs

Die man page der login.defs erklärt offenherzig:

Much of the functionality that used to be provided by the shadow password suite is now handled by PAM. Thus, /etc/login.defs is no longer used by programs such as: login(1), passwd(1), su(1)

Trotzdem ist die Datei noch da und wird von einigen Programmen genutzt. Sie sieht im Kopf wie folgt aus:

# *REQUIRED*
#   Directory where mailboxes reside, _or_ name of file, relative to the
#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
#   QMAIL_DIR is for Qmail
#
#QMAIL_DIR      Maildir
MAIL_DIR        /var/spool/mail
#MAIL_FILE      .mail

Fängt man erstmal an, an dieser Datei – vermutlich erfolglos – herumzubasteln, bekommt man wirklich graue Haare. Die naheliegendste Variante, nämlich den Eintrag QMAIL_DIR durch Entfernen des Rautenzeichens zu aktivieren, ist überraschenderweise keine gute Idee; dass die man page diese Einstellung gar nicht erwähnt, lässt schon tief blicken. So sieht’s dann nämlich aus:

# useradd dummy
configuration error - unknown item 'QMAIL_DIR' (notify administrator)

Fan-tas-tisch. Die NEWS-Datei der shadow-utils erklärt denn auch, dass die Einstellung aus der login.defs entfernt wurde – und zwar 2005. Interessanterweise kennt die man page auch die Einstellung MAIL_FILE nicht, sondern ausschließlich MAIL_DIR. Sie weiß aber auch gleich zu verkünden, dass nur usermod und userdel diese Einstellung benutzen – und useradd sowieso nicht. Was aber sehen wir in src/useradd.c?

      if (strcasecmp (create_mail_spool, "yes") == 0) {
              spool = getdef_str ("MAIL_DIR") ? : "/var/mail";
              file = alloca (strlen (spool) + strlen (user_name) + 2);
              sprintf (file, "%s/%s", spool, user_name);
              fd = open (file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0);
              [...]
      }

Ist also glatt gelogen; useradd benutzt die Einstellung sehr wohl. Die man page von useradd bekräftigt das auch und erwähnt nicht nur MAIL_DIR, sondern auch MAIL_FILE und behauptet:

The MAIL_DIR and MAIL_FILE variables are used by useradd, usermod, and userdel to create, move, or delete the user´s mail spool.

Das ist nun wiederum auch gelogen, denn wenn MAIL_FILE statt MAIL_DIR gesetzt ist, macht useradd damit … überhaupt nichts. Und auch usermod und userdel, die beim Löschen eines Users dessen Mailbox aus dem zentralen mit MAIL_DIR angegebenen Verzeichnis löschen, unternehmen in Bezug auf Mail schlicht gar nichts, wenn MAIL_FILE gesetzt ist.

Nun, noch weiter in die Tiefe wollen wir hier nicht gehen. Belassen wir es dabei, dass das, was in der /etc/login.defs steht, das, was in der zugehörigen man page steht, das, was in den man pages von useradd, usermod und userdel steht, und schließlich das, was im Code der shadow-utils steht, erheblich voneinander abweicht und sich oftmals sogar widerspricht – kurz, das Ganze funktioniert nur dann sauber, wenn man exakt den traditionellen Standard benutzt: Mailboxen in einem zentralen Verzeichnis.

mailx

CentOS benutzt das mailx-Paket, um den Befehl mail bereitzustellen. Die meisten kennen den Befehl vornehmlich zu dem Zweck, um auf der Kommandozeile direkt Mails via Pipe versenden zu können (some-command | mail recipient@domain.tld). Allerdings ist mail auch ein Mailreader, der auf die Umgebungsvariable MAIL zurückgreift – was von daher erstaunlich ist, weil diese Variable gerade nicht zu denen gehört, die mail laut man page konsultiert:

Mail utilizes the HOME, USER, SHELL, DEAD, PAGER, LISTER, EDITOR, VISUAL and MBOX environment variables.

Trotzdem wird sie benutzt und zeigt dann auch gleich, wieso hier ohnehin Hopfen und Malz verloren ist:

$ mail
/home/jonas/Maildir/: Is a directory

Das mailx-Paket von CentOS hat also schlicht keinen Maildir-Support. Mit dem aktualisierten Paket, das sich in CentOS 6 findet, wird das offenbar kein Problem mehr sein, aber darum soll es hier ja nicht gehen.

bash

Hier endlich mal ein Lichtblick: Die bash unterstützt die Umgebungsvariable MAIL und kann auch korrekt mit Maildirs umgehen. Sie benutzt es, um standardmäßig alle 60 Sekunden nach neuen Mails zu suchen und den Benutzer zu informieren, und das klappt auch:

$ echo | mail $USER ; sleep 60 ; true
You have new mail in /home/jonas/Maildir/

PAM

Möchte man auch direkt beim SSH-Login über neue Mails informiert werden, so kann dies zeitgemäß mit pam_mail.so erledigt werden. Dazu braucht’s nur eine Zeile (danach sshd-Neustart nicht vergessen, sonst wirkt es nicht):

$ tail -1 /etc/pam.d/sshd
session    optional     pam_mail.so dir=~/Maildir

Die Angabe von dir ist nötig, weil pam_mail.so ansonsten ganz traditionell in /var/mail nach einer Mailbox oder einem Maildir sucht (mit anderen Worten: Überraschung! Dass evtl. ein anderes Verzeichnis als MAIL_DIR in /etc/login.defs definiert ist, spielt überhaupt keine Rolle). Es erkennt automatisch, ob es eine Mailbox oder ein Maildir ist, denn eine Mailbox wäre ja eine Datei, während ein Maildir ein Verzeichnis wäre. So sieht es dann in der Anwendung aus:

$ ssh jonas@helium.uberspace.de
You have new mail in folder /home/jonas/Maildir.

mkinitrd und Filesystem-Labels

Freitag, 09. Juli 2010

Au Backe, das hätte deutlich schiefer gehen können.

Nicht selten betreiben wir Server mit einem Xen-Kernel als Dom0 und binden die DomU aber nicht von einer lokalen Festplatte ein, sondern via iSCSI. Das stellt sich dann so dar, dass die Dom0 eine /dev/sda hat (z.B. eine eingebaute Festplatte); das iSCSI-Target wird dann eingebunden und steht als /dev/sdb bereit. Von diesem Device werden dann aber keine Partionen direkt gemountet, sondern das Device wird in der Xen-Konfiguration der DomU als phy:-Device angesprochen. So weit, so gut – klappt auch einwandfrei.

Nun hat der anaconda-Installer von CentOS 5 die Angewohnheit, für die Root- und die /boot-Partition Labels zu vergeben. Diese kann man auf der Shell z. B. mit e2label einsehen und auch nachträglich jederzeit ändern. In der /etc/fstab wird dann die Root-Partition nicht mit /dev/sda2 referenziert, sondern mit LABEL=/, weil die Partition eben das Label namens “/” erhalten hat. Der Gedanke dahinter ist eigentlich gar nicht mal schlecht: Ändert ein Device seine Bezeichnung, beispielsweise weil ein zusätzliches Gerät am SCSI-Bus hängt und eine sda plötzlich eine sdb ist, so kann es dennoch unverändert angesprochen werden, weil es sein Label behält. Und das funktioniert auch prima.

Bis auf eins.

Wir führten auf einer Dom0 ein Kernel-Update durch. In diesem Zuge wurde auch eine neue initrd erstellt. Hierbei stellt mkinitrd alle für den Bootvorgang nötigen Module zusammen und strickt ein minimales init-Script. Das hat auch tausend Mal prima funktioniert – bis heute. Heute war nämlich gerade ein iSCSI-Target eingebunden – was an sich auch kein Problem ist, denn mkinitrd interessiert sich, was Treiber für Blockdevices angeht, eigentlich nur für die Devices, die in der /etc/fstab als zum Booten nötig referenziert werden. Nun nennt die /etc/fstab aber LABEL=/ als Root-Device, und damit nimmt das Unheil seinen Lauf. Zunächst einen Blick auf die Konfiguration:

# head -1 /etc/fstab
LABEL=/ / ext3 defaults 1 1

# e2label /dev/sda2
/

# df -h | head -2
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2              31G  1.9G   27G   7% /

Und jetzt das Problem. Es ist wie gesagt gerade ein iSCSI-Target eingebunden, das vom Kernel auf /dev/sdb gemappt wird und das nur eine Partition hat:

# ls -l /dev/disk/by-path/ip-*
lrwxrwxrwx 1 root root  9 Jul  8 22:32 /dev/disk/by-path/[...]-lun-0 -> ../../sdb
lrwxrwxrwx 1 root root 10 Jul  8 22:32 /dev/disk/by-path/[...]-lun-0-part1 -> ../../sdb1

Und eben jene Partition … hat auch das Label “/”:

# e2label /dev/sdb1
/

mkinitrd -v zeigt dann, dass es zwar versucht, das Richtige zu tun (nämlich herauszubekommen, was für eine Art Device die Root-Partition ist, damit es die dafür nötigen Treiber in die initrd einbinden kann, löst das Label aber prompt auf genau das falsche Device auf:

...
Found root device sdb1 for LABEL=/
Looking for driver for device sdb1
Found iscsi component /sys/devices/platform/host6/session5/target6:0:0/6:0:0:0
...

Damit erstellt es letztlich eine initrd mit dem falschen Root-Device – und baut dazu den gesamten iSCSI-Support mit ein, bis hin zu einem iscsistart-Aufruf, der die Zugangsdaten beinhaltet, die nötig sind, um das Target vom iSCSI-Host einbinden zu können. Ohne das -v dabei sieht man davon … nix. Vor allem sahen wir schon deshalb nichts davon, weil wir nicht mal mkinitrd selbst aufgerufen hatten – das hatte new-kernel-pkg aufgerufen, und auch das wiederum hatten wir nicht aktiv benutzt, sondern es befindet sich im %postinstall-Abschnitt des Kernel-RPMs, das wir gerade mit yum upgrade kernel-xen auf den neuesten Stand gebracht haben. Wie schon einige Male davor, immer ohne Probleme. Davor war eben zum Zeitpunkt der Kernel-Updates auch noch kein iSCSI-Target eingebunden.

Nach einem Reboot zeigte sich ein absurdes Bild. Beim Booten war deutlich erkennbar, wie sich der Server faktisch das iSCSI-Device holte und als /dev/sda vorzeigte; die lokale Festplatte war dadurch nun plötzlich /dev/sdb (in diesem Zusammenhang mag man ein zynisches “Ja und, dafür gibt’s doch die Labels!” einwerfen. Sehr witzig, haha). Merkwürdigerweise war der Inhalt der Root-Partition definitiv der, der von der Root-Partition der lokalen Platte kam – obwohl jene laut mount das iSCSI-Device sein sollte. Kurz, das System befand sich in nicht wirklich definiertem Zustand, und darüberhinaus mussten wir uns darum sorgen, dass das fragliche iSCSI-Device, das gerade angeblich unsere Root-Partition darstellte (aber irgendwie eben auch wieder nicht) Schaden davontragen könnte, weil es nämlich parallel dazu auf einem anderen Xen-Host bereits eingebunden und aktiv in Benutzung war. Wir können uns bislang nicht erklären, wie es zu dieser merkwürdigen Differenz zwischen angeblichem und realem Mount-Zustand kommen konnte, aber auf wundersame Weise blieb das iSCSI-Target von diesem Schindluder völlig unbeeindruckt. Puh..!

Der Bugfix war letztlich trivial: Wir haben in der /etc/fstab der Dom0 alle Labels durch echte Devicenamen ersetzt und die initrd neu erstellt. Ein Reboot, und das System befand sich wieder in definiertem Zustand. Für heute: Mit einer großen Portion Glück davongekommen. Und viel über mkinitrd gelernt.

IPv6-Tunnel mit 6in4 unter CentOS

Mittwoch, 06. Januar 2010

Ich hab mir vor einer Weile bei tunnelbroker.net von Hurricane Electric einen Account geklickt und mir darüber einen IPv6-Tunnel zugelegt. IPv6-Tunnel sind derzeit leider noch ein notwendiges Übel, da bisher bei nahezu keinem DSL-Anbieter in Deutschland IPv6 verfügbar ist. Die wenigen die überhaupt IPv6 anbieten verlangen dafür meines Wissens unabhängig von der normalen Grundgebür eine Extra-Gebühr, außerdem sind es soweit ich es bisher mitbekommen habe ausnahmslos Reseller des ehemaligen Fernmeldeamtes der Bundespost.

Bei Hurricane Electric bekommt man kostenlos einen Account über den man bis zu vier IPv6-Tunnel nutzen kann. Dabei wird einem jeweils ein /64er Netz zugewiesen. Dessen Dimension muß man sich am Anfang erstmal verdeutlichen: Der gesamte IPv4-Adressraum ist 32 Bit lang, man bekommt nun ein Netz der doppelten Länge, hat also nicht rund 4 Milliarden Adressen zur Verfügung, sondern 4 Milliarden zum Quadrat. So astronomisch dies klingen mag: das ist die Standard-Netzgröße bei IPv6. Man kann das Netz verkleinern wenn man unbedingt möchte, es empfiehlt sich aber nicht. Erstens sind 64 Bit für das lokale Netz nur die Hälfte der verfügbaren Bits in einer IPv6-Adresse, d.h. es gibt nochmal 4 Milliarden zum Quadrat solcher Netze (also mehr als genug), zweitens bieten nur Netze mit dieser Standard-Größe das durchaus interessante Feature Autokonfiguration an.

Mit vier Tunneln kann man also vier /64er Netze bei Hurricane nutzen. Wem das noch nicht ausreicht, weil er z.B. hinter dem Tunnel mehrere /64er Subnetze betreiben möchte (z.B. ein WLAN, eine DMZ, ein internes Netz), der kann sich auch ein /48er IPv6-Netze erklicken, die dann ebenfalls über die Tunnel geroutet werden. Mit einem /48er verfügbt man dann über 32.768 /64er Subnetze.

Für den Tunnelaufbau werden bei Hurricane angenehmerweise sehr einfache und sehr direkte Konfigurationsanleitungen für eine Vielzahl von Betriebssystemen angeboten, wobei diese aber allesamt für ein Publikum gedacht sind das die Kommandozeile nicht scheut (dies dürfter allerdings 99% der derzeitigen IPv6-Enthusiasten abdecken).

Für Linux gibt es zwei Methoden. Hier zunächst die traditionelle:


ifconfig sit0 up
ifconfig sit0 inet6 tunnel ::$REMOTEIPV4
ifconfig sit1 up
ifconfig sit1 inet6 add $LOCALIPV4
route -A inet6 add ::/0 dev sit1

Und hier die moderne:


modprobe ipv6
ip tunnel add he-ipv6 mode sit remote $REMOTEIPV4 local $LOCALIPV4 ttl 255
ip link set he-ipv6 up
ip addr add $LOCALIPV6 dev he-ipv6
ip route add ::/0 dev he-ipv6
ip -f inet6 addr

(Hurricane gibt auf ihrer Webseite diese Befehle schon mit den richtigen IPs eingetragen aus, so daß man sie in die Kommandozeile kopieren kann.)

In beiden Fällen wird buchstäblich der Weg des geringsten Widerstands gegangen, anders als die meisten Anbieter von IPv6-Tunneln die ich bisher kennengelernt habe, wird einem nicht die Verwendung abstruser Daemons aufgezwungen, die einen dann gegenüber dem Tunnelserver aufwendig authentifizieren. (Das war früher besonders eklig, weil man die Software ganz oft noch selbst übersetzen mußte, dann init-Skripte schreiben mußte und sie oft nicht ganz einfach zu konfigurieren war.) Sollte man unter den für diese Aufgabe geeigneten Daemons einen brauchbaren finden, kann man diesen natürlich trotzdem verwenden.

Wer darauf verzichten kann, dem wird es leicht gemacht, denn unter https://ipv4.tunnelbroker.net/ipv4_end.php kann man seinen Tunnelendpunkt aktualisieren, wobei man von dort auch eine Anleitung und ggf. Fehlermeldungen bekommt. Die Anleitung ist wieder angenehm einfach:


Please use the format https://ipv4.tunnelbroker.net/ipv4_end.php?ipv4b=$IPV4ADDR&pass=$MD5PASS&user_id=$USERID&tunnel_id=$GTUNID
Where:

$IPV4ADDR = The new IPv4 Endpoint (AUTO to use the requesting client's IP address)
$MD5PASS = The MD5 Hash of your password
$USERID = The UserID from the main page of the tunnelbroker (not your username)
$GTUNID = The Global Tunnel ID from the tunnel_details page

Ich hab mir für diese Aufgabe ein Skript geschrieben, das hier heruntergeladen werden kann.

Nun muß man nur noch dafür sorgen, daß dieses Skript auch ausgeführt wird, wenn sich die lokale IPv4 ändert. Auf einem Laptop kann das durchaus komplizierter werden, aber auf einem „ortsstabilen“ Rechner läßt sich dies wunderbar mit cron oder am besten mit runwhen lösen, das ich an dieser Stelle mal wieder empfehlen möchte.

Am besten kombiniert man die Aktualisierung des Tunnelendpunktes gleich mit dem nächtlichen DSL-Reconnect. Ich habe auf meinem Heimserver ein Skript laufen, das morgens um 5 die DSL-Verbindung resettet um der leidigen Zwangstrennung durch den Provider zuvorzukommen und vor allem um diese Trennung auf eine Zeit zu verlegen, zu der ich mit hoher Wahrscheinlichkeit nicht am Rechner arbeite. Dieses Skript habe ich nun um eine Zeile erweitert, damit der IPv6-Tunnel aktualisiert wird, sobald die DSL-Verbindung wieder steht. (Dies ist natürlich nur nötig, wenn man keine statische IPv4 hat, also bei der Zwangstrennung seine IP wechselt. Ansonsten läuft der Tunnel ganz normal weiter.) Bei runwhen geht das sehr einfach mit einem svc -a /service/tunnelbroker-update. Der Vorteil von runwhen ist hierbei, daß man mit den bei daemontools oder runit üblichen Mitteln bequem ein Log schreiben lassen kann.

Blieb zuletzt nur noch ein Problem zu lösen: So schön einfach und direkt die von Hurricane empfohlenen Befehle für den Tunnelaufbau auch sein mögen, möchte ich trotzdem ungern dafür noch ein Skript schreiben, denn eigentlich bringt CentOS schon alle nötigen Tools mit um IPv6-Tunnel aufzubauen. Ich kann nachvollziehen, daß Hurricane nur den generellsten Weg beschreibt der in jeder Linux-Distribution funktionieren dürfte, aber für mich selbst wünsche ich mir doch was anderes und ich nehme dafür auch gerne in Kauf, daß ich mich erst durch die CentOS-Dokumentation wühlen mußte, um den richtigen Weg zu finden. Wühlen ist der richtige Ausdruck, denn die Online-Dokumentation ist in dem Punkt etwas dürftig. Aber die tatsächlich hilfreiche Dokumentation ist netterweise in jedem CentOS schon vorinstalliert: die Datei /usr/share/doc/initscripts-*/sysconfig.txt.

Um die nötigen Einstellungen zu erläutern möchte ich nochmal daran erinnern, wie laut der Anleitung von Hurricane der Tunnel aufgebaut wird: Zuerst wird das Interface sit0 auf den entfernten Endpunkt des Tunnels konfiguriert, dann das Interface sit1 auf den lokalen Endpunkt und schließlich wird die Route gesetzt.

Unter CentOS 5.4 gestaltet sich das nun leider etwas kontraintuitv. Man kann zwar sit0 auf der Kommandozeile anlegen, aber man sollte nicht versuchen dafür in /etc/sysconfig/network-scripts/ eine ifcfg-sit0 anzulegen. Sie wird im besten Fall ignoriert und führt im ungünstigsten Fall zu Fehlern. Statt dessen sollte man nur eine ifcfg-sit1 anlegen und Ihr in etwa diesen Inhalt geben:


# Hurricane Electric 6in4 tunnel
NAME="tunnelbroker.net"
TYPE=sit
DEVICETYPE=sit
DEVICE=sit1
ONBOOT=yes
BOOTPROTO=none
USERCTL=no
PEERDNS=no
IPV6INIT=yes
IPV6ADDR="$LOCALIPV6/64"
#IPV6_MTU=1280
#IPV6TO4_MTU="1280"
IPV6_ROUTER=yes
IPV6_AUTOCONF=no
IPV6TUNNELIPV4=$REMOTEIPV4

Ich hab wieder wie oben schon die IP-Adressen ggf. ersetzt. Zu beachten ist, daß IPV6ADDR="" die IPv6-Adresse in CIDR-Notation erwartet, also mit Angabe der Netzpräfixlänge.

Wenn das Interface sit1 hochgebracht wird, wird das Interface sit0 automatisch angelegt und korrekt konfiguriert.

Die hier verwendeten Optionen habe ich mir aus /usr/share/doc/initscripts-*/sysconfig.txt zusammengesucht. Mag sein, daß die eine oder andere nicht unbedingt notwendig ist, aber mit diesem Setup funktioniert mein Tunnel. Die Optionen IPV6_MTU und IP6TO4_MTU habe ich als Hinweis drin stehen lassen. Je nach Setup kann es sein, daß man an diesen Einstellung drehen muß, 1280 ist jeweils der niedrigste zulässige Wert.

In die /etc/sysconfig/network sollte man nun folgendes Eintragen:


NETWORKING_IPV6=yes
IPV6_AUTOTUNNEL=yes
IPV6_DEFAULTDEV="sit1"

Damit wird IPv6 generell aktiviert (ist es bei CentOS aber eigentlich sowieso, wenn ich das richtig sehe), das Tunneling aktiviert und schließlich dafür gesorgt, daß eine IPv6-Defaultroute angelegt wird, die über das richtige Interface läuft.

Ich hatte zu Anfang etwas Probleme mit dem Eintrag IPV6_DEFAULTDEV="sit1" und mußte da etwas rumprobieren. Eine Zwischenlösung bot die Datei /etc/sysconfig/static-routes-ipv6, in der ich die korrekte Default-Route zeitweilig eingetragen hatte. Beim Recherchieren zu diesem Problem bin ich über verschiedene Meldungen gestolpert, daß es in CentOS mit der IPv6-Default-Route wohl Probleme gäbe. Vor allem sollte wohl die Route sit1 ::/0 nicht funktionieren, statt dessen solle man sit1 2008::/3 verwenden. Das mag für frühere CentOS Versionen vielleicht richtig gewesen sein, für CentOS 5.4 kann ich das aber nicht bestätigen. Bei mir funktionierte die Route sit1 ::/0 einwandfrei und mit dem Eintrag IPV6_DEFAULTDEV="sit1" in der /etc/sysconfig/network wird diese Route auch vollkommen korrekt vom System erzeugt und eingetragen.

Wenn man nun das Netzwerk neu startet oder das Interface sit1 hochfährt, wird der Tunnel aufgebaut (man sollte vorher natürlich bei Hurricane die richtigen Daten hinterlegt haben, also z.B. einmal das tunnelbroker-update-Skript ausgeführt haben).

Um die Funktionstüchtigkeit des Tunnels zu testen braucht man z.T. andere Tools als bei IPv4, z.B. ping6 oder traceroute6. mtr akzeptiert den Schalter -6;, netstat und route benötigen den Schalter -A inet6.

Ich werde in nächster Zeit noch mehr dazu posten, wie man IPv6 von seinem Router zu seinen Endgeräten bringt, wie man djbdns IPv6 so halbwegs beibiegt (wer mit Daniel J. Bernstein vertraut ist, denn wird es nicht wundern: er mag IPv6 nicht und implementiert es nicht – ich kann seine Gründe nachvollziehen, finde das aber angesichts der mittlerweile geschaffenen Tatsachen etwas albern), was bei ip6tables zu beachten ist und wenn mir Zeit zum experimentieren bleibt, wie man MobileIPv6 nutzt.


Impressum