DNS und Suchdomains

  • Hallo in die Runde (ja, mich gibt es noch :) ),

    mir ist heute ein sehr verrücktes Verhalten auf einem Server begegnet, welches ich gerne mal mit dem Schwarmwissen hier technisch etwas ausdiskutieren und analysieren wollte.

    Seit einigen Tagen hat sich ein Debian Trixie basierter VPS beschwert, dass dort keine Nextcloud App Updates mehr installiert werden konnten. Beim Downloadversuch des entsprechenden tar-Archivs kam es zu einem TLS Handshake Failure. Der Downloadversuch an dieser Stelle erfolgte über php8.4-curl.

    Zum Debugging habe ich dann mit curl und wget auf der Bash versucht, eben jenes tar-Archiv herunterzuladen, was funktionierte. Danach probierte ich, das ganze auf IPv4 oder IPv6 einzuschränken - das Problem tauchte nur bei IPv6 auf... und ab hier wird es verrückt, da GitHub (wie ihr vielleicht wisst) nur IPv4 anbietet. Allerdings haben sowohl curl, als auch wget auf zwei Cloudflare IPv6 Adressen aufgelöst.

    Wenn ich allerdings github.com gegen die Netcup DNS Server (und auch andere DNS Server) manuell mit dig/host/nslookup aufgelöst habe, dann kam (so wie es auch sein muss), ein NXDOMAIN zurück. Ab dem Punkt habe ich dann langsam an mir selbst gezweifelt, den kompletten Server auf den Kopf gestellt, wenngleich ich wusste, dass da keine Konfiguration sein kann, welche quer schießt, weil alles meinem Standardsetup enspricht und sich weitere Server, die ähnlich aufgesetzt waren, eben nicht so verhalten haben.

    Zur Problemlösung: Nehmen wir mal an, der Hostname des Servers ist srv01 und er hängt unter der Domain example.org - dementsprechend habe ich den FQDN auf srv01.example.org gesetzt und die Suchdomain in der /etc/resolv.conf auf example.org gesetzt. In meinem Falle war die Domain nicht von mir verwaltet, und irgendein spezieller Spezialexperte hat einen Wildcard-Record mit Ziel Cloudflare eingerichtet. Dadurch wurde, nachdem der Request auf den AAAA Record von github.com mit NXDOMAIN beantwortet wurde, anstatt des A Records von github.com der AAAA Record von github.com.example.org aufgelöst.

    Am Ende konnte ich das Problem recht einfach lösen, indem ich den sowieso nicht zwingend benötigten search-Eintrag aus der resolv.conf rausgeschmissen habe.

    Aber ich habe Fragen... einige. Warum verhält sich php8.4-curl eben genau so? Meine Erwartung wäre eine Auflösung in folgender Reihenfolge: AAAA, A, AAAA auf search-Domain, A auf search-Domain

    Und insbesondere - warum verhalten sich curl und wget auf der Bash anders? Dort hatte ich das Verhalten nur, wenn ich explizit den -6 Parameter mitgegeben habe. Ich hätte außerdem erwartet, dass PHP 8.4-curl am Ende nur ein "Frontend" für libcurl ist, gleichermaßen wie die CLI Applikation curl genauso nur ein "Frontend" für libcurl ist, und ich dementsprechend ein einheitliches Verhalten vorfinde - oder habe ich da einen Denkfehler?

    Bin ich mit meiner Erwartungshaltung da alleine oder seht ihr das auch so? Und hat da evtl. jemand tiefergreifendes Wissen, um das Verhalten zu erklären?

    "Denn der radikalste Zweifel ist der Vater der Erkenntnis."

    -Max Weber

  • Wenn ein FQDN auf Cloudflare-IPs auflöst, dann befindet sich der betriebene Server (das "Origin").i.d.R. hinter Cloudflare (Proxy, genannt "Edge")

    Ob der Server IPV4-only ist wäre dabei irrelevant, da das "Edge" IPv4+IPv6 ist, die nachgelagerte Verbindung vom Edge zum Origin wäre dann IPv4-only.

    Die Verbindung vom User/Client zum "Edge" läuft hierbei über Zertifikate von Cloudflare. Vom Edge zum Origin in der Regel dann über eigene (Lets Encrypt,....) oder von Cloudflare bereitgestellten Wildcard-Origin-Zertifikate (die ich auf dem Server nutzen kann)

    Mich hat "löst auf Cloudflare-IPs" sofort getriggert....aber dann wäre das Verhalten überall das selbe....

  • Wenn ein FQDN auf Cloudflare-IPs auflöst, dann befindet sich der betriebene Server (das "Origin").i.d.R. hinter Cloudflare (Proxy, genannt "Edge")

    Ob der Server IPV4-only ist wäre dabei irrelevant, da das "Edge" IPv4+IPv6 ist, die nachgelagerte Verbindung vom Edge zum Origin wäre dann IPv4-only.

    Die Verbindung vom User/Client zum "Edge" läuft hierbei über Zertifikate von Cloudflare. Vom Edge zum Origin in der Regel dann über eigene (Lets Encrypt,....) oder von Cloudflare bereitgestellten Wildcard-Origin-Zertifikate (die ich auf dem Server nutzen kann)

    Mich hat "löst auf Cloudflare-IPs" sofort getriggert....aber dann wäre das Verhalten überall das selbe....

    Da haben wir uns wohl sehr offensichtlich hochgradig missverstanden. Ich weiß durchaus, wie Cloudflare funktioniert, allerdings stehen weder der betroffene Server, noch GitHub, hinter Cloudflare. Das betrifft nur "den Rest" der betroffenen Domain (in meiner Veranschaulichung example.org). Das Verhalten bzgl. HTTPS und TLS ist nachvollziehbar und korrekt, wenn man verstanden hat, was in Puncto DNS passiert - nur, was hinsichtlich DNS nicht funktioniert ist nicht nachvollziehbar.


    Mir wurde per Konversation die Ausgabe eines LLM geschickt, welches generiert hat, dass php-curl wohl abweichend zu curl (konkret unter Debian) und wget nicht den glibc Resolver nutzt, sondern den von c-ares. Konkret soll es wohl so sein, dass NXDOMAIN "Stop" bedeutet und NODATA "Probier es nochmal anders" (der Resolver nutzt dann die Suchdomain) - und der glibc Resolver berücksichtigt das, wohingehen c-ares NXDOMAIN wie NODATA behandelt, wodurch das beschriebene Verhalten entstehen soll.

    Ich hatte noch keine Zeit, das zu validieren. Aber ich werde dieser Annahme auf jeden Fall nochmal nachgehen, da sie das Verhalten auf jeden Fall recht nachvollziehbar erklären würde. Also, es bliebe dann natürlich immer noch die Frage, warum c-ares das so macht (aka was sich die Entwickler dabei dachten), aber das lässt sich dann sicher auch noch herausfinden.

    "Denn der radikalste Zweifel ist der Vater der Erkenntnis."

    -Max Weber

  • Ergebnis: falsches Ziel, TLS-Fehler. das Entfernen des search-Eintrags behebt es.

    Das ist mir durchaus klar. Aber Interessant, den von dir verlinkten Issue habe ich wohl bisher übersehen. Danke für den Hinweis!

    Ich habe das Problem jetzt mal tiefergreifend analysiert und es hat tatsächlich nichts mit irgendwelchen libc's oder libcurl's.

    ArtCore7 Die LLM Ausgabe war eine komplette Halluzination, php-curl nutzt libcurl und damit einhergehend kein c-ares, genauso wie das curl auf der CLI. Generell hat das ganze nichts mir c-ares zu tun, das ist im curl Kontext seit 2010 nicht mehr auf Debian zu finden.

    Generell konnte ich sowohl mit unterschiedlichen Debian (und damit glibc und (lib)curl) Versionen, als auch unterschiedlichen PHP Versionen keine Unterschiede feststellen.

    Das Problem lag tatsächlich in einer Nextcloud eigenen DNS-Middleware, welche explizit den A Record und dann explizit den AAAA Record auflöst. Diese Middleware greift auf dns_get_record von PHP zurück. Zu gut deutsch passiert da das selbe, wie wenn curl oder wget mit -6 aufgerufen wird - AAAA ist NXDOMAIN, also weiter mit dem AAAA Record der Domain + search Domain. Denn wir haben explizit nach AAAA bzw. einer IPv6 Adresse gefragt. Alles verhält sich so, wie es soll. Nur die Nextcloud DnsMiddleware "is a bissl doof".

    Im Endeffekt ist das ganze halt ein Feature von dns_get_record, man kann halt entweder explizit A oder explizit AAAA auflösen, aber nicht den normalen Fallback Mechanismus nutzen. Den gibt es da schlicht und ergreifend nicht.

    Andere Anwendungen bekommen das ja auch hin, aber die werden sicher selbst nochmal die Antworten "sortieren" bzw. priorisieren. Mein dirty Fix, den ich auch im von Morfyum verlinkten Issue vorgeschlagen habe, wäre, das Host Feld der DNS Antwort mit der angefragten Domain zu vergleichen und alles, was nicht gleich ist, zu discarden.

    Ich denke die sauberste Variante wäre es, das ganze irgendwie zu sortieren... aber das ist imho nicht ganz so einfach bzw. würde da einen größeren Change an der Code Base erfordern.

    Achja - falls ihr euch fragt: Warum zum Henker haben die ne eigene DnsMiddleware?! Diese Middleware cached die DNS Anfragen im Memory Cache (z.B. Redis) - also die Antwort ist in erster Linie: DNS Caching.


    Danke nichtsdestotrotz für eure Ideen, insbesondere an Morfyum für den Issue. :)

    "Denn der radikalste Zweifel ist der Vater der Erkenntnis."

    -Max Weber

  • Wegen dem wollte ich den LLM Response auch nicht hier posten, da ohne eigener Prüfung eben genau zu so was kommen kann. Fande die Antwort aber erstmal logisch. Was doch noch selbst verifiziert werden muss, dazu hat die Z3it gefehlt :*