====== 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).