Sendmail and dual-stack IPv6

We’ve been using IPv6 for a few years, but for various reasons we hadn’t yet prepared our sendmail MTAs to use the new protocol. We run a dual-stack environment, so all servers need to use both IPv4 and IPv6. According to sendmail’s documentation it should be possible to use the host name for both daemons, so initially we tried it like that in our .mc file:

DAEMON_OPTIONS(`Name=MTA-v4,Family=inet,A=smtp-out.rrz.uni-koeln.de,M=fh')
DAEMON_OPTIONS(`Name=MTA-v6,Family=inet6,A=smtp-out.rrz.uni-koeln.de,M=fh')
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')
CLIENT_OPTIONS(`Name=MSA-v4,Family=inet,A=smtp-out.rrz.uni-koeln.de,M=h')
CLIENT_OPTIONS(`Name=MSA-v6,Family=inet6,A=smtp-out.rrz.uni-koeln.de,M=h')

That worked fine on a test system, but for reasons unknown it failed on our actual production server. It resulted in these error messages:

Mar 23 10:35:39 smtp-out.rrz.uni-koeln.de sendmail[6662]: NOQUEUE: SYSERR(root): opendaemonsocket: daemon MTA-v6: cannot bind: Address already in use
Mar 23 10:35:39 smtp-out.rrz.uni-koeln.de sendmail[6662]: daemon MTA-v6: problem creating SMTP socket
Mar 23 10:35:39 smtp-out.rrz.uni-koeln.de sendmail[6662]: NOQUEUE: SYSERR(root): opendaemonsocket: daemon MTA-v6: server SMTP socket wedged: exiting

We have now implemented a workaround: instead of the hostname we use the actual IPv6 address for the IPv6 daemon and client:

DAEMON_OPTIONS(`Name=MTA-v4,Family=inet,A=smtp-out.rrz.uni-koeln.de,M=fh')
DAEMON_OPTIONS(`Name=MTA-v6,Family=inet6,A=IPv6:2a00:a200:0:12::25,M=fh')
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')
CLIENT_OPTIONS(`Name=MSA-v4,Family=inet,A=smtp-out.rrz.uni-koeln.de,M=h')
CLIENT_OPTIONS(`Name=MSA-v6,Family=inet6,A=IPv6:2a00:a200:0:12::25,M=h')

One more tip: with an IPv4-only setup we used the ‚b‘ flag (use the incoming interface for sending the message) as modifier for the DAEMON_OPTIONS, but with dual-stack that doesn’t work: if you receive a message via IPv4 but have to send it via IPv6 (or vice versa), it will fail.

Web-Browser und -Server… was reden die da eigentlich??? Server-Sockets mit nc

Wer sich mit Webservern und -browsern beschäftigt, wird irgendwann an den Punkt kommen, wo man einfach mal wissen will, „Was zur Hölle der Browser und der Server da genau bereden“

Tools wie wget helfen einem zwar, zu überprüfen, ob ein Server eine Datei wirklich ausliefert, aber viele Funktionen werden im HTTP-Header ausgehandelt und die Server reagieren dabei speziell auf die unterschiedlichen, browserspezifischen Anfragen.

Wenn es also so aussieht, als würde der Server einem Firefox andere Daten schicken, als einem Chrome, möchte man sicherlich wissen, ob es wirklich so ist und wie sich die Kommunikation generell unterscheidet.

Hier kann ein Trick helfen, über den ich kürzlich gestolpert bin. Er beruht auf dem Befehl nc (netcat), der in vielen Konstellationen hilfreich sein kann.

nc (netcat)

nc öffnet entweder eine Verbindung zu einem Server-Port (z.b. dem HTTP-Port (80) eines Webservers) und verhält sich dabei sehr ähnlich zu telnet.
Im Gegensatz zu telnet kann nc jedoch auch selbst einen Socket öffnen und auf eingehende Anfragen antworten. Hierfür wird der Switch -l verwendet.

Egal, in welcher Richtung die Kommunikation aufgebaut wird, verbindet nc immer die Standard-Eingabe (stdin) mit dem Kommunikationspartner.
Wird der Befehl also einfach so verwendet, können Sie direkt mit der Tastatur eingeben, was dem Kommunikationspartner gesendet werden soll.
Startet man auf einem Rechner ein lauschenden Server-Socket auf Port 54321:

# nc -l 54321

… kann man sich von einem anderen Rechner aus damit verbinden:

# nc hostname.des.servers 54321

Nun hat man eine Verbindung, die man zum Chatten verwenden kann.

Auf dem üblichen Weg lassen sich per Pipe auch die Ausgaben anderer Befehle über diese Leitung zu übertragen, statt die Tastatur Eingabe zu verbinden.
Startet man den Server z.B. so:

# ls -l | nc -l 54321

… bekommt man beim Verbinden mit dem Socket das aktuelle Verzeichnis, in dem der Server gestartet wurde angezeigt. Danach schließt sich die Verbindung und sowohl Server- als auch Client-Prozesse werden gestoppt.

Sehen was der Browser sendet:

So ist nc also schon nützlich: Man kann einen Server-Socket öffnen und im Webbrowser dessen Adresse eingeben. Im obigen Beispiel also http://localhost:54321/. Zwar wird im Browser so nicht unbedingt etwas sinnvolles angezeigt, weil unser nc-Server kein HTTP spricht, aber auf der Konsole können wir nun sehen, welche Anfrage genau der Browser an unseren Server geschickt hat:

GET / HTTP/1.1
Host: localhost:54321
Connecdern: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36 Vivaldi/1.0.403.20
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: _pk_id.2478.1fff=bda69bf5b5894886.1457526065.1.1457526065.1457526065.

Dies ist nun aber nur eine einzelne Anfrage und wir können nicht die Antwort des Servers sehen, der uns eigentlich interessiert.

Umleiten einer Verbindung

Hier kommt nun eine weitere praktische Zutat ins Spiel: Named Pipes. Während wir mit dem Pipe-Symbol (Senkrechter Strich: |) nur die Ausgabe eines Programms mit der Eingabe des direkt folgenden Programms verbinden können, werden Named Pipes im Filesystem abgelegt und können auf diese Weise angesprochen. Diese Pipes werden mit dem Befehl mkfifo angelegt, sie verhalten sich dabei weitgehend wie Dateien.

Named Pipes können wir nun dazu verwenden, zwei nc-Prozesse miteinander zu verbinden: Einen, der auf Verbindungen vom Browser wartet, einen der eine Verbindung zu einem Webserver herstellt:

Anlegen der Named Pipe (der Name und Pfad können frei gewählt werden):

# mkfifo /tmp/proxyfifo

Zwei nc-Prozesse starten und verbinden

# nc -l -p 54321 </tmp/proxyfifo | nc server.domain.de 80 >/tmp/proxyfifo

Löschen der Pipe:

#rm /tmp/proxyfifo

Statt http://server.domain.de geben wir nun im Browser ein: http://localhost:54321.

Der Browser zeigt uns nun die Webseite des Servers an. Da unsere nc-Prozesse aber nur jeweils eine Verbindung aufbauen und sich danach beenden, werden wahrscheinlich Bilder und CSS-Dateien nicht vollständig geladen. Beherrschen Browser und Webserver beide „Keep-Alive“ werden jedoch durchaus mehrere Ressourcen übertragen bevor die Verbindung beendet wird – nur halt nicht alle.

Dies ist bis jetzt noch wenig sinnvoll, aber da die Verbindung nun durch unsere Hände geleitet wird, können wir uns einklinken, und mitlesen, was die beiden Gesprächspartner miteinander austauschen.

Belauschen der Verbindung:

# mkfifo /tmp/proxyfifo
# nc -l -p 8080 </tmp/proxyfifo | tee /dev/stderr | nc server.domain.de 8480 | tee /dev/stderr >/tmp/proxyfifo
# rm /tmp/proxyfifo

Der Einfachheit halber werden hier beide Kommunikationsrichtungen per tee zusätzlich auf der Standard-Fehlerausgabe (stderr) ausgegeben, was zum Mitlesen ausreicht.

In manchen Fällen möchte man darüber hinaus in die Kommunikation Eingreifen und die übertragenen Daten „on-the-fly“ manipulieren, auch dies ist mit diesem Ansatz möglich.

Da der Browser im obigen Beispiel glaubt mit „localhost“ zu kommunizieren, überträgt er in seinem HTTP-Request einen falschen Host, dies könnte man beispielsweise mit sed korrigieren wollen:

# mkfifo /tmp/proxyfifo
# nc -l -p 8080 </tmp/proxyfifo | sed -u "s/Host: localhost:8080/Host: rrzk.uni-koeln.de/g" | tee /dev/stderr | nc rrzk.uni-koeln.de 80
# rm /tmp/proxyfifo

Mit diesem Beispiel kann man die Webseite des RRZK über den Aufruf http://localhost:8080 laden und sich anschauen welche Daten ausgetauscht werden. (Wie erwähnt wird die Seite so nicht vollständig geladen).

Aufräumen:

Damit keine Bruchstücke liegenbleiben sollte man eine Named Pipe immer wieder neu anlegen und nach dem Aufruf direkt löschen.

Andere Anwendungsgebiete:

nc kann hier mit jeder Art TCP/IP-Verbindung umgehen, es ist also nicht auf Webkommunikation begrenzt. Besonders bei Anwendungen mit dauerhaft gehaltenen Verbindungen kann nc hier sein volles Potenzial ausspielen. Dies kann besonders Interessant sein bei:

  • Mail-Servern
  • Chat-Servern
  • Spiele-Servern
  • generell allem, bei dem man eine Serveradresse angeben muss

Sie können so rausfinden, welches Protokoll Ihr Netzwerkdrucker spricht und ob eine angeblich verschlüsselte Verbindung wirklich verschlüsselt ist (nc zeigt Binärdaten, wie verschlüsselte oder komprimierte Verbindungen und Dateiinhalte natürlich nur in Form von Datenmüll an).

Fazit:

Mit nc lassen sich auf viele Weisen Daten sammeln, die einem bei der Fehlersuche und -analyse hilfreich sein können.
Obige Beispiele sind nur ein erster Ansatz, sicherlich gibt es noch raffiniertere Kombinationen. Schreiben Sie gerne Ihre eignen Tricks zu diesem Thema in die Kommentare.

Die Zwickmühle beim Betreiben von verschlüsselten Netzdiensten aus Betreibersicht

Angesichts der Schwachstellen rund um bestimmte Verschlüsselungsarten (Poodle und Logjam waren die bekanntesten in letzter Zeit) hat man es als Betreiber schwer, die „optimale“ Konfiguration für Netzdienste zu finden, die verschlüsselte Kommunikation anbieten. Auf der einen Seite möchte man nach Möglichkeit Benutzer mit älteren Geräten, die noch nicht die neuesten Verfahren implementiert haben, nicht völlig von der Nutzung ausschließen, auf der anderen Seite gelten bestimmte Verfahren inzwischen als so unsicher, dass man diese als Serverbetreiber auf gar keinen Fall mehr anbieten möchte, um Nutzer nicht in trügerischer Sicherheit zu wägen.

Das gilt insbesondere dann, wenn als Szenario droht, dass ein Angreifer sich in die Verbindung zwischen Server und Client einklinken kann und dann dafür sorgt, dass die beiden eigentlichen Kommunikationspartner sich auf eine Primitiv-Verschlüsselung einlassen, weil der Angreifer vortäuscht, der jeweils andere Partner würde keine starke Verschlüsselung unterstützen („Downgrade-Attack“). In einem solchen Fall braucht der Angreifer dann nur noch die Primitiv-Verschlüsselung zu knacken anstelle der starken Verschlüsselung, die die beiden Kommpunikationspartner im Normalfall untereinander vereinbart hätten.

Webserver und andere Dienste

Weiter verkompliziert wird die Lage dadurch, dass Angriffsszenarien bei verschiedenen Netzdiensten unterschiedlich zu beurteilen sind. So sind Angriffe, die darauf beruhen, dass einer der Kommunikationspartner unfreiwillig dazu gebracht werden kann, häufig Datenpakete mit annähernd gleichem Inhalt zu senden, bei Webseiten bis zu einem gewissen Grad realistisch. Schafft es der Angreifer, das Opfer auf eine Webseite unter seiner Kontrolle zu locken, so sind automatisierte Datenabrufe durch eingebetteten Skriptcode denkbar, ohne dass es direkt auffällt. Bei anderen Diensten, beispielsweise E-Mail mit einem Mailclient, gibt es hingegen kein ernstzunehmendes Szenario, wie ein Angreifer von außerhalb den Computer des Opfers automatisiert dazu bringen kann, selbständig mit gewisser Regelmäßigkeit gleichartige Datenpakete zu verschicken. Das ist umso mehr eine Besonderheit des Webs gegenüber anderen Netzdiensten, weil das Angriffsziel „Session-Cookie“ auch nur im WWW-Bereich wirklich existiert.

Alte Software überall

Als wäre dieses Spannungsfeld nicht schon vertrackt genug, kann als weitere Schwierigkeitsstufe noch dazukommen, dass man nicht nur bei den fremden Kommunikationspartnern nicht die neuesten Verschlüsselungsverfahren voraussetzen kann, sondern dass man auch als Anbieter nicht all das nutzen kann, was theoretisch verfügbar ist. So steht am RRZK für den Betrieb von Webservern i.d.R. als Betriebsystem Red Hat Enterprise Linux 6 (RHEL6) zur Verfügung. Dieses bringt aber nicht die jeweils neuesten Programmversionen mit, sondern im Regelfall diejenigen Versionen, die bei Erscheinen des Betriebssystems aktuell waren, jedoch natürlich um in der Zwischenzeit bekanntgewordene Sicherheitslücken bereinigt.

Für RHEL6 bedeutet das ganz konkret, dass nur die Funktionen von openssl 1.0.1 zur Verfügung stehen (anstelle von openssl 1.0.2) sowie der Apache-Webserver aus der 2.2er Versionslinie (anstatt 2.4). Damit sind einige der Empfehlungen für Serverbereiter, wie Sie beispielsweise von den Entdeckern des Logjam-Problems gegeben werden, nicht umsetzbar. Das Definieren individueller sog. Diffie-Hellman-Parameter etwa ist erst mit den neuesten Versionen des Apache-Webservers (ab 2.4.8) möglich.

Empfehlung für Apache 2.2 unter RHEL6

Um nun unter RHEL6 einen Apache-Webserver zu betreiben, der Webseiten ausschließlich verschlüsselt (per https) ausliefert, und das unter den gegebenen Umständen mit einem als möglichst sicher geltenden Kompromiss, kann man folgende Einstellungen in der allgemeinen Apache-Konfiguration verwenden:


SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!ADH:!MD5:!RC4
SSLHonorCipherOrder on

Das ist zunächst einmal wenig spektakulär und kaum anders als das, was von den Logjam-Entdeckern empfohlen wird. In der Praxis läuft es darauf hinaus, dass die hier vorgeschlagene Konfiguration keine Präferenz für AES-128-Verschlüsselung enthält, so dass von den meisten heutigen Clients eine AES-256-Verschlüsselung verwendet werden wird. Ob man in dem gegebenen Kontext (Abruf von Webseiten) nun AES-128 oder AES-256 den Vorzug geben sollte ist für mich nicht zu beurteilen und wird in der Praxis wohl auch kaum eine Rolle spielen. Die theoretische Angreifbarkeit von AES-256 gegenüber AES-128 (hier ein alter und bekannter Blogartikel von Bruce Schneider dazu) bezieht sich auf mögliche Related-Key-Angriffe und ist in dieser Frage von untergeordneter Bedeutung.

Lässt man die oben genannte Einstellung SSLHonorCipherOrder hingegen auf dem Standardwert off, statt sie wie empfohlen auf on zu setzen, so ändert sich in der Praxis bei den meisten Browsern wenig. Durch das Setzen von SSLHonorCipherOrder on sorgt man de facto nur dafür, dass Benutzer mancher Versionen des Internet Explorers unter Windows 7 zu ihrem Glück gezwungen werden und auch bei ihnen eine Verbindung mit Forward Secrecy aufgebaut wird. Auf die Belange von Nutzern, die auch heute noch die extrem veraltete und per se unsichere Kombination von Internet Explorer 6 und Windows XP einsetzen, wird hier keine Rücksicht mehr genommen. Diese früher nicht ganz kleine Gruppe an Webseitenbesuchern machte in der Vergangenheit viele faule Kompromisse notwendig.

Dem Browser den Weg zur Verschlüsselung weisen

Legt man Wert darauf, in dem beliebten SSL-Servertest von Qualys besonders gut abzuschneiden, ist SSLHonorCipherOrder on unbedingt notwendig. Jedoch reicht das Setzen dieser und der anderen allgemeinen Verschlüsselungseinstellungen nicht aus. Für ein gutes Testergebnis muss man auch dafür sorgen, dass Besucher ausschließlich verschlüsselt mit dem Server kommunizieren. Solange unverschlüsselte Kommunikation im Web der Normalfall ist, sind dazu noch ein paar weitere Anstrengungen in der Apache-Konfiguration notwendig.

Webseitenbesucher, die – aus welchem Grund auch immer – eine unverschlüsselte Verbindung zum Server aufbauen möchten, müssen also von diesem Vorhaben abgehalten werden. Verwendet man dazu virtuelle Hosts in der Apache-Konfiguration, so kann man die Besucher, die keine Verschlüsselung verwenden, per


<VirtualHost *:80>
  RedirectMatch permanent (.*) https://meinhostname.uni-koeln.de$1
</VirtualHost>

umlenken. Für Named Virtual Hosts wäre hier natürlich noch eine weitergehende Konfiguration nötig. Gezeigt werden soll anhand dieses Konfigurationsschnipsels eigentlich nur, dass man die Besucher am besten mit einer dauerhaften Umleitung (permanent) auf die verschlüsselte Version der Website lenkt.

https und nur https, in guten wie in schlechten Zeiten

Als Kür sendet man dann noch die Information an die Browser der Webseitenbesucher, es in Zukunft gar nicht erst über eine unverschlüsselte Verbindung zu probieren, sondern ausschließlich per https mit dem Server zu kommunizieren:


<VirtualHost *:443>
  # hier stehen normalerweise Einstellungen wie ServerName, DocumentRoot etc.
  
  # vvv Einschalten von HSTS aka HTTP Strict Transport Security, RFC 6797
  Header always set Strict-Transport-Security: max-age=31536000
  # ^^^ Strict Transport Security, funktioniert mit Apache 2.2.15
</VirtualHost>

In diesem Beispiel wird der abrufende Browser instruiert, dass die Information, mit diesem Server nur verschlüsselt zu kommunizieren, ca. ein Jahr lang (31536000 Sekunden) gültig ist. Dies kann man zum Glück auch schon mit dem bei RHEL6 mitgelieferten Webserver Apache 2.2.15 so einstellen.

Mit den auf diese Weise optimierten Einstellungen erhält der Webserver dann von dem erwähnten SSL-Test die Bestnote A+ attestiert, vorausgesetzt die übrigen Einstellungen (zum Zertifikat und der Kette der Zwischenzertifizierungsstellen etc.) sind ebenfalls in Ordnung. Diese Einstellungen sind aber nicht spezifisch für RHEL6, daher soll hier darauf nicht weiter eingegangen werden.

Kampf dem Herzinfarkt – zu lauten Sound unter Linux beheben

Der kleine Quickie am Montagmorgen: Seit Jahren ärgert mich das Problem, dass unter Linux speziell USB-Soundkarten viel zu laut angesteuert werden. Entweder steigt die Lautstärke irgendwo zwischen Stufe 20 und 30 sprunghaft von „einsamer Bergsee bei Windstille“ auf „startender Düsenjet“ oder ist (mit dem altbekannten „ignore_dB=1“-Trick) schon bei Stufe 2 eigentlich viel zu laut.

Nun bin ich zufällig im Blog von Chris Jean über eine Alternativlösung gestolpert, die sehr einfach umzusetzen ist und einfach funktioniert. Es gilt in der Datei

/usr/share/pulseaudio/alsa-mixer/paths/analog-output.conf.common

im Block

[Element PCM]

die Zeile

volume = merge

zu ersetzen durch

volume = ignore
volume-limit = 0.0075

Und schön lässt sich das Ganze wieder wunderbar regeln. Zuvor kann man im Alsamixer noch die Soundkarten feinjustieren, damit die Master-Ausgabe optimal die eigenen Bedürfnisse abdeckt.

Projekt Mepevea – D’r Zoch kütt!

Als umweltbewusster oder zumindest geiziger Mitarbeiter des Öffentlichen Dienstes verzichtet man in der Regel bei längerer Anfahrt zum Arbeitsplatz auf den privaten PKW und nimmt freudig am öffentlichen Personennahverkehr (ÖPNV) teil. Sprich: Die Deutsche Bahn (und in Köln auch die KVB) ist unser Freund! Gerüchteweise sind die bereitgestellten Verkehrsmittel nicht immer dann vor Ort, wenn man es laut Fahrplan erwarten könnte. Damit man die daraus resultierende Wartezeit nicht am Bahnsteig, sondern am Frühstückstisch bzw. im bequemen Bürosessel verbringen kann, sind aktuelle Informationen über die Verspätungen unerlässlich.

Nun hat sich in der Vergangenheit der Service der DB dahingehend deutlich verbessert. So sind die Verspätungsinformationen inzwischen minutengenau und in Realzeit sowohl im Web als auch mittels der App „DB Navigator“ abrufbar. Der o.g. Mitarbeiter des Ö.D. ist allerdings nicht nur geizig (jaja, und umweltbewusst), sondern auch klickfaul und noch dazu ein Spielkind. So kam ich auf die Idee, sowohl in meinem trauten Heim als auch im Büro mittels ohnehin vorhandener Technik einen (für mich) optimalen Anzeigebildschirm zu basteln.

Dieser sollte nicht nur die aktuellen Verspätungen meiner Zugverbindungen, sondern auch weitere interessante Informationen anzeigen, genauer gesagt: Aktuelle Nachrichten, Wettervorhersage und (zuhause) zusätzlich das Kamerabild einer per WLAN verbundenen IP-Kamera. Als Hardware kamen ein günstiger und dank Notebook-Anschaffung ohnehin kaum noch gebrauchter PC-Bildschirm sowie zeitgemäß ein Raspberry Pi zum Einsatz. Das System sollte in jedem Fall ohne weitere Peripherie, speziell ohne Maus und Tastatur, auskommen. Softwareseitig setzte ich daher auf Google Chrome im Kiosk-Modus. Mittels der Erweiterung „Easy Auto Refresh“ kann man dafür sorgen, dass Chrome die angezeigte Seite automatisch einmal pro Minute neu lädt. Das Kamerabild läuft ohnehin im Streaming-Mode.

Der graphische Desktop des Raspi musste so eingestellt werden, dass er sich nicht automatisch abschaltet. Die Kontrolle über die Anzeige sollte ausschließlich per Ein/Aus-Knopf des Monitors ablaufen. Dies erreicht man über die eine Einstellung in LightDM.

Da ich mir die Installation und Konfiguration eines Webservers sparen wollte, verwende ich eine einfache lokale HTML-Seite auf dem Raspi. Die beiden gewünschten Elemente „Aktuelle Nachrichten“ und „Wettervorhersage“ sind sehr leicht über passende Widgets realisierbar. Ich habe hierzu die Angebote von wetterdienst.de und rp-online genutzt, es gibt jedoch zahlreiche weitere Anbieter.

mepevea

Richtig interessant wurde es dann bei der Einbindung der Verspätungsanzeige. Wie ich feststellen musste, bietet die Bahn leider keine geeignete API zu diesem Zweck. Mir blieb nichts anderes übrig als die entsprechende Webseite zu parsen. Diese Erkenntnis war die Geburtsstunde von Projekt „Mepevea“ (MEin PErsönlicher VErspätungsAnzeiger).

Wie erwähnt wollte ich auf die Installation und den Betrieb eines Webservers verzichten. Die Anzeige soll ja ohnehin nur für mich persönlich laufen. Daher musste ich die eigentliche Logik nebst Parser in ein Pythonskript packen, welches per Cronjob aufgerufen wird (ja, ich arbeite unter Linux und ignoriere Windows seit Jahren – die Portierung sollte aber kein großes Problem darstellen). Als Basismodul für den Parser dient natürlich „BeautifulSoup“, darüber hinaus werden urllib zum Abruf der Seite und einige weitere Module benötigt. Der Start lautet also:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import bs4, urllib2, time, fileinput, sys, urllib

„fileinput“ verwende ich, um später den <div>-Block im HTML durch die korrekten Daten auszutauschen, z.B.:

for line in fileinput.FileInput("/home/pi/anzeige/bahnlinks.html",inplace=1):
if line.startswith('<div id="bahn">'):
   line = text
   sys.stdout.write(line)

Natürlich macht es Sinn, abhängig vom Wochentag und der Tageszeit die Anzeige zu variieren (Hinfahrt, Rückfahrt, Abend/Wochenende), also z.B.:

timestamp = time.localtime(time.time())
if timestamp[6] > 4:
   textlist.append("<b>Bahnanzeige erst am Montag wieder! Schönes Wochenende!</b>")

Hier wird schon klar: Individuelle Anpassung ist unerlässlich und ich kann die Beispiele nur anreißen. Keine Sorge: Am Ende werde ich als „großes Beispiel“ mein komplettes Skript bereitstellen.

Zentrales Element des Skriptes ist die Parserfunktion. Sie erhält als Parameter die URL der Bahn (dazu später) und jagt sie durch BeautifulSoup:

def parser(url):
   page = urllib2.urlopen(url).read()
   soup = bs4.BeautifulSoup(page)

Man möge mir an dieser Stelle glauben, dass wir die spannenden Inhalte erhalten, wenn wir nach den Keywords, genauer gesagt den <td>-Klassen „overview timelink“ und „overview tprt“ suchen:


zeilen = soup.find_all('td', {"class" : "overview timelink"})
verspaetungen = soup.find_all('td', {"class" : "overview tprt"})

Schon hier erkannt man, wo das größte Problem unserer schönen Bastelei liegt: Sollte die Bahn die Klassennamen aus irgendwelchen Gründen ändern, funktioniert natürlich nichts mehr. Das gleiche gilt für die URLs und die HTML-Struktur. Genau aus diesem Grund gibt es ja i.d.R. kapselnde APIs, aber die stehen hier wie gesagt nicht zur Verfügung.

Standardmäßig erhält man von der Bahn die nächsten drei Züge ab dem definierten Zeitpunkt. Ich habe die finale Version noch so erweitert, dass man dies variieren kann, aber das würde hier zu weit führen. Ebenso müsste ich nun eigentlich auf die Details von BeautifulSoup eingehen, um den folgenden Codeblock zu erläutern. Aber auch dies möchte ich mir sparen und auf die gute Online-Dokumentation des Moduls verweisen. Unsere Verbindungen sowie die aktuellen Verspätungen erhalten wir so:


parsedtext = ''
zaehler = 0
for zeile in zeilen:
   for zelle in zeile.children:
      parsedtext += zelle.contents[0]
   parsedtext += '<span style="color: red;">'
   for verspaetung in verspaetungen[zaehler].children:
      if str(verspaetungen[zaehler]).count("okmsg") > 1 or str(verspaetungen[zaehler]).count("red") > 1:
         parsedtext += verspaetung.contents[0]
         break
   parsedtext += '</span>'
   zaehler += 1

Ich bin mir zu 99% sicher, dass dies nicht die eleganteste Version ist, um die Informationen zu erhalten und aufzubereiten. Aber sie funktioniert. Wer das Ganze kürzer, schöner und verständlicher hinbekommt, ohne dass die Funktionalität leidet, möge sich bei mir melden.

Kommen wir nun zu den benötigten URLs. In einer ersten Version hatte ich pro Zug eine URL auf Basis des Bahntools „query2.exe“ verwendet, die auch deutlich einfacher zu parsen war (Anmerkung: Bitte von der Endung „.exe“ nicht täuschen lassen: Es handelt sich um einen Webservice, nicht um ein lokales Programm.). Leider musste ich feststellen, dass die Bahn bei jeder (geplanten) Mini-Fahrplanänderung die URL komplett verändert. Auf Dauer war das also leider keine Lösung. Stattdessen verwende ich nun die „Vorstufe“ namens „query.exe“. Diese hat klar definierte und – hoffentlich – dauerhaft beständige Parameter. Als Parameter benötigen wir den Code des Startbahnhofs, den Code des Zielbahnhofs und die Startzeit.

Während die Startzeit natürlich jedem selbst überlassen bleibt und einfach in der Form hh:mm verwendet wird, muss man sich die Codes (sog. IBNR) der Bahnhöfe einmalig heraussuchen. Dies geht zum Glück sehr einfach mittels einer Onlinesuche.

Lautet die IBNR des Startbahnhofs bspw. 8000208, die des Zielbahnhofs 8000133 und die gewünschte Startzeit ist 17:00 Uhr, lautet die gesuchte URL:

http://reiseauskunft.bahn.de/bin/query.exe/dox?S=8000208&Z=8000133&time=17:00&start=1

Damit lässt sich nun für jede beliebige Verbindung und Kombination von Tageszeiten ein passender Anzeiger (eben ein „Mepevea“) bauen.

Für weitere Ideen, Verbesserungsvorschläge etc. bin ich jederzeit dankbar. Und wenn jemand die Bahn überreden könnte, doch mal eine entsprechende API bereitzustellen, das wäre ein Traum. 😉

Wie versprochen: Den vollständigen Text des Skriptes sowie eine Beispiel-HTML-Seite findet man unter http://dl.distinguish.de/mepevea.zip

AirPrint-Erfahrungen

Seit einiger Zeit (ab Version 4.2.1) können iOS-Geräte wie z.B. iPads und iPhones drucken. Der offizielle Weg funktioniert aber nur in Heimnetzwerken und mit wenigen Druckermodellen. Im Netz kursieren viele Anleitungen, wie man diese Beschränkung umgehen kann. Was ich hier darstelle, ist nicht neu, sondern nur ein Erfahrungsbericht über die Fallstricke, die einem begegnen können. Der beste Ausgangspunkt für eigene Versuche, den ich gefunden habe, ist dieser Blogeintrag. Insbesondere die dort aufgelisteten Links sind sehr hilfreich.

Auf die grundsätzlichen Dinge, wie die Konfiguration von CUPS und das Erstellen der Servicerecords im DNS, gehe ich hier nicht ein. Das ist an anderer Stelle (s.o.) schon zur Genüge getan. Folgende Probleme hatte ich zunächst:

  • Farbausdruck ging nicht
  • Druck aus Safari ging nicht

Das letztere Problem wurde, wie man im CUPS-Log (mit debug-Logging) sehen konnte, dadurch ausgelöst, dass das zu druckende Dokument als URF-Image geschickt wurde. URF ist ein „raster image format“, für das Apple den MIME-Typ image/urf verwendet, das aber leider nirgends dokumentiert ist. Eigentlich sollte URF in meinem Fall nicht verwendet werden, weil ich (gemäß den Anleitungen) urf=none deklariert hatte. Ich hielt das für ein möglicherweise neues Problem und habe deshalb nach Lösungen zum Drucken von URF gesucht. Es sei hier schon verraten: das war eine falsche Fährte. Dennoch folgt ein kurzer Exkurs zum Drucken von URF.

Frühere Versionen von Mac OS X hatten einen CUPS-Filter namens urf2pdf, mit dem das Drucken von URF möglich war. Mit dem Update auf 10.6.5 hat Apple diesen Filter gelöscht, man findet ihn aber noch im Netz. Wenn man den (mit den richtigen Permissions, also root:wheel als owner/group) installiert, und in den CUPS-Einstellungen den MIME-Type image/urf aktiviert, klappt das tatsächlich – aber nur unter Mac OS X. Ich habe keine Möglichkeit gefunden, CUPS unter Linux beizubringen, mit URF umzugehen.

Das zweite Problem war, dass alle Ausdrucke schwarzweiß waren, obwohl im Servicerecord für den Drucker Farbfähigkeit annonciert war. Wie ich jetzt weiß, war beider Rätsel Lösung offenbar identisch: Tippfehler im Servicerecord. Beim Studium der „Bonjour Printing Specification“ von Apple fiel mir auf, dass ich ein (ganz anderes) Attribut falsch geschrieben hatte. Nachdem ich alles entsprechend angepasst hatte, gingen auf einmal Farb- und Duplexdruck. Es sieht so aus, als ignoriere der Parser alle Attribute nach einem falsch geschriebenen. Deshalb wurde auch mein urf=none nicht ausgewertet. Mit der korrigierten Fassung geht jetzt auch ein CUPS-Server unter Linux, weil die iOS-Geräte jetzt alle Druckjpbs als PDF schicken.

Fazit: wie so oft in der IT können kleine Ursachen große Auswirkungen haben.

VPN-Unterstützung für Android-Endgeräte – Konfiguration der Klienten

Die letzten Tage habe ich mit der Integration von VPN für Android-Geräte verbracht. An dieser Stelle entschuldige ich mich vorab für mehrere Verbindungsabbrüche bei den Nutzern, die den IPSec-Klienten verwenden, denn durch die Umstellung der Verschlüsselungskonfiguration musste ich mehrmals morgens die IPSec-Verbindungen trennen.

Einige der Android-Smartphones von Samsung haben schon vor einigen Monaten VPN-Unterstützung in Form des AnyConnect-Klienten erhalten. Dieser verwendet als Protokoll SSL-VPN und sollte somit die wenigsten Probleme mit Firewalls etc. haben, da die Kommunikation nur über den Port 443 (TCP und UDP) und alle Sessions nur vom Klienten aufgebaut werden. Ich empfehle daher, diesen weiterhin zu verwenden, wo dieser verfügbar ist.

Um die restlichen Android-Endgeräte ua. auch  Tablets mit VPN zu versorgen, musste ein völlig anderer Typ von VPN aktiviert werden, L2TP-IPSec.  Dabei wird zuerst eine IPSec-Verbindung aufgebaut, in der wiederum ein L2TP-Tunnel erstellt wird.

Wie dies auf den Endgeräten konfiguriert wird habe ich exemplarisch unter http://rrzk.uni-koeln.de/vpnandroid.html dokumentiert. Da die Hersteller teilweise die Bezeichnungen und Menüstruktur verändern, können diese unter Umständen abweichen.

Bei der Verschlüsselung habe ich mich für mehr Sicherheit und damit für AES gegenüber 3DES entschieden. In der Literatur wird AES oft als ressourcenlastiger bezeichnet, was gerade bei den leistungsschwächeren Mobilgeräten in einem höheren Energiebedarf und somit einer kürzeren Batterielaufzeit resultieren könnte. Dazu habe ich aber keine Informationen gefunden und kann die Problematik daher nicht bewerten.

Ich bin gespannt, wie hoch die Nutzung von VPN über Android sein wird. Leider dauert es ja oft, bis sich die Nachricht über die neue Unterstützung von Endgeräten herumspricht.

 

Anleitung zur Einrichtung von L2TP-IPSec unter Android: http://rrzk.uni-koeln.de/vpnandroid.html

Perl-Modul SAVI-Perl mit aktueller Sophos-Version für Linux verwenden

Wir betreiben neben Ironport für die zentralen Mailserver noch eine weitere Anti-Spam- und Anti-Viren-Infrastruktur als „Altlast“ für Institute, die keinen LDAP-Server betreiben. Dort wird als Anti-Virus-Software seit vielen Jahren ClamAV und Sophos Antivirus eingesetzt. Für Letzteres musste jetzt ein Update installiert werden, weil die alte Version demnächst nicht mehr unterstützt wird. Sophos wird bei uns mit dem Perl-Modul SAVI-Perl in amavisd-new eingebunden. Das ging nach dem Update zunächst nicht mehr, obwohl ich das Modul gegen die neue Sophosversion gebaut hatte. Die Ursache ist, dass sich der Pfad der .vdl- und .ide-Dateien geändert hat. Zwar kann man SAVI-Perl beim Kommando load_data diesen Pfad übergeben, aber (unsere Version von) amavisd-new unterstützt das nicht. Die einfachste Lösung war deshalb ein symbolischer Link vom aktuellen Pfad /opt/sophos/lib/sav auf den bisherigen Pfad /opt/sophos/sav.

Im Knast und doch frei – iPod Touch unter Linux befüllen

Auch wenn MacOS X bekanntlich auf Unix basiert, ignoriert Apple die Linuxbenutzer leider beständig und veröffentlicht kein Programm á la iTunes, mit dem unsereins seinen iPod Touch oder sein iPhone unter Linux mit Musik befüllen kann. Zwar existieren  Lösungen wie „iFuse„, die das Gerät als USB-Laufwerk einbinden, aber das allein reicht nicht, da die iTunes-Datenbank des Gerätes von einem einfachen Kopiervorgang nichts mitbekommt und die neuen Musikdateien nicht anzeigt.

Ich suchte daraufhin nach einer Lösung, die insbesondere ohne das berühmte „Jailbreaking“ auskam und so den Nutzungsregelungen und Garantiebedingungen von Apple nicht widersprach. Gefunden habe ich zunächst einen Artikel auf „FERNmanns Blog„, der über das o.g. iFuse hinaus auf eine spezielle Version von libgpod verweist, die man nach der verlinkten Anleitung selbst kompilieren muss. Das klappte bei mir (Ubuntu 9.10 Karmic Koala) auch, allerdings musste ich zwei Anpassungen vorher (!) machen, die im Blogeintrag nicht bzw. erst im Kommentar erwähnt sind:

  • zusätzliches Installieren der Pakete libsqlite0-dev, libsqlite3-dev, gtk-doc-tools, intltool, libltdl-dev, libtool, libgcrypt11-dev, libgnutls-dev, libgpg-error-dev, libtasn1-3-dev
  • manuelles Kompilieren und Nachinstallieren der Software libimobiledevice von dieser Quelle

Bevor der geneigte Leser sich aber gleich ans Kompilieren macht: Inzwischen gibt es noch eine viel viel einfachere Lösung, ebenfalls dokumiert auf „FERNmanns Blog„. Die erste Lösung habe ich für den Fall noch erwähnt, dass der einfache Weg aus irgendeinem Grund scheitert. Zu letzterem Weg ist noch zu sagen, dass ich bei meinem Ubuntu alle Vorkommen von „libiphone“ in der Paketliste durch „libimobiledevice“ ersetzen und das Paket „python-iphone“ rausstreichen musste. Danach kann man mittels Rhythmbox einwandfrei auf die Musiksammlung des iPods zugreifen. Viel Spaß!

Keiner versteht mich…

Seit einem Upgrade des Hostsystems auf Ubuntu 8.10 waren die Keyboardschemata in allen meinen VM-Guests verhunzt. Das hat zwar bisweilen amüsante Effekte („Pfeil-nach-unten“ war z.B. auf einmal das Signal für „mach einfach alles zu, frag erst gar nicht“), nach kurzer Zeit wird es aber sehr nervig. Nach einigem Herumprobieren mit Tastaturtreibern und Co. stöberte ich dann doch mal in der VMWare Knowledge Base und fand diesen Hinweis. In aller Kürze: Durch die Umstellung auf die neuen „evdev„-Treiber sendet das Hostsystem nun andere Tastencodes an VMWare und das knallt dementsprechend. In dem KB-Artikel werden einige Hinweise zur Behebung gegeben, bei mir genügten folgende zwei Zeilen in der Datei „/etc/vmware/config“:

xkeymap.nokeycodeMap = true
xkeymap.keysym.ISO_Level3_Shift = 0x138

Die erste Zeile behob bereits fast alle Probleme, die zweite war für die besonders bockige „AltGr“-Taste (was im übrigen für „Alt Graph“ steht, wie ich nun auch weiß) nötig. Der Wert „ISO_Level3_Shift“ kann dabei auf jedem System anders aussehen, Näheres dazu im KB-Artikel.

Wem auch der o.g. Artikel nicht weiterhilft, der findet im folgenden Blogeintrag weitere Lösungsvorschläge:

http://tinyurl.com/5kd7uz