RFC: 1034
Statut : Standard
Retour à l'index français
Les "résolveurs" sont des programmes qui interfacent les applications utilisateur aux serveurs de noms de domaines. Dans le cas le plus simple, un résolveur reçoit une requête provenant d'une application (ex., applications de courrier électronique, TELNET, FTP) sous la forme d'un appel d'une fonction de bibliothèque, d'un appel système etc., et renvoie une information sous une forme compatible avec la représentation locale de données du système.
Le résolveur est situé sur la même machine que l'application recourant à ses services, mais devra par contre consulter des serveurs de noms de domaines sur d'autres hôtes. Comme un résolveur peut avoir besoin de contacter plusieurs serveurs de noms, ou à l'extrême inverse obtenir les informations directement à partir de son cache local, le temps de réponse d'un résolveur peut varier selon de grandes proportions, depuis quelques millisecondes à plusieurs secondes.
L'une des raisons les plus importantes qui justifient l'existence des résolveurs est d'éliminer le temps d'acheminement de l'information depuis le réseau, et de décharger simultanément les serveurs de noms, en répondant à partir des données cachées en local. Il en résulte qu'un cache partagé entre plusieurs processus, utilisateurs, machines, etc., sera incomparablement plus efficace qu'une cache non partagé.
L'interface client du résolveur est largement dépendante des conventions de l'hôte local, mais on peut exprimer trois fonctions typiques qui rentrent dans le cadre de cette interface :
Cette fonction est souvent définie à l'image d'anciens mécanismes utilisant les fichiers HOSTS.TXT. A partir d'une certaine chaîne de caractères donnée, l'appelant désire obtenir une ou plusieurs adresses IP sur 32 bits. Dans le contexte du DNS, cette demande se traduit par une requête sur des RR de type A. Comme le DNS ne préserve pas l'ordre des RR, cette fonction peut choisir de trier et répondre par toutes les adresses obtenues, ou seulement la "meilleure" adresse si le client est plus enclin à n'accepter qu'une adresse unique en retour. Notez qu'il est recommander d'utiliser un retour multiple, mais un retour d'adresse unique peut dans certains cas être la seule solution pour émuler le fonctionnement d'anciens services basés sur des fichiers HOSTS.TXT.
Cette fonctionnalité suivra souvent dans sa formulation, la forme de fonctions plus anciennes. A partir d'une adresse IP 32 bits, le requérant désire une chaîne de caractères donnant le nom de la machine. Le sens des octets de l'adresse IP sera alors inversé. Les quatre octets ainsi transformés étant alors utilisé comme composante de nom, on les suffixera de la chaîne "IN-ADDR.ARPA". Une requête de type PTR est alors envoyée pour obtenir le RR donnant le nom primaire de l'hôte en question. Par exemple, une requête à propos de la machine d'adresse IP 1.2.3.4 recherchera des RR PTR pour le nom de domaine "4.3.2.1.IN-ADDR.ARPA".
Cette fonction récupère des informations arbitraire à partir du DNS, et n'a pas de fonctionnalité antérieure correspondante. Le requérant fournit un QNAME, QTYPE, et une QCLASS, et désire obtenir tous les RR correspondants. Cette fonction utilisera de préférence la représentation DNS pour toutes les données des RR plutôt que celle de l'hôte local, et retournera le contenu de ces RR (ex., TTL) plutôt qu'une forme traitée selon les conventions locales.
Lorsque le résolveur exécute la fonction, on pourra s'attendre à l'une des réponses suivantes :
Il est important de noter que les fonctions de translation entre des noms d'hôte et des adresses peuvent retourner la combinaison d'une "erreur de nom" et d'une erreur "donnée non trouvée" dans un seul retour d'erreur, alors que la fonction de recherche générale ne le pourra pas. Une raison pour ceci est que les applications peuvent dans un premier temps demander un certain type d'information à propos d'un hôte puis dans une seconde requête un autre type d'information à propos du même hôte ; si les deux erreurs sont combinées, alors les requêtes inutiles ralentiraient l'application.
Lorsqu'il essaie de résoudre une requête particulière, le résolveur peut s'apercevoir que le nom demandé est un alias. Par exemple, le résolveur s'aperçoit que le résultat d'une translation est de ce type lorsque le RR renvoyé est un CNAME. Si possible, ce cas de détection d'un alias devra être signalée au client.
Dans la plupart des cas, un résolveur relancera la résolution sur le nouveau nom translaté donné dans le RR CNAME. Cependant, lors de l'appel à la fonction de recherche généralisée, le résolveur ne suivra pas la chaîne d'alias lorsque le RR CNAME est reçu en réponse à une requête sur ce même type. Ceci permet justement d'émettre des requêtes pour savoir si un alias existe. Autrement dit, si le type de requête demandé est CNAME, l'utilisateur s'intéresse effectivement au RR CNAME en tant que tel, et non l'objet final qu'il représente.
Un certain nombre de conditions spécifiques peuvent apparaître lorsque l'on traite avec des alias. On cherchera à éviter des longues chaînes de redirection par alias, dans la mesure ou cela porte atteinte à l'efficacité du système. Par contre, cette situation ne sera pas signalé comme un cas d'erreur. Inversement, des bouclages d'une chaîne de redirection par alias ainsi que des alias pointant sur des noms inexistants devront être signalés comme erreur, laquelle sera reportée au client.
Concrètement, tous les résolveurs pourront se retrouver occasionnellement dans l'incapacité d'achever une résolution. Cette situation peut apparaître lorsqu'un résolveur perd le contact avec une partie du réseau à cause d'une panne réseau ou d'un routeur, ou, de façon moins courante dans le cas d'une indisponibilité ou défection simultanée de tous les serveurs correspondant à une zone.
Il est essentiel que cette classe d'erreur ne soit pas reportée au client au même titre qu'une erreur de nom ou que d'une erreur sur l'existence des données. Non seulement ce type d'erreur irrite notablement l'utilisateur humain, mais peut aussi causer de sérieux problème lorsqu'une messagerie utilise le DNS.
Il serait possible dans de tels cas d'erreurs de résoudre cette situation momentanée en bloquant la requête indéfiniment, dans l'attente de la levée de la condition de faute. Mais il s'agit d'une mauvaise idée, surtout lorsque le client est un processus serveur qui pourrait exploiter ce temps d'attente à des tƒches bien plus utiles. La solution préconisée est de toujours admettre qu'une erreur "temporaire" puisse être un des résultats possibles de l'appel à une fonction de résolution, même si cela peut rendre l'émulation de certaines fonctions basées sur le principe du HOSTS.TXT plus ardue.
Toutes les implémentations de résolveur utilisent des algorithmes sensiblement différents, et utilisent la plupart de leur code pour traiter les erreurs de toutes natures plutôt que les occurrences "normales". Cette section expose une stratégie recommandée de base pour mener les opérations de résolution, les détails pouvant être trouvés dans la [RFC-1035].
Une possibilité pour l'implémentation de la fonction résolveur est de déporter la fonction de résolution au dehors de la machine locale vers un serveur de noms supportant le mode récursif. Ceci constitue une méthode simple pour offrir le service de de noms de domaines à un PC un peu faible en ressources, et pour centraliser le cache pour l'ensemble des machines et utilisateurs d'un réseau local ou d'une organisation.
Tout ce dont le noyau de résolution minimal à besoin est une liste d'adresses de serveurs de noms susceptible de mener la résolution récursive à notre place. Ce type de résolveur aura certainement besoin de ces informations stockées dans un fichier de configuration, car il n'aura probablement pas la sophistication suffisante pour localiser celle-ci dans la base de données des domaines. De plus, l'utilisateur aura besoin de vérifier que les serveur mentionnés peuvent effectivement fournir le service récursif ; un serveur de noms quel qu'il soit est tout à fait libre de refuser le service récursif à une partie ou la totalité de ses clients. L'utilisateur devra contacter son administrateur local pour savoir quels sont les serveurs qu'il pourra utiliser.
Ce type de service comporte un certain nombre de limites et de défauts. Comme les requêtes peuvent être traitées dans un temps totalement arbitraire, le noyau aura souvent des difficultés à optimiser les temporisations de retransmission de paquets UDP signalant des paquets perdus ou des serveurs défaillants ; le serveur de noms pourra facilement être débordé par un noyau un peu trop zélé, surtout s'il interprète toutes les retransmissions comme des nouvelles requêtes. L'utilisation de TCP pourrait être une réponse à ce problème, mais l'implantation de TCP reviendrait à consommer pratiquement autant de ressources sur l'hôte qu'un résolveur complet.
En plus de ses ressources propres, le résolveur peut aussi disposer d'accès partagés à des données de zones maintenues par un serveur de noms local. Ceci donne au résolveur l'avantage d'un accès plus rapide aux données, mais impose que le résolveur surveille qu'aucune donnée mise en cache ne vienne masquer une donnée pour cette zone. Dans cette partie, nous appellerons "information locale" la réunion des informations contenues dans le cache et celles de la zone partagée, en sous-entendant que les données "autorisées" seront toujours utilisées de préférence à toute donnée du cache lorsque les deux sont présentes simultanément en local.
Les algorithmes de résolution qui suivent supposent que toutes les fonctions ont été exprimées sous forme d'une fonction de recherche généralisée, et utilisent les structures de données suivantes pour représenter la progression de la requête au niveau du résolveur :
SNAME | le nom de domaine sur lequel porte la recherche. |
STYPE | le QTYPE de la requête. |
SCLASS | la QCLASS de la requête. |
SLIST | une structure qui décrit les serveurs de noms et la zone concernée par la requête en cours de traitement par le résolveur. Cette structure garde la trace des serveurs de noms que le résolveur estime actuellement être les plus susceptibles de détenir l'information désirée ; cette trace est remise à jour si l'information arrivant au résolveur est de nature à remettre en cause cette estimation. Cette structure contiendra un champ équivalent à un nom de zone, des champs pour représenter les serveurs de noms identifiés pour cette zone, les adresses de ces derniers, et des informations de type "historique" permettant d'estimer quel est le serveur suivant le mieux placé pour obtenir les informations recherchées. L'équivalent du nom de zone est un décompte du nombre d'identifiants (considérés à partir de la racine) que SNAME a en commun avec la zone objet de la recherche courante ; ceci donne une mesure de la "distance" qui sépare encore le résolveur de SNAME. |
SBELT | une structure "ceinture de sécurité" d'une forme identique à SLIST, initialisée à partir d'un fichier de configuration, et qui liste les serveurs qui devraient être utilisés lorsque le résolveur ne dispose plus ou pas assez d'informations locales pour guider la sélection de serveurs de noms. Le décompte de correspondance sera fixé à -1 pour indiquer qu'aucun des identifiants ne correspond. |
CACHE | une structure qui enregistre les résultats de précédentes réponses. Les résolveurs sont responsables de la purge des RR dont la durée de vie a expiré (dans le cache). La plupart des implémentations convertissent l'intervalle spécifié dans les RR reçus en une sorte de date "absolue" de péremption lorsque le RR est enregistré dans le cache. Plut"t que décrémenter les durées de vie individuellement, le résolveur n'a plus qu'à ignorer ou supprimer les RR "périmés" lorsqu'il les rencontre au cours d'une recherche, ou encore supprimer les RR dont la date de péremption est antérieure à la date courante lors d'opérations temporisées de récupération de mémoire (par destruction des vieux RR). |
L'algorithme de haut niveau contient quatre étapes :
L'étape 1 cherche la donnée désirée dans le cache. Si la donnée y est trouvée, on suppose qu'elle est suffisamment fiable pour une exploitation "normale". Certains résolveurs disposent d'une option configurable par l'utilisateur qui force à ignorer les données du cache et à consulter directement un serveur "autorisé". Ce fonctionnement n'est pas recommandé par défaut. Si le résolveur dispose d'un accès direct à la définition de zone d'un serveur de nom local, il cherchera à établir si les données demandées n'y sont pas présente sous une forme "autorisée". Si oui, on utilisera de préférence les données "autorisées", plutôt que les données trouvées dans le cache.
L'étape 2 recherche auprès de quel serveur de nom l'on va requérir la donnée recherchée. La stratégie usuelle est de chercher d'abord des RR de serveurs de noms disponibles en local, en partant du domaine SNAME, puis le père de SNAME, son grand-père, et ainsi de suite vers la racine. Ainsi, si SNAME était Mockapetris.ISI.EDU, cette étape rechercherait des RR NS pour le domaine Mockapetris.ISI.EDU, puis ISI.EDU, puis EDU, et enfin . (la racine). Ces RR NS donnent la liste des noms des hôtes de la zone co‹ncidant avec ou englobant SNAME. On copie ces noms dans SLIST, puis on détermine leur adresse à l'aide des données locales. Il peut se produire que certaines adresses ne puissent pas être identifiées en local. Le résolveur peut alors adopter plusieurs attitudes ; la plus sage est de "forker" le résolveur pour créer des processus "fils" dont la tƒche sera de récupérer ces adresses, tandis que le père continuera la recherche sur les serveurs dont l'adresse est d'ores et déjà disponible. De façon évidente, les choix et options de design sont assez complexes et largement fonction des possibilités de l'hôte local. Les concepteurs de résolveurs devront considéré les priorités dans l'ordre suivant :
Si la recherche de RR NS échoue, alors le résolveur initialisera la SLIST à partir de la structure SBELT. L'idée de base est que, lorsque le résolveur ne sait pas par où commencer pour rechercher une information, il utilisera une liste prédéfinie dans un fichier de configuration de serveurs supposés pouvoir être utiles. Bien qu'il puisse exister certaines situations particulières, on intégrera usuellement dans cette liste deux serveurs sur la racine et deux serveurs dans la zone où réside l'hôte. Le chiffre de deux (minimum) est donné pour assurer la redondance des données. Les serveurs de la racine pourront permettre un accès éventuel à d'autres parties (en fait, toutes) de l'espace de domaines. Les deux serveurs locaux permettront au résolveur de pouvoir être capable de continuer la résolution de noms locaux, même si le réseau local se retrouve isolé d'Internet suite à la défaillance d'une liaison ou d'un routeur.
En plus de fournir les adresses et noms des serveurs, la structure de données SLIST peut être triée de façon à donner une indication sur le "meilleur" serveur à utiliser, et s'assurer que toutes les adresses et noms de serveurs seront contactés chacun son tour. Le tri peut être une simple fonction de préséance des adresses locale sur les autres, ou peut être une fonction complexe de statistiques sur les événements passés, telle qu'une analyse des temps de réponse moyens et des taux de réussite.
L'étape 3 émet des requêtes jusqu'à ce qu'une réponse soit donnée. La stratégie consiste à utiliser toutes les adresses à tour de r"le, avec une temporisation donnée entre chaque émission. En pratique, il est important d'utiliser toutes les adresses d'un hôte "multiport", sachant qu'une politique de retransmission trop soutenue ralentit la réponse lorsque de multiples résolveurs sont impliqués dans une recherche sur le même serveur de nom (et même parfois pour un seul résolveur). La structure SLIST contient typiquement des données pour contr"ler les temporisations et garder trace des précédentes transmissions.
L'étape 4 s'occupe de l'analyse des réponses. Le résolveur devra faire preuve d'une grande parano‹a dans l'analyse de ces réponses. Il devra en outre que la réponse correspond bien à la requête émise grƒce à la lecture du champ ID dans la réponse. La réponse idéale proviendrait d'un serveur "autorisé" donnant les informations (en général l'adresse) attendues ou encore une erreur de nom. L'information est alors transmise au client et recopiée dans le cache en prévision d'une requête identique future si sa durée de vie (TTL) est supérieure à 0.
Si la réponse indique une redirection à effectuer, le résolveur vérifiera d'abord si le serveur mentionné est plus "proche" de la réponse que les serveurs dont on dispose dans SLIST. Ceci sera fait en comparant le décompte d'identifiants correspondants dans SLIST avec celui obtenu par calcul sur le SNAME dans le RR NS du message de redirection. Si tel n'est pas le cas, la réponse est considérée comme dénuée d'intérêt et sera ignorée. Si la redirection est utilisable, le RR NS de redirection et toute RR d'adresse obtenue pour les serveurs délégués devront être copiés dans le cache. Les serveurs de noms sont ajoutés à la SLIST, et la recherche recommence.
Si la réponse contient un CNAME, la recherche doit être réitérée avec le nom canonique CNAME sauf si la réponse donnée contient déjà l'information pour ce même nom canonique, où si la requête originale portait effectivement sur un CNAME lui-même.
Plus de détails et des astuces d'implémentation peuvent être trouvés dans la [RFC-1035].