Nachdem Google mit dem Public-DNS Dienst unter 8.8.8.8 zum Standard in allen Fragen der DNS-Problembehebung geworden ist, springen nun immer mehr Firmen auf. Aktuell treibt 9.9.9.9 die Sau durch Dorf. Dabei generiert diese Idee massive Probleme, wettbewerbsrechtlich und technisch.

Wettbewerb

Zunächst gibt es eine massive Beschränkung von leicht merkbaren IP-Adressen. Der IPv4 Adressraum läßt nur 220 Adressen der Form x.x.x.x zu.

Davon benutzen schon einige die IPs für DNS Dienste:

  • 8.8.8.8 PTR google-public-dns-a.google.com.
  • 9.9.9.9 PTR dns.quad9.net.
  • 75.75.75.75 PTR cdns01.comcast.net.
  • 79.79.79.79 PTR public-dns-a.as9105.net.
  • 99.99.99.99 PTR dnsr4.sbcglobal.net.
  • 108.108.108.108 PTR 108-108-108-108.pools.spcsdns.net.
  • 114.114.114.114 PTR public1.114dns.com.

Einige benutzen die IPs für ihre eigenen Nameserver:

  • 77.77.77.77 PTR ns3.hiweb.ir.
  • 93.93.93.93 PTR ns.ngenix.net.
  • 199.199.199.199 PTR NS1.Shane.co.
  • 208.208.208.208 PTR ns1648.ztomy.com.

Andere haben eigene Ideen:

  • 16.16.16.16 PTR ldtools.gre.hp.com.
  • 23.23.23.23 PTR select.zone.
  • 76.76.76.76 PTR lo0-rtc-svw.nco.riseb.net.
  • 145.145.145.145 PTR Multicast-RendezvousPoint.surf.net.
  • 192.192.192.192 PTR medmgmt-192.tajen.edu.tw.

Der Rest macht sich gar keine Gedanken und gibt die IPs an Kunden raus. 69 davon haben einen entsprechenden Reverse-DNS Eintrag.

Nehmen wir einfach mal an, es liese sich mit diesen Adressen ein DNS-Geschäft machen. Dann kommt die Frage auf, ob diese extrem knappe Ressource gerecht verteilt ist und zukünftige Marktteilnehmer mit ihren innovativen Idee auch die Chance auf Teilnahme bekommen können.

Die Antwort der zuständigen (nationalen) Wettbewerbsbehörde liegt auf der Hand: Natürlich nicht.

Damit bedürfen diese Adressen der Regulierung bzw. der Versteigerung wie bei Funkfrequenzen.

Eigenbedarf

Die offenkundigste Schlussfolgerung des Theaters um 9.9.9.9 ist, selbst weiter zu machen. Ich habe kurzerhand die IP 10.10.10.10 als DNS-Anycast konfiguriert und in Betrieb genommen.

$ dig AAAA lutz.donnerhacke.de @10.10.10.10 +dnssec +multiline
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 727
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 3, ADDITIONAL: 1

;; ANSWER SECTION:
lutz.donnerhacke.de.    CNAME   pro.donnerhacke.de.
lutz.donnerhacke.de.    RRSIG   CNAME 5 3 57600 ...
pro.donnerhacke.de.     AAAA    2001:4bd8:1:1:209:6bff:fe49:79ea
pro.donnerhacke.de.     RRSIG   AAAA 5 3 57600 ...

;; AUTHORITY SECTION:
donnerhacke.de.         NS      avalon.iks-jena.de.
donnerhacke.de.         NS      broceliande.iks-jena.de.
donnerhacke.de.         RRSIG   NS 5 2 57600 ...

;; Query time: 11 msec
;; SERVER: 10.10.10.10#53(10.10.10.10)
;; WHEN: Fri Nov 17 21:04:34 CET 2017
;; MSG SIZE  rcvd: 672

Die Antwort kommt mit dem AD-Flag, das eine erfolgreich mit DNSSEC validierte Auskunft bekundet. Damit ist schon mal Sicherheit abgehakt.

Da 10.0.0.0/8 ein privater IP-Bereich ist, der nicht öffentlich erreicht werden kann, ist ausgeschlossen, dass der Kunde einen Nameserver irgendwo im Internet befragt. Stattdessen befragt er einen nächstgelegenen Server im Zuständigkeitsbereich seines ISP. Er hat damit die Gewährleistung, dass niemand die IP per Routingtricks im Internet entführt hat. In Konsequenz hat er damit sichergestellt ausschließlich mit seinem Vertragspartner zu kommunizieren und diesen haftbar machen zu können.

Die Verwendung eines lokalen Servers gestattet dem DNS Betreiber, auf die Weitergabe von Kundeninformationen zu verzichten. Ein angenehmer Nebeneffekt davon ist, dass alle Antworten für alle Anfragenden passen und somit effektiv gecached werden können. Zusammen mit der kurzen Laufzeit zwischen Server und Kunde kann so eine DNS Anfrage deutlich schneller beantwortet werden.

Da auf diese Weise die lokal günstig erreichbaren CDNs bevorzugt werden, wir das Surferlebnis insgesamt fluffiger. Regionale Datenquellen entlasten auch die Außenleitungen des ISP und erlauben so auch anderen Nutzern ein besseres Internet.

Was noch zu tun ist, ist der Hotline beizubringen, bei DNS Problemen nicht mehr auf die 8.8.8.8 zu verweisen, sondern stattdessen die 10.10.10.10 zu empfehlen. Das wird Zeit brauchen. Ebenso wird es dauern, bis die Techniker vor Ort nicht beim ersten Problem die DNS Einstellungen verändern, und wenn, dann auch die 10.10.10.10.

Es ist abzusehen, dass Kunden die 10er IPs auch intern verwenden. Für diese Kunden wird es dann die 100.100.100.100 geben. Ich bin ja nicht so.

Und wenn Du kein Kunde von uns bist? Dann tritt Deinen ISP, dass er auch einen solchen Service aufbaut! Es wäre Best Current Practice, diese IPs überall mit den o.g. Garantien erreichen zu können.

Das FreeBSD Handbuch für Portierungen ist eigentlich ziemlich klar. Allerdings funktionieren die Aktionen nur als root. Entwickeln mit solchen Rechnten mag ich nicht. Im IRC und den Mailinglisten heißt es, das sei halt so. Man könne ja mit pourdriere testen. Allerdings benötigt das ebenfalls root-Rechte.

Folgt man dem Handbuch, so ist das alles sehr einfach: Directory anlegen, Makefile schreiben und pkg-descr ausfüllen.

Der nächste Schritt ist das Herunterladen der Quellen. Schon da hatte ich erste Probleme, denn eigentlich wollte ich die Software nicht nochmal separat veröffentlichen. Aber die Idee des Ports ist halt, dass es um die Einbindung von Fremdsoftware geht. Und die liegt halt an anderer Stelle. Also lege ich eine extra Veröffentlichung an.

Damit der Port weiß, dass er die richtigen Dateien läd, werden Prüfsummen erstellt.

$ make makesum
=> parpd-1.1.tgz doesn't seem to exist in /usr/ports/distfiles/.
=> /usr/ports/distfiles/ is not writable by you; cannot fetch.
*** Error code 1

Logisch. Ich bin ja nicht root auf dem System. Und in das Standardverzeichnis darf ich nicht schreiben. Was nun?

In /usr/ports/Mk/bsd.port.mk steht:

# DISTDIR               - Where to search for and store copies of original sources
#                                 Default: ${PORTSDIR}/distfiles

Das kann ich ja umstellen, vielleicht geht's dann?

$ export DISTDIR=/tmp/myport
$ make makesum
=> parpd-1.1.tgz doesn't seem to exist in /tmp/myport/.
=> Attempting to fetch ftp://ftp.iks-jena.de/pub/mitarb/lutz/parpd/parpd-1.1.tgz
parpd-1.1.tgz                                 100% of   16 kB   10 MBps 00m00s
$ cat distinfo
TIMESTAMP = 1510327772
SHA256 (parpd-1.1.tgz) = 95318905767c1123eab87efa4fa664a57e5ed8f697802c6b7d5d0799ad8ea6e6
SIZE (parpd-1.1.tgz) = 17197

Na also! Geht doch.

Alle weiteren Schritte funktionieren dann als Nutzer ohne weitere Probleme.

Nunja, ein Problem gibt es doch noch. Hat man nämlich DEVELOPER=yes in dem make Optionen gesetzt, so erscheint bei jeden Aufruf von make

/!\ parpd-1.1: Makefile warnings, please consider fixing /!\

Not validating first entry in CATEGORIES due to being outside of PORTSDIR.
Please ensure this is proper when committing.

Ist ja auch klar. Natürlich bin ich als normaler Nutzer nicht im originalen PORTSDIR tätig. Die Meldung kann man getrost ignorieren.

Kaputtes xDSL ist ein nervendes Problem hier. Wir haben die Schmerzen gemildert, indem wir die Netzmasken verkleinerten. Während der letzten Monate verschärfte sish die Situation wieder, weil rigide Filter auf den DSLAM ausgerollt wurden und Geräte hinzu kamen, die nicht in der Lage waren mit den kleinen Netzmasken umzugehen. Wir hatten das Problem grundsätzlich zu lösen.

Problem

Große Netzwerke haben eine große Anzahl an sichtbaren MAC Adressen. Einige Geräte (z.B. DSLAMs) verhalten sich seltsam, wenn sie zuviele MACs zu sehen bekommen. Deshalb versuchen die Netzwerkbetreiber ihre Netze zu segmentieren, so dass keine Frames mehr von einer entfernten, kleinen Lokation zu eienr anderen gelangen können. Die Blockade von Quertraffic zuwischen Kunden heißt split-horizon. Kunden in verschiedenen Teilen des Netzwerkes können dabei nicht mehr miteinander kommunizieren.

local proxy arp1

Große Netzwerke sind schwer zu betreiben. Deswegen wird möglichst nahe am Endkunden, also am DSLAM gefiltert. Diese "Fist-Hop-Security" Filter sind nur für einfache Anwendungsfälle gedacht und neigen dazu Pakete in nicht-standard-Situationen zu verwerfen. Man kann dann diese Filter nur abschalten oder damit leben.

Meistens lesen diese Geräte die DHCP-Kommunikation mit und passen danach ihre Filter an. Nutzer mit statischen IP Adressen machen aber oft gar kein DHCP, so dass diese Filter nicht zu lernen haben. Andere Nutzer haben mehr als ein Endgerät oder ganze Netzbereiche zugeteilt bekommen. In all dieses Fällen versagen die DLSAM-Filter.

Eine weitere Sicherheitsmaßnahme besteht darin, den Broadcast-Verkehr zu unterbinden, so er nicht dazu dient, die MAC Adresse zur dem Filter bekannten IP zu ermitteln. Die Idee hinter diesem Filter ist, dass jeder, der die MAC Adresse des Endgeräts kennt, dann automatisch berechtigt ist, mit diesem zu kommunizieren. Es genügt also, die Broadcasts von Endkunden zu Endkunden zu blockieren, um effektiv nur noch erlaubte Kommunikation zu haben.

Setzt man DHCP-Sniffing, Broadcast-Filter und Split-Horizon zusammen ein, erhält man ein typisches xDSL-Netzwerk, in dem die Nutzer nur mit dem zentralen Router reden können. Sämtliche darüber hinaus gehende Kommunikation ist nicht möglich.

Einfache Lösung

Gibt es nur einen einzelnen Router im Netz, so genügt es dort local-proxy-arp anzuschalten: Jede ARP-Anfrage (eines Endgeräts) wird vom Router mit der MAC-Adresse des Router-Interfaces beantwortet. Auf diese Weise können die Kunden im Umweg über den Router miteinander reden (hair pinning).

local proxy arp3

Da der Router die MAC-Adresse des Endgeräts schon bei der ARP-Anfrage dieses Geräts nach seinem Default-Router lernt, muss der Router oft gar nicht selbst ARP-Anfragen per Broadcast stellen. Einige Routermodelle erneuern die auslaufenden Cache Einträge per Unicast-Anfrage, die von den DSLAM-Filtern durchgelassen werden. Auf diese Weise kann man ein solches Netz ohne merkbare Störungen betreiben.

Gibt es allerdings mehrere Router oder Server an zentraler Stelle,. so wird es kompliziert. Local-proxy-arp kann nun nicht mehr eingesetzt werden, da die Router sonst sich gegenseitig die ARP-Anfragen beantworteten und anschließend die Pakete im Kreis laufen.

Andererseits bekommen DHCP-Server Probleme, weil sie auf den ARP-Test "Ist die IP noch frei?" Fake-Antworten vom Router bekommen. Local-proxy-arp stört alle Arten dieser Anwendungen erheblich.

Anderer Ansatz

Um unser Netz hier trotzdem am Laufen zu halten, stellt eine neue Software (parpd) die notwendigen ARP-Antworten. In Abhängigkeit von frei konfigurierbaren Regeln antwortet der Daemon auf ARP-Anfragen mit einer passenden Antwort. Dies kann die reale MAC des Endgeräts sein oder auch die MAC-Adresse eines Routers (redirect).

Die Software lernt durch passives Zuhören die realen MAC-IP Paare. Selbstverständlich ignoriert sie dabei Antworten von anderen Instanzen, beschränkt sich also auf die originalen Quellen. parpd erneuert auslaufende ARP Cache-Einträge mit Unicast-Anfragen. Nur um die Redirect-MAC zu ermitteln, darf sie auf Broadcast zurück greifen.

Antworten können aber auch verzögert werden, d.h. die ersten Anfragen eines Gerätes nach einer bestimmten IP werden innerhalb einer gewissen Zeit ignoriert. Auf diese Weise kann ein DHCP-Server seine Überprüfungen vornehmen, bekommt aber dann doch eine Antwort, wenn er auf direkter Kommunikation besteht.

Die frei konfigurierbaren Regeln gestatten die Anpassung an komplexere Aufbauten, z.B. überlappenden Netzen.

Beispiel

Wie sieht das in der Praxis aus? So:

cache
 timeout       302     # seconds
 tablesize     3499    # expecting about 10000 entries
 refresh       3*5     # 3 retries a 5 seconds each
 delay         4*3     # respond at 4th retry in 3 seconds
end

interface em0
 timeout       1.011
 # do not respond for queries to our own infrastructure
 rule          0.0.0.0/0        198.51.100.0/29    ignore
 # delay queries from the DHCP server
 rule          198.51.100.4/32  198.51.100.0/24    delay tell
 # help the routers/servers to reach the clients
 rule          198.51.100.0/29  198.51.100.0/24    tell
 # interclient communication through hairpinning at the default gateway
 rule          198.51.100.0/24  198.51.100.0/24    198.51.100.1
 # help erroneous clients arping for everything
 rule          198.51.100.0/24  0.0.0.0/0          verbose 198.51.100.1
 # multihomed server with weak host model
 rule          192.0.2.0/24     198.51.100.0/24    tell
 # show missing entries
 rule          0.0.0.0/0        0.0.0.0/0          verbose ignore
end

Seit Wochen nervt eine bestimmte Kiste mit Bind, dass die Hints für den Startup von der Realität abweicht. Und erstaunlicherweise hat sie recht.

Das Problem

Oct  2 17:07:27 named[1117]: checkhints: b.root-servers.net/AAAA (2001:500:200::b) extra record in hints
Oct  2 17:07:39 named[1117]: checkhints: b.root-servers.net/AAAA (2001:500:84::b) missing from hints
Oct  2 17:07:39 named[1117]: checkhints: b.root-servers.net/AAAA (2001:500:200::b) extra record in hints
Oct  2 17:08:17 named[1117]: checkhints: b.root-servers.net/AAAA (2001:500:84::b) missing from hints
Oct  2 17:08:17 named[1117]: checkhints: b.root-servers.net/AAAA (2001:500:200::b) extra record in hints

Ich kann den Cache löschen, aber das Problem kommt einige Tage später wieder.

Auch die originale Quelle der Hint-Files bestätigt, dass ich nichts falsch konfiguriert habe.

Der Fehler

Wie immer bei DNS-Problemen schaut man bei DNSviz nach.

b.root-servers.net-2017-10-02-15_17_03-UTC

Alles OK? Nein, da ist doch ein kleines Warndreieck!

2017-10-02-172109_238x422_scrot

Das ist exakt die Beschreibung meines Problems: Es gibt im Internet noch Einträge, die die alte, fehlerhafte IP enthalten.

Die Ankündigung passt auch prima zu dem ersten Auftreten des Problems:

As previously announced, B-Root’s IPv6 addresswas renumbered
to 2001:500:200::b, effective 2017-06-01.
(Or IPv6 address previously was 2001:500:84::b; we will continue to
operate service onthe old address for at least 6 months.)

Problem solved?

Die Lösung

Natürlich ist das Problem nicht gelöst. Es muss jemand benachrichtigt werden, der das Problem fixed. Aber wer?

$ dig ns net +short | while read a; do
   echo -n "$a ";
   dig +nottl +nocl aaaa b.root-servers.net @$a |
     egrep -i '^b.root-servers.net.*AAAA';
 done | sort

a.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
b.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
c.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
d.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
e.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
f.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
g.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
h.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
i.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
j.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
k.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
l.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b
m.gtld-servers.net. b.root-servers.net. AAAA    2001:500:84::b

Also alle. Die gesamte Delegation von NET ist kaputt.

Verantwortlich für .net ist Versign. Und die verweisen für die Delegierung auf Verisign (im Auftrag IANA). (Ja, das hatte ich anfangs falsch.)

Domain Name: ROOT-SERVERS.NET
Registry Domain ID: 2751247_DOMAIN_NET-VRSN
Registrar WHOIS Server: whois.networksolutions.com
Registrar URL: http://www.networksolutions.com
Updated Date: 2017-03-05T17:07:51Z
Creation Date: 1995-07-04T04:00:00Z
Registrar Registration Expiration Date: 2020-07-03T04:00:00Z
Registrar: NETWORK SOLUTIONS, LLC.
Registrar IANA ID: 2
Registrar Abuse Contact Email: abuse@web.com
Registrar Abuse Contact Phone: +1.8003337680
Reseller: 
Domain Status: 
Registry Registrant ID: 
Registrant Name: VERISIGN INC.
Registrant Organization: VERISIGN INC.
Registrant Street: 12061 BLUEMONT WAY
Registrant City: RESTON
Registrant State/Province: VA
Registrant Postal Code: 20190-5684
Registrant Country: US
Registrant Phone: +1.7039481212
Registrant Phone Ext: 
Registrant Fax: +1.7039483670
Registrant Fax Ext: 
Registrant Email: noc@verisign.com
Registry Admin ID: 
Admin Name: IANA Root Management, ICANN
Admin Organization: ICANN
Admin Street: 12025 Waterfront Drive #300
Admin City: Los Angeles
Admin State/Province: CA
Admin Postal Code: 90094
Admin Country: US
Admin Phone: +1.13103015800
Admin Phone Ext: 
Admin Fax: +1.13108238649
Admin Fax Ext: 
Admin Email: kim.davies@icann.org

Also schreibe ich die beide mal an.

Beim Erstellen eines Programms, das Daten aus einem Puffer kratzt, stolperte ich über einen sehr seltsamen Fehler in C. Es kostet mich ernstlich Mühe, das Problem auch nur zu verstehen.

Das Programm

Zuerst habe ich das Problem eingedampft auf ein minimales Beispiel:

#include <stdio.h>

int main(void) {
   int len, step;
   char data[5];

   for(len = 27; sizeof(data) < len; len -= step) {
      step = sizeof(data) + 2; 
      printf("len = %3d, taking %d away.\n", len, step);
   }
}

Was tut das Programm?

  • Es gibt einen Puffer mit einer initialen Länge von 27 Byte.
  • Passt die Struktur nicht mehr in den Restpuffer, brich ab.
  • Solange die gesuchte Struktur aber noch rein passt, verarbeite sie (fehlt im Beispiel).
  • Nach der Verarbeitung verkleinere die Rest-Datenmenge um die verarbeitete Struktur plus ein passendes Alignment (hier fest 2).

Der benutzte Puffer, das Verschieben des Arbeitszeigers und die eigentliche Datenverarbeitung sind in dem Beispiel entfallen.

Überraschung

Und hier die Ausgabe:

len =  27, taking 7 away.
len =  20, taking 7 away.
len =  13, taking 7 away.
len =   6, taking 7 away.
len =  -1, taking 7 away.
len =  -8, taking 7 away.
len = -15, taking 7 away.
len = -22, taking 7 away.
len = -29, taking 7 away.
len = -36, taking 7 away.

Wow! Warum beendet sich das Programm denn nicht?

Die Größe der Struktur ist "5". Das ist ganz bestimmt nicht kleiner als "-1", oder etwa doch?

Ganz offensichtlich ist der Vergleich "5" ist kleiner als  "-1" wahr, aber warum?

Evtl. hab' ich ja irgendwelche Warnungen des Compilers übersehen?

$ cc -O2 -Wall -o t t.c
[ ... nichts ... ]
$ cc --version
FreeBSD clang version 3.9.1 (tags/RELEASE_391/final 289601) (based on LLVM 3.9.1)
Target: x86_64-unknown-freebsd11.0
Thread model: posix
InstalledDir: /usr/bin

Nein, auch nicht.

Erklärung

Wenn der C-Compiler den Wert des "signed int" mit dem Namen "len" in einen "unsigned int" verwandeln würde, dann wäre das Ergebnis erklärt. Der Vergleichwert wäre dann also bei mehr als 4 Mrd., also deutlich größer als die Länge der Struktur.

Aber warum sollt der Compiler eine solche Umwandlung durchführen?

Es bleibt nur ein Blick in die Norm:

  • In 6.5.8 "Relational operators" heißt es: If both of the operands have arithmetic type, the usual arithmetic conversions are performed.
  • In 6.3.1.8 "Usual arithmetic conversions" heißt es: If the operand that has unsigned integer type has  rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with  unsigned integer type.
  • In 6.3.1.1 "Boolean, characters, and integers" heißt es: The rank of any unsigned integer type  shall equal the rank of the corresponding signed integer type.

Für den Vergleich zwischen zwei normalen Integer-Typen – der eine mit, der andere ohne Vorzeichen – gilt also, dass beide Operatoren nach unsigned konvertiert werden: In diesem Fall also von -1 auf 4 Mrd.

Voraussetzung für diese Interpretation ist allerdings, dass der sizeof-Operator einen vorzeichenlosen Integer-Typ liefert. Also wieder die Norm lesen:

  • In 6.5.3.4 "The sizeof operator" heißt es: The result is an integer constant. Huch? Keine Aussage zu Vorzeichen?
  • Etwas später liest man: The value of the result is implementation-defined, and its type (an unsigned integer type) is size_t.

Man müsste also das Spiel gewinnen, wenn man die Variable "len" einen größeren Rank verpasst. Leider klappt das weder mit "long" noch mit "long long".

Erst eine beherzter Cast des sizeof-Operators nach "int" löst das Problem:

#include <stdio.h>

int main(void) {
   int len, step;
   char data[5];
   
   for(len = 27; (int)sizeof(data) < len; len -= step) {
      step = sizeof(data) + 2; 
      printf("len = %3d, taking %d away.\n", len, step);
   }
}

Und das ergibt:

len =  27, taking 7 away.
len =  20, taking 7 away.
len =  13, taking 7 away.
len =   6, taking 7 away.

Ende der Geschichte.

Wer mag, kann mal herausbekommen, ob der Umgang des Compilers im Falle von "long" und "long long" standardkonform ist. Ich habe da meine Zweifel.

Heute Nachmittag zeigte eine Kundenmaschine einen spontanen Anstieg der Auslastung. Auf den ersten Blick sah es so aus, dass einfach viel los war, Es gab so viele Anfragen auf die Webseite, dass die Limits erreicht wurden. Diese Grenzen verhindern, dass die Maschine unbenutzbar langsam wird. Dann meldete sich der Kunde und erklärte die Hintergründe.

Lastanstieg

httpd-anfragen

Ein wunderbarer Anstieg an Anfragen zu einem bestimmten Zeitpunkt. Es klingt dann exponentiell ab.

httpd-prozesse

Und er reißt das Limit der kleinen Maschine.

Mehr Prozesse zu starten, würde nur die Bearbeitung der anderen Prozesse noch weiter verlangsamen. Der dadurch entstehende Rückstau aus Datenbank, Platte etc. verschlimmert das Problem nur.

Wenn die Kiste voll beschäftigt ist, nimmt sie keine weiteren Anfragen an. Also meldet sich der Kunde.

Erklärung

Die Webseite sei jetzt genau ganz wichtig, weil man doch einen Projekttag machen würde. Und dazu habe man an sehr viele Schulen in den letzten Wochen Informationen gegeben. Da die Plätze pro Veranstaltung beschränkt sind, habe man sich eine zentrale Anmeldung eingerichtet.

Die Anmeldewebseite sieht so aus:

2017-09-14-190938_777x202_scrot

Wir hatten also eine Menge Schüler, die in einer Menge Schulen darauf warteten, zu einem festen Zeitpunkt auf eine Webseite zu klicken, deren Inhalt aus einer Datenbank generiert wird und dabei komplett fair ACID-Prinzipen ausführen will.

Kurz: Der Kunde hat einen distributed Denial of Service Angriff bestellt und bekommen.

Ich hatte heute ein längeres Gespräch mit einer Journalistin, die fragen zur DDR-Top-level-domain ".dd" hatte. Das Gespräch war lang. Allerdings stellte sich schnell heraus, dass sie zu jung ist, um sich die Realität von vor 30 Jahren vorstellen zu können.

Probleme beim Telefonat

Zuerst kam es zu einem Verständnisproblem der gesellschaftlichen Situation. Sie konnte sich nicht vorstellen, dass man nicht einfach mal in den USA bei Jon Postel anruft, um eine Länderdomain zu registrieren.

Insbesondere gelang es mir nicht, ihr begreiflich zu machen, welche politische Dimension diese Anfrage hat. Ein Mitarbeiter an einer Universität kann nicht im Namen des gesamten Landes sprechen und handeln.

Wesentlich schwerwiegender waren allerdings die inzwischen eingefahrenen Gedankenwege der "Digital Natives". Sie können es sich schlicht nicht vorstellen, ohne Internet und Smartphone zu agieren.

Eine der Fragen war, ob ich ein spontanes Foto hätte, wie ich in der Uni an einem Rechner (es war damals PC-10) sitze. Ganz abgesehen davon, ob diese Aufnahme auf Papier/Film vorliegen könnte, zeigt es das Selbstverständnis eines "Ich dokumentiere mein Leben mit Selfies"-Typs.

Erklärungen im Nachgang

Kurz danach kam eine Liste von Fragen, die es wert sind, halbwegs ernsthaft beantwortet zu werden. Es sind Fragen, die aus der Sicht meiner Kinder gestellt werden könnten. Deswegen veröffentliche ich hier meine Antworten.

Andererseits kann man schon die Frage stellen, ob nicht jemand, der das beruflich macht, mehr vom Telefonat hätte mitnehmen können. Vielleicht sind die Fragen aber auch nur zur Einholung von Zitaten erneut gestellt und pointiert überhöht. Möglicherweise habe ich auch nicht sauber genug erklärt.

Gab es in der DDR bei diesen „internetähnlichen“ Kommunikation auch Dienste, die mit heutiger „GOOGLE“ Suchmaschine zu vergleichen sind? Wenn ja, erklären Sie mir wie und wer dieses Verfahren genutzt hat.

Ja, es gab (und gibt) an den Bibliotheken der Städte, Universitäten und Firmen die Möglichkeit der Katalogrecherche (https://de.wikipedia.org/wiki/Bibliothekskatalog). War die gewünschte Information nicht lokal in der Bibliothek vorrätig, so bediente man sich der Fernleihe (https://de.wikipedia.org/wiki/Fernleihe).

Benennen Sie die drei wichtigsten Gründe, warum die DDR nicht ins World Wide Web gestartet ist und erklären Sie warum.

Der allerwichtigste Grund warum die DDR nicht ins WWW gestartet ist, ist die historische Kausalität. Die DDR ist untergegangen (1990 siehe https://de.wikipedia.org/wiki/Wende_und_friedliche_Revolution_in_der_DDR), bevor das WWW erfunden wurde (1991 siehe https://de.wikipedia.org/wiki/World_Wide_Web). Lediglich die rechtzeitige Erfindung einer Zeitmaschine (https://de.wikipedia.org/wiki/Zeitmaschine) hätte der DDR das WWW bringen können. Dazu ist es aber bis jetzt nicht gekommen.
Der zweite Grund ist, dass für den Betrieb eines Servers (https://de.wikipedia.org/wiki/Server) am Internet eine Standleitung (https://de.wikipedia.org/wiki/Standleitung) benötigt wird, die zu einem anderen Knoten des Internets reicht. Zu dem damaligen Zeitpunkt waren Leitungen (insbesondere Weitverkehrsleitungen) ein sehr rares Gut. Das dauerhafte Belegen einer Telefonwählleitung wurde (und wird) als Fehler behandelt und die Verbindung amtsseitig getrennt. Eine grenzüberschreitende Leitung ins NSW (https://de.wikipedia.org/wiki/Nichtsozialistisches_Wirtschaftsgebiet) stellte eine unüberwindliche politische Hürde da.
Der dritte Grund ist, dass zu dem Zeitpunkt das Internet (https://de.wikipedia.org/wiki/Internet#Ab_1989_Kommerzialisierung_und_das_WWW) als nicht relevant eingestuft wurde. Stattdessen beschäftigten sich die an Netzwerken interessierten Personen mit OSI (https://de.wikipedia.org/wiki/OSI-Modell), i.d.R. also mit X.25 Netzwerken (https://de.wikipedia.org/wiki/X.25). Wer sich mit Internet beschäftigte, war ein akademischer Außenseiter.
Bonus-Info: Zu den ersten deutschen Webseiten *nach der Wende* gehört das Sekteninformationssystem Religio (http://www.religio.de/) aus Thüringen, dass ab 1992 startete.

Beschreiben Sie mir wie sich das  „Surfen“ in Alltag der DDR gestaltete? Was hat man dafür gebraucht und wie funktionierte es. (Sie haben bereits erwähnt, es gab Bastler, die diese Technik zuhause ausgetestet haben).

Da das "Surfen" in der angefragten Zeit noch gar nicht möglich war (mangels WWW), benutzte man andere Formen der elektronischen Kommunikation. Die einzige nennenswerte Verbreitung hatten die Mailbox-Netze (https://de.wikipedia.org/wiki/Mailbox_(Computer)) die nur kurze Telefonverbindungen benötigten. Der Betreiber einer Mailbox musste den Familien-Telefonanschluss (wenn der überhaupt vorhanden war) zweckentfremden. Es war also während der Kommunikation eines Mailboxnutzers oder der Mailbox selbst nicht möglich, das Telefon zu benutzen. Auch musste die Familie lernen, mit dem kurzen Anklingeln durch andere Rechner klar zu kommen. So durfte man nicht sofort ans Telefon gehen, sondern erst, wenn das Klingeln nicht aufhörte.
Daneben gab es erste Internet-Experimente von Enthusiasten in einzelnen Laboren einzelner Universitäten. Dabei wurde höchstens eine Handvoll Rechner lokal zusammen geschaltet. Diese Netze verließen den Laborraum praktisch nicht.

Gibt es offizielle Zahlen, wie viele Bürger damals das „interne“ Internet genutzt haben?

Mangels Internet gab es gar keine Nutzer.

Welche Reaktionen und Folgen hätte das Internet in der DDR, wenn die Domain offiziell genehmigt worden wäre und die Bürger hätten auch „außerhalb“ kommunizieren können?

Die Existenz der Top-Level-Domain ".dd" (https://de.wikipedia.org/wiki/.dd) ist allein durch den reservierten Eintrag in der internationalen Liste der offiziellen Abkürzungen von Ländernamen (https://de.wikipedia.org/wiki/ISO-3166-1-Kodierliste) gerechtfertigt. Die bei einzelnen Experimenten an einzelnen Universitäten benötigten Namen wurden von den Beteiligten durchaus mit dem kanonischen Namen "kiste.uni-xxx.dd" benutzt. Eine über solche Testaufbauten hinaus gehende Verwendung ist nicht bekannt.
Aus der Geschichte der Mailboxnetze vor allem im Zusammenhang mit den Friedensbibliotheken im Vorfeld der Wende zeigt, dass eine aktive Kommunikation aus kleinen Gruppen große Bewegungen machen kann.
Die Kommunikation der DDR-Bürger mit dem Ausland entsprach durchaus den damals üblichen Standards: Es wurden Briefe geschrieben, telefoniert und sich getroffen. Alles natürlich im Rahmen der geltenden Möglichkeiten.

Ein Kunde hat nach einem Umbau am Außenanschluss massive Probleme mit der Stabilität der IPv6 Versorgung. Nach nächtlicher Inaktivität ist am folgenden Morgen keine IPv6 Kommunikation möglich. Beginnt man auf der ASA zu debuggen, verschwindet das Problem sofort.

Heisenbergsches Nichts

Zunächst stellt sich die Frage, was denn so spannendes in der Nacht passiert sein kann. Eigentlich nichts.

Genau das ist das Problem. Es ist nichts passiert. Genau deswegen geht es nicht mehr. Zur Überprüfung lösche ich den IPv6 Nachbarschafts-Cache und das Problem tritt sofort wieder auf. Der IPv6 Nachbarschaftseintrag für das default Gateway will und will nicht wieder kommen.

Pingt man von der ASA aus ein externes Ziel an, verschwindet das Problem instantan. Auch der IPv6 Nachbarschaftseintrag ist wieder vorhanden.

Das Problem kann also kontrolliert ein- und ausgeschaltet werden. Damit ist der Heisenbug in einen Bohrbug verwandelt und die Suche kann beginnen.

Gestörte Nachbarschaft

Zuerst aktiviere ich das Debugging für IPv6 Nachbarschaftskram.

asa# debug ipv6 nd
asa# debug ipv6 icmp
asa# clear ipv6 neighbors
ICMPv6-ND: DELETE -> INCMP: 2001:db8:700:1d::1
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: INCMP deleted: 2001:db8:700:1d::1
ICMPv6-ND: INCMP -> DELETE: 2001:db8:700:1d::1
ICMPv6-ND: DELETE -> INCMP: 2001:db8:700:1d::1
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: INCMP deleted: 2001:db8:700:1d::1
ICMPv6-ND: INCMP -> DELETE: 2001:db8:700:1d::1
ICMPv6-ND: DELETE -> INCMP: 2001:db8:700:1d::1

Das Spiel wiederholt sich endlos.

Die ASA benötigt den Nachbarschaftseintrag des Default Gatways, der gerade fehlt (DELETE), und versucht dann per Neighbour Solication (NS) wieder die MAC zur IP zu ermitteln (INCoMPlete).

Allerdings bekommt sie keine Antwort zurück.

Also jetzt mal von der ASA aus pingen:

asa# ping 2001:db8::1
ICMPv6: Sending echo request to 2001:db8::1
ICMPv6-ND: INCMP deleted: 2001:db8:700:1d::1
ICMPv6-ND: INCMP -> DELETE: 2001:db8:700:1d::1
ICMPv6-ND: DELETE -> INCMP: 2001:db8:700:1d::1
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
?

Es fehlt nach wie vor die Antwort vom gegenüber liegenden Router. Deswegen schreibt der Ping sein erstes "?" hin.

ICMPv6: Sending echo request to 2001:db8::1
ICMPv6-ND: Sending NS for 2001:db8:700:1d::1 on outside
ICMPv6: Received ICMPv6 packet from 2001:db8:700:1d::1, type 136

Und auf einmal ist die Antwort da!

Sofort macht sich die ASA über die Rückmeldung her:

ICMPv6-ND: Received NA for 2001:db8:700:1d::1 on outside from 2001:db8:700:1d::1
ICMPv6-ND: INCMP -> REACH: 2001:db8:700:1d::1
ICMPv6: Received ICMPv6 packet from 2001:db8::1, type 129
ICMPv6: Received echo reply from 2001:4bd8::1
!

Das Ping Echo ist zurück, es schreibt ein "!" auf die Zeile und alles geht wieder.

Wenn man jetzt mal genau hinschaut, erkennt man deutlich den Unterschied zwischen den unbeantworteten Anfragen und der erfolgreichen Anfrage.

Ganz genau hinschauen! Sieht man's?

Der kleine Unterschied

Genau, da ist kein Unterschied.

Aber es muss etwas geben, was den Effekt auslöst. Also muss man noch genauer hinschauen.

asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 neighbor-advertisement 
asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 neighbor-redirect 
asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 neighbor-solicitation 
asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 router-advertisement 
asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 router-renumbering 
asa(conf)# access-list debug-38594 extended permit icmp6 any6 any6 router-solicitation
asa# capture d-38594 access-list debug-38594 packet-length 1500 interface outside circular-buffer

Es werden alle Nachbarschafts- und Router-Nachrichten mitgeschnitten. In voller Länge, damit man auch was sehen kann.

Und nun schauen wir mal nach den fehlenden Details:

asa# show capture d-38594 detail
17: 07:36:17.423180 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

18: 07:36:17.433342 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6400:0: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

19: 07:36:18.415887 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

20: 07:36:18.423211 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6400:0: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

21: 07:36:19.415887 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

22: 07:36:19.421441 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6400:0: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

23: 07:36:20.422921 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

24: 07:36:20.428124 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6400:0: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

25: 07:36:21.415856 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

26: 07:36:21.419350 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6400:0: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255) 

Die ASA (fe80::6400:0) fragt per Link-Local Multicast (ff02::1:ff00:1) nach der MAC zur IP 2001:db8:700:1d::1. Soweit war das im Debug schon zu sehen.

Überraschenderweise antwortet die Zielmaschine (2001:db8:700:1d::1) der ASA (fe80::6400:0) mit den gewünschten Daten.

Das bedeutet, dass trotz Umbaus am Uplink keine Störung dort vorliegt: Die Antworten kommen an!

Und es bedeutet weiter, dass es allein ein Problem der ASA ist, was hier abgeht.

Als nächstes wird ein Ping von der ASA aus probiert:

27: 07:36:22.396021 6412.25e3.e7fd 203a.0762.b442 0x86dd Length: 86
 fe80::6400:0 > fe80::223a:7ff:fe62:b442: icmp6: neighbor sol:
 who has fe80::223a:7ff:fe62:b442(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32,hlim 255)

28: 07:36:22.399408 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 78
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor adv:
 tgt is fe80::223a:7ff:fe62:b442(RS) [class 0xe0] (len 24, hlim 255)

29: 07:36:22.416009 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 2001:db8:700:1d::2 > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

30: 07:36:22.425988 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > 2001:1438:700:1d::2: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

Zuerst kommt ein Abgleich der Nachbarschaftsbeziehung zwischen den Link-Local-Adressen selbst. Dieser funktioniert.

Und spontan ist die folgende Antwort für die ASA akzeptabel.

Das Problem besteht darin, dass die ASA für durchgereichten Datenverkehr die ND nach dem Default-GW mit der Quell-IP fe80::xxx macht, und dann die Antwort ignoriert. Wenn Sie dagegen selbst pingt, ist die Quell-IP des ND allerdings 2001:... und dann akzeptiert sie auch die Antwort.

Und wie sieht man das in dem Ausgabewust (der hier gekürzt ist)? Mit sort | uniq -c.

Auf der Zielgeraden

Ich hab' mal mit der link-lokal Adresse als Default-Route gespielt, weil ja offenbar kein Problem besteht, die MAC einer Link-Local Adresse zu ermitteln.

Es tritt das gleiche Problem auf:

5081: 11:22:27.164588 6412.25e3.e7fd 3333.ff62.b442 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff62:b442: icmp6: neighbor sol:
 who has fe80::223a:7ff:fe62:b442(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32,hlim 255)

5082: 11:22:27.167609 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor adv:
 tgt is fe80::223a:7ff:fe62:b442(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len32, hlim 255)

5083: 11:22:28.164557 6412.25e3.e7fd 3333.ff62.b442 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff62:b442: icmp6: neighbor sol:
 who has fe80::223a:7ff:fe62:b442(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32,hlim 255)

5084: 11:22:28.165869 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor adv:
 tgt is fe80::223a:7ff:fe62:b442(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len32, hlim 255)

5085: 11:22:29.173925 6412.25e3.e7fd 3333.ff62.b442 0x86dd Length: 86
 fe80::6400:0 > ff02::1:ff62:b442: icmp6: neighbor sol:
 who has fe80::223a:7ff:fe62:b442(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32,hlim 255)

5086: 11:22:29.180914 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor adv:
 tgt is fe80::223a:7ff:fe62:b442(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len32, hlim 255)

Wie bisher: Anfrage von Link-Local wird beantwortet, aber seitens der ASA nicht verarbeitet.

5087: 11:22:30.164664 6412.25e3.e7fd 3333.ff62.b442 0x86dd Length: 86
 2001:db8:700:1d::2 > ff02::1:ff62:b442: icmp6: neighbor sol:
 who has fe80::223a:7ff:fe62:b442(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32,hlim 255)

5088: 11:22:30.172262 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > 2001:db8:700:1d::2: icmp6: neighbor adv:
 tgt is fe80::223a:7ff:fe62:b442(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0](len 32, hlim 255)

Wenn die ASA aber mit ihrer offiziellen Adresse anfragt, gibt es kein Problem.

Und noch etwas fällt auf:

5089: 11:22:31.194234 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor sol:
 who has fe80::6400:0(src lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32, hlim 255)

5090: 11:22:32.200871 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor sol:
 who has fe80::6400:0(src lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32, hlim 255)

5091: 11:22:33.207508 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > fe80::6400:0: icmp6: neighbor sol:
 who has fe80::6400:0(src lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32, hlim 255)

Umgekehrt mag sie auch nicht auf Anfragen nach ihrer eigenen Link-Local Adresse antworten. Das gilt inbesondere auch dann, wenn das Paket schon an sie selbst adressiert ist.

5092: 11:22:35.178915 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 fe80::223a:7ff:fe62:b442 > 2001:db8:700:1d::2: icmp6: neighbor sol:
 who has 2001:db8:700:1d::2(src lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255)

5093: 11:22:35.179464 6412.25e3.e7fd 203a.0762.b442 0x86dd Length: 78
 2001:db8:700:1d::2 > fe80::223a:7ff:fe62:b442: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::2(RS) [class 0xe0] (len 24, hlim 255)

Wohl aber antwortet sie auf die Anfrage an ihre offizielle IP nach ihrer offiziellen IP.

Es scheint so, als ob die ASA die eigene Link-Local Adresse nicht mag.

Der Fehler scheint darin zu bestehen, dass die Link-Local Adresse auf der ASA nicht geändert werden darf. Warum auch immer.

Normalerweise habe ich händisch vergebene Link-Local Adressen nach dem Schema fe80::Gerät:Interface, was die Routingtabellen schön lesbar macht.

Also habe ich die Link-Local Adresse auf "system-default" gestellt und es scheint zu gehen. Selbst nach einem Löschen der Nachbarschafts-Caches erholt sich das System binnen Sekundenfrist von allein.

5123: 14:20:32.560914 6412.25e3.e7fd 3333.ff00.0001 0x86dd Length: 86
 fe80::6612:25ff:fee3:e7fd > ff02::1:ff00:1: icmp6: neighbor sol:
 who has 2001:db8:700:1d::1(src lladdr: 64:12:25:e3:e7:fd) [class 0xe0] (len 32, hlim255)

5124: 14:20:32.569077 203a.0762.b442 6412.25e3.e7fd 0x86dd Length: 86
 2001:db8:700:1d::1 > fe80::6612:25ff:fee3:e7fd: icmp6: neighbor adv:
 tgt is 2001:db8:700:1d::1(RSO)(tgt lladdr: 20:3a:07:62:b4:42) [class 0xe0] (len 32,hlim 255) 

Ein schöner Bug, Cisco.

Die Firma Qualys bietet einen populären SSLTest an. Leider scheinen sie in letzter Zeit einen Fehlgriff getan zu haben, indem sie die CAA Tests einführten. Das Problem ist, dass CAA etwas völlig anderes tut, als die Betreiber annehmen.

Warum CAA?

CAA wurde im RFC 6844 standardisiert und vom CA Forum ab 8. September als verpflichtend vereinbart.

Es geht um folgendes (aus dem RFC)

The Certification Authority Authorization (CAA) DNS Resource Record
allows a DNS domain name holder to specify the Certification
Authorities (CAs) authorized to issue certificates for that domain.
Publication of CAA Resource Records allows a public Certification
Authority to implement additional controls to reduce the risk of
unintended certificate mis-issue.

Der Webseitenbetreiber kann also im DNS seiner Webseitenzone angeben, welche CA für den Server Zertifikate ausstellen darf.

Der RFC stellt nochmal explizit klar:

Like the TLSA record defined in DNS-Based Authentication of Named
Entities (DANE) [RFC6698], CAA records are used as a part of a
mechanism for checking PKIX certificate data.  The distinction
between the two specifications is that CAA records specify an
authorization control to be performed by a certificate issuer before
issue of a certificate and TLSA records specify a verification
control to be performed by a relying party after the certificate is
issued.

Die Zielgruppe des CAA Records ist also die CA, die bei der Zertifikatserstellung prüfen kann, ob der Betreiber sich auch an diese CA wenden wollte. Der Gedanke dabei ist, dass eine CA erkennen kann, dass sie von einem Angreifer für eine fehlerhafte Zertifikatserstellung missbraucht wird.

Die Zielgruppe von TLSA Records dagegen sind die Browser, die bei der Zertifikatsvalidierung prüfen können, ob das beim Verbindungsaufbau präsentierte Zertifikat vom echten Webseitenbetreiber stammt. Der Gedanke dabei ist, dass ein Browser erkennen kann, ob ihm ein falsches Zertifikat unter geschoben werden soll.

Wie deutlich der CAA Record auf den Betrieb einer CA ausgerichtet ist, sieht man daran, dass die Autoren von Comodo (einer CA) stammen und als Beispiel angeben, welche Nutzerkennung im Commodo-Portal für die Zertifikatserstellung benutzt werden darf (aus dem RFC):

example.com.  CAA 0 issue "ca.example.net; account=230123"

Böse formuliert kann man den CAA Record als Abwehrmechanismus von Comodo verstehen, wenn wieder mal fälschlich Zertifikate ausgestellt wurden. Die CA könnte dann darauf verweisen, dass der Webseitenbetreiber ja angeben hätte können, dass diese CA gar nicht für ihn arbeiten darf.

Woher bekommt man nun so einen CAA Eintrag, wenn man einen braucht?

  • Auf der Webseite von SSLmate kann man sich die Records erzeugen.
  • Den notwendigen Issuer-String kann man bei einer inoffiziellen Registry nachschlagen.

Interessant ist dabei, welche Issuer-Strings die CAs so anerkennen. Symantec ist es beispielsweise egal, welcher Reseller zum Zuge kommt. Es ist also nicht möglich, "thawte.com" anzugeben und so GeoTrust auszuschließen.

Ebenso interessant ist, dass der RFC vermeidet, der IANA die Pflege der Issuer-Strings aufzuerlegen. Dabei wäre das echt nützlich gewesen. Die referenzierte Registry hat lustigerweise ein "fork me on Gitlab" Banner in der Ecke.

Was SSLabs tut

Zunächst mal hat Qualsys auf die Ankündigung des CA-Forums reagiert, und prüft auf die Existenz des Eintrags. Ist der Eintrag vorhanden, gibt es Zusatzpunkte für einen A+ Status. Das hebt die Motivation natürlich.

Also schauen wir mal. Eintrag vornehmen und testen:

2017-08-23-184740_578x445_scrot

Ist das nicht cool? Das Zertifikat stammt von Symantec, und der Test befindet den CAA Eintrag für gut.

Aber kann er überhaupt einen Eintrag testen, der gar nicht für die Verwendung in einem Browser vorgesehen ist? Schließlich hat der Test ja keinen Zugriff auf die Validierungslogik der CAs.

Also testen wir auch das.

2017-08-23-185026_573x442_scrot

Wie bitte? Ein ganz offensichtlicher Widerspruch wird mit Zusatzpunkten bewertet?

Wenn man versteht, dass CAA ausschließlich für die  CAs da ist, ist das keine Überraschung. Vielleicht soll ja auch das nächste Zertifikat von einer anderen CA ausgestellt werden? Der Betreiber der Webseite benutzt halt nur noch das noch gültige alte Zertifikat weiter. Gründe kann es vieles geben.

Im Kern fällt es auf die Aussage zurück, dass der Zeitpunkt der Auswertung des CAA Records bei der Zertifkatserstellung wichtig ist. Dieser Zeitpunkt unterscheidet sich erheblich von dem der Zertifikatsvalidierung!

Noch viel witziger sind die Ausschlusskriterien für die Verwendung von CAA:

  • Wenn der CAA Test schon zweimal in der Vergangenheit erfolgreich war und das im Certifcate Transparency Log steht.
    Ich darf also die CA nicht wechseln?
  • Wenn die ausstellende Sub-CA dies in ihren Verträgen ausschließt.
    Diese Sub-CAs waren bisher schon immer eine Quelle von Fehlern.
  • Wenn die CA auch Betreiber des DNS ist.
    Die Großen schauen also weg.
  • Wenn die DNS Abfrage fehlschlägt aus Gründen, die nicht die CA zu verantworten hat, die Anfrage aber wenigsten einmal versucht wurde und die Zone nicht komplett bis zur Wurzel DNSSEC validierbar ist.
    Also immer.

Ehrlich gesagt ist das ein Frechheit.

Und nun?

Wer auch immer einen Draht zu Qualys SSLabs hat, er möge den Leuten dort auf die Füße treten:

  • Entfernt die CAA Prüfung!
  • Prüft TLSA!

So, Leute: Es wird ernst. Die Root-Zone ist schon eine ganze Weile signiert und man soll auch dort mal die Schlüssel wechseln. Das ist nicht einfach, weil alle Betreiber rekursiver Resolver daran mitwirken müssen.

Es gibt drei Typen von Betroffenen:

  • Der Resolver macht kein DNSSEC, dann vergesst es.
  • Der Resolver validiert DNSSEC und es interessiert Euch nicht, dann plant einen Paniktag ein.
  • Der Resolver validiert DNSSEC und ihr wollt Panik vermeiden, dann lest und testet.

Worum geht's?

Fragt man die Root-Nameserver nach ihrem Schlüsselmaterial so gibt es folgende Antwort:

;; QUESTION SECTION:
;.                      IN DNSKEY

;; ANSWER SECTION:
.                       DNSKEY  257 3 8 (
                                AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTO
                                ...
                                9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU=
                                ) ; key id = 20326
.                       DNSKEY  257 3 8 (
                                AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQ
                                ...
                                LmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=
                                ) ; key id = 19036
.                       DNSKEY  256 3 8 (
                                AwEAAYvxrQOOujKdZz+37P+oL4l7e35/0diH/mZITGjl
                                ...
                                jpi+V7pgh0o1KYXZgDUbiA1s9oLAL1KLSdmoIYM=
                                ) ; key id = 15768
.                       RRSIG   DNSKEY 8 0 172800 20170831000000 (
                                20170810000000 19036 .
                                D2D0oJblRe/C86Eti+vOLIHll7hvI9mN/O6S9gZqKvN2
                                ...
                                fkMFPGKWv4Gi1BlE+r+a9FDFz4ypjwdbvA== )

Die Root-Zone hat also aktuell drei Schlüssel:

  • Einen Arbeitsschlüssel (key id = 15768) und
  • zwei  Hauptschlüssel von denen Ihr bisher den mit der ID 19036 auf der Platte habt.
  • Der Schlüssel mit der ID 20326 ist neu.

Zum 11. Oktober 2017 wird die Root-Zone mit dem neuen Schlüssel unterschrieben. Dann müsst Ihr den neuen Key auf der Platte haben, sonst fällt bei Euch DNS komplett aus.

Ich habe das selbst schon mal hinbekommen, als am 26.12. mir die Signaturen der Nameserver-Records meiner Test-Root ausliefen. Ein Remote-Zugriff klappte nicht mehr, weil die SSH die IPs nicht nachschlagen konnte, die einzelnen Geräte in Panik die Dienste neu starteten und diese schon beim Start keine Gegenstelle mehr erreichen konnten (IPs nachschlagen ging nicht mehr) und sich instantan wieder beendeten.

Manuell konnte ich an der Konsole des rekursiven Nameserver den Fehler beheben. Nach einer frostigen Fahrradtour in die Firma. Ich habe geschwitzt!

Was ist zu tun?

Eure Software sollte also erkennen, dass es einen neuen Schlüssel gibt und den auf die Platte legen.

Nehmen wir an, es sei unbound. Dann findet ihr eine Datei /etc/unbound/root.key (o.ä.)

; autotrust trust anchor file
;;id: . 1
;;last_queried: 1502962961 ;;Thu Aug 17 11:42:41 2017
;;last_success: 1502962961 ;;Thu Aug 17 11:42:41 2017
;;next_probe_time: 1503005390 ;;Thu Aug 17 23:29:50 2017
;;query_failed: 0
;;query_interval: 43200
;;retry_time: 8640
.       172800  IN      DNSKEY  257 3 8 AwEAAaz/t...V74bU= ;{id = 20326 (ksk), size = 2048b}
   ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1502399011 ;;Thu Aug 10 23:03:31 2017
.       3696    IN      DNSKEY  257 3 8 AwEAAagA...ihz0= ;{id = 19036 (ksk), size = 2048b}
   ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1291045951 ;;Mon Nov 29 16:52:31 2010

Diese Datei enthält bereits beide Schlüssel und alles ist gut(TM).

Hat man dagegen unbound irgendwann mal aufgesetzt und nie richtig eingerichtet, so schaut die Datei so aus:

;;id: . 1
;;last_queried: 1414101618 ;;Fri Oct 24 00:00:18 2014
;;last_success: 1414101618 ;;Fri Oct 24 00:00:18 2014
;;next_probe_time: 1414143412 ;;Fri Oct 24 11:36:52 2014
;;query_failed: 0
;;query_interval: 43200
;;retry_time: 8640
.       86390   IN      DNSKEY  257 3 8 AwEAA...k1ihz0= ;{id = 19036 (ksk), size = 2048b}
   ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1291283901 ;;Thu Dec  2 10:58:21 2010sdf 

Wie fixed man das?

Zuerst einmal sollte unbound wissen, dass er die Datei selbst aktualisieren soll:

$ fgrep root.key /etc/unbound/unbound.conf
 auto-trust-anchor-file: "/etc/unbound/root.key"

Klar soweit?

Wenn auch das nicht hilft, kann es sein, dass die Datei nicht die notwendigen Rechte hat.

-rw-r--r-- 1 root root 758 Okt 24  2014 /etc/unbound/root.key
-rw-r--r-- 1 unbound unbound 1250 2017-08-17 11:42 /etc/unbound/root.key 

Das ist doch wohl deutlich, oder? Und natürlich leicht zu fixen.

Und andere Resolver-Software? Im Kern geht es um RFC 5011 Unterstützung. Die findet man bei Bind und anderer Software.

Achja, bitte schaut doch mal nach den Kundensystemen, von denen ihr wisst oder ahnt.