Zum Hauptinhalt springen

7. Resolver Implementation (Resolver-Implementierung)

Die obersten Ebenen des empfohlenen Resolver-Algorithmus werden in RFC-1034 diskutiert. Dieser Abschnitt behandelt Implementierungsdetails unter der Annahme der im Nameserver-Implementierungsabschnitt dieses Memos vorgeschlagenen Datenbankstruktur.


7.1. Transforming a User Request into a Query (Transformation einer Benutzeranfrage in eine Abfrage)

Der erste Schritt, den ein Resolver unternimmt, ist die Transformation der Anfrage des Clients, die in einem für das lokale Betriebssystem geeigneten Format angegeben ist, in eine Suchspezifikation für RRs bei einem bestimmten Namen, die einem bestimmten QTYPE und QCLASS entsprechen.

Richtlinien für Abfragespezifikationen

Präferenz für einzelnen Typ und Klasse: Wo möglich, sollten (SHOULD) QTYPE und QCLASS einem einzelnen Typ und einer einzelnen Klasse entsprechen, da dies die Verwendung zwischengespeicherter Daten viel einfacher macht.

Grund: Das Vorhandensein von Daten eines Typs in einem Cache bestätigt nicht die Existenz oder Nichtexistenz von Daten anderer Typen. Daher ist die einzige Möglichkeit, sicher zu sein, eine autoritative Quelle zu konsultieren.

QCLASS=* Einschränkung: Wenn QCLASS=* verwendet wird, sind autoritative Antworten nicht verfügbar.

Anfragezustandsinformationen

Da ein Resolver in der Lage sein muss, mehrere Anfragen zu multiplexen, wenn er seine Funktion effizient erfüllen soll, wird jede ausstehende Anfrage normalerweise in einem Block von Zustandsinformationen dargestellt.

Dieser Zustandsblock enthält typischerweise:

1. Zeitstempel (Timestamp)

Zweck: Angabe der Zeit, zu der die Anfrage begann.

Verwendung:

  • Der Zeitstempel wird verwendet, um zu entscheiden, ob RRs in der Datenbank verwendet werden können oder veraltet sind
  • Dieser Zeitstempel verwendet das zuvor diskutierte absolute Zeitformat für die RR-Speicherung in Zonen und Caches

TTL-Interpretation:

  • Wenn der TTL eines RR eine relative Zeit anzeigt, muss der RR rechtzeitig sein, da er Teil einer Zone ist
  • Wenn der RR eine absolute Zeit hat, ist er Teil eines Caches, und der TTL des RR wird mit dem Zeitstempel für den Beginn der Anfrage verglichen

Vorteil von Zeitstempeln: Die Verwendung des Zeitstempels ist der Verwendung einer aktuellen Zeit überlegen, da sie es RRs mit TTLs von Null ermöglicht, auf die übliche Weise in den Cache eingegeben zu werden, aber dennoch von der aktuellen Anfrage verwendet zu werden, selbst nach Intervallen von vielen Sekunden aufgrund von Systemlast, Abfrage-Neuübertragungstimeouts usw.

2. Arbeitsbegrenzungsparameter (Work Limitation Parameters)

Zweck: Eine Art von Parametern zur Begrenzung der Arbeitsmenge, die für diese Anfrage ausgeführt wird.

Begründung: Die Arbeitsmenge, die ein Resolver als Antwort auf eine Client-Anfrage ausführt, muss begrenzt werden, um sich zu schützen gegen:

  • Fehler in der Datenbank, wie z.B. zirkuläre CNAME-Referenzen
  • Betriebsprobleme, wie z.B. Netzwerkpartitionierung, die den Resolver daran hindert, auf die benötigten Nameserver zuzugreifen

Implementierung:

  • Während lokale Grenzen für die Anzahl der Male, die ein Resolver eine bestimmte Abfrage an eine bestimmte Nameserver-Adresse neu überträgt, wesentlich sind
  • Der Resolver sollte (SHOULD) einen globalen pro-Anfrage-Zähler haben, um die Arbeit an einer einzelnen Anfrage zu begrenzen
  • Der Zähler sollte (SHOULD) auf einen Anfangswert gesetzt und dekrementiert werden, wenn der Resolver eine Aktion ausführt (Neuübertragungstimeout, Neuübertragung usw.)
  • Wenn der Zähler Null durchläuft, wird die Anfrage mit einem temporären Fehler beendet

Parallele Anfragen: Beachten Sie, dass wenn die Resolver-Struktur es einer Anfrage ermöglicht, andere parallel zu starten, wie z.B. wenn die Notwendigkeit, auf einen Nameserver für eine Anfrage zuzugreifen, eine parallele Auflösung für die Adressen des Nameservers verursacht, die erzeugte Anfrage mit einem niedrigeren Zähler gestartet werden sollte (SHOULD). Dies verhindert, dass zirkuläre Referenzen in der Datenbank eine Kettenreaktion von Resolver-Aktivitäten auslösen.

3. SLIST-Datenstruktur

Die in RFC-1034 diskutierte SLIST-Datenstruktur.

Zweck: Diese Struktur verfolgt den Zustand einer Anfrage, wenn sie auf Antworten von fremden Nameservern warten muss.


7.2. Sending the Queries (Senden der Abfragen)

Wie in RFC-1034 beschrieben, besteht die grundlegende Aufgabe des Resolvers darin, eine Abfrage zu formulieren, die die Anfrage des Clients beantwortet, und diese Abfrage an Nameserver zu richten, die die Informationen bereitstellen können.

Herausforderungen bei der Abfrageformulierung

Der Resolver hat normalerweise nur sehr starke Hinweise darauf, welche Server zu fragen sind, in Form von NS RRs, und muss möglicherweise:

  • Die Abfrage überarbeiten, als Antwort auf CNAMEs
  • Die Menge der Nameserver überarbeiten, die der Resolver abfragt, als Antwort auf Delegierungsantworten, die den Resolver auf Nameserver verweisen, die näher an den gewünschten Informationen sind

Zusätzlich zu den vom Client angeforderten Informationen muss der Resolver möglicherweise seine eigenen Dienste in Anspruch nehmen, um die Adresse der Nameserver zu bestimmen, die er kontaktieren möchte.

Resolver-Modell

Das in diesem Memo verwendete Modell geht davon aus, dass:

  • Der Resolver die Aufmerksamkeit zwischen mehreren Anfragen multiplext, einige vom Client und einige intern generiert
  • Jede Anfrage wird durch einige Zustandsinformationen dargestellt
  • Das gewünschte Verhalten ist, dass der Resolver Abfragen an Nameserver auf eine Weise überträgt, die:
    • Die Wahrscheinlichkeit maximiert, dass die Anfrage beantwortet wird
    • Die Zeit minimiert, die die Anfrage benötigt
    • Übermäßige Übertragungen vermeidet

Schlüsselalgorithmus

Der Schlüsselalgorithmus verwendet die Zustandsinformationen der Anfrage, um:

  • Die nächste zu abfragende Nameserver-Adresse auszuwählen
  • Ein Timeout zu berechnen, das die nächste Aktion verursacht, falls keine Antwort eintrifft

Die nächste Aktion ist normalerweise eine Übertragung an einen anderen Server, kann aber ein temporärer Fehler an den Client sein.

SLIST-Initialisierung

Ausgangspunkt: Der Resolver beginnt immer mit einer Liste von Servernamen, die abgefragt werden sollen (SLIST).

Anfänglicher Inhalt:

  • Diese Liste enthält alle NS RRs, die der nächsten Vorgängerzone entsprechen, die der Resolver kennt
  • Um Startprobleme zu vermeiden, sollte (SHOULD) der Resolver eine Reihe von Standardservern haben, die er abfragt, wenn er keine geeigneten aktuellen NS RRs hat

Adresshinzufügung: Der Resolver fügt dann SLIST alle bekannten Adressen für die Nameserver hinzu und kann parallele Anfragen starten, um die Adressen der Server zu erwerben, wenn der Resolver den Namen, aber keine Adressen für die Nameserver hat.

Historische Informationen

Um die Initialisierung von SLIST abzuschließen, fügt der Resolver alle historischen Informationen, die er hat, an jede Adresse in SLIST an.

Typische historische Daten:

  • Eine Art gewichtete Durchschnitte für die Antwortzeit der Adresse
  • Die Schlagquote der Adresse (d.h., wie oft die Adresse überhaupt auf die Anfrage geantwortet hat)

Wichtige Hinweise:

  • Diese Informationen sollten (SHOULD) auf pro-Adresse-Basis aufbewahrt werden, nicht auf einer pro-Nameserver-Basis, da die Antwortzeit und Schlagquote eines bestimmten Servers von Adresse zu Adresse erheblich variieren können
  • Diese Informationen sind tatsächlich spezifisch für ein Resolver-Adresse / Server-Adresse-Paar, sodass ein Resolver mit mehreren Adressen separate Historien für jede seiner Adressen führen möchte
  • Für Adressen, die keine solche Historie haben: eine erwartete Rundreisezeit von 5-10 Sekunden sollte (SHOULD) der Worst Case sein, mit niedrigeren Schätzungen für dasselbe lokale Netzwerk usw.

Delegierungsbehandlung: Beachten Sie, dass jedes Mal, wenn eine Delegierung befolgt wird, der Resolver-Algorithmus SLIST neu initialisiert.

Serverauswahl und Timeout

Rangfolge: Die Informationen etablieren eine teilweise Rangfolge der verfügbaren Nameserver-Adressen.

Auswahlstrategie: Jedes Mal, wenn eine Adresse ausgewählt wird, sollte (SHOULD) der Zustand geändert werden, um ihre erneute Auswahl zu verhindern, bis alle anderen Adressen versucht wurden.

Timeout-Berechnung: Das Timeout für jede Übertragung sollte (SHOULD) 50-100% größer sein als der durchschnittliche vorhergesagte Wert, um Varianz in der Antwort zu ermöglichen.

Sonderfälle

Bootstrapping-Problem:

  • Der Resolver kann auf eine Situation stoßen, in der keine Adressen für einen der in SLIST benannten Nameserver verfügbar sind und die Server in der Liste genau diejenigen sind, die normalerweise verwendet würden, um ihre eigenen Adressen nachzuschlagen
  • Diese Situation tritt typischerweise auf, wenn die Glue-Adress-RRs eine kleinere TTL haben als die NS RRs, die die Delegierung markieren, oder wenn der Resolver das Ergebnis einer NS-Suche zwischenspeichert
  • Der Resolver sollte (SHOULD) diese Bedingung erkennen und die Suche bei der nächsten Vorgängerzone oder alternativ bei der Root neu starten

Serverfehler:

  • Wenn ein Resolver einen Serverfehler oder eine andere bizarre Antwort von einem Nameserver erhält, sollte (SHOULD) er ihn aus SLIST entfernen
  • Der Resolver möchte möglicherweise eine sofortige Übertragung an die nächste Kandidaten-Serveradresse planen

7.3. Processing Responses (Verarbeitung von Antworten)

Der erste Schritt bei der Verarbeitung ankommender Antwort-Datagramme ist das Parsen der Antwort.

Antwort-Parsing-Verfahren

Dieses Verfahren sollte (SHOULD) umfassen:

1. Header-Überprüfung:

  • Den Header auf Plausibilität überprüfen
  • Datagramme verwerfen, die Abfragen sind, wenn Antworten erwartet werden

2. Abschnitts-Parsing:

  • Die Abschnitte der Nachricht parsen
  • Sicherstellen, dass alle RRs korrekt formatiert sind

3. TTL-Überprüfung (Optional):

  • Als optionalen Schritt die TTLs der ankommenden Daten überprüfen und nach RRs mit übermäßig langen TTLs suchen
  • Wenn ein RR eine übermäßig lange TTL hat, sagen wir größer als 1 Woche:
    • Entweder die gesamte Antwort verwerfen
    • Oder alle TTLs in der Antwort auf 1 Woche begrenzen

Antwortabgleich

Der nächste Schritt besteht darin, die Antwort mit einer aktuellen Resolver-Anfrage abzugleichen.

Empfohlene Strategie:

  • Einen vorläufigen Abgleich mit dem ID-Feld im Domänen-Header durchführen
  • Dann überprüfen, dass der Frageabschnitt den aktuell gewünschten Informationen entspricht

Implementierungsanforderung: Dies erfordert, dass der Übertragungsalgorithmus mehrere Bits des Domänen-ID-Felds einer Anfrage-ID irgendeiner Art widmet.

Besondere Überlegungen

Quelladressvariante:

  • Einige Nameserver senden ihre Antworten von anderen Adressen als der, die zum Empfangen der Abfrage verwendet wurde
  • Das heißt, ein Resolver kann nicht (CANNOT) darauf vertrauen, dass eine Antwort von derselben Adresse kommt, an die er die entsprechende Abfrage gesendet hat
  • Dieser Nameserver-Bug wird typischerweise in UNIX-Systemen angetroffen

Neuübertragungsbehandlung:

  • Wenn der Resolver eine bestimmte Anfrage an einen Nameserver neu überträgt, sollte (SHOULD) er in der Lage sein, eine Antwort von einer der Übertragungen zu verwenden
  • Wenn er jedoch die Antwort verwendet, um die Rundreisezeit für den Zugriff auf den Nameserver zu erfassen:
    • Muss er in der Lage sein zu bestimmen, welche Übertragung der Antwort entspricht (und Übertragungszeiten für jede ausgehende Nachricht behalten)
    • Oder nur Rundreisezeiten basierend auf anfänglichen Übertragungen berechnen

Fehlende Zonendaten:

  • Ein Nameserver hat gelegentlich keine aktuelle Kopie einer Zone, die er gemäß einigen NS RRs haben sollte
  • Der Resolver sollte (SHOULD) den Nameserver einfach aus der aktuellen SLIST entfernen und fortfahren

7.4. Using the Cache (Verwendung des Caches)

Im Allgemeinen erwarten wir, dass ein Resolver alle Daten zwischenspeichert, die er in Antworten erhält, da sie bei der Beantwortung zukünftiger Client-Anfragen nützlich sein können.

Es gibt jedoch mehrere Arten von Daten, die nicht (SHOULD NOT) zwischengespeichert werden sollten:

Daten, die nicht zwischengespeichert werden sollten

1. Unvollständige Mengen:

  • Wenn mehrere RRs desselben Typs für einen bestimmten Eigentümernamen verfügbar sind, sollte (SHOULD) der Resolver sie alle oder keine von ihnen zwischenspeichern
  • Wenn eine Antwort abgeschnitten ist und ein Resolver nicht weiß, ob er eine vollständige Menge hat, sollte (SHOULD NOT) er keine möglicherweise teilweise Menge von RRs zwischenspeichern

2. Nicht-autoritative Daten über autoritative:

  • Zwischengespeicherte Daten sollten niemals (MUST NOT) anstelle von autoritativen Daten verwendet werden
  • Wenn das Zwischenspeichern dies verursachen würde, sollten (SHOULD NOT) die Daten nicht zwischengespeichert werden

3. Inverse Abfrageergebnisse:

  • Die Ergebnisse einer inversen Abfrage sollten nicht (SHOULD NOT) zwischengespeichert werden

4. Wildcard-Abfrageergebnisse:

  • Die Ergebnisse von Standardabfragen, bei denen der QNAME *-Labels enthält, wenn die Daten zum Konstruieren von Wildcards verwendet werden könnten
  • Grund: Der Cache enthält nicht unbedingt vorhandene RRs oder Zonengrenzinformationen, die notwendig sind, um die Anwendung der Wildcard-RRs einzuschränken

5. Daten zweifelhafter Zuverlässigkeit:

  • RR-Daten in Antworten zweifelhafter Zuverlässigkeit
  • Wenn ein Resolver unaufgeforderte Antworten oder RR-Daten erhält, die nicht angefordert wurden, sollte (SHOULD) er sie verwerfen, ohne sie zwischenzuspeichern
  • Grundlegende Implikation: Alle Plausibilitätsprüfungen an einem Paket sollten (SHOULD) durchgeführt werden, bevor irgendetwas davon zwischengespeichert wird

Cache-Update-Strategie

Wenn ein Resolver eine Menge von RRs für einen Namen in einer Antwort hat und die RRs zwischenspeichern möchte:

  • Sollte (SHOULD) er seinen Cache auf bereits vorhandene RRs überprüfen
  • Je nach Umständen werden entweder die Daten in der Antwort oder im Cache bevorzugt
  • Die beiden sollten niemals kombiniert werden (MUST NOT)
  • Wenn die Daten in der Antwort aus autoritativen Daten im Antwortabschnitt stammen, werden sie immer bevorzugt

Best Practices Summary (Zusammenfassung der Best Practices)

Für effiziente Resolver-Implementierung

  1. Verwenden Sie Abfragen mit einzelnem Typ und Klasse, wenn möglich, für bessere Cache-Nutzung

  2. Halten Sie den Status pro Anfrage einschließlich Zeitstempel und Arbeitszähler

  3. Behalten Sie die Historie pro Adresse für intelligente Serverauswahl

  4. Implementieren Sie geeignete Timeout-Strategien (50-100% über der vorhergesagten Zeit)

  5. Behandeln Sie Sonderfälle wie Bootstrapping-Probleme und Serverfehler

  6. Parsen Sie Antworten sorgfältig mit Header-Überprüfungen und Formatvalidierung

  7. Speichern Sie selektiv zwischen - nicht alle Daten sollten zwischengespeichert werden

  8. Bevorzugen Sie autoritative Daten gegenüber zwischengespeicherten Daten, wenn beide verfügbar sind


Verwandt: Siehe 6. Name Server Implementation (Nameserver-Implementierung) für Serverseiten-Details