GitHub
Prototyppackages/mdns/src

mDNS

@ralphschuler/mdns

Entdeckt Dienste im lokalen Netz über Multicast-DNS und sammelt Antworten nach Name und Record-Typ.

multicastDNS-SDLAN discovery

01 · Problem

Wofür braucht man das?

Geräte im selben LAN sollen Dienste finden, ohne einen zentralen DNS-Server oder fest konfigurierte IP-Adressen zu benötigen.

02 · Denkmodell

Das mentale Modell

mDNS ist eine gemeinschaftliche Multicast-Zone. Queries werden nicht wie RPCs korreliert, sondern Antworten für Name und Typ innerhalb eines kurzen Fensters gesammelt.

Im Repository

MDNS registriert lokale Records und versucht Queries über eine erfundene TXT-Query-ID zuzuordnen. Die Antwort echo't diese ID nicht; Abhängigkeit und NodeNext-Imports sind fehlerhaft, sodass das Package nicht baut.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. UDP-Multicast-Socket für Port 5353 öffnen und Response-Listener zuerst registrieren.
  2. Standardkonforme Frage mit Name und Typ senden.
  3. Passende Answer- und Additional-Records während eines Sammelfensters erfassen.
  4. Records normalisieren und deduplizieren, danach Listener und Timer entfernen.
  5. Beim Shutdown alle ausstehenden Queries abbrechen und Socket schließen.

04 · Bauteile

Die entscheidenden Verträge

MDNS.query(name, type) Soll einen passenden DNSRecord als Promise auflösen.
MDNS.announce(name, type, ttl, data) Registriert im Repository einen Record, sendet aber keine proaktive Announcement-Response.
destroy() Entfernt Listener und zerstört die multicast-dns-Instanz.
DNSRecord / DNSType Typen für A, AAAA, PTR, TXT und SRV ohne vollständig gekoppelte Payloads.

05 · Build it yourself

Selbst implementieren

Verwende das normale DNS-Protokoll und korreliere über Name, Typ und Zeitfenster statt über proprietäre Request-IDs.

  1. Modelliere Record-Typ und Payload als diskriminierte Union.
  2. Registriere Listener vor dem Senden und sammle mehrere Antworten bis zum Timeout.
  3. Bereinige Listener, Timeout und Pending-Promise bei Erfolg, Fehler, Abort und Shutdown.
minimal.ts · unabhängig vom Package
async function query(name: string, type: string, signal: AbortSignal) {
  const answers: unknown[] = [];
  const onResponse = (packet: any) => {
    for (const record of [...packet.answers, ...packet.additionals]) {
      if (record.name === name && (type === "ANY" || record.type === type)) {
        answers.push(record);
      }
    }
  };
  socket.on("response", onResponse);
  try { socket.query({ questions: [{ name, type }] }); await delay(500, signal); }
  finally { socket.off("response", onResponse); }
  return deduplicate(answers);
}

06 · Verifizieren

Was du testen solltest

  • Mehrere Antworten, Duplikate und fremde Name/Typ-Kombinationen werden korrekt behandelt.
  • Timeout, Abort und destroy entfernen Listener und settle'n jedes Promise genau einmal.
  • PTR, SRV, TXT, A und AAAA behalten jeweils die richtige Datenform.

07 · Grenzen

Kompromisse und Stolperfallen

  • mDNS funktioniert nur innerhalb einer Multicast-Domain und ist kein Internet-Service-Discovery.
  • Antworten sind untrusted; Service-Metadaten beweisen keine Identität.
  • Betriebssysteme und Netzwerke können Multicast filtern oder bündeln.
Wichtig

Ein mDNS-Query ist keine 1:1-RPC-Anfrage. Mehrere Geräte dürfen gleichzeitig und verzögert antworten.

08 · Weiterdenken

Quellcode und Nachbarn

Originalcode auf GitHub ansehen