Première rédaction de cet article le 12 mars 2013
La vie du programmeur d'applications réseau n'est pas facile. Il a souvent besoin de résoudre des noms en adresses IP. Il existe pour cela des API standards depuis longtemps. Mais elles ne donnent pas toute l'information nécessaire, loin de là. Aura-t-on un jour de meilleures API ?
Le mécanisme normal en C pour résoudre un
nom en adresse est
getaddrinfo()
. (Si vous rencontrez
un programmeur qui utilise encore
gethostbyname()
, euthanasiez-le :
cette fonction, qui était limitée à IPv4, a été
remplacée il y a longtemps.) Dans d'autres langages de programmation,
des fonctions similaires existent, parfois avec le même nom (comme
getaddrinfo()
en Python), parfois sous un autre nom (comme
LookupHost
en Go). Notez que, dans ces langages de plus
haut niveau, on n'a la plupart du temps pas
besoin de faire ces résolutions de noms explicitement. On
appele des fonctions de connexion qui prennent un nom en paramètre
(comme Dial
en
Go).
Ces fonctions ont des limitations communes. D'abord, elles
n'indiquent pas pendant combien de temps l'information est
valable. Or, les adresses IP changent et une application qui
fonctionne longtemps (un navigateur Web, par
exemple), si elle voulait garder en mémoire le résultat de
getaddrinfo()
ne saurait pas pour combien de
temps cela serait possible (si le nom a été trouvé dans le
DNS, getaddrinfo()
ne
permet pas de récupérer le TTL). Résultat,
l'application continue parfois à utiliser une adresse qui n'est plus
valable, phénomène connu sous le nom de pinning
(cf. RFC 5887, par exemple).
Autre limite de getaddrinfo()
et de ses
équivalents, il n'indique pas si la résolution a été sécurisée ou
pas. getaddrinfo()
peut utiliser plusieurs
sources pour faire la résolution : le DNS mais
aussi /etc/hosts
(ou équivalent, pour les
systèmes non-Unix),
LDAP, etc (la liste des sources est
configurable, par exemple sur Ubuntu, c'est
dans /etc/nsswitch.conf
.) Certaines de ces sources
peuvent être considérées comme sûres (/etc/hosts
,
LDAP avec TLS, DNS avec
DNSSEC), d'autres pas (DNS sans DNSSEC, car il
est vulnérable aux attaques par empoisonnement de cache). Mais l'application
qui utilise getaddrinfo()
ne le sait pas !
L'information (pourtant essentielle) sur l'authenticité du résultat
n'est pas renvoyée au programme.
Ce n'est pas tout : une autre limite de ces fonctions de résolution
de noms est qu'elles ne permettent que de trouver une adresse IP en échange
d'un nom. On a souvent besoin de plus d'informations, que l'on trouve
dans le DNS. Par exemple, la plupart des protocoles réseau (mais,
hélas, pas HTTP) permettent de stocker dans le
DNS le nom du serveur qui assure un service pour un domaine donné (ce
qui sépare le nom du domaine de celui du serveur alors qu'en HTTP, le
serveur du domaine example.com
est forcément la
machine example.com
),
avec d'autres indications comme le numéro de
port à utiliser. Cela se fait via les
enregistrements SRV décrits dans le RFC 2782. Ils sont utilisés, par exemple, dans
XMPP. Cela veut dire qu'un logiciel de
messagerie instantanée ne peut pas se contenter
de getaddrinfo()
, il doit faire des requêtes DNS
plus générales. Même cas pour OpenSSH lorsqu'il
cherche des clés publiques dans le DNS (RFC 4255) ou pour un client Web qui veut
trouver les enregistrements DANE (RFC 6698).
Et c'est là que les ennuis commencent : il n'existe pas d'API standard pour cela. (Voir deux questions sur Stack Overflow, « Code to do a direct DNS lookup » ou « Querying full DNS record ».) On ne manque pas de bibliothèques mais aucune n'est standard, obligeant le programmeur à en choisir une et à demander à ceux qui compilent son programme d'installer ladite bibliothèque. En C, on a :
res_query()
, qui font que
certains la considèrent comme la solution standard, malgré ses
difficultés d'utilisation,Et c'est pareil pour tous les langages de programmation par exemple, en Python, il a l'excellente DNSpython mais aussi plusieurs autres bibliothèques. Même chose pour Go qui a godns mais pas du tout de paquetage DNS standard. Et ces trois langages ne sont que des exemples, ce n'est pas mieux pour les autres langages (signalez-moi les langages de programmation ayant une bibliothèque standard permettant de récupérer des enregistrements SSHFP et de vérifier si cela a été obtenu de manière sécurisée).
Bref, avoir une API standard ne serait pas du luxe. Pour C, un nouvel effort est en cours, et fait l'objet d'une campagne de promotion à la réunion IETF d'Orlando : getdns. getdns a tous les services souhaités ici, est conçu pour C (si c'est un succès, son adaptation à d'autres langages viendra peut-être par la suite), n'a pas encore de mise en œuvre et a la particularité que les structures de données, parfois complexes, du DNS, sont modélisées dans un langage très proche de JSON.
Programmeurs d'applications réseau utilisant C, c'est le moment de lire la proposition d'API, et de faire des commentaires !
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)