====== std.net.dns ====== DNS (Domain Name System) übersetzt Hostnamen in IP-Adressen und umgekehrt. Die Unit implementiert einen vollständigen DNS-Resolver über UDP mit Unterstützung für alle gängigen Record-Typen: A, AAAA, MX, NS, CNAME, TXT, PTR, SOA, SRV, CAA, DNSKEY und DS. Auflösungen können gegen den System-Resolver, Google Public DNS (8.8.8.8) oder Cloudflare DNS (1.1.1.1) gerichtet werden. Einsatzbereiche sind Domainvalidierung, Mail-Routing (MX-Lookup), Infrastruktur-Abfragen, DNSSEC-Analysen und alle Anwendungen, die Hostnamen selbst auflösen müssen ohne auf libc-Resolver zu setzen. import std.net.dns; import std.alloc; // Der Aufrufer stellt den Ergebnispuffer: 32 Byte Kopf, danach der Datenbereich. var res: int64 := alloc(512); if (DNSResolve("example.com"c as int64, 11, 0x08080808, res)) { DNSPrintIP(DNSResultGetIPv4(res)); } ''DNSResolve'' nimmt **vier** Argumente: Hostname als Adresse, dessen Länge, den DNS-Server als gepackte IPv4-Adresse (''0'' = Voreinstellung) und den Ergebnispuffer. Es gibt keine Fassung mit nur einem Argument. ---- ===== Imports ===== * ''std.net.socket'' * ''std.net.types'' ---- ===== Konstanten ===== ^ Name ^ Typ ^ Wert ^ Sichtbarkeit ^ | ''DNS_QR_QUERY'' | ''int64'' | ''0'' | pub | | ''DNS_QR_RESPONSE'' | ''int64'' | ''1'' | pub | | ''DNS_OPCODE_QUERY'' | ''int64'' | ''0'' | pub | | ''DNS_RD'' | ''int64'' | ''1'' | pub | | ''DNS_RA'' | ''int64'' | ''1'' | pub | | ''DNS_TYPE_A'' | ''int64'' | ''1'' | pub | | ''DNS_TYPE_AAAA'' | ''int64'' | ''28'' | pub | | ''DNS_TYPE_CNAME'' | ''int64'' | ''5'' | pub | | ''DNS_TYPE_MX'' | ''int64'' | ''15'' | pub | | ''DNS_TYPE_TXT'' | ''int64'' | ''16'' | pub | | ''DNS_TYPE_NS'' | ''int64'' | ''2'' | pub | | ''DNS_TYPE_SOA'' | ''int64'' | ''6'' | pub | | ''DNS_TYPE_PTR'' | ''int64'' | ''12'' | pub | | ''DNS_TYPE_SRV'' | ''int64'' | ''33'' | pub | | ''DNS_TYPE_CAA'' | ''int64'' | ''257'' | pub | | ''DNS_TYPE_DS'' | ''int64'' | ''43'' | pub | | ''DNS_TYPE_DNSKEY'' | ''int64'' | ''48'' | pub | | ''DNS_TYPE_ANY'' | ''int64'' | ''255'' | pub | | ''DNS_CLASS_IN'' | ''int64'' | ''1'' | pub | | ''DNS_RCODE_OK'' | ''int64'' | ''0'' | pub | | ''DNS_RCODE_FORMERR'' | ''int64'' | ''1'' | pub | | ''DNS_RCODE_SERVFAIL'' | ''int64'' | ''2'' | pub | | ''DNS_RCODE_NXDOMAIN'' | ''int64'' | ''3'' | pub | | ''DNS_RCODE_NOTIMP'' | ''int64'' | ''4'' | pub | | ''DNS_RCODE_REFUSED'' | ''int64'' | ''5'' | pub | | ''DNS_PORT'' | ''int64'' | ''53'' | pub | | ''DNS_TIMEOUT_SEK'' | ''int64'' | ''2'' | pub | | ''DNS_VERSUCHE'' | ''int64'' | ''3'' | pub | ---- ===== Typen ===== ==== DNSResult (struct) ==== ^ Feld ^ Typ ^ | ''success'' | ''bool'' | | ''recordType'' | ''int64'' | | ''ttl'' | ''int64'' | | ''rcode'' | ''int64'' | | ''dataLen'' | ''int64'' | ---- ===== Funktionen ===== ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''DNSResolve(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | IPv4-Adresse eines Hostnamens auflösen | | ''DNSResolveEx(hostname: int64, hostnameLen: int64, dnsServerIP: int64, queryType: int64, resultPtr: int64): bool'' | pub | DNS-Abfrage für beliebigen Record-Typ | | ''DNSResolveAAAA(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | IPv6-Adresse eines Hostnamens auflösen | | ''DNSResolveAAAAGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | AAAA-Abfrage über Google DNS | | ''DNSResolveAAAACoudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | AAAA-Abfrage über Cloudflare DNS | | ''DNSResolveCNAME(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | CNAME-Record eines Hostnamens auflösen | | ''DNSResolveCNAMEGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | CNAME-Abfrage über Google DNS | | ''DNSResolveCNAMECloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | CNAME-Abfrage über Cloudflare DNS | | ''DNSResolveMX(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | MX-Record einer Domain auflösen | | ''DNSResolveMXGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | MX-Abfrage über Google DNS | | ''DNSResolveMXCloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | MX-Abfrage über Cloudflare DNS | | ''DNSResolveNS(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | NS-Record einer Domain auflösen | | ''DNSResolveNSGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | NS-Abfrage über Google DNS | | ''DNSResolveNSCloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | NS-Abfrage über Cloudflare DNS | | ''DNSResolveTXT(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | TXT-Record einer Domain auflösen | | ''DNSResolveTXTGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | TXT-Abfrage über Google DNS | | ''DNSResolveTXTCloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | TXT-Abfrage über Cloudflare DNS | | ''DNSResolveSOA(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | SOA-Record einer Domain auflösen | | ''DNSResolveSOAGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | SOA-Abfrage über Google DNS | | ''DNSResolveSOACloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | SOA-Abfrage über Cloudflare DNS | | ''DNSResolvePTR(ip: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | Reverse-DNS-Lookup für IP-Adresse | | ''DNSResolvePTRGoogle(ip: int64, resultPtr: int64): bool'' | pub | PTR-Abfrage über Google DNS | | ''DNSResolveSRV(service: int64, serviceLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | SRV-Record eines Dienstes auflösen | | ''DNSResolveSRVGoogle(service: int64, serviceLen: int64, resultPtr: int64): bool'' | pub | SRV-Abfrage über Google DNS | | ''DNSResolveSRVCloudflare(service: int64, serviceLen: int64, resultPtr: int64): bool'' | pub | SRV-Abfrage über Cloudflare DNS | | ''DNSResolveCAA(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | CAA-Record einer Domain auflösen | | ''DNSResolveCAAGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | CAA-Abfrage über Google DNS | | ''DNSResolveDS(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | DNSSEC DS-Record auflösen | | ''DNSResolveDSGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | DS-Abfrage über Google DNS | | ''DNSResolveDNSKEY(hostname: int64, hostnameLen: int64, dnsServerIP: int64, resultPtr: int64): bool'' | pub | DNSKEY-Record einer Domain auflösen | | ''DNSResolveDNSKEYGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | DNSKEY-Abfrage über Google DNS | | ''DNSResolveGoogle(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | A-Record über Google Public DNS auflösen | | ''DNSResolveCloudflare(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | pub | A-Record über Cloudflare DNS auflösen | | ''GetHostByName(hostname: pchar): int64'' | pub | IP-Adresse als int64 zurückgeben; Auflösungsreihenfolge siehe unten | | ''ResolveHost(hostname: int64): IPAddr'' | pub | Hostname zu IPAddr-Struktur auflösen | | ''DNSPrintIP(ip: int64)'' | pub | IPv4-Adresse als Text ausgeben | | ''DNSPrintIPV6(data: int64)'' | pub | IPv6-Adresse als Text ausgeben | | ''DNSResultGetIPv4(resultPtr: int64): int64'' | pub | IPv4-Adresse aus DNS-Ergebnis lesen | | ''DNSResultGetTTL(resultPtr: int64): int64'' | pub | TTL-Wert aus DNS-Ergebnis lesen | | ''DNSResultGetType(resultPtr: int64): int64'' | pub | Record-Typ aus DNS-Ergebnis lesen | | ''DNSResultIsSuccess(resultPtr: int64): bool'' | pub | Erfolg einer DNS-Abfrage prüfen | ---- ===== Wie GetHostByName auflöst ===== Seit **1.0.20A** wird nicht mehr jeder Name über das Netz abgefragt (#1330). Die Reihenfolge: - **literale IPv4** — ''"127.0.0.1"'' wird als Adresse erkannt, nicht als Name abgefragt - **''/etc/hosts''** — damit funktioniert ''"localhost"'' und jeder dort eingetragene Name - **Nameserver aus ''/etc/resolv.conf''** - **Google DNS** als Rückfall import std.net.dns; fn Zeige(name: pchar): void { var ip: int64 := GetHostByName(name); PrintLn(" ", name, " -> ", IntToStr((ip >> 24) & 255), ".", IntToStr((ip >> 16) & 255), ".", IntToStr((ip >> 8) & 255), ".", IntToStr(ip & 255)); } fn main(): int64 { Zeige("127.0.0.1"); Zeige("localhost"); Zeige("example.com"); return 0; } 127.0.0.1 -> 127.0.0.1 localhost -> 127.0.0.1 example.com -> 172.66.147.243 **Für alle Units mit einem ''host''-Parameter heißt das: ''localhost'' und ''127.0.0.1'' funktionieren jetzt** — betrifft unter anderem ''std.db.redis'', ''std.net.imap'', ''smtp'', ''mongo'', ''quic'', ''telnet'', ''ntp'', ''https'', ''rest'' und ''sip''. Frühere Fassungen dieser Seiten schränkten auf „nur öffentlich auflösbare Namen" ein; das gilt nicht mehr. ==== Zeitgrenze und Wiederholungen ==== Eine Anfrage wartet **zwei Sekunden** auf Antwort und wird bis zu **dreimal** gestellt; danach schlägt die Auflösung fehl. Die Werte stehen als ''DNS_TIMEOUT_SEK'' und ''DNS_VERSUCHE'' in der Unit. Bis lyxc 1.1.3B las ''DNSResolve'' die Antwort ohne jede Zeitgrenze: blieb das Paket aus — verworfene Anfrage, Paketverlust, unerreichbarer Server —, kehrte ''GetHostByName'' **nie** zurück ([[https://github.com/SEOLizer/LyX-Compiler/issues/1641|#1641]]). Bei UDP ist genau das der Normalfall, weil es keine Verbindung gibt, die abbricht. Gesetzt wird die Grenze über ''UDPSocketSetRecvTimeout'' aus [[lyx_-_programmiersprache:units:net:socket|std.net.socket]]. > **Zwei Units nehmen weiterhin nur literale IPv4:** ''std.db.postgres'' und ''std.db.mysql'' zerlegen den Host selbst in vier Zahlen und kennen weder ''/etc/hosts'' noch DNS. Dort ist ''"localhost"'' unbrauchbar. ---- ===== Auflösung über den System-Resolver ===== ^ Signatur ^ Beschreibung ^ | ''DNSResolveSystem(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | fragt den in ''/etc/resolv.conf'' eingetragenen Nameserver | | ''DNSResolveSystemEx(hostname: int64, hostnameLen: int64, queryType: int64, resultPtr: int64): bool'' | dasselbe mit wählbarem Record-Typ | Damit muss der Nameserver nicht im Programm stehen — es gilt, was das System vorgibt. **Ohne lesbare ''/etc/resolv.conf'' wird still ''8.8.8.8'' verwendet.** Der Quelltext fällt auf Googles Nameserver zurück, wenn das Parsen kein Ergebnis liefert: var ns: int64 := dns_parse_resolv_conf(); if (ns == 0) { ns := IPPack(8, 8, 8, 8); } Es gibt weder Meldung noch Rückgabewert, an dem sich das erkennen ließe. In abgeschotteten Umgebungen — Container ohne ''/etc/resolv.conf'', chroot, seccomp-beschränkte Prozesse — gehen die Anfragen dann an einen fremden Anbieter, statt zu scheitern. Wer das ausschließen muss, verwendet ''DNSResolve'' mit ausdrücklich angegebenem Server. ---- ===== Zwischenspeicher ===== ^ Signatur ^ Beschreibung ^ | ''DNSResolveWithCache(hostname: int64, hostnameLen: int64, dnsServerIP: int64, queryType: int64, resultPtr: int64): bool'' | wie ''DNSResolveEx'', beantwortet Wiederholungen aber aus dem Zwischenspeicher | | ''DNSCacheClear()'' | Zwischenspeicher leeren | ^ Kenngröße ^ Wert ^ | Plätze | 16 | | Größe je Eintrag | 224 Byte | | Vorgabe-TTL | 300 Sekunden | Die 16 Plätze sind fest vergeben. Wer mehr verschiedene Namen abfragt, verdrängt ältere Einträge — für eine Handvoll wiederkehrender Ziele ist der Zwischenspeicher gedacht, nicht als allgemeiner Resolver-Cache. ---- ===== DNS over HTTPS ===== ^ Signatur ^ Beschreibung ^ | ''DNSResolveDoH(hostname: int64, hostnameLen: int64, resultPtr: int64): bool'' | Auflösung über HTTPS statt über UDP/53 | | ''DNSResolveDoHEx(hostname: int64, hostnameLen: int64, queryType: int64, resultPtr: int64): bool'' | dasselbe mit wählbarem Record-Typ | DoH verpackt die Anfrage in HTTPS. Das verbirgt sie vor Beobachtern auf dem Weg und kommt durch Netze, die UDP/53 sperren — der Anbieter des DoH-Dienstes sieht die Anfragen dafür im Klartext. ---- ===== IPv6 ===== ^ Signatur ^ Beschreibung ^ | ''GetHostByNameV6(hostname: int64, outHi: int64, outLo: int64): bool'' | Namen zu einer AAAA-Adresse auflösen; schreibt zwei ''int64''-Hälften | | ''DNSResultGetIPv6Hi(resultPtr: int64): int64'' | obere 64 Bit der IPv6-Adresse aus dem Ergebnis | | ''DNSResultGetIPv6Lo(resultPtr: int64): int64'' | untere 64 Bit | | ''DNSResolvePtr6(ip6: int64, dnsServerIP: int64, resultPtr: int64): bool'' | Rückwärtsauflösung einer IPv6-Adresse | | ''DNSResolvePtr6Google(ip6: int64, resultPtr: int64): bool'' | dasselbe über Googles Nameserver | | ''DNSResolvePtr6Cloudflare(ip6: int64, resultPtr: int64): bool'' | dasselbe über Cloudflare | | ''TCPConnectHostIPv6(hostname: int64, port: int64): TCPConn'' | AAAA-Auflösung und TCP-Verbindung in einem Schritt | ''outHi'' und ''outLo'' sind **Zeiger auf ''int64''** — die Funktion schreibt dorthin mit ''poke64''. Die 16 Bytes im Ergebnis liegen ab Versatz 40 in Netzwerk-Byte-Order. ''TCPConnectHostIPv6'' ist der kürzeste Weg zu einer IPv6-Verbindung: es nimmt einen nullterminierten Namen und einen Port in Host-Byte-Order und liefert eine fertige ''TCPConn''. Letzte Aktualisierung: 2026-08-19 — Zeitgrenze und Wiederholungen der Auflösung ergänzt ([[https://github.com/SEOLizer/LyX-Compiler/issues/1641|#1641]]). Vorherige Aktualisierung: 2026-08-18 — Kurzbeispiel auf die tatsächliche Signatur berichtigt; die Unit ist seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1608|#1608]] wieder übersetzbar (''pchar''/''int64'' waren nur halb umgestellt, 53 abhängige Dateien betroffen).