Ich sehe was, was Du nicht siehst …

Ich sehe was, was Du nicht siehst …

... und das ist ziemlich dumm. Oder doch nicht? Mal wieder Freitag, ein DynDNS2-Protokoll kompatibler Update Client behauptet, er kann die Antwort vom Server nicht verstehen. Es ist also eine gute Zeit, um sich das mal näher anzusehen.

Ok, DynDNS usw. ist genau genommen egal: Letztendlich ist das eine API die via http bzw. https auf irgendeinen Webserver bzw. Webservice zugreift. Die Daten zur Anfrage werden klassischerweise als GET oder POST übermittelt, die Antwort kommt als irgendein ASCII-Text zurück. Reiner Text, XML, JSON - so irgendwas. Unterm Strich: Das ist eine Anfrage an eine Web-API. Reicht für den Moment, kann also auch weit jenseits von DNS-Servern und wechselnden IP-Adressen passieren.

So, und was passiert denn hier jetzt? Der Client behauptet er versteht die Antwort vom Webserver nicht. Per tcpdump oder wireshark einen trace erstellt erhält man den unten gezeigten Screenshot. Das funktioniert übrigends super da DynDNS2 tatsächlich noch http verwendet. Auch wenn viele Implementationen inzwischen https ebenso können - aber halt nun mal nicht alle. Und das ursprüngliche Protokoll war auf "http" festgelegt.

ddclient wireshark

Im Screenshot ist ein Testanfrage. Mit "nohost" als Antwort ist die zwar in einen Fehler gelaufen, macht aber nichts. Deutlich sichtbar ist eine 6 in der Zeile davor, genauso wie eine 0 in der Zeile danach. Der DynDNS-Client erwartet aber direkt "nohost" und keine Zahl. Also ja, nachvollziehbar.

Wobei, das ganze mal in einem normalen Webbrowser geöffnet und mit F12 in die Entwicklertools gewechselt ergibt Folgendes:

Webdevel DynDNS

Ok, das ist jetzt kein "nohost" Fehler sondern eine "nochg" Statusmeldung. Aber egal, der gleiche Server nur ein anderer Client der angefragt hat: Beim Webbrowser fehlen die Zahlen. Richtig spannend: Ein tcpdump von dieser Anfrage: Die Zahlen sind da. Zusammengefasst: Der Webbrowser kommt mit diesen Zahlen zurecht, er schneidet sie heraus bzw. hat sie, wie auch immer, verarbeitet. Der Automat welcher die API kontaktiert hingegen nicht. Seltsam. Oder doch nicht?

Nein, eigentlich nicht. Das ist ein normales Verhalten bei http. Doch der Reihe nach. Da steht als Webserver Apache und dies stimmt auch. Hier passiert folgendes: Wenn man das mod_deflate aktiviert kann der Webserver Inhalte vorm Übertragen komprimieren. Das spart Übertragungsbandbreite, geht allerdings auf CPU-Kosten. Da die letzten Jahre verhältnismäßig gesehen die CPUs immer leistungsfähiger geworden sind gegenüber der verfügbaren Internetbandbreite: Eine leichte Rechnung. Nächster Einschub: Ein Webserver übermittelt im Kopf die Größe der Daten welche er übermittelt. Bei statischen Daten wie zum Beispiel einer ISO-Datei: Einfach im Dateisystem nachgeschaut wie groß die Datei ist und gut. Der Webbrowser dankt es, in dem er beim Download anzeigt, wie viel er bereits übertragen hat. In Relation zur Zeit ergibt das die Downloadgeschwindigkeit, in Relation zu der Datengröße den bereits erreichten Fortschritt in Prozent. Daraus ableiten kann man nun noch die geschätzte Zeit bis zur Fertigstellung des Downloads.

Wie ist das aber bei Inhalten, die dynamisch zur Laufzeit erstellt werden? Da weiß man doch gar nicht, wie groß die letztendlich sind. Den Fall kennt sicherlich auch jeder: Der Browser weiß, wie viel er bereits heruntergeladen hat, nur weiß er nicht wie viel noch kommt und somit auch nicht wie lange dies wohl dauern wird. Wozu die ganze Erklärung? Da der Webserver nicht weiß wie groß die Daten werden hat er als Transfer-Encoding "chunked" gewählt. Also sehr frei übersetzt "gestückelt". Als Trenner in Einzelteile nimmt ein Webserver ein ganz einfaches Maß: Er überträgt Textdaten, also betrachtet er das zeilenweise. Die Zeile "nohost" aus dem Screenshot oben ist nun mal 6 Zeichen lang. Danach folgt noch eine leere Zeile und die ist, oh Wunder, 0 Zeichen lang. Der Webbrowser versteht natürlich chunked encoding und bereitet die Daten bevor er sie anzeigt richtig auf. Ein tcpdump hingegen zeigt die blanken Daten wie sie soeben eben übertragen wurden. Für beide Ansichten gilt somit: Richtig, aus dem jeweiligen Betrachtungswinkel heraus.

Und wie löst man das Ganze? mod_deflate im Apache abschalten? Nein, will man nicht unbedingt. Gibt viele Gründe warum man den behalten sollte. Es gibt allerdings noch einen anderen Weg: chunked encoding kam mit http/1.1, bei http/1.0 gab es das noch nicht. Also folgenden Eintrag in die Apache-Konfig für die API-Datei: "SetEnv downgrade-1.0". Die Direktive macht genau das was sie einem suggeriert: Egal mit welcher Variante vom http-Protokoll die Anfrage rein kommt: tue intern so, als wäre es eine http/1.0 Anfrage. Und da es hier noch kein chunked encoding gab ist der Spuk vorbei. Der client, in diesem Falle ddclient, kann wieder fehlerfrei mit seiner API.

Zusammenfassend betrachtet: Ein Einzelfall? Sicherlich nicht. Warum sonst sollte der apache Webserver die Möglichkeit besitzen intern einen Downgrade des anfragenden Protokolls vorzunehmen. Ich kenne in der Tat noch einige weitere Fälle in dem man dieses Vorgehen verwendet. Somit alles gut, der Freitag ist gerettet, das Problem ist gelöst.

Moment, stopp. Wirklich? Mal ernsthaft bitte! Schau nochmals in den Screenshot vom tcpdump rein. Wenn, wie in diesem Falle, der Client nicht mit den Varianten von möglichen http/1.1-Antworten klar kommt und stattdessen http/1.0 benötigt: Warum gibt er dann wie in der ersten Zeile sichtbar als verwendetes Protokoll http/1.1 an? Mit einem http/1.0 hätte es dieses Problem doch nie gegeben. Chunked encoding gibt es erst seit http/1.1. Es ist leider nun mal so, dass das Problem des Clients auf dem Server einfacher zu beheben ist wie an dem Ort wo es tatsächlich passiert: Im Server war es eine einzelne Zeile in der Konfig. Beim Client müsste man auf keine Ahnung wie vielen Installationen entsprechend nachbessern. Daraus resultierend ist die weit verbreite Meinung, dass der Server schuld sein muss, wenn er mit dem Client nicht richtig kommunizieren kann. Das mag ab und zu sicherlich richtig sein, aber nun mal eben nicht immer. Also behebt man als Admin mal wieder die Fehler der Anderen, obwohl man selbst bis dahin alles komplett richtig gemacht hätte. Ein Einzelfall? Sicherlich nicht ...

 

Kein NXDOMAIN heute: dig vs. FORMERR

Kein NXDOMAIN heute: dig vs. FORMERR

Die gängigen zwei Gründe für einen NXDOMAIN bei einer DNS-Anfrage sind: Vertippt und vergessen. Bei vertippt ist es egal ob dies auf der Client Seite oder in der Zonendatei passiert ist: Vertippt bleibt vertippt. Und vergessen kennt jeder: Es hätte schon längst in der Zonendatei drin stehen sollen. Hätte. Nur was ist wenn man wie beim NXDOMAIN kein Ergebnis bekommt und stattdessen als Status FORMERR?

Ich hatte es bereits neulich schon einmal von einem DNS Problem: "lame server" oder viel Spaß mit DNS. Hier verweigerte ein Server die Antwort obwohl er diese liefern müsste. Nur warum hat er dies getan? Was wäre wenn die Zonendatei und die Konfiguration korrekt wären? Was wäre wenn dieser eine Nameserver anstatt NXDOMAIN dann doch tatsächlich einen FORMERR zurück liefert? Und sogar bei Einträgen die es gibt der FORMERR kommt? Was wäre wenn das Dein DNS-Server wäre und Du jetzt nach der Ursache suchen müsstest?

Da kann man allerdings noch einen oben drauf setzen: Das ist kein generelles Problem, bei vielen funktioniert alles wunderbar. Und auch einschlägige Testtools welche man auf diversen Internetseiten findet liefern das korrekte Ergebnis zurück. Also gut, los geht es. Schauen wir uns das doch nochmals genauer an.

Was wissen wir bereits? Grundsätzlich funktioniert der DNS-Server. Der Fehler ist reproduzierbar und er ist selektiv. Das heißt bei den Personen wo dieses Problem auftritt, tritt es bei jeder DNS-Anfrage auf. Für alle anderen ist alles in bester Ordnung. Somit gibt es zwei Gruppen: Die wo es funktioniert und diejenigen wo es nicht funktioniert. Es gilt also den Unterschied zu suchen. Da für beide Gruppen der Server der gleiche ist muss die Ursache auf dem Client liegen. Irgendwas muss bei der vermeintlich gleichen Frage an den Server unterschiedlich sein. Also fangen wir mal an der Stelle an und betrachten die Frage an den Server genauer.

Zurück an die Konsole

Also gut, es geht darum zu finden was auf Client Seite passiert ist. Somit starte ich mein Werkzeug der Wahl: dig. Schauen wir uns doch mal an was hier zurück kommt:

steffen@gmn:~$ dig <domain>.com @ns1.<domain>.com

; <<>> DiG 9.16.1-Ubuntu <<>> <domain>.com @ns1.<domain>.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: FORMERR, id: 27153
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 247f6f7828e8660c (echoed)
;; QUESTION SECTION:
;<domain>.com. IN A

;; Query time: 204 msec
;; SERVER: 1.2.3.4#53(1.2.3.4)
;; WHEN: Di Jun 16 21:36:49 CEST 2020
;; MSG SIZE rcvd: 55

Grün markiert ist mein eingegebenes Kommando. Rot der FORMERR. Das wissen wir bereits. Aber halt, in der blau markierten Zeile mit Cookie: Da steht echoed in der Klammer, jedoch sollte hier good stehen. Also nochmals die gleiche Anfrage gestellt, dieses mal jedoch mit der zusätzlichen Option +noedns:

steffen@lka:~$ dig <domain>.com @ns1.<domain>.com +noedns

; <<>> DiG 9.16.1-Ubuntu <<>> <domain>.com @ns1.<domain>.com +noedns
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23374
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;<domain>.com. IN A

;; ANSWER SECTION:
<domain>.com. 3600 IN CNAME sub.<domain>.com.

;; Query time: 204 msec
;; SERVER: 1.2.3.4#53(1.2.3.4)
;; WHEN: Di Jun 16 21:36:57 CEST 2020
;; MSG SIZE rcvd: 57

Und siehe an, das hat funktioniert. Dabei wäre es egal ob ich als Option +noedns wie gezeigt oder +nocookie verwendet hätte. Beide Optionen liefern wieder die gewohnten Ergebnisse zurück. Gesucht, gefunden: Der DNS-Server hat ein Problem mit EDNS.

Und nun?

Naja, was kann man tun? Bei mir hier im Netz läuft ein lokaler bind Server fürs DNS Caching. Gemäß Doku kann man hier sagen, dass immer dann wenn er den betroffenen Server kontaktiert werden soll EDNS abschaltet wird:

server <IP address or prefix> { edns no; };

Der Link dazu: https://kb.isc.org/docs/aa-01219. Aber mal ehrlich: Will ich das tun? Nein, dass will ich nicht. Warum sollte ich die Probleme eines Dritten bei mir im DNS Resolver lösen? Hier liegt ja offensichtlich ein Fehler vor der klar wird wenn man z.B. ins RFC 6891, Absatz 6.1.2 schaut:

Any OPTION-CODE values not understood by a responder or requestor MUST be ignored.

Der Link zum RFC: https://tools.ietf.org/html/rfc6891#section-6.1.2. "Must be ignored"... Und was bekomme ich? FORMERR. Also alles andere als ignoriert. Soso...

Nein, dann soll doch lieber der DNS-Server Betreiber die passenden Updates einspielen damit EDNS bzw. die Cookies richtig funktionieren. Ich bin garantiert nicht der einzige mit dem Problem und ich werde es auch sicherlich nicht bleiben. EDNS ist nun mal wichtig für die kommenden DNS Erweiterungen.

Weitere Details zu den DNS Cookies sowie zu EDNS gefällig? Ein sehr guter Ausgangspunkt finde ich ist der DNS Flag Day von 2019: https://dnsflagday.net/2019/. Ebenso interessant dazu ist der ISC EDNS Compliance Test: https://ednscomp.isc.org/. Auch hier finden sich viele praktische Infos rund um das Thema EDNS. Und besonders Schick, deswegen heißt das Ding ja "Konformitätstest": Hier kann man den betroffenen Server testen lassen und bekommt einen ausführlichen Bericht mit vielen weiteren Detailinformationen. Neben dem bereits genannten RFC ist auch dieses hier interessant welches die Cookies nochmals erklärt: https://tools.ietf.org/html/rfc7873#section-2.1.

 

RBLs von Spamhaus: Irgendwie anders herum…

RBLs von Spamhaus: Irgendwie anders herum…

Jeder der eine Emailadresse hat oder sogar einen eigenen Mailserver betreibt weiß es: UCE oder Spam ist einfach nur lästig... Zeit was dagegen zu tun. Blacklists sollen es sein. Dumm nur, wenn die von Spamhaus nicht mag...Doch der Reihe nach, was ist passiert? Folgendes Szenario: Ein kleiner Server steht irgendwo bei einem der großen Hoster im Schrank. Funktioniert alles wunderbar. Nur wenn man eine Testabfrage an Spamhaus senden will passiert rein gar nichts:

# host 2.0.0.127.zen.spamhaus.org d.gns.spamhaus.org
;; connection timed out; no servers could be reached

Hm, seltsam... Eigentlich hat man mit einer anderen Antwort gerechnet. Der gleiche Befehl am heimischen PC oder über eine andere Internetverbindung ausgeführt liefert hingegen das erwartete Ergebnis:

# host 2.0.0.127.zen.spamhaus.org d.gns.spamhaus.org
Using domain server:
Name: d.gns.spamhaus.org
Address: 194.68.44.148#53
Aliases: 

2.0.0.127.zen.spamhaus.org has address 127.0.0.2
2.0.0.127.zen.spamhaus.org has address 127.0.0.10
2.0.0.127.zen.spamhaus.org has address 127.0.0.4

Jetzt wird es seltsam. Also mal das Internet nach Rat gefragt 😉

Ursachensuche

Das war nach kurzer Suche rasch erledigt. Spamhaus sperrt komplette Internetbereiche vorm Zugriff auf Ihre Listen wenn Sie der Meinung sind, dass Server in diesem Segment "böse Dinge" tun. Ich lasse an der Stelle die Links die ich dazu gefunden habe mal weg - denke die haben in dem Artikel nichts zu suchen da unterm Strich jeder Serverhoster von diese Problem betroffen sein könnte. Es sollten sich genügend Erfahrungen von anderen Benutzern vom Internet zu diesem Thema finden lassen. Oder man macht den obigen Schnelltest und überzeugt sich selbst 😉

Erschwerte Rahmenbedingungen

Naja, was wird man wohl tun können bzw. müssen? Also mal der Reihe nach alles durch probiert:

  • host 2.0.0.127.zen.spamhaus.org liefert einen Timeout. Wenn das gleich bei einem neu aufgesetzten Server passiert steht in der resolv.conf wohl noch der bzw. die DNS-Server vom Hoster drin. Dann stehen diese wohl in einem Netzwerksegment das von Spamhaus gesperrt wurde.
  • host 2.0.0.127.zen.spamhaus.org d.gns.spamhaus.org funktioniert ebenfalls nicht? Dann ist von der Sperre auch noch die Adresse des eigenen Rechners betroffen.
  • Naja, man kann ja schnell einen anderen Nameserver benutzen. Gibt ja z.B. die beiden frei erreichbaren von dem großen Suchmaschinenanbieter mit dem großen "G" im Anfang vom Namen: host 2.0.0.127.zen.spamhaus.org 8.8.8.8. Hm, ebenfalls timeout? Die etwa auch gesperrt? Ja, das mag prinzipiell schon sein. Auf der anderen Seite sperren einige Betreiber von DNS-Servern auch den Zugriff auf RBLs über ihre Systeme. So oder so, unterm Strich war das schon wieder nichts. Und auf der anderen Seite: Bei dem Betreiber dieser DNS-Systeme weiß man ja, dass der sein Geld damit verdient, dass er Besucherprofile von einem über die gestellten DNS-Anfragen kreiert. Zusätzlich bleibt hier die spannende Frage ob man das überhaupt so will.

Annäherung an die Lösung

Also muss irgendein DNS-Server her der frei verfügbar ist und idealerweise nichts oder nur kaum etwas protokolliert. Und ideaerweise keine Profile oder sonst was erzeugt. Auch hier sollten sich im Internet Server finden lassen wie z.B. die von DigitalCourage oder OpenDNS. Es gibt mehr davon wie man zunächst vielleicht denken mag mit vielen verschiedenen Beweggründen. Mir soll es reicht sein, ich habe eine Alternative gefunden:

# host 2.0.0.127.zen.spamhaus.org 208.67.222.220
Using domain server:
Name: 208.67.222.220
Address: 208.67.222.220#53
Aliases: 

2.0.0.127.zen.spamhaus.org has address 127.0.0.2
2.0.0.127.zen.spamhaus.org has address 127.0.0.4
2.0.0.127.zen.spamhaus.org has address 127.0.0.10

Und siehe da: Es funktioniert! Ok, jetzt könnte ich diese Server in der resolv.conf meines Linuxservers kurz eintragen. Doch halt, das würde alle DNS-Anfragen über diese Server leiten. Eigentlich schon wieder nicht das was ich haben wollte. Also nochmals anders.

Ein eigener DNS-Server

Genau, das ist doch die Lösung: Ein eigener DNS-Server. Im Caching-Modus. Also übers Internet nicht erreichbar, nur via localhost und macht für mich meine DNS-Anfragen. Löst diese direkt ohne irgendwelche Abhängigkeiten auf, legt das alles noch im Cache ab. Und, damit Spamhaus funktioniert, eine Forwarding-Zone für zen.spamhaus.org. eingerichtet.

Das kann man mit so gut wie jedem DNS-Server machen. An der Stelle mag ich selbst unbound: Der ist klein, schlank, in allen gängigen Distributionen bereits enthalten und richtig fix konfiguriert. Ok, ggf. muss man sich kurz schlau machen wie man den bei seiner eigenen Distribution letztendlich auch verwendet. Bei einigen wird es reichen die resolv.conf anzupassen, bei ein paar anderen wird man ggf. systemd-resolve vorher noch deaktivieren müssen. Das sollte sich aber im Handbuch bzw. der Paketbeschreibung zu unbound in der jeweiligen Distribution rasch ermitteln lassen.

Nachdem das erledigt ist und erste Testauflösungen via unbound funktionieren wird noch rasch dessen Konfig um diese Zeilen erweitert (die DNS-Server ggf. sinngemäß anpassen):

# Spamhaus
forward-zone:
  name: "zen.spamhaus.org."
  forward-addr: 46.182.19.48	# DigitalCourage
  forward-addr: 208.67.222.220	# OpenDNS
  forward-addr: 208.67.222.222	# OpenDNS

Unbound neugestartet und schon, oh wunder, ist sogar Spamhaus vom eigenen Server aus erreichbar 🙂 Angenehmer Seiteneffekt dieser Lösung: Über die DNS-Server von Dritten laufen nur Teilmengen der eigentlichen Anfrageflut. Für den größten Teil bleibe ich, dank eigenem caching-Proxy, mein eigener Herr.

Wildes Let’s Encrypt

Wildes Let’s Encrypt

Let’s Encrypt Zertifikate sind inzwischen fürs Webhosting weit verbreitet: Die Akzeptanz ist hervorragend, die Erstellung sowie regelmäßigen Verlängerungen sind gut automatisierbar. Außer bei den inzwischen angebotenen Wildcard-Zertifikaten. Hier ist Handarbeit angesagt. Oder doch nicht? (mehr …)