Manchmal muss man Dinge tun, die nicht direkt in den eigentlichen Aufgabenbereich fallen. Aufgrund von Abwesenheit der üblichen Verdächtigen musste ich heute beim Updaten von Windows Servern aushelfen. Und das war mal ein spannendes Erlebnis, weil ein Update so richtig Ärger gemacht hat.

Gleich vorweg: Ja, man kann da viel automatisieren. Deswegen sieht man auch lokales Management der Updates. Unsere Spezialität im Cloud-Geschäft besteht aber darin, individuelle Lösungen mit dem Kunden zusammen zu erstellen und nicht ausschließlich identische Maschinen von der Stange zu nehmen oder den Kunden mit dem Updateproblem allein zu lassen. Also ist einiges an Handarbeit nach wie vor notwendig, um nach dem Update sicher zu stellen, dass die benötigten Dienste auch wirklich laufen.

Es hängt und hängt und hängt

Wenn besonders viele Systeme auf einmal angefasst werden müssen, ist es besonders nervig, wenn es nicht schnell genug vorwärts geht.

windows-update-stalled

An der Stelle kann man warten und warten. Manchmal geht's nach einer halben Stunde spontan weiter. Manchmal aber auch nicht.

Nein, natürlich sitzt da niemand davor und wartet, sondern die Updaterei erfolgt parallel. Man sieht halt nur, dass einige Kisten nicht weiter machen.

Also mal in den Taskmanager geschaut und festgestellt, dass ein Updateprozess nicht weiter macht. Den kann man manuell abschießen.

windows-update-kill

Ein beherzter Kill des Prozesses zeigt unmittelbare Wirkung.

windows-update-running

Beim späteren Reboot wird der Update dann korrekt installiert. Insofern ist das kein Problem.

Interessanter ist die Frage nach der Ursache dieses Phänomens. Und da hatte ich Glück.

windows-update-ursache

Wie man sehen kann, ist der aktiv laufende Prozess die alte Version des Tools, das aktualisiert werden soll.

Da das Tool zur Entfernung bösartiger Software sicherlich auch Signaturen solcher Software enthält, besteht eine gewisse Wahrscheinlichkeit, dass eine ältere Version diese neuen Signaturen als bösartig einstufen kann. Wenn das der Fall ist, wird sie die Ausführung der bösartigen Software verhindern.

Und damit steht der Update-Prozess.

Zur Gegenprobe kille ich den alten Prozess und siehe an: Das Update läuft sofort und ohne Fehler durch.

Heute flog mal wieder eine seltsame Fehlermeldung durchs Log bei der auch normales Googlen keine sinnvollen Ergebnisse brachte. Deswegen möchte ich sie hier dokumentieren.

bestmx_map_lookup: MX host 2001:4420:f501:0400::2. includes map delimiter character 0x3A 

Der Übeltäter war schnell gefunden: Eine E-Mail an eine taiwanische Adresse.

550 5.1.2 <xxx@ems.shiyeu.gov.tw>... Invalid MX record for recipient host ems.shiyeu.gov.tw 

Also schauen wir uns mal den MX genauer an:

$ host ems.shiyeu.gov.tw
ems.shiyeu.gov.tw has address 117.56.237.218
ems.shiyeu.gov.tw has address 192.168.5.252
ems.shiyeu.gov.tw has address 192.168.56.1
ems.shiyeu.gov.tw has IPv6 address 2001:4420:f501:400::2
ems.shiyeu.gov.tw mail is handled by 10 117.56.237.218.
ems.shiyeu.gov.tw mail is handled by 10 2001:4420:f501:0400::2.

Autsch! Da ist wohl jemanden aufgefallen, dass man keine IP-Adressen in den MX schreiben darf, weil dann Namen wie 117.56.237.218.ems.shiyeu.gov.tw. entstehen. Aber anstatt den Fehler zu verstehen und den Namen eines Servers hin zuschreiben, hat man einfach einen Punkt an die IP-Adresse angehängt und so den DNS-Namen verkürzt.

Der MTA interpretiert aber den Doppelpunkt (0x3A) als Trennzeichen in Maps (Hilfetabellen) und beschwert sich dann darüber.

Würde nur legacy IP(v4) benutzt, käme nicht mal eine so deutliche Fehlermeldung. Denn grundsätzlich könnte eine IP(v4)-Adresse auch ein gültiger DNS Name sein: Er hat alphanumerische Texte, die durch Punkte getrennt sind. Das zu der IP als Name interpretiert dann keine IP existiert, macht die Fehlersuche allerdings nicht einfacher.

Spielereien

Also spielen wir mal:

$ORIGIN donnerhacke.de.
broken-mx    MX  0  1.2.3.4
broken-mx2   MX  0  1.2.3.4.

Das ergibt dann bei der Abfrage im DNS:

$ host broken-mx.donnerhacke.de
broken-mx.donnerhacke.de mail is handled by 0 1.2.3.4.donnerhacke.de.

$ host broken-mx2.donnerhacke.de
broken-mx2.donnerhacke.de mail is handled by 0 1.2.3.4.

Und damit versuche ich jetzt mal E-Mails zu verschicken.

from=<test@broken-mx.donnerhacke.de>, size=40, nrcpts=1, proto=ESMTP, daemon=MTA, relay=... 

Das geht? Ja, natürlich. Ich habe ja einen Wildcard Eintrag. Der passt auch auf 1.2.3.4.donnerhacke.de. Und damit sieht das aus wie ein korrekter Absender.

550 5.1.2 <test@broken-mx2.donnerhacke.de>... Illegal MX record for recipient host broken-mx2.donnerhacke.de

Der andere Eintrag funktioniert aber nicht. Wie erwartet gibt es keine schwerwiegende Fehler-Meldung über irgendwelche Map-Zeichen, sondern nur eine blanke Ablehnung. Der Grund ist einfach, dass es für 1.2.3.4. keine IP Adresse im DNS gibt.

Beim Versenden der E-Mail an diesen Empfänger schaut es noch anders aus:

rcpt to: <test@broken-mx.donnerhacke.de>
250 2.1.5 <test@broken-mx.donnerhacke.de>... Recipient ok
rcpt to: <test@broken-mx2.donnerhacke.de>
250 2.1.5 <test@broken-mx2.donnerhacke.de>... Recipient ok
DATA
...
250 2.0.0 u4I8Kv6c010237 Message accepted for delivery 

Und was passiert genau?

to=<test@broken-mx.donnerhacke.de>, relay=1.2.3.4.donnerhacke.de. [217.17.193.188], stat=User unknown
to=<test@broken-mx2.donnerhacke.de>, relay=1.2.3.4., stat=Deferred: 1.2.3.4.: No route to host

In einem Fall greift der Wildcard-Eintrag, aber der Server nimmt keine E-Mail für solch einen Nutzer an.

In dem anderen Fall kann keine Adresse ermittelt und deswegen kann auch der Zielserver erreicht werden. Da eine solche Situation von externen Diensten abhängig ist und diese auch mal fehlerhaft sein können (die Namensauflösung kann schlicht auch mal scheitern), wir die E-Mail zurück gelegt und später nochmal versucht.

May 18 10:22:49 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:23:49 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:24:50 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:25:50 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:26:50 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:27:50 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
May 18 10:28:50 to=<test@broken-mx2.donnerhacke.de>, stat=Deferred: 1.2.3.4.: No route to host
...

Für den Admin ist die Meldung allerdings fehlerträchtig. Es ist leicht zu übersehen, das es sich um einen DNS-Namen und nicht um eine IP-Adresse handelt. Man kann Stunden damit zubringen, den Fehler überhaupt zu erkennen.

Die Seite https://ssl-tools.net/ ist eine Webseite, die vieles rund um Zertifikate prüft. Das macht sie gut, wenn auch Verbesserungsbedarf bei z.B. internen CAs besteht. Aber das ist Geschmackssache. Reale Fehler als valid auszuzeichnen ist allerdings keine Geschmacksfrage, sondern ein ernstes Problem. Akut führt die Seite es an sich selbst vor.

Zertifikate laufen aus

Im Gegensatz zu OpenPGP laufen die Zertifikate unter X.509 (aka SSL) nach einer festen Zeit aus. Bei DNSSEC ist das auch so, aber da ist der Erneuerungsprozess der Signaturen i.d.R. voll automatisiert, weil es alle Signaturen lokal erzeugt werden können. Bei X.509 muss man mit einem externen Partner regelmäßig zusammen arbeiten, um ein Zertifikat zu erneuern. https://letsencrypt.org schlägt deswegen ein Verfahren vor, diese Interaktion zu automatisieren und damit ähnlich leicht handhabbar zu machen, wie DNSSEC.

Aber bislang ist man meist immer noch mit den klassischen Zertifikaten unterwegs. Und hat sich um den regelmäßigen Austausch manuell zu kümmern. Das klappt nicht immer.

Heute schrie mein Webbrauser über fehlerhafte, weil abgelaufene Zertifikate von ssl-tools.net.

Reflexionen

Aber wie sieht sich die Seite selbst? Wird sie ebenfalls laut schreien und Warnungen anzeigen?

Oh, wirklich?

Das Zertifikatskästchen ist grün und vertrauenswürdig, aber in den Details steht was von seit 13 Stunden abgelaufen.

Ebenfalls witzig ist die Diskrepanz zwischen dem DANE-Kästchen (rot und böse) und den Details dort: valid.

Was ist denn nun bei DANE wirklich los? Alles rot oder alles grün? Was ist denn mit DNSSEC los?

Na das schaut ja gar nicht gut aus: Die gesamten DNSSEC-spezifischen Records (Signaturen) fehlen in der Zone!

Wie kann man da nur ein grünes valid hinschreiben?

Andere Sicht

Andere Testseiten wie https://www.ssllabs.com/ sind da wesentlich restriktiver:

In einem früheren Beitrag hatte ich anhand eines graphischen Beweises gezeigt, wie man sich den Satz des Pythagoras herleiten kann. Leider enthält der Beweis einige Ungereimtheiten, die ich geflissentlich ignoriert hatte. Welche Bedeutung diese Ungereimtheiten haben können, sei an einem konkreten Beispiel demonstriert.

Überraschung

In dem täglich durchfliegenden Datenstrom war heute ein Prachtstück des missratenen Beweises.

dreieck-fail

Wie man klar erkennen kann, liegen zwei verschiedene Zerlegungen ein und desselben Dreiecks in identische Teile vor. Aber irgendwie hat sich da eine Lücke aufgetan!

Ganz offensichtlich handelt es sich um einen Scherz, der deutlich macht, wie genau man auf seine Voraussetzungen achten muss.

Also rekapitulieren wir mal:

  • Handelt es sich um ein und dasselbe Dreieck?
  • Sind die Teilstücke identisch?
  • Haben die Stücken die Form, die sie vorgeben?
  • Ist die Zerlegung universell, oder handelt es sich um einen Spezialfall?

Beginnen wir mir der zweiten Frage: Sind die Teilstücken identisch?

Das ist leicht zu prüfen: Man zählt die Kästchen, die jedes Teilstück in jede Richtung einnimmt und schaut, ob alle Linien wirklich gerade sind. Das ist in beiden Bildern auf die gleiche Art der Fall.

Die zweite Frage ist also mit Ja zu beantworten.

Nun zu ersten Frage. Auch hier ist die Überprüfung genauso leicht: Man zählt wieder die Kästchen 13 breit und 5 hoch. Die Linien sind auch alle gerade, oder?

So ganz klar ist das nicht, denn das große Dreieck wird ja zusammen gestückelt. Es wäre also durchaus möglich, einer Täuschung zu unterliegen.

Also legen wir das rote und das türkisfarbene Dreieck mal direkt aufeinander und zeichnen die Linien dünn.

dreieck-overlap

Huch?! Da ist ja eine kleine Abweichung!

Wenn man die Dreiecke mal genau aufeinander malt, gibt es folgende Form:

dreieck-bereich

So richtig dreieckig sieht das nicht aus!

Damit ist die Frage drei mit einem eindeutigen Nein zu beantworten: Die Form ist nicht das, was sie zu sein vorgibt. Die dick gezeichneten Linien sind der Quell der Täuschung.

Und somit ist auch die fehlende Fläche gefunden: Der schmale, aber lange Bereich hat genau den Flächeninhalt des fehlenden Kästchens.

Hausaufgabe

Damit ist der Fall aber noch nicht beendet. Denn es bleibt Frage vier: Handelt es sich um einen Spezialfall?

Aber wo könnte denn der Spezialfall vorliegen? In der Zerlegung des Rechtecks.

Wer möchte, kann mal selbst knobeln, wann man das Rechteck nach der Vertauschung der Dreiecke auf die angegebene Weise zerlegen kann. Ist diese Zerlegung nämlich generell möglich, so müsste sie bei Verwendung eines richtigen Dreiecks keine Lücke lassen.

Ich freue mich über Eure Erfolgsmeldungen in den Kommentaren.

Heute morgen begann eine ClamAV Installation bei einem Kunden zu spinnen. Freshclam, der Updater von ClamAV, weigert sich die Aktualisierungen vorzunehmen. Wenn man den Grund dann kennt, ist alles wohl dokumentiert. Wenn auch die Ursache in einer schlechte Pflege der Produktionsumgebung von ClamAV liegt.

Der Morgen

Eine E-Mail vom cron berichtete Schlimmes vom Versuch die Datenbank des ClamAV zu aktualisieren.

ERROR: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
ERROR: getfile: Download interrupted: Operation now in progress (IP: 62.27.56.14)
ERROR: Can't download daily.cvd from db.DE.clamav.net
ERROR: getpatch: Can't download daily-21465.cdiff from database.clamav.net
ERROR: getfile: Download interrupted: Operation now in progress (IP: 62.27.56.14)
ERROR: Can't download daily.cvd from database.clamav.net

Unglücklicherweise hörten diese Fehler nicht auf. Also muss man auf der Maschine schauen, was falsch läuft.

Ein händisch angeworfener Update produziert eine lange Liste von Fehlversuchen:

ClamAV update process started at Thu Mar 17 11:14:42 2016
main.cvd is up to date (version: 57, sigs: 4218790, f-level: 60, builder: amishhammer)
WARNING: getfile: daily-21465.cdiff not found on remote server (IP: 62.27.56.14)
WARNING: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
Trying host db.DE.clamav.net (88.198.17.100)...
connect_error: getsockopt(SO_ERROR): fd=4 error=111: Connection refused
Can't connect to port 80 of host db.DE.clamav.net (IP: 88.198.17.100)
Trying host db.DE.clamav.net (178.63.73.246)...
nonblock_connect: connect timing out (30 secs)
Can't connect to port 80 of host db.DE.clamav.net (IP: 178.63.73.246)
Trying host db.DE.clamav.net (84.39.110.99)...
nonblock_connect: connect timing out (30 secs)
Can't connect to port 80 of host db.DE.clamav.net (IP: 84.39.110.99)
WARNING: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
WARNING: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
WARNING: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
WARNING: getpatch: Can't download daily-21465.cdiff from db.DE.clamav.net
WARNING: Incremental update failed, trying to download daily.cvd
nonblock_recv: recv timing out (30 secs)
WARNING: getfile: Download interrupted: Operation now in progress (IP: 62.27.56.14)
WARNING: Can't download daily.cvd from db.DE.clamav.net
Trying again in 5 secs...

Bei jedem Versuch schaut das ähnlich aus. Egal, ob man es einige Minuten später oder gleich nochmal probiert.

Manchmal klappt aber auch eine Verbindung und der Download ist extrem langsam. Es dauert mehrere Minuten, bis 1% der Daten angekommen sind. Aber dann hat freshclam schon wieder aufgegeben.

Also einen Sniffer angeworfen und geschaut, was da eigentlich abgeht: Es wird z.B. die URL http://db.DE.clamav.net/daily.cvd abgerufen.

Mit einem wget auf der gleichen Maschine gibt es aber keinerlei Schwierigkeiten, diese Datei zu laden. Es geht richtig schnell.

Vielleicht hat ja die Maschine ein Durchsatzproblem in Richtung Festplatte? Nein, auch nicht. Selbst ein wget parallel zu einem langsamen dahin kriechenden freshclam ins das gleiche Verzeichnis, in das freshclam auch reinschreibt, ist rattenschnell.

Ein Blick ins DNS zeigt, dass das Problem auch auf Serverseite liegen kann. Also mal testen:

$ dig +short db.DE.clamav.net |
 while read a; do
   echo $a;
   wget -Y off -O /dev/null http://$a/daily.cvd;
 done

Ergebnis:

IP Datenrate
88.198.17.100 Connection refused
130.133.110.67 22.3 KB/s
144.76.28.11 404 Not Found
176.9.115.53 301 Moved Permanently
178.63.73.246 Connection timed out
193.27.49.165 781 KB/s
195.30.97.3 503 Service Temporarily Unavailable
212.227.138.145 Connection timed out
213.174.32.130 404 Not Found
62.27.56.14 600 Byte/s (3 KB/s mit langen Pausen)
62.201.161.84 2.41 MB/s
62.245.181.53 1.71 MB/s
84.39.110.99 Connection timed out

Das ist ja großes Kino! Die Qualität des Servernetzwerkes ist durchaus noch etwas ausbaufähig.

Ursache und Fehlerbehebung

Um mit solchen Ausfällen im Content Delivery Network umgehen zu können, hat freshclam einen Verfügbarkeitscache: Die Datei mirrors.dat.

Ein Blick in die Datei zeigt

$ freshclam --list-mirrors | fgrep Ignore | sort | uniq -c
      5 Ignore: No
     10 Ignore: Yes

Der größte Teil der Server wird also schon komplett ignoriert. Die paar Server, die noch zulässig sind, tauchen aber nicht mehr in der DNS-Auslösung mit auf. Im Endergebnis gibt es kaum noch zulässige Server, die freshclam benutzen darf und die sind extrem langsam oder funktionslos.

Nach dem Löschen der mirrors.dat fluscht der Update wieder.

Und jetzt fällt mir auch der Hinweis am Ende der freshclam Ausgabe wieder ein: Update failed. Your network may be down or none of the mirrors listed in /etc/freshclam.conf is working. Check http://www.clamav.net/doc/mirrors-faq.html for possible reasons.

Natürlich hatte ich schon am Anfang auf diesen Link geklickt. und war bei der Installationsanleitung gelandet. Jetzt habe ich mir die Mirrors-FAQ nochmal heraus gesucht und folgendes gefunden: It is also possible that you recently had a prolonged network outage and freshclam blacklisted all the mirrors: remove mirrors.dat from the DatabaseDirectory and try again.

Na prima. Könntet ihr bitte Eure Links und Eure Mirrors fixen? Danke.

In den letzten Tages ist etwas geschehen, von dem ich nicht erwartete, es überhaupt zu erleben. Entsprechend erschüttert war ich, so erschüttert, dass mich die Kinder fragten, was denn los sei. AlphaGo hatte das dritte Spiel gegen Lee Sedol gewonnen. Aber nicht der Gewinn des Spiels war mein Problem, sondern die Art und Weise: Der Mensch hat anscheinend fehlerfrei gespielt, die Maschine dagegen hat mit unerklärlichen Zügen gewonnen.

Künstliche Intelligenz

Was ist das Besondere an einer Maschine, die Go spielt?

Im Gegensatz zu vielen anderen Spielen (auch Schach), sind die Varianten des Spieles so unüberschaubar, dass man Go eher aus dem Gefühl heraus spielt, als einem logischen Weg zu folgen. Man bewertet eine komplexe, unübersichtliche Situation nach intuitiven Maßstäben und handelt aus dem Bauch heraus.

Go_board

Von Donarreiskoffer - Selbst fotografiert, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=43383

Im Go zu brillieren heißt also, über eine hervorragende Intuition zu verfügen und mit sicherem Bauchgefühl zu spielen. Das sind normalerweise nicht die Merkmale, die man einem Computerprogamm zuschreibt.

In diesem Sinne ist AlphaGo auch nicht programmiert, sondern trainiert worden. Das Programm ist so aufgebaut, dass es eine Art Gehirn nachbildet und dieses Gehirn lernt dann über eine längere Zeit anhand von Beispielen und konkreten Vorgaben.

Die Vorgaben waren bei AlphaGo der Schlüssel zum Erfolg. Man hatte dem Programm eine Art Instinkt eingesetzt, der es ihm ermöglichte die Spielzüge zu verstehen, die normalerweise nie ausgespielt werden.

Denn Go ist ein Spiel der Andeutung: Man spielt praktisch nie die Konsequenzen bis zum bitteren Ende. Die Spielstellungen bleiben halbfertig auf dem Brett, Gebiete werden nicht gesichert, Angriffe nicht zu Ende gespielt. Ohne Konsequenzen ist aber das Lernen schwierig, denn die Korrektur falschen Verhaltens fehlt.

Das ist durchaus ein Problem der klassischen Pädagogik: Man muss sich nicht die Finger an der heißen Herdplatte verbrennen, mit der Gabel in die Augen stechen, oder mit dem Fahrrad vor die Hausmauer fahren, um gefährliches Handeln zu unterlassen. Dieser Teil des Lernprozesses ist rein abstrakt, er spielt allein mit der Vorstellung möglicher Folgen.

Bisherige Modelle der künstlichen Intelligenz, d.h. nach gebauten Gehirnen, wurden trainiert, indem sie ein komplettes Handlungsbeispiel vorgesetzt bekamen und für die korrekte Handlung belohnt, für eine fehlerhafte Handlung bestraft wurden. Das simulierte Gehirn hat dann die günstigen Verbindungen bevorzugt und die ungünstigen Vernetzungen abgebaut. Ganz wie in einem menschlichen Gehirn.

Bei AlphaGo wurde das Programm mit Beispielpartien von Go-Wettkämpfen gefüttert. Um das Spiel der Andeutungen verstehen zu können, ist es aber notwendig, den angedeuteten Gedanken zu Ende führen zu können und das wurde dem Programm für eine Reihe elementarer Fälle fest einprogrammiert. Auf diese Weise konnte die Software eine völlig klare Spiel-Situation final und korrekt beurteilen. Allein aus dem Training heraus wäre das mangels zu Ende gespielter Beispielpartien nicht erlernbar gewesen.

Künstliche Intelligenz ist also eine Gehirnsimulation, die in der Lage ist, Verhalten durch Training zu erlernen.

Verstehen, was passiert

AlphaGo ist bei weitem nicht der erste Versuch, mit einer künstlichen Intelligenz zu arbeiten. Das Forschungsgebiet ist schon sehr alt. Es wird normalerweise betrieben, um zu verstehen, wie Denkprozesse ablaufen.

Ein Beispiel: Google versucht – wie viele andere Unternehmen auch – Bilder zu verstehen. Dabei geht es darum, in Worte zu fassen, was auf dem Bild dargestellt ist. Für uns Menschen eine einfache Aufgabe. Für einen Computer ein ernsthaftes Problem.

Das entsprechende Forschungsprojekt von Google zeigte prima Ergebnisse: 

dog_with_hat

Wofür man das brauchen kann, ist auch völlig logisch: Ein autonomes Fahrzeug muss seine Umgebung wahrnehmen können.

traffic_google

Das eigentlich Interessante daran, ist die Art, wie der Computer zu diesen Ergebnissen gekommen ist. Dazu wird das simulierte Gehirn genau untersucht.

Es stellte sich heraus, dass die Bilderkennung in mehreren Schichten abläuft:

  • Zuerst werden Kanten ermittelt
  • dann werden die Kantenlinien zu bestimmten Mustern gruppiert, wobei die Orientierung nicht mehr wichtig ist
  • die Muster werden zu größeren Gruppen zusammengefasst
  • und die Gruppen im Verhältnis des Gesamteindrucks (was ist alles auf dem Bild?) kategoriersiert

Witzigerweise kann man die ersten Schritte auch vernünftig visualisieren und verstärken. Dabei entstehen ästhetisch ansprechende Bilder (in einem frühen Stadium) oder verstörendende Überlagerungen (in die späteren Schritten). Gerade letztere haben dem Algorithmus den Namen DeepDream eingegeben. Es hat nämlich den Eindruck, als ob Computer träumen.

ibis

Wirklich nützlich dagegen sind die überraschenden Einsichten, was so ein Computer genau gelernt hat. Am Beispiel einer Hantel hatte die Maschine nämlich ganz andere Dinge für wichtig erachtet als der Mensch.

dumbbells

Man sieht deutlich, dass der Computer den Arm des Kraftsportlers als integralen Bestandteil der Hantel ansieht. Schließlich hat man das Programm mit hunderten Fotos aus Fitness-Studios trainiert. Und dem Computer fehlt das notwendige Verständnis, den Arm als irrelevant weg zu lassen.

Im Ganzen gesehen, ist bis hierher nichts besonders überraschend. Der Mensch hat sich Hilfsmittel gebaut, die schnell und zuverlässig eine Aufgabe erledigen. Er versteht, was dabei passiert und kann im Zweifel die Vorgänge im Einzelnen überprüfen.

Der Schreck

Schon nach den ersten Partien zwischen AlphaGo und Lee war die Überraschung groß. Denn AlphaGo spielte ungewöhnlich.

Eine Maschine, die Millionen von Partien gegen sich selbst gespielt hat, kann durchaus feststellen, welche Züge bisher nicht genügend Beachtung gefunden haben und diese einfach mal ausprobieren. Das Ergebnis ist dann ein ungewöhnlicher Spielzug, der einen menschlichen Gegner verunsichern kann. Der Mensch beurteilt die Situation dann falsch und verliert. An dieser Stelle kann man von dem Programm lernen, den menschlichen Erfahrungsschatz erweitern und die neuen Züge analysieren.

Im dritten Spiel trat aber etwas mehr als ungewöhnliches auf: Die Kommentatoren war plötzlich der Meinung, die Maschine spiele fehlerhaft, während der Mensch korrekt handle. Allerdings verlor der Mensch kurz darauf.

Das qualitativ Neue an der Situation ist, dass der Mensch nicht mehr erklären kann, was da eigentlich passiert ist. Und das macht Angst.

Eine künstliche Intelligenz, deren Entscheidungen sich unserem menschlichen Verständnis entziehen, hat etwas bedrohliches. Sie greift direkt die geistige Vormachtstellung des Menschen (in seinem eigenen Selbstverständnis) an.

Die Kommentatoren flüchten sich in emotionale Gebiete. Die Formulierung "Sie spielt wie eine Göttin" muss man sich auf der Zunge zergehen lassen. Der Kommentator hat die Maschine vermenschlicht und bewundert ihre Intelligenz. Man hört ebenfalls heraus, dass die Maschine "wusste, dass sie gewinnen werde".

Unplanbare Schritte

Völlig unabhängig davon, ob es gelingt diese Partien im Detail zu analysieren und die neuen Spielzüge zu verstehen, muss ein anderer Gesichtspunkt berücksichtigt werden.

Die Zwischenschritte, die eine künstliche Intelligenz durchschreitet, um an ihr Ziel zu kommen, sind nicht durch Training erlernt worden. Der Mensch hat der Maschine also nicht beigebracht, auf welchem Wege das Ziel zu erreichen ist. Die Maschine hat sich selbst den Weg zum Ziel überlegt.

Solange es sich um ein Brettspiel handelt, ist es unerheblich, wie eine Maschine handelt. Verlässt man aber das Spielfeld und kehrt in die reale Welt zurück, so muss man sich wirklich Gedanken machen.

Wenn eine solche künstliche Intelligenz damit beauftragt wird, autonom ein Auto zu fahren, welche Reaktionen soll sie in bestimmten, unübersichtlichen Situationen zeigen? Muss dann der Computer über Leben und Tod entscheiden? Diese Debatte läuft, aber sie behandelt den Fall immer noch unter dem Gesichtspunkt, wir könnten der Maschine an dieser Stelle Vorschriften machten. Das werden wir voraussichtlich nicht können. Weil wir die Maschinen dafür nicht mehr genau genug verstehen.

Wenn eine solche künstliche Intelligenz damit beauftragt wird, in einem Krankenhaus die Patienten zu überwachen (ja, das ist DeepMind) und zu medikamentieren, genügt uns dann eine 15% höhere Überlebenswahrscheinlichkeit als Erfolg? Oder wollen wir auch verstehen, warum bestimmte Patienten nicht durchgekommen sind? Vielleicht war deren Tod Voraussetzung für das Überleben anderer Kranker. Vielleicht deshalb, weil der Computer dort Anzeichen einer Infektionskrankheit gesehen hat, die sich im gesamten Klinikum auszubreiten drohte. Und da er über keine anderen Mittel verfügte, als die Medikamente zu dosieren, hat er diesen Zwischenstand in Kauf genommen.

Wenn eine solche künstliche Intelligenz damit beauftragt wird, die begehrten Studienplätze in Deutschland gerecht zuzuteilen, warum sollte sie nur auf den Notendurchschnitt schauen? Warum sollte sie nicht auch ein gesamtgesellschaftliches Ziel berücksichtigen und damit die jungen Leute an den Ort schicken, wo sie aus Sicht des Computers am nützlichsten sind. Oder warum sollte nicht auch in die Entscheidung einfließen, wie hoch die Wahrscheinlichkeit eines Studienabbruchs ist? Wer kann denn hinterher kontrollieren, auf welche Weise die Maschine zu dieser Auswahl gekommen ist?

Was mir also ernsthafte Bauchschmerzen bereitet, ist eine Tatsache: Die von der künstlichen Intelligenz angesteuerten Zwischenschritte unterliegen keiner ethischen Kontrolle, sondern ausschließlich der Nützlichkeit bei der Erreichung des Zieles.

Genau dieser Punkt hat die Kommentatoren des dritten Spiels von AlphaGo gegen Lee Sedol verunsichert. Während Herr Lee die Komplexität des Go-Spiels anhand langer Traditionen auf einige wenige zulässige Gassen einschränkt, kennt die Maschine keine solchen Skrupel.

die_human

Und wir erleben soeben den Punkt, an dem wir unsere eigene Schöpfung nicht mehr verstehen. Ein Punkt, den ich nicht zu erleben glaubte.

Ich habe also Asimov gelesen.

Der Bug mit fragmentieren IPSec Paketen in der ASA war ja laut genug durch die Presse gegangen. Aber nicht alle Systeme lassen sich so einfach aktualisieren.

Wo's klappt und wo nicht

Kein Problem stellen die Failover-Systeme da, die noch in der 8er Reihe verharren. Der Update des erfolgt ganz planmäßig

  • Software auf Standby-Gerät spielen
  • Standby booten
  • Failover tiggern
  • Testen, ob alles geht
  • Software auf (nun anderes) Standby-Gerät spielen
  • (anderes) Standby booten

Kunde merkt davon gar nichts. Das war machbar, sobald die neue Firmware zur Verfügung stand.

Schwieriger wurde es bei Geräten, für die keine Software mehr existiert (PIX) oder noch die neue Software nicht korrekt funktionierte (CSCuy28710).

Als Notlösung wurde dort die ACL auf der Control-Plane so gesetzt, dass UDP/500 und UDP/4500 nicht mehr schaden konnten:

object-group service ike-udp
 service-object udp destination eq isakmp
 service-object udp destination eq 4500
!
object-group network ike-peers
 network-object host b.c.d.e
!
access-list to_cpu extended permit object-group ike-udp object-group ike-peers any
access-list to_cpu extended deny object-group ike-udp any any log warnings
access-list to_cpu extended permit ip any any log warnings
!
access-group to_cpu in interface outside control-plane 

In der Object-group iks-peers stehen die bekannten Gegenstellen, die noch VPN-Tunnel aufbauen dürfen. Das skaliert natürlich nicht besonders gut für VPN-Einwahl, reicht aber für alles aus, was nur Lan2Lan-Tunnel hat. In jedem Fall nimmt es Druck aus dem Problem.

Schrittweiser Upgrade

Cisco empfiehlt bestimmte Versionenpfade einzuhalten, um automatische Übernahmen der alten Konfigurationen zu ermöglichen. Da das Ergebnis dieser Übernahmen meist zu schrecklich ist, um es so zu lassen, ziehe ich es vor, eine minimale Konfiguration zum Upgrade zu verwenden. Diese lässt auch größere Sprünge zu, solange nur die IP Konfiguration der Interfaces und der SSH Zugang erhalten bleiben.

Beim Versuch von 9.1(1) auf 9.1(7) zu springen, scheitert das an der Fehlermeldung

asa# copy /noconfirm tftp://2001:db8::67/asa917-smp-k8.bin flash:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
No Cfg structure found in downloaded image file 

Diese Meldung kommt also, bevor das Image aufs Flash geschrieben werden soll. Da er das Image nicht in den Flash legt, kann er auch nicht davon booten.

Dieses Problem ist aber wohl dokumentiert, man muss eben einen bestimmten Upgrade-Pfad einhalten.

asa# copy /noconfirm tftp://2001:db8::67/asa912-smp-k8.bin flash:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
No Cfg structure found in downloaded image file 

Was jetzt? Das ist genau das Image, das verwendet werden soll, um diesen Fehler nicht zu bekommen. Auch andere Versuche mit neueren Images führen zu keinem Erfolg: Das aktuell laufende System weigert sich, ein neues Image abzuspeichern! Der Fehler ist seit gestern auch bei Cisco bekannt: CSCuh25271

Aber Moment mal: Das aktuell laufende Image?

Was wäre denn, wenn ich das Image einfach so laden würde. Also irgendwie in die Box reinmogeln (per USB?) und dann davon booten. Das sollte doch gehen?!

Konkreter gefragt: Was wäre, wenn das aktuell laufende Image nicht da wäre? Dann würde sich auch niemand darüber aufregen, dass irgendwelche Strukturen fehlen. Oder etwa doch?

Wenn kein laufendes Image da ist, fällt man auf den ROMMON zurück. Aber den kann man beim Booten auch direkt aufrufen und dann ein Image vom TFTP laden und starten.

Gesagt getan: Es funktioniert.

Einfach so. Und dann kann man auch alle anderen Images aufs Flash installieren.

Ich habe das Problem, dass DSLAMs das DSL-Netz segmentieren, während die Layer2 Wolke es als ein durchgehendes Netz ansehen. Ein Lösungsvorschlag ist, die Layer2 Wolke zu drastisch zu verkleinern. Dies probiere ich aus.

Ausgangslage

local proxy arp1

Die DSLAMs verhindern eine direkte Kommunikation von CPEs, die an diesem einem DSLAM angeschlossen sind. Eine Firma kann also nicht mit ihren Mitarbeitern im gleichen Dorf kommunizieren, wenn diese von zu Hause arbeiten wollen.

Die kanonische Lösung mit local-proxy-arp besteht darin, dass der Router die ARP-Antworten fälscht und damit die Kommunikation wieder ermöglicht. Leider macht das massiv Probleme, wenn man Redundanz oder mehrere zentrale Geräte in das Netz bringen will.

Netzmaske verkleinern

Wie ich gelernt habe, besteht die branchenübliche Lösung darin, dem Endgerät (CPE) eine extrem kleine Netzmaske (/32) zu geben. Damit glaubt das Endgerät es sei alleine am Netz.

Aber wie erreicht es sein Gateway? Das liegt doch außerhalb des zugewiesenen Netzes? Was man bräuchte wäre folgendes:

# ip address add a.b.c.d/32 dev eth
# ip route a.b.c.e/32 dev eth
# ip route 0.0.0.0/0 via a.b.c.e

Aber wie bekommt man so etwas Krankes der CPE beigebogen? Schließlich hat sich der Kunde den Router selbst gekauft und wir haben keinen Einfluss auf die Kiste.

Alles was, wir tun können, ist eine passende DHCP Antwort schicken. Also probiere ich das mal (ganz vorsichtig)

subclass "Dynamisch" 1:00:90:33:1f:19:1a {option subnet-mask 255.255.255.255;}
subclass "Dynamisch" 1:9c:c7:a6:ba:e0:1b {option subnet-mask 255.255.255.255;}

Das sollte tun (Pools etc. sind anderweitig konfiguriert).

Und nun der Test vom Router aus:

cisco#ping 198.51.100.128

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 198.51.100.128, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 4/5/8 ms

cisco#ping  198.51.100.201

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 198.51.100.201, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 8/12/24 ms

cisco#sh arp | in 198.51.100.128|198.51.100.201
Internet  198.51.100.201          2   9cc7.a6ba.e01b  ARPA   Vlan140
Internet  198.51.100.128          2   0090.331f.191a  ARPA   Vlan140

Tada! Das tut doch schon mal. Und Tests an dem Gerät bestätigen auch die Funktionalität des Internets.

Andere Server

Nun der kompliziertere Teil. Wie kommen zentrale Geräte, die nicht das Gateway sind, mit dem Setup klar?

Probieren wir's aus:

linux# ip addr add 198.51.100.108/23 dev eth_slot
linux# ping -c2 198.51.100.201
PING 198.51.100.201 (198.51.100.201) 56(84) bytes of data.
64 bytes from 198.51.100.201: icmp_seq=1 ttl=64 time=7.01 ms
64 bytes from 198.51.100.201: icmp_seq=2 ttl=64 time=6.83 ms

--- 198.51.100.201 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 6.834/6.922/7.011/0.121 ms 

Und der Tcpdump dazu sagt:

13:36:57.930798 00:1b:21:2d:3a:bb > 9c:c7:a6:ba:e0:1b, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.201: icmp 64: echo request seq 1

13:36:57.937778 9c:c7:a6:ba:e0:1b > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.201 > 198.51.100.108: icmp 64: echo reply seq 1

13:36:58.935366 00:1b:21:2d:3a:bb > 9c:c7:a6:ba:e0:1b, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.201: icmp 64: echo request seq 2

13:36:58.942188 9c:c7:a6:ba:e0:1b > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.201 > 198.51.100.108: icmp 64: echo reply seq 2 

Geht hin und her. Die Pakete kommen direkt von der CPE (eine Fritzbox) und reden mit dem Server.

Stop mal! Warum kommen die Pakete direkt? Sollten die nicht über den Router gehen?

Offensichtlich hat die Fritzbox gelernt, dass sie dieses Gerät direkt am WAN-Bein erreichen kann und schickt auch die Pakete direkt.

Genauer gefragt: Ist das ein Problem?

Wenn zwei CPEs miteinander reden sollen, aber nicht können (DSLAM-Sperre), dann können sie gegenseitig ihre ARP-Anfragen nicht sehen und beantworten. Also werden sie nie versuchen, direkt miteinander zu kommunizieren. Also kein Problem.

Apropos ARP. Da waren keine ARP-Pakete im Tcpdump. Also nochmal mit gelöschtem ARP-Cache.

linux# arp -d 198.51.100.201
linux# ping  -c2 198.51.100.201
PING 198.51.100.201 (198.51.100.201) 56(84) bytes of data.
64 bytes from 198.51.100.201: icmp_seq=2 ttl=63 time=6.97 ms

--- 198.51.100.201 ping statistics ---
2 packets transmitted, 1 received, 50% packet loss, time 999ms
rtt min/avg/max/mdev = 6.970/6.970/6.970/0.000 ms

Und der Dump dazu:

13:46:38.389346 00:1b:21:2d:3a:bb > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
 arp who-has 198.51.100.201 tell 198.51.100.108

13:46:38.390063 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 60:
 arp reply 198.51.100.201 is-at 00:07:b4:00:8c:02

13:46:38.390073 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.201: icmp 64: echo request seq 1

13:46:38.396544 9c:c7:a6:ba:e0:1b > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 60:
 arp reply 198.51.100.201 is-at 9c:c7:a6:ba:e0:1b

13:46:39.389251 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.201: icmp 64: echo request seq 2

13:46:39.396208 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.201 > 198.51.100.108: icmp 64: echo reply seq 2

Das erste Paket ging über local-proxy-arp und wurde nicht beantwortet.

Das könnte daran liegen, dass die Fritzbox bereits einen ARP EIntrag hat, so dass sie das ankommende Paket als gespooft verwirft. Aber das bedarf noch der Klärung.

Innovaphone

Die andere Test-CPE ist eine Innovaphone.

linux# arp -d 198.51.100.128
linux# ping  -c2 198.51.100.128
PING 198.51.100.128 (198.51.100.128) 56(84) bytes of data.
64 bytes from 198.51.100.128: icmp_seq=2 ttl=127 time=5.86 ms

--- 198.51.100.128 ping statistics ---
2 packets transmitted, 1 received, 50% packet loss, time 1000ms
rtt min/avg/max/mdev = 5.860/5.860/5.860/0.000 ms

Auch das geht! Aber auch hier fehlt das erste Paket. Liegt es am proxy ARP?

13:56:05.356955 00:1b:21:2d:3a:bb > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
 arp who-has 198.51.100.128 tell 198.51.100.108

13:56:05.359382 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 60:
 arp reply 198.51.100.128 is-at 00:07:b4:00:8c:02

13:56:05.359392 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 1

13:56:05.362879 00:90:33:1f:19:1a > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 64:
 arp reply 198.51.100.128 is-at 00:90:33:1f:19:1a

13:56:06.356946 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 2

13:56:06.362793 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 2 

Diesmal erfolgt der Ping komplett über den zentrale local-proxy-arp Router.

Und noch ein Pingtest bei vorhandenem ARP-Eintrag:

linux# ping  -c2 198.51.100.128
PING 198.51.100.128 (198.51.100.128) 56(84) bytes of data.
64 bytes from 198.51.100.128: icmp_seq=1 ttl=127 time=6.02 ms
64 bytes from 198.51.100.128: icmp_seq=2 ttl=127 time=5.84 ms

--- 198.51.100.128 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 5.841/5.930/6.020/0.118 ms

Und der Dump dazu:

14:09:37.939110 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 1

14:09:37.945105 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 1

14:09:38.943687 00:1b:21:2d:3a:bb > 00:07:b4:00:8c:02, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 2

14:09:38.949516 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 2 

Die Kommunikation erfolgt komplett über den Router.

Stop mal! Warum antwortet die Innovaphone nicht auf ARP? Für einen zentralen Server heißt das, dass er auf local-proxy-arp angewiesen ist.

Aber genau diese Funktion soll doch abgeschaltet werden! Das ist genau der Zweck der Übung.

Bei einem Versuch einige Minuten später zeigt sich erstaunlicherweise ein anderes Bild

14:23:44.753899 00:1b:21:2d:3a:bb > 00:90:33:1f:19:1a, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 1

14:23:44.759817 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 1

14:23:45.757222 00:1b:21:2d:3a:bb > 00:90:33:1f:19:1a, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 2

14:23:45.762979 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 2

Die Pakete werden direkt an die Innovaphone gesendet, aber über den Router beantwortet. Das ist komplett in Ordnung!

Aber was ist da passiert? Ich lösche nochmal den ARP-Cache auf dem Linux und schnüffle mit:

14:38:22.492139 00:1b:21:2d:3a:bb > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42:
 arp who-has 198.51.100.128 tell 198.51.100.108

14:38:22.498015 00:90:33:1f:19:1a > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 64:
 arp reply 198.51.100.128 is-at 00:90:33:1f:19:1a

14:38:22.498027 00:1b:21:2d:3a:bb > 00:90:33:1f:19:1a, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 1

14:38:22.503751 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.128 > 198.51.100.108: icmp 64: echo reply seq 1

14:38:22.509747 ac:f2:c5:df:30:3f > 00:1b:21:2d:3a:bb, ethertype ARP (0x0806), length 60:
 arp reply 198.51.100.128 is-at 00:07:b4:00:8c:02

14:38:23.497404 00:1b:21:2d:3a:bb > 00:90:33:1f:19:1a, ethertype IPv4 (0x0800), length 98:
 IP 198.51.100.108 > 198.51.100.128: icmp 64: echo request seq 2

Die Innovaphone scheint sich diesmal kooperativer zu verhalten. Damit hat sie den Test auch bestanden.

Fazit

Der Ansatz scheint zu tun.

  • Ein Fritzbox als CPE tut wie erwartet. Die bedient andere Geräte im gleichen Layer2 Netzwerk direkt, sobald sie ARP-Kontakt hatte.
  • Eine Innovaphone als CPE tut völlig korrekt. Der Rückweg geht immer den konfigurierten Weg über den Router. Im Test hatte sie sich ab und zu mal zickig, aber kein prinzipelles Problem.

Beide benutzen den Router, der außerhalb ihres logischen Netzsegementes liegt, korrekt. Andere zentrale Komponenten werden ebenso behandelt.

Damit steht einer schrittweisen Einführung nichts prinzipelles im Wege.

Ich habe daheim eine Sun Ultra 5 mit Solaris. Die benutze ich als Mailserver oder graphische Firewall. Wer E-Mail lesen will, muss sich per Xming auf die Kiste verbinden und dort arbeiten. Die Kommunikation macht die Sun per UUCP mit jengate.thur.de. Klappt eigentlich ganz gut. Bis zu einem Umbau an meinem häuslichen DSL-Anschluss. Danach ging nichts mehr.

Überraschung

256px-SUN-Ultra5

Was kann eine lokale Verbindung zwischen zwei Geräten nur so kaputt machen? Gewechselt wurde nur die Konfiguration des DSL-Routers, der nun auf einer anderen Leitung mit anderen Zugangsdaten laufen sollte.

Danach bliebt das Xming in einem beruhigend grauem Fenster stehen. Der Anmeldebildschrim kam und kam nicht hoch.

xming-fail

Also Wireshark angeworfen und mit geschnüffelt.

xdmcp-fail

Wie? localhost kann kein Display öffnen? Und die Nachricht kommt von der Sun?

Die ersten Tage habe ich damit zugebracht, die Konfiguration der Sun auseinander zu nehmen. Erfolglos.

Entscheidender Hinweis

Irgendwann bin ich über den rettenden Beitrag gestolpert. Wie immer kann man sich nachträglich nicht erklären, welche Suchbegriffe man immer anders hatte, um das passende Ergebnis derartig lange zu verfehlen.

Dieser Beitrag redet ausschließlich vom reverse DNS. Und was sagt die Sun dazu?

;; QUESTION SECTION:
;111.44.168.192.in-addr.arpa.   IN      PTR

;; ANSWER SECTION:
111.44.168.192.in-addr.arpa. 429 IN     PTR     localhost.

;; Query time: 5 msec
;; SERVER: 192.168.44.254#53(192.168.44.254)

Was zur Hölle? Diese DSL-Box hatte vor der Umstellung doch korrekte Antworten geliefert!

Nach längerer vergeblicher Konfiguration an der Box, versuchte ich endlich die blöde Drecksplastik zu umgehen.

Ich grab' mir also einfach den DNS Server aus den DSL-Daten und frage direkt an:

Primärer DNS:  195.50.140.248
Sekundärer DNS:  195.50.140.246

Auf geht's!

;; QUESTION SECTION:
;111.44.168.192.in-addr.arpa.   IN      PTR

;; AUTHORITY SECTION:
168.192.in-addr.arpa.   300     IN      SOA     prisoner.iana.org. hostmaster.root-servers.org. 2002040800 1800 900 604800 604800

;; Query time: 38 msec
;; SERVER: 195.50.140.248#53(195.50.140.248)

Alles bestens! Endlich ist die Fehlerquelle ausgemacht und umgangen.

Trotzdem funktioniert es weiterhin nicht.

xming-fail

Beim genaueren Hinschauen hatte ich doch beide DNS Server in die /etc/resolv.conf eingetragen. Sollte der andere?

;; QUESTION SECTION:
;111.44.168.192.in-addr.arpa.   IN      PTR

;; ANSWER SECTION:
111.44.168.192.in-addr.arpa. 600 IN     PTR     localhost.

;; Query time: 23 msec
;; SERVER: 195.50.140.246#53(195.50.140.246)

WTF? Und diese Kiste antwortet auch noch schneller?

Dann ist es ja kein Wunder, dass die Sun sich für die schnellere Antwort entschied und so daneben lag.

Einfache Lösung

Die triviale Lösung besteht darin, einfach den korrekten Namen ins /etc/hosts zu schreiben

192.168.44.111     pc.goldberg.jena.thur.de

Trotzdem bleibt Xming beim grauen Fenster.

xming-fail

Aber der Sniffer zeigt, dass ich auf dem richtigen Weg bin:

xdmcp-pc

Das DNS hat tatsächlich Einfluss auf die Meldung!

Jetzt ist auch klar, was bisher genau passiert ist:

  • Der XDMCP-Dienst auf der Sun hat einen reverse DNS gemacht
  • und diesen Namen als Ziel für die X11-Anwendungen übergeben.
  • Die Anwendung macht eine Vorwärtsauflösung dieses Namens
  • und landet auf der falschen Maschine (dort, wo kein X-Server läuft).

Aber warum steht da nicht der volle Name?

Ganz einfach: Weil die ultra die gleiche Domain benutzt und sie aus Effizienzgründen heraus kürzt.

Korrekte Lösung

Ich könnte den Hack weiter führen und noch den Kurznamen in die /etc/hosts Datei eintragen. Das ist aber nervig und fehleranfällig.

Es soll auch einfach so gehen. Also muss ich das DNS korrekt flicken. Und das geht am einfachsten, indem man einen lokalen DNS Dienst betreibt.

Erstmal etwas vor konfigurieren und dann gleich starten:

# svcadm enable svc:/network/dns/server

Jetzt wird es spannend. Wird der Xming eine Antwort bekommen?

Zumindest der lokale DNS-Client ist zufrieden, wenn auch initial etwas langsam:

;; QUESTION SECTION:
;111.44.163.192.in-addr.arpa.   IN      PTR

;; AUTHORITY SECTION:
192.in-addr.arpa.       10800   IN      SOA     z.arin.net. dns-ops.arin.net. 2016013077 1800 900 691200 10800

;; Query time: 2045 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)

Aber nun endlich die Nagelprobe!

xdmcp-ok

Hurra! Die Kommunikation tut wieder!

xming-ok

CARP ist eine coole Lösung, wenn man mehrere Systeme hat, die sich eine IP teilen sollen. Aber von gestern zu heute war da ein Wurm drin. Ein Server hat sich geweigert, wieder seine Aufgabe als CARP-Master zu erfüllen. Ich stand kurz vor dem Reboot des Systems.

Aus und vorbei

netzplan-animiert

Beim Blick auf die Auslastung der Leitungen zeigte sich eine relativ hohe Last auf einem der Server des NAT-Clusters während eine andere Maschine es sich gemütlich machte.

Eigentlich war nichts auffällig. Der Teufel steckte offenbar im Detail.

Konnte es sein, dass sich die Balancierung des CARP verschoben hatte, so dass ein Teil der Kunden auf einen andere Maschine geleitet wurden?

Wenn ja, müsste sich das im CARP-Status der fraglichen Maschine zeigen.

# for i in 0 1 2 3; do ifconfig carp$i; done
carp0: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 1 advbase 1 advskew 200
carp1: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 2 advbase 1 advskew 100
carp2: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 3 advbase 1 advskew 133
carp3: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 100.100.0.1 netmask 0xffff8000 
        carp: BACKUP vhid 4 advbase 1 advskew 166

Ja, die Kiste hat schlicht keinen Bock mehr. Aber warum?

Ich schaue mir mal den CARP-Status aller Maschinen des Clusters in der Übersicht an.

$ for i in 1 2 3 4; do
    echo server$i;
    ssh root@server$i sysctl net.inet.carp;
    for k in 0 1 2 3; do
      ssh root@server$i ifconfig carp$k | fgrep advbas;
    done;
  done

server1
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: MASTER vhid 1 advbase 1 advskew 100
        carp: MASTER vhid 2 advbase 1 advskew 133
        carp: BACKUP vhid 3 advbase 1 advskew 166
        carp: BACKUP vhid 4 advbase 1 advskew 200
server2
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 1
        carp: BACKUP vhid 1 advbase 1 advskew 200
        carp: BACKUP vhid 2 advbase 1 advskew 100
        carp: BACKUP vhid 3 advbase 1 advskew 133
        carp: BACKUP vhid 4 advbase 1 advskew 166
server3
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 166
        carp: BACKUP vhid 2 advbase 1 advskew 200
        carp: MASTER vhid 3 advbase 1 advskew 100
        carp: BACKUP vhid 4 advbase 1 advskew 133
server4
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 1
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 133
        carp: BACKUP vhid 2 advbase 1 advskew 166
        carp: BACKUP vhid 3 advbase 1 advskew 200
        carp: MASTER vhid 4 advbase 1 advskew 100

Die virtuelle Host-ID (vhid) zwei ist falsch. Server2 ist nicht für diese vhid zuständig, obwohl er eine kleinere advskew hat.

Ebenso auffällig ist die Aussage, das dieser Server2 suppress_preempt auf einem anderen Wert stehen hat. Dieser Wert gibt an, dass der Server glaubt, er sei nicht bereit CARP aktiv zu machen. Unglücklicherweise ist der Wertread-only.

Ursachenforschung

Server2 glaubt also in einem Fehlerzustand zu sein. Aber welcher kann das sein? Und wie kann man ihn aus dem Weg räumen?

Die Man-Page war jedenfalls nicht hilfreich. Sie sagt, ein Interface müsse down sein. Aber das ist offensichtlich nicht der Fall.

Eine Suche im Sourcecode offenbart, dass dieser Fehlerzustand ausschließlich in der Datei ip_carp.c existiert und nur dort behandelt wird.

[lutz@server2 /usr/src/sys]# fgrep -lR suppress_preempt .
./netinet/ip_carp.c

Das macht es schon einmal sehr einfach.

int carp_suppress_preempt = 0;
SYSCTL_INT(_net_inet_carp, OID_AUTO, suppress_preempt, CTLFLAG_RD,
    &carp_suppress_preempt, 0, "Preemption is suppressed");

Es gibt also eine globale Variable des Kernels, deren Wert per sysctl ausgelesen werden darf. Nach dem Booten ist die 0.

static void
carpdetach(struct carp_softc *sc, int unlock)
{
...
        if (sc->sc_suppress)
                carp_suppress_preempt--;
        sc->sc_suppress = 0;

        if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS)
                carp_suppress_preempt--;
        sc->sc_sendad_errors = 0;
...

Wenn ein CARP-Interface entfernt wird, wird der globale Zähler dekrementiert, wenn dieses Interface den Sperrzustand eingeleitet hatte.

static void
carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
{
...
        sc_tv.tv_sec = sc->sc_advbase;
        if (carp_suppress_preempt && sc->sc_advskew <  240)
                sc_tv.tv_usec = 240 * 1000000 / 256;
        else
                sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256;
        ch_tv.tv_sec = ch->carp_advbase;
        ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256;
...

Bei der Verarbeitung von CARP-Nachrichten wird jede CARP-Instanz als letztmöglicher Fallback angesehen, indem maximale Werte angenommen werden.

Das ist zwar beruhigend, aber ändert nichts an dem Wert selbst.

static void
carp_send_ad_locked(struct carp_softc *sc)
{
...
                advbase = sc->sc_advbase;
                if (!carp_suppress_preempt || sc->sc_advskew > 240)
                        advskew = sc->sc_advskew;
                else
                        advskew = 240;
                tv.tv_sec = advbase;
                tv.tv_usec = advskew * 1000000 / 256;
...

Bei der Generierung von CARP-Nachrichten an andere Systeme werden maximale Werte announciert, so eine Sperre vorliegt.

Damit wissen die anderen von den Problemen dieser Maschine.

...
                if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) {
                        SC2IFP(sc)->if_oerrors++;
                        if (sc->sc_sendad_errors < INT_MAX)
                                sc->sc_sendad_errors++;
                        if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
                                carp_suppress_preempt++;
                                if (carp_suppress_preempt == 1) {
                                        CARP_SCUNLOCK(sc);
                                        carp_send_ad_all();
                                        CARP_SCLOCK(sc);
                                }
                        }
                        sc->sc_sendad_success = 0;
                } else {
                        if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
                                if (++sc->sc_sendad_success >=
                                    CARP_SENDAD_MIN_SUCCESS) {
                                        carp_suppress_preempt--;
                                        sc->sc_sendad_errors = 0;
                                }
                        } else
                                sc->sc_sendad_errors = 0;
                }
...

Jetzt wird es interessant (und der IPv6 Teil ist identisch).

Wenn beim Aussenden der CARP-Nachricht ein Fehler auftritt, zählt er die Fehler hoch. Überschreiten diese die MAX-Grenze, geht der globale Block an. Funktioniert es dann wieder MIN-mal hintereinander, wird die Sperre wieder aufgehoben. Die Instanz selbst wird nicht als geblockt markiert.

Soweit so logisch.

static void
carp_sc_state_locked(struct carp_softc *sc)
{
...
        if (sc->sc_carpdev->if_link_state != LINK_STATE_UP ||
            !(sc->sc_carpdev->if_flags & IFF_UP)) {
...
                if (!sc->sc_suppress) {
                        carp_suppress_preempt++;
                        if (carp_suppress_preempt == 1) {
                                CARP_SCUNLOCK(sc);
                                carp_send_ad_all();
                                CARP_SCLOCK(sc);
                        }
                }
                sc->sc_suppress = 1;
        } else {
                SC2IFP(sc)->if_flags |= sc->sc_flags_backup;
                carp_set_state(sc, INIT);
                carp_setrun(sc, 0);
                if (sc->sc_suppress)
                        carp_suppress_preempt--;
                sc->sc_suppress = 0;
        }
...

Und schließlich noch: Wenn das zugehörige Interface den Link-Status ändert, dann blockiere ebenfalls die zugehörige CARP Instanz.

Außerdem soll global blockiert werden, damit ein System, dass nicht mehr volle Konnektivität hat, sich nicht mehr aktiv um die Verarbeitung von Kundendaten bemüht.

Soweit auch logisch.

Mir erscheint die Stelle mit dem CARP_SCUNLOCK gefolgt von carp_send_ad_all aber wie eine Racecondition. Schließlich greift die Senderoutine auf die gleichen Werte zu und die Blockierung der betroffenen Instanz erfolgt erst danach der Aussendung.

Das klingt irgendwie unlogisch. Vermutlich habe ich es schlicht falsch verstanden. Es ist aber auch ziemlich uninteressant, weil neuere Kernel den Code komplett anders haben.

Fehlerbehebung

Herausgekommen ist, dass der globale Zähler nur dann wieder verschwindet, wenn entweder die Zähler von allein zurück gehen, oder die Interfaces gelöscht werden.

Na da bleibt nicht viel: Alle Interfaces manuell löschen und händisch neu anlegen.

Bei der Gelegenheit wurde auch der CARP-Loglevel erhöht. So bleibt ein letzter Blick:

$ for i in 1 2 3 4; do
    echo server$i;
    ssh root@server$i sysctl net.inet.carp;
    for k in 0 1 2 3; do
      ssh root@server$i ifconfig carp$k | fgrep advbas;
    done;
  done

server1
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: MASTER vhid 1 advbase 1 advskew 100
        carp: BACKUP vhid 2 advbase 1 advskew 133
        carp: BACKUP vhid 3 advbase 1 advskew 166
        carp: BACKUP vhid 4 advbase 1 advskew 200
server2
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 200
        carp: MASTER vhid 2 advbase 1 advskew 100
        carp: BACKUP vhid 3 advbase 1 advskew 133
        carp: BACKUP vhid 4 advbase 1 advskew 166
server3
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 166
        carp: BACKUP vhid 2 advbase 1 advskew 200
        carp: MASTER vhid 3 advbase 1 advskew 100
        carp: BACKUP vhid 4 advbase 1 advskew 133
server4
net.inet.carp.allow: 1
net.inet.carp.preempt: 1
net.inet.carp.log: 2
net.inet.carp.arpbalance: 1
net.inet.carp.suppress_preempt: 0
        carp: BACKUP vhid 1 advbase 1 advskew 133
        carp: BACKUP vhid 2 advbase 1 advskew 166
        carp: BACKUP vhid 3 advbase 1 advskew 200
        carp: MASTER vhid 4 advbase 1 advskew 100

Prima!