Typischerweise haben Server einen RAID-Controller, der einen Festplattenausfall vor dem Betriebssystem verstecken kann. Wenn also eine Platte den Geist aufgibt, kann man sie wechseln, ohne auf irgendeine Besonderheit des installierten Systems Rücksicht nehmen zu müssen. Das erleichtert die Arbeit im Rechenzentrum erheblich: Platte tot → Austauschen → Fertig.

Redundante Redundanz

Auf einen Satz Server ist Proxmox zum Spielen drauf gekommen. Der Installer richtet auf einer ausgewählten Platte das System ein. In dem Fall also auf dem Hardware-RAID. Soweit so gut.

Für das Storage möchte ich auf Ceph zurück greifen, auf Neudeutsch hyperkonvergent arbeiten. Deswegen habe ich den größten Teil der Platte frei gelassen um den Rest als OSD einbinden zu können.

Ceph verwaltet eine eigene Redundanz über die OSD-Datenträger. Es berücksichtigt dabei großräumigere Strukturen als nur Platten an einem Contoller. Dies führt zu massiver Platzverschwendung: Daten liegen nicht mindestens doppelt, sondern vier- bis sechsfach vor.

Wird das Hardware-RAID aufgebrochen, kann Ceph die einzelen Platte direkt verwalten und damit effizienter umgehen. Aber was wird  aus dem Basissystem?

Eine Neuinstallation später steht fest, dass der Proxmox-Installer das System ausschließlich auf eine der beiden Platte installiert hat. Konzeptionell ist das nachvollziehbar, da so mehr Platz für die OSDs bleibt. Geht die Systemplatte kaputt, installiert man den Knoten halt komplett neu und der Cluster erledigt den Rest.

Ich scheue aber den Aufwand, da die Netzwerkinstallation des Basissystem hier doch stärker vom Proxmox-Standard abweicht, als erwartet. Aber dazu ein andermal.

Aus eins mach zwei

Zuerst ein Blick auf die Situation direkt nach der Installation:

root@server21:~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux LVM

Die Platte sdb ist leer.

Im ersten Schritt kopiere ich den Anfang der Platte incl. alle Boot-Informationen:

root@server21:~# dd if=/dev/sda of=/dev/sdb bs=512 count=1050623

Ja, die GPT ist auf der zweiten Platte kaputt, da die Kopie am Ende der Platte fehlt. Aber das behebt fdisk beim nächsten Aufruf.

So kann nun die zweite Platte so eingerichtet werden, wie später es sein soll:

root@server21:~# fdisk /dev/sdb
[...]
Command (m for help): t
Partition number (1-3, default 3): 
Hex code (type L to list all codes): 29

Changed type of partition 'Linux LVM' to 'Linux RAID'.

Command (m for help): p
Disk /dev/sdb: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sdb1       34     2047     2014 1007K BIOS boot
/dev/sdb2     2048  1050623  1048576  512M EFI System
/dev/sdb3  1050624 41943040 40892417 19.5G Linux RAID

Und wenn wir schon mal hier sind, dann auch gleich das OSD vorbereiten

Command (m for help): n
Partition number (4-128, default 4): 
First sector (41943041-585937466, default 41945088): 
Last sector, +sectors or +size{K,M,G,T,P} (41945088-585937466, default 585937466): 

Created a new partition 4 of type 'Linux filesystem' and of size 259.4 GiB.

Command (m for help): t
Partition number (1-4, default 4): 
Hex code (type L to list all codes): 76

Changed type of partition 'Linux filesystem' to 'Ceph OSD'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Damit sehen die Platten so aus:

lvm-raid1

Die grünen Partitionen sind schon in Ordnung, die grünen Inhalte ebenfalls. Rot markierte Teile sind noch beheben, die Blauen noch unbenutzt.

Aus zwei mach eins

Zunächst muss das RAID als solches fertig werden. Es soll ein Spiegel werden, aber anfangs nur mit einer Partition.

root@server21:~# mdadm --create /dev/md0 -n 1 -f -l 1 /dev/sdb3 
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90

Sehr gute Frage! Ich habe den Boot-Kram in separaten Boot-Partitionen, was kann da schon schief gehen?

mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sdb3[0]
      20429824 blocks super 1.2 [1/1] [U]
      
unused devices: <none>

Schaut gut aus. Jetzt nur noch die Daten des LVM rein kopieren.

Die Idee ist dabei, das LVM aufzublasen und dann die alte Partition wieder raus zu nehmen.

root@server21:~# pvcreate /dev/md0
  Physical volume "/dev/md0" successfully created.
root@server21:~# pvdisplay 
  --- Physical volume ---
  PV Name               /dev/sda3
  VG Name               pve
  PV Size               19.50 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4991
  Free PE               3775
  Allocated PE          1216
  PV UUID               ijshQ9-3z2d-oVxd-WJB2-8LUv-HEfL-lTZzEi
   
  "/dev/md0" is a new physical volume of "19.48 GiB"
  --- NEW Physical volume ---
  PV Name               /dev/md0
  VG Name               
  PV Size               19.48 GiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               G8kgdF-Gcec-ddbO-92ys-9rsf-dkpo-Za9C4a

root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0       lvm2 ---  19.48g 19.48g
  /dev/sda3  pve lvm2 a--  19.50g 14.75g

Es gibt nun zwei LVM-Datenträger, von denen einer das Volume enthält. Nun zum Umzug.

root@server21:~# vgextend pve /dev/md0
  Volume group "pve" successfully extended
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 19.48g
  /dev/sda3  pve lvm2 a--  19.50g 14.75g
root@server21:~# vgdisplay -C
  VG  #PV #LV #SN Attr   VSize  VFree 
  pve   2   1   0 wz--n- 38.98g 34.23g
root@server21:~# vgreduce pve /dev/sda3 
  Physical volume "/dev/sda3" still in use

Vergrößern ging, aber die alte Partition lässt sich nicht entfernen!

Warum? Weil noch Daten drauf sind. Schließlich wurde ja nur neuer Platz hinzugefügt. Nur der ist unbenutzt.

root@server21:~# pvmove /dev/sda3
  /dev/sda3: Moved: 0.00%
  /dev/sda3: Moved: 18.17%
  /dev/sda3: Moved: 36.43%
  /dev/sda3: Moved: 54.52%
  /dev/sda3: Moved: 72.86%
  /dev/sda3: Moved: 91.04%
  /dev/sda3: Moved: 100.00%
root@server21:~# pvdisplay 
  --- Physical volume ---
  PV Name               /dev/sda3
  VG Name               pve
  PV Size               19.50 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4991
  Free PE               4991
  Allocated PE          0
  PV UUID               ijshQ9-3z2d-oVxd-WJB2-8LUv-HEfL-lTZzEi
   
  --- Physical volume ---
  PV Name               /dev/md0
  VG Name               pve
  PV Size               19.48 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              4987
  Free PE               3771
  Allocated PE          1216
  PV UUID               G8kgdF-Gcec-ddbO-92ys-9rsf-dkpo-Za9C4a

Nun ist nichts mehr auf der alten Partition in Benutzung. "Allocated PE" ist 0.

Also müsste sich die Partition nun entfernen lassen.

root@server21:~# vgreduce pve /dev/sda3 
  Removed "/dev/sda3" from volume group "pve"
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 14.73g
  /dev/sda3      lvm2 ---  19.50g 19.50g

Hurra! Nun noch die Partition dem LVM entziehen.

root@server21:~# pvremove /dev/sda3
  Labels on physical volume "/dev/sda3" successfully wiped.
root@server21:~# pvdisplay -C
  PV         VG  Fmt  Attr PSize  PFree 
  /dev/md0   pve lvm2 a--  19.48g 14.73g

Und die Partition umwidmen.

root@server21:~# fdisk /dev/sda

Welcome to fdisk (util-linux 2.29.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux LVM
Command (m for help): t
Partition number (1-3, default 3): 
Hex code (type L to list all codes): 29

Changed type of partition 'Linux LVM' to 'Linux RAID'.

Command (m for help): p
Disk /dev/sda: 279.4 GiB, 300000000000 bytes, 585937500 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3B2CD483-DE39-45BA-BF6A-C35E2AD8F783

Device       Start      End  Sectors  Size Type
/dev/sda1       34     2047     2014 1007K BIOS boot
/dev/sda2     2048  1050623  1048576  512M EFI System
/dev/sda3  1050624 41943040 40892417 19.5G Linux RAID

Command (m for help): n
Partition number (4-128, default 4): 
First sector (41943041-585937466, default 41945088): 
Last sector, +sectors or +size{K,M,G,T,P} (41945088-585937466, default 585937466): 

Created a new partition 4 of type 'Linux filesystem' and of size 259.4 GiB.

Command (m for help): t
Partition number (1-4, default 4): 
Hex code (type L to list all codes): 76

Changed type of partition 'Linux filesystem' to 'Ceph OSD'.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Bei der Gelegenheit auch gleich noch die OSD Partition vorbereitet. Sehr schön.

Jetzt kann das RAID breit gezogen werden.

root@server21:~# mdadm -a /dev/md0 /dev/sda3
mdadm: added /dev/sda3
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sda3[1](S) sdb3[0]
      20429824 blocks super 1.2 [1/1] [U]

Nein.Das ist kein "hot spare", das ist Bestandteil des RAIDs selbst. Ich hätte wohl gleich mit zwei Partitionen, davon eine als "none", anfangen sollen.

root@server21:~# mdadm -r /dev/md0 /dev/sda3
mdadm: hot removed /dev/sda3 from /dev/md0
root@server21:~# mdadm --grow /dev/md0 -n 2 -a /dev/sda3
mdadm: added /dev/sda3
raid_disks for /dev/md0 set to 2
root@server21:~# cat /proc/mdstat 
Personalities : [raid1] 
md0 : active raid1 sda3[1] sdb3[0]
      20429824 blocks super 1.2 [2/1] [U_]
      [>....................]  recovery =  3.2% (669248/20429824) finish=1.4min speed=223082K/sec 

Hurra! Jetzt schaut es so aus.

lvm-raid2

Reboot

Da nun alles im laufenden Betrieb umgezogen ist, bleibt nur noch der finale Reboot.

Klappt aber nicht, weil der Grub das LVM-Volume nicht mehr findet. Sollte /boot nicht separat liegen?! Mal beim Nachbar nachschauen:

root@server22:~# mount | grep boot
/dev/sda2 on /boot/efi type vfat ...

Ohje. Also nochmal von vorn und diesmal mit "--metadata=0.9". Siehe an, es geht.

Aber was ist eigentlich passiert? Zur Erinnerung nochmal die Warnung.

mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90

Die Metadaten des RAID können also am Anfang (neu) oder am Ende (alt) der Partition stehen. Wenn sie am Ende stehen, muss niemand irgendwas von dem RAID1 (Mirror) verstehen, um auf den Inhalt zugreifen zu können. Die Partition sieht halt aus, als gäbe es gar kein RAID.

Stehen die Daten am Anfang der Partition, muss die Software damit umgehen können. Im Prinzip ist das auch sehr einfach, weil man nur über die RAID-Kennung hinweg springen muss. Leider kann das Grub nicht und ist damit ein steter Quell von Problemen.

Wir fahren nach Berlin! Vom Leiden einer Reisebuchung am ersten April.

Es ist BCIX Stammtisch und ich darf dabei sein. Hurra!

Anreise

Dazu muss eine Reise gebucht werden und schon kommt das erste Problem auf: Ich kann auf dem Bahn-Portal nicht bezahlen. Die Zahlung per Kreditkarte wird abgelehnt.

Anruf beim Support: "Das ist zu Ihrer Sicherheit! Sie haben schon so oft mit Kreditkarte Bahnfahrkarten gekauft, das könnte auch ein Betrüger sein, also ist das nun gesperrt. Gegen Sie zum Schalter!"

Genau genommen funktioniert mit der Commzerbank das 3D Secure Verfahren nie, weswegen jeder, der ein Konto dort hat es ausschaltet. Nun besteht die Bahn spontan auf der Einhaltung des Verfahren, auch wenn die Bank es direkt als unnötig ablehnt. Die Bahn kann mit der Ablehnung aber nicht umgehen und die Buchung scheitert.

Was auch nicht geht, ist ein Umstellung auf Lastschrift. Nicht, weil der Prozess per Post und Papier abläuft, sondern weil er aus Sicherheitsgründen seitens der Bahn abgebrochen wird. Es gab ja eben erst eine fehlgeschlagene Kreditkartenbuchung.

Auf eine öffentliche Beschwerde hin, antwortet die Bahn:

Aktuell sind verstärkt betrügerische Aktivitäten basierend auf sogenannten Phishing-E-Mails zu verzeichnen. Als eine vorsorgliche Maßnahme zum Schutz unserer Kunden können deshalb Sparpreis-Tickets auf bahn.de und im DB Navigator bis auf Weiteres nur

  • per "Sofort." (SOFORT Überweisung) und
  • Kreditkarte unter Abfrage des 3D-Secure-Passwortes

bezahlt werden. Dafür bitten wir um Verständnis.

https://www.bahn.de/p/view/home/info/sonderkommunikation-phishing.shtml

Der Betrüger darf also den teuren Flexpreis gern zu meinen Lasten in Anspruch nehmen, nicht aber die Sparpreise. Super, Deutsche Bahn!

Und nein, ich werde meine Online-Banking-Daten nicht irgendeinem fremden Unternehmen in die Hände drücken. Das fällt aus.

Übernachtung

Und nun zu Teil zwei: Ich brauch ein Hotel, weil nach der Veranstaltung nichts mehr nach Hause fährt.

Bei Booking alles soweit kein Problem, nur gibt's keinen Ausdruck der Buchung mehr direkt auf die Hand. Das neue Verfahren generiert das PDF offenbar aus einem C64-Font heraus:

2019-04-01-150217_1278x1022_scrot

Echt retro.

Eine unglückliche Platzierung eines Datenschutzlinks wird unfreiwillig komisch, wenn dann Fehler auftreten.

Bildschirmfoto vom 2019-02-26 10.18.10

Genau. Kein Kamerabild, weil ... ganz unten "Powered by Datenschutz" steht.

Eigentlich ist es ganz anders.

Im Rahmen der DSGVO wurde der Webseite ein Footer mit einem Datenschutzlink verpasst. Allerdings beißt sich das mit dem bisherigen Design, bei dem die Sponsoren als "Powered by" aufgeführt sind.

Als dann die Kamera kein Bild liefern konnte, entstand dieser Schnappschuß-.

Ein Kunde beschwerte sich über Netzwerkprobleme. Zwischen zwei seiner Server würde immer wieder ein SMB/CIFS-Mount weg brechen. Nicht, dass es irgendwelche bemerkbaren Störungen gegeben hätte, aber es gäbe halt immer wieder diese Fehlermeldungen im Log.

Aufbau

Der Kunde hat in seinem Layer2-Segment eine ganze Latte Server stehen. Einer davon spielt Windows-Fileserver für eine Gruppe von Windows Rechnern. Ein anderer ist das Linux-Monitoring-System, das u.a. regelmäßig versucht auf die Freigabe zuzugreifen.

Das Ganze hat eine längere Vorgeschichte, die vor einem halben Jahr zur Empfehlung führte, doch konsequent auf SMB1 zu verzichten. Dieser Teil ist nicht von Belang, sondern das, was der Empfehlung folgte.

Denn seit der Umstellung hat das Monitoring-Linux seltsame Einträge im Kernellog stehen:

Feb 12 19:07:02 kernel: CIFS VFS: Server a.b.c.d has not responded in 120 seconds. Reconnecting...

Woher kommen die 120 Sekunden? Das Handbuch hilft weiter:

echo_interval=n

sets the interval at which echo requests are sent to the server on an idling
connection. This setting also affects the time required for a connection to
an unresponsive server to timeout. Here n is the echo interval in seconds.
The reconnection happens at twice the value of the echo_interval set for
an unresponsive server. If this option is not given then the default value of
60 seconds is used.

Das erklärt schon mal die 120 Sekunden: Alle Minute wird ein SMB Echo versendet und wenn zweimal kein Echo beantwortet wird, nimmt man an die Verbindung sei tot. Deswegen wird seitens des Kunden (verständlicherweise) vermutet, dass es Paketverlust im Netzwerk gäbe.

Allein diese Vermutung zu widerlegen, dauert Wochen. Dazu wird auf beiden Seiten der Datenverkehr mitgeschnitten und Paket für Paket nebeneinander gelegt.

Dem eigentlichen Problem ist man damit aber leider immer noch nicht näher gekommen.

Analyse

Immer wieder wird so ein Mitschnitt angeschaut, um irgendeine Auffälligkeit zu entdecken.

smb-tcp-flow

Es ist sehr schön zu sehen, wie jede Minute das Keep-Alive Request-Response Spiel passiert. Anschließend werden Daten übertragen.

Kurz darauf kommt die Kommunikation zum Erliegen und der im Log erwähnte Timeout schlägt zu. Zwischen 19:05:01.99... und 19:07:02.25... liegen etwas mehr als 120 Sekunden. Das passt so weit.

Auffällig ist der Übertragungsfehler (der mit dem TCP-Keepalive), der direkt vor dem Abbruch der Verbindung rein schlägt. Das muss untersucht werden!

Warum ist die Zeile schwarz? Weil der Keepalive genau ein Byte nochmal sendet, dass schon lange geackt wurde. Es ist eine sehr ungewöhnliche Kommunikation. Wireshark markiert solche Sequenzfehler mit schwarzer Farbe.

  • Um 19:05:01.949511 werden 128 Byte empfangen.
  • Um 19:05:01.997203 wird der Empfang dieser 128 Bytes bestätigt.
  • Um 19:07:01.999481 wird das letzte der 128 Bytes nochmal übertragen (zusammen mit dem Keepalive-Flag)

Wenn die Bestätigung des Datenempfangs (ACK) nicht angekommen wäre, würden die gesamten 128 Byte nochmal gesendet. Werden sie aber nicht.

Hat irgend eine Firewall unterwegs an den Sequenznummern gespielt? Es ist aber gar keine Firewall dazwischen, beide Server stehen im gleichen LAN und sehen sich direkt. Der Mitschitt auf der anderen Seite bestätigt, dass die Bestätigung komplett angekommen ist.

Warum sollte der Kernel also ein einzelnes Byte nochmal senden? Es stellt sich heraus, dass die Windows-Implementation des TCP-Keepalives genau ein Byte nochmal sendet, während die Linux-Implementation das Keepalive ohne Payload auskommt. Es handelt sich offenbar um eine Anpassung von Windows an kaputte Middleware, die TCP-Pakete ohne Payload verwirft.

Der Teil ist also in Ordnung. Aber was ist es dann?

Vielleicht hat es irgendwo Verzögerungen gegeben? Also schauen wir mal auf die Round-Trip-Zeiten. Vielleicht gibt es Ausreißer.

smb-tcp-rtt

Von der remote Stelle gibt es keine besonderen Auffälligkeiten. Alles schön.

smb-tcp-rtt2

Auch die lokale Verarbeitung ist völlig unauffällig: Das der Kernel direkt bearbeiten kann, ist nahezu in Nullzeit erledigt. Wenn die Anwendungssoftware involviert ist, dauert's länger. Man sieht sehr schön, wie regelmäßig die Messungen vorgenommen werden.

Auch hier ist nichts auffällig. Aber was ist es dann?

Beim genaueren Hinsehen fällt auf, dass um 19:06:00 ein Echo-Request hätte versendet werden sollen. Der fehlt aber!

Kernel Archäologie

Im Linux-Kernel ist für das Versenden der Echo-Requests die Funktion cifs_echo_request zuständig. Dort steht:

static void
cifs_echo_request(struct work_struct *work)
{
 int rc;
 struct TCP_Server_Info *server = container_of(work,
     struct TCP_Server_Info, echo.work);
 unsigned long echo_interval;

 /*
  * If we need to renegotiate, set echo interval to zero to
  * immediately call echo service where we can renegotiate.
  */
 if (server->tcpStatus == CifsNeedNegotiate)
  echo_interval = 0;
 else
  echo_interval = server->echo_interval;

 /*
  * We cannot send an echo if it is disabled.
  * Also, no need to ping if we got a response recently.
  */

 if (server->tcpStatus == CifsNeedReconnect ||
     server->tcpStatus == CifsExiting ||
     server->tcpStatus == CifsNew ||
     (server->ops->can_echo && !server->ops->can_echo(server)) ||
     time_before(jiffies, server->lstrp + echo_interval - HZ))
  goto requeue_echo;

 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
 if (rc)
  cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
    server->hostname);

requeue_echo:
 queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
}

Der Code ist in mehrfacher Hinsicht interessant:

  • Zum Einen wird ein Echo nur gesendet, wenn dafür eine echte Notwendigkeit besteht.
  • Zum Anderen handelt es sich um ein Daisy-Chain Scheduling: Erst nach getaner Arbeit wird die nächste Aktion geplant.

Was die Notwendigkeit betrifft, so werden keine Echos ausgesendet, solange die letzte Response kürzer als eine Echo-Abstand einging.

Aber was ist eine Response? Im Code wird der server-›lstrp immer dann auf die aktuelle Zeit gesetzt, wenn ein Paket empfangen wird. Unabhängig davon ob es ein Echo-Response oder normale Daten sind.

Das Abziehen von HZ (eine Sekunde) ist eine Maßnahme dagegen, dass die Echo-Response auf die eigene Anfrage schon als interessanter Traffic interpretiert wird. Dieser hartkodierte Wert gilt also unter der Annahme, dass die Antwort der Gegenstelle immer schneller da ist als in einer Sekunde.

Betreibt man einen solchen SMB Zugriff über eine längere Strecke oder gegen einen langsameren Server, so wird jeder zweite Echo-Request unterdrückt, wenn kein weiterer Traffic auftritt. Das führt direkt dazu, dass SMB nur im LAN wirklich funktioniert.

Aufgrund der Protokollarchitektur werden alle Anfragen sequentiell bearbeitet. Wenn also ein Echo-Request gesendet wird, während noch eine andere Abfrage an den Server läuft, so wird die Verarbeitung des Echo-Requests erst dann erfolgen, wenn der vorherige Request bearbeitet wurde. Eine asynchrone Bearbeitung wurde mit dem Wechsel von SMB1 zu SMB2 aufgegeben. Stattdessen soll der Server den Client mitteilen, dass die Bearbeitung einer aufwändigeren Anfrage noch andauert.

In diesem Fall war um 19:05:01.91... eine Antwort vom Server eingegangen. Das Echo-Paket hätte gegen 19:06:00 gesendet werden sollen. Das ist haarscharf daneben!

Die zweite Auffälligkeit ist das Scheduling. Erst, wenn alle Arbeiten (Echo-Paket versenden) erledigt sind, wird der nächste Echo-Versand geplant und zwar 60 Sekunden später. Die gesamte Verarbeitungszeit fehlt in der Planung. Das führt dazu, dass die Echo-Pakete nicht genau nach 60 Sekunden versendet werden, sondern immer ein Stück später.

Man sieht das im Mitschnitt sehr schön: 19:01:55.05, 19:02:56.49, 19:03:57.94, 19:04:59.37, 19:06:00.90, 19:07:02.27. Die Abstände betragen etwa 61,5 Sekunden. Also 1,5 Sekunden mehr als geplant. Im letzten Schritt ist das Intervall kürzer, weil das Echo-Paket ja nicht versendet werden musste.

Racecondition

Was wirklich passiert ist schnell erklärt: Das Unterdrücken des geplanten Echo-Requests ist fehlerhaft.

Im Detail:

smb-tcp-timing
  • Durch das Daisy-Chaining-Schedulung entsteht eine Lücke.
  • Kommt Traffic unglücklich kurz nach dem letzten Echo, so wird das geplante Echo unterdrückt.
  • Durch die Lücke verzögert sich der nächste Echo-Versand bis nach dem Timeout, das hart auf das doppelte Echo-Intervall gesetzt wird.

Besonderen Charme hat die Erkenntnis, dass der finale Echo-Request erst versendet wird und danach der Timeout zuschlägt, weil die erste Aktion beim Empfangen des Echo-Response ist, auf einen Timeout zu prüfen und abzubrechen. Ironischerweise hat also das erfolgreiche Echo den Abbruch getriggert.

Stellt sich nun die Frage, seit wann das Problem auftritt und wer dafür verantwortlich ist:

  • Im Patch c740 werden fest alle 60 Sekunden Echo-Requests versendet, wenn kein anderer Traffic auftrat. (Jan 11, 2011)
  • Im Patch fda3 werden diese Echos genutzt um nach dem fünffachen Intervall (konfigurierbar) ohne Traffic den Timeout auszulösen. (Jan 20, 2011)
  • Im Patch 6dae wird die Konfigurierbarkeit von 60s x variabel(5) zu variabel(60s) x zwei umgestellt. (Feb 21, 2012)

Die Lücke und das Unterdrücken wurde also am 11. Januar 2011 eingeführt. Allerdings hat diese keine Auswirkung, da der Timeout erst beim fünffachen Intervall eintritt.

Mit der Umstellung vom 21. Februar 2012 wirkt sich die Lücke nun aus, da man den Timeout hart auf das doppelte Intervall setzte.

Lösungen

Es gibt drei Möglichkeiten.

Zum einen kann man die Lücke beseitigen, indem man das Scheduling zu festen Zeiten macht (immer 60 Sekunden zum letzten Schedule-Zeitpunkt addieren). Es genügt übrigends nicht, das Rescheduling an den Anfang der Routine zu stellen. Damit wird die Lücke nur kürzer, bleibt aber bestehen.

Eine andere Möglichkeit wäre, den Echo-Request unabhängig von anderem Traffic in jedem Fall zu versenden. Motto: Wenn eh schon Traffic läuft, stört der zusätzliche Request auch nicht mehr. Es besteht dabei die potentielle Gefahr, dass sich ein Server an einem Echo zwischen anderen Requests verschluckt.

Und dann wäre es noch denkbar, dass man dem gesamten Problem aus dem Weg geht, indem man minimal die dreifache Intervall-Länge wartet.

Für einen Quick-Fix sollte man den dritten Weg beschreiten: Aus einer 2 eine 3 im Code machen:

static bool
server_unresponsive(struct TCP_Server_Info *server)
{
 /*
  * We need to wait 2 echo intervals to make sure we handle such
  * situations right:
  * 1s  client sends a normal SMB request
  * 2s  client gets a response
  * 30s echo workqueue job pops, and decides we got a response recently
  *     and don't need to send another
  * ...
  * 65s kernel_recvmsg times out, and we see that we haven't gotten
  *     a response in >60s.
  */
 if ((server->tcpStatus == CifsGood ||
     server->tcpStatus == CifsNeedNegotiate) &&
     time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
  cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
    server->hostname, (2 * server->echo_interval) / HZ);
  cifs_reconnect(server);
  wake_up(&server->response_q);
  return true;
 }

 return false;
}

Bleibt nur noch die Frage nach dem TCP-Keepalive. Windows hat exakt 120s bis es auf einer TCP Session einen Keepalive schickt. Man sieht sehr schön, dass zuerst der Windows-Server den TCP-Keepalive schickt, weil er das letzte Paket eher abgesendet hat als es beim Linux ankam.

Danksagung

Die gesamte Analyse wurde von meinem Kollegen Jens durchgeführt, der mich nur bat, die Dinge zusammen zu schreiben. Was ich hier mit getan habe.

jetzt muss nur noch ein Bugreport an die richtige Stelle geschickt werden.

Microsoft stellt einen eigenen BGP Router für Windows bereit. Wir benötigen an einer Stelle, wo bisher nur ein paar Hyper-V fähige Kisten stehen einen unabhängigen Internetzugang. Was liegt also näher als alles aus einer Hand zu bauen?

Installation

Auf eine Windows VM kommt aus der RAS Rolle das Feature LAN Routing zum Einsatz. Damit kann die VM zwischen Interfaces routen.

Als nächstes wird die BGP Rolle installiert. Auch das ist problemlos, die benötigten Abhängigkeiten sind gleich dabei.

Alle folgenden Schritte benötigen die Powershell, was dem geneigten Admin sehr entgegen kommt. Zuerst also einen neuen BGP Router definieren.

PS> Add-BgpRouter -BgpIdentifier <IPAddress> -LocalASN <UInt32>

Man gibt also seine lokales AS Nummer an (zum experimentieren gibt private Nummern) und eine eindeutige IP Adresse, unter der der Router arbeiten wird. Am besten die IP eines Interfaces. Erfreulich ist die Verwendung eines UInt32, der auf die Unterstützung von 4-Byte ASNs hinweist.

Als nächstes kommt dann die Einrichtung eines BGP Peers, also eines Nachbar mit dem diese Maschine reden soll.

PS> Add-BgpPeer [-Name] <String> -LocalIPAddress <IPAddress> -PeerASN <UInt32> -PeerIPAddress <IPAddress>

Der Peer bekommt einen sprechenden Namen unter dem er später erscheinen soll. Des weiteren wird die AS-Nummer des Peers benötigt. Wenn diese die gleiche ist, wie die eigene, handelt es ich um ein i(nternal)BGP, sonst um ein e(xternal)BGP Peer.

Die Kommunikation erfolgt zwischen zwei IP Adressen, die auf beiden Seiten übereinstimmen müssen. I.d.R. werden da IP Adressen genommen, die sich im gleichen Netz befinden und direkt miteinander reden können. Die meisten eBGP Peers erwarten das. bei iBGP ist eine durchaus längere Routingstrecke zwischen den Peers nichts ungewöhnliches.

Cisco als Gegenstelle

Zum Test lasse ich den Server gegen einen normalen Cisco Router arbeiten.

router bgp 15725
 neighbor <WindowsIP> remote-as 65432
 address-family ipv4
  neighbor <WindowsIP> activate
  neighbor <WindowsIP> soft-reconfiguration inbound
  neighbor <WindowsIP> prefix-list from_windows in
  neighbor <WindowsIP> prefix-list to_windows out
 exit-address-family
!
ip prefix-list from_windows seq 5 deny 0.0.0.0/0 le 32
ip prefix-list to_windows seq 1 permit 185.98.236.0/22
ip prefix-list to_windows seq 5 deny 0.0.0.0/0 le 32

Für den Anfang gebe ich nur eine Route raus und nehme nichts an. Sicher ist sicher.

Die BGP Session kommt hoch und das Windows lernt eine Route!

Mit Get-BgpPeer und Get-BgpRouteInformation kann man sich die Ergebnisse ansehen. Die Route taucht sogar in der normalen Routing Tabelle auf.

Auffällig ist aber, dass die Cisco etwas seltsames anzeigt:

  Neighbor capabilities:
    Route refresh: advertised and received(new)
    Four-octets ASN Capability: advertised
    Address family IPv4 Unicast: advertised and received
    Graceful Restart Capability: advertised
    Enhanced Refresh Capability: advertised

Irgendwie fehlt da die 4-Byte ASN Funktionalität. Gleich mal ausprobieren.

PS> Add-BgpPeer test4byte -LocalIPAddress <IPAddress> -PeerASN 199932 -PeerIPAddress <IPAddress>
windows bgp 4byte asn

Oops. Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Full Table

Aber probieren wir mal was anderes. Was tut die Kiste, wenn sie der vollen Internet-Routingtabelle ausgesetzt wird?

(config)#ip prefix-list to_windows seq 2 perm 0.0.0.0/0 le 24

Die CPUs gehen auf Anschlag und bleiben dort eine ganze Weile. Trotzdem bleibt das System benutzbar. Der RAM Bedarf steigt um zwei GByte, was ziemlich okay ist.

Anschließend sind alle Kerne mit ca 50% CPU belastet ohne dass irgendeine Aktivität von außen rein kommt. Seltsam.

Ein Blick in die BGP Routingtabelle mit Get-BgpRouteInformation zeigt, dass alle knapp 750.000 Routen angekommen sind. Allerdings braucht die Maschine unter CPU Volllast für die Ausgabe geschlagene drei Minuten.

Die Überraschung gibt es aber mit dem Blick in die aktive Routing Tabelle:

windows bgp routing missing

Dies ist mit unvollständig nur unzureichend umschrieben.

Real fehlen abertausende Routen wie die folgenden:

B     206.0.0.0/15 [20/0] via 94.135.173.249, 4d15h
B     206.2.0.0/16 [20/0] via 94.135.173.249, 4d15h
B     206.2.76.0/24 [20/0] via 94.135.173.249, 00:36:24
B     206.3.0.0/19 [20/0] via 5.102.160.98, 4w0d
B     206.3.32.0/19 [20/0] via 94.135.173.249, 4d15h
B     206.3.42.0/24 [20/0] via 5.102.160.98, 19:43:50
B     206.3.64.0/18 [20/0] via 94.135.173.249, 4d15h
B     206.3.128.0/17 [20/0] via 94.135.173.249, 4d15h
B     206.4.0.0/14 [20/0] via 94.135.173.249, 4d15h
B     206.5.12.0/22 [20/0] via 94.135.173.249, 4d15h
B     206.8.0.0/14 [20/0] via 94.135.173.249, 4d15h
B     206.8.2.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.88.0/24 [20/0] via 5.102.160.98, 19:43:49
B     206.8.120.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.121.0/24 [20/0] via 94.135.173.249, 4d15h
B     206.8.122.0/24 [20/0] via 94.135.173.249, 4d15h

Das heißt, dass die Maschine nun nicht in der Lage die Pakete korrekt ans Ziel zuzustellen!

Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Wegräumen

Also nehme ich das Announcement der Routen wieder weg.

(config)#no ip prefix-list to_windows seq 2 perm 0.0.0.0/0 le 24

Nach erfreulich schnellen 40 Sekunden sinkt die CPU Last rapide auf nahe 0. Allerdings sind noch immer tausende von Routen im Kernel aktiv.

Als ich zur Kontrolle mir die BGP Routingtabelle mit Get-BgpRouteInformation anzeigen lassen will, behauptet das System, dass die betreffenden Dienste nicht laufen würden.

windows bgp rras dead

Erst im Ereignislog zeigt sich das ganze Ausmaß der Katastrophe:

windows bgp crash

Es hat so ziemlich jeden laufenden Dienst abgeschossen. Nicht nur Routing, sondern auch die Nutzerverwaltung, die Hardware Treiber etc. pp.

Das ist ein KO-Kriterium. Eigentlich müsste ich hier sofort aufhören zu evaluieren.

Zum Glück starten alle Services von alleine neu und ich kann Screenshots für den Blog machen.

IPv6 teste ich nicht mehr.

Es wird ja viel über Quantenkommunikation in Weitverkehrsnetzen geredet, aber was Quantenmechanik für die Netzwerker real bedeutet, bleibt unklar. Dabei kennen die Netzwerker der Welt makroskopische Quantenphänomene aus erster Hand.

1280px-Schroedingers_cat_film_copenhagen.svg

Von Christian Schirm - Eigenes Werk, CC0, https://commons.wikimedia.org/w/index.php?curid=68587012

Eine Interpretation der Quantenmechanik beschreibt die Verschränkung verschiedener Zustände und die bei der Messung auf den gerade gemessenen Zustand kollabieren. Im Kern besagt diese Interpretation, dass unmittelbar nach der Messung das System im ermittelten Zustand ist. Es sagt nichts darüber aus, wie sich das System weiter entwickeln wird.

Netzwerker kennen das Problem beim Einkauf von Leitungswegen:

  • Die Enden der Leitung sind Vertragsbestandteil und damit feste Randbedingungen. Der Weg, den die Leitung nehmen wird, ist unbekannt.
  • Es ist zwar möglich einen bestimmten Leitungsweg vorzugeben oder sich zusichern zu lassen. Jedoch behält sich der Betreiber vor, im Fall von Störungen oder anderen Schwierigkeiten, den Leitungsweg zu ändern.
  • Wo genau eine Leitung lang geht, erfährt man nur dann, wenn von einer (Bagger-)Störung betroffen ist.

Insofern ist jeder zugekaufte Leitungsweg ein makroskopischer Quanteneffekt:

  • Das Messwerkzeug Bagger ermittelt den Ort einer Leitung zum Zeitpunkt der Messung.
  • Mit Eintreten des Baggerschadens ist der Ort der Leitung sicher bestimmt.
  • Bei der Behebung des Schadens wird ein neuer Funktionszustand erreicht, der möglicherweise als als Reparatur am Ort oder durch Verlagerung des Leitungswegs realisiert wurde.
  • Der neue Leitungsweg ist somit wiederum ein neuer makroskopischer Quantenzustand.

Die deutsche Wirtschaft besteht hauptsächlich aus kleinen, spezialisieren Unternehmen. Die meisten von ihnen haben nichts mit IT am Hut, brauchen es aber trotzdem. Also holen sie sich einen Bekannten als Dienstleister bis irgendwann mal aufgeräumt werden muss.

Der Auftrag

Ein typisches 10-Personen-Unternehmen wendet sich an uns, weil ein Bekannter uns empfahl.

Die Firma gibt es schon lange, hat in diese Gegend hier expandiert und nun diesen Teil abgespalten. Dieser Teil braucht also neue, eigenständige IT. Der Auftrag besteht darin, herauszubekommen, welche Dienste die Ex-Abteilung überhaupt benötigt, wo die bisher betrieben wurden und wie man die separiert. Natürlich muss die Umstellung im laufenden Betrieb stattfinden.

So weit, so gut.

Dass zu den meisten Dienstleistungen – weil bisher intern – keine Verträge existieren, ist nachvollziehbar. Dass die Mitarbeiter nur ihre Arbeit machen, so wie man es ihnen gesagt hat, ist nachvollziehbar. Dass bei der Hauptfirma keiner weiß, welche Dienste existieren und welche Verträge bestehen, ist schwierig aber eben auch nicht zu ändern. Dass die bisherigen Dienstleister nicht zwingend Lust haben zu helfen, ist nachvollziehbar.

Kurz und gut, der Auftrag besteht mehr aus Unternehmensberatung als aus Technik. Es gelingt, über mehrere Monate hinweg, Daten zu verlagern, Dienste wie Steuerbüro, Bank, Dokumentenverwaltung, E-Mails, Webauftritt neu aufzusetzen.

Branchensoftware

Was sich als wirklich schwierig gestaltet, ist die eingesetzte Branchenlösung.

Selbstverständlich gibt es online so gut wie keine Dokumentation, denn die Lösung wurde von einem anderen KMU entwickelt und ist nur regional von Bedeutung. Sie ist aber groß genug, um die Abwicklung ausschließlich über Partner (Systemhäuser) zu realisieren.

Selbstverständlich ist jede Installation eine individuell angepasste Vor-Ort-Installation, für die der Hersteller weder Auskunft gibt, noch davon Kenntnis hat. Die klassische Antwort ist da in der Regel: Diese Version ist völlig veraltet.

Es stellt sich heraus, dass die Mitarbeiter über ein VPN auf einem Terminalserver an einem anderen Firmenstandort arbeiten. Leider kann niemand etwas zu dem Server und der dortigen Software sagen. Der betreffende Mitarbeitet ist schon länger nicht mehr angestellt.

Bei einem Vor-Ort-Termin bekommen wir heraus, dass die Software offenbar nur ein Frontend ist, die ihrerseits ein Backend anspricht. Wo dieses Backend steht, weiß keiner.

Die Backend-IP führt zu einem Systemhaus in der Nachbarstadt. Dort weiß man zunächst nichts von dem Kunden oder gar einem Serverbetrieb. Mehr aus Neugier folgt man unseren Angaben und meldet zurück: Endlich wissen wir, was diese Maschine da soll. Wir konnten die bisher nicht zuordnen. Übernehmen Sie die?

Selbstverständlich gibt es weder Vertrag zwischen Firma und Systemhaus, noch irgendwelche Zahlungen, wobei man bei letztem allgemein unsicher ist.

Technik

Was dann bei uns ankam, waren drei Geräte.

Man sagte uns, ein Server habe viele Festplatten und sei echt schwer. Es steht APC drauf. Sie haben also die USV mit ausgebaut und versendet.

Ein Server ist ein Tower, der andere im 19" Einbaurahmen. Mal sehen, was da drauf ist.

Ja, die Erwartungen an das heutige Internet haben sich gewandelt. Es ist nicht mehr die vorgeblich heile Welt, in der man vertrauensvoll mit anderen kommunizieren konnte. Jeder Dienstleister, sei es die besuchte Webseite oder der eigne Provider, wird argwöhnisch unter die Lupe genommen. Über all diesem steht die Furcht vor der Politik, dem Staat und den Geheimdiensten.

Lauscher

Es ist nur vernünftig, nicht zu gutgläubig im Netz unterwegs zu sein. Man kann seine E-Mails verschlüsseln (und macht es doch nicht), man kann darauf achten, Webseiten nur über verschlüsseltes HTTPS zu besuchen, man kann SSH und viele andere verschlüsselte Protokolle nutzen. Alle diese Methoden schützen vor dem Ausspionieren auf dem Transportweg.

Aber sie tun es nicht vollständig. Immer noch kann man erkennen, wer mit wem wie viel Daten austauscht. Um das zu verschleiern, muss man auf TOR-Netzwerke setzen. Eine andere Alternative ist es, sämtliche Nutzungsarten auf wenige große Anbieter zu verteilen. Man geht nicht nur in der Masse unter, sondern läßt den Mitlauscher auch im unklaren über seine detaillierten Aktivitäten.

Wer bin ich?

Trotzdem bleibt ein weiteres Problem: Die Namensauflösung. Wir sind es gewohnt, bei E-Mail-Adressen, URL-Zeilen, Spiele-Servern, ja bei jeder Interaktion mehr oder weniger sprechende Namen zu benutzen. Der Dienst, der die Namen in IP-Adressen der zugehörigen Server umwandelt ist das DNS, das Domain-Name-System.

DNS ist clever konstruiert, es funktioniert wie eine verteilte Datenbank. Die innere Struktur der Namen entspricht Hierarchieebenen, die in unterschiedlicher Verantwortung stehen und von vielen verschiedenen Parteien betrieben wird. Die Delegation reicht bis in die Firma oder den Hobbykeller. Von dort aus wird die ganze Welt mit Auskünften versorgt, falls mal jemand wirklich was mit mir zu tun haben will. Das System stellt die Auskunftsdaten in den Hoheitsbereich des jeweiligen (Web-, Mail-)Server-Betreibers. Die Entscheidung, wer welche Auskunft bekommt, liegt damit praktisch beim Endnutzer. So kann eine Firma beispielsweise intern mehr und andere Dienste betreiben als nach außen sichtbar sein sollen.

Eine weitere clevere Idee ist, die Namensauflösung in spezielle Software, die Resolver, durchzuführen. Alles, was diese Software benötigt, ist ein Internetzugang und eine kleine Anzahl fester Root-Server-Adressen, die zu wirklich jeder Frage eine Antwort kennen (auch wenn diese nur heißt, man möge bitte da drüben nachfragen). Diese Resolver merken sich alle Ergebnisse, die sie im Laufe der Zeit zu Gesicht bekommen und halte sie eine bestimmte (einstellbare) Zeit vor. So können sie viele Anfragen direkt beantworten und belästigen nicht den Rest der Welt. Caching sorgt so dafür, dass die Last der DNS-Quell-Server nicht zu groß wird. Da diese Resolver so wenig Anforderungen stellen, kann und soll praktisch jeder und jedes Gerät einen solchen Resolver betreiben.

Früher waren jedoch nicht alle Geräte so leistungsstark, einen vollen Resolver selbst zu betreiben. Also hat die Firma oder der Provider einen großen, leistungsfähigen zentralen Resolver hingestellt den alle Clients benutzen. Der Caching-Effekt wird durch diese regionale Zentralisierung größer, es werden deutlich weniger Anfragen an die DNS-Quell-Server geschickt.

Fäschungen und Zensur

Das Problem mit dem System ist, dass alle Anfragen unverschlüsselt und unauthentisiert sind. Jeder auf dem Weg kann mitlesen und die Antworten beliebig verändern. Da veränderte Antworten gefährlich sind (Umlenkung der Bankseite zu Phishern), wurde DNSSEC erfunden. Es unterschreibt die DNS-Antworten und verhindert somit eine Manipulation. Wer als Betreiber einer eigenen Zone diese nicht unterschreibt, handelt fahrlässig. Es ist wie der Betrieb eines HTTP-Server ohne HTTPS: Man bringt seine Nutzer und Kunden in Gefahr.

Auch die letzte Meile, also die Verbindung zum zentralen Resolver kann man mit DNSSEC gegen Manipulationen schützen. Alternativ kann man hier auch auf die gehypten Verfahren DNS-over-TLS (DOT) oder DNS-over-HTTPS (DoH) setzen, die zusätzlich die letzte Meile verschlüsseln. Besser ist es aber gleich einen eigenen DNSSEC validierenden Resolver auf dem Endgerät zu betreiben, denn das schützt auch gegen Manipulationen am vorgegeben Resolver selbst. Einige Provider lenken Tippfehler auf eigene Seiten um (NXDOMAIN-Rewriting), das muss man sich ja nicht antun.

Bleibt das Problem, das DNS Anfragen i.d.R. immer den vollen Namen anfragen als z.B. www.heise.de, auch wenn sie sich an einen Root-Server wenden. Die Idee dabei ist, die Antwortzeiten zu verkürzen, wenn der angefragte Server ohnehin schon mehr Details kennt, die er gleich mit schicken kann. Solche zusätzlichen Antworten wurden für Angriffe ausgenutzt, indem der DNS-Server von firma.de bei der Frage nach www.firma.de auch immer gleich noch eine (falsche) Antwort für www.heise.de mitschickte und die Resolver diese treudoof lernten. Mit DNSSEC wird es wieder möglich, diese zusätzlichen Antworten auszuliefern, weil der Resolver sie anhand der Signaturen als valide erkennen kann. Hat man das nicht, muss man mit den Antworten sorgsam umgehen.

Privatsphäre

Das Privacy-Problem ist nun noch anzugehen: Alle Root-Server bekommen die vollen Anfragen zu sehen. Aber auch hier gibt es seit Anbeginn eine Empfehlung: DNS kann Zoneninhalte komplett transferieren. Mit AXFR (Vollabzug) oder IXFR (Änderungen) kann ein Resolver präventiv die komplette Zone ein lernen und braucht nie wieder die Quell-Server mit konkreten Fragen zu belästigen. Die Root-Zone unterstützt das Modell, es ist für jeden Nutzer, der Wert auf Privatsphäre legt, zu empfehlen.

Die meisten Top-Level-Domains unterstützen den Zonentransfer nicht, meist aus markenrechtlichen Überlegungen. Hier würden also zumindest ein Teil der Anfragen aufschlagen. Es gibt seit eingen Jahren jedoch auch Resolver, die gerade bei den TLDs nur nach der delegierten Zone fragen und so die Privatsphäre der Anwender schützen.

Auch für private oder Firmen-Zonen ist ein offenes AXFR meist sinnvoll. Nicht nur, dass man wichtige Server so wesentlich stabiler betreibt, man gestattet so auch seinen Nutzern eine höhere Privatsphäre. Selbstverständlich darf man ins DNS keine ernsthaften Geheimnisse rein schreiben, aber das macht man ja sowieso nicht. Mit beliebig vielen Versuchen kann man die Namen immer automatisiert herausbekommen.

Fazit

Zusammengefasst kann man sagen: DNS ist gereift, es kann mit den Bedrohungen der Überwachung und Zensur umgehen. Alles was man tun muss, ist einen eigenen, validieren Resolver zu betreiben, wenn möglich mit einer Kopie der Root-Zone. Bis auf DNSSEC (gegen Zensur) sind das alles Empfehlungen aus den Frühzeiten des DNS.

Wenn ein Protokoll alt wird, stirbt mangels Nutzung einfach aus. Protokolle wie DNS überleben jedoch, indem sie sich an geänderte Anforderungen anpassen oder flexibel genug eingesetzt werden können.

Mein persönlicher Vorwurf an die Protagonisten von DoH ist folgender: Wer ein verteiltes System zugunsten einer Handvoll großer Anbieter aufgibt, dabei aktive Nutzungsfälle wie Split-DNS sabotiert und auf lokale Validierung verzichtet, der bekommt zentrale Überwachungs- und Zensursysteme. Es ist von einem technischen Redakteur unverantwortlich, seine Leser derartig in die Irre zu führen und sie damit in Gefahr zu bringen.

Das Internet basiert auf zwei grundsätzlichen Prinzipien: Dezentraliät und Interoperabilität. Internet ist das genaue Gegenteil von großen, zentralen Plattformen. Es ist die große, weite Landschaft, nicht der eingezäunte Garten.