9.15. Noms et DNS¶
Chaque page jusqu’ici a utilisé des adresses IP numériques – 192.168.1.20 et autres. Les applications réelles ne le font presque jamais. Les serveurs sont nommés example.com ou api.example.com, et l’application recherche le nom à l’exécution pour trouver une IP à laquelle envoyer des paquets. Cette recherche, c’est le Domain Name System, ou DNS.
9.15.1. Ce à quoi un nom se résout¶
Un nom n’est qu’une étiquette. example.com ne porte en lui-même aucune information d’IP – il doit être recherché, de la même manière qu’un numéro de téléphone est recherché dans un annuaire. L’infrastructure DNS est l’annuaire distribué de l’internet, et le résultat d’une recherche est une ou plusieurs adresses IP auxquelles la caméra peut se connecter.
example.com -> 93.184.216.34
Un même nom se résout souvent en plusieurs adresses (pour la répartition de charge, la redondance géographique, les versions IPv4 et IPv6 du même service). N’importe laquelle convient ; l’application en choisit une et l’essaie, en se rabattant sur la suivante en cas d’échec.
9.15.2. Comment se déroule la recherche¶
Lorsque la caméra demande example.com :
La caméra envoie un petit datagramme UDP (oui, UDP – voir UDP – envoyer un paquet et espérer pour le mieux) à son serveur DNS configuré. L’adresse du serveur DNS provient du même échange DHCP qui a attribué à la caméra sa propre IP.
Le serveur DNS peut déjà avoir la réponse en cache (on la lui a demandée récemment). Si c’est le cas, il répond immédiatement.
Sinon, le serveur DNS parcourt la hiérarchie DNS globale : interroger les serveurs racine à propos de
.com, interroger ces serveurs à propos deexample.com, interroger ces serveurs à propos du nom. Tout ce parcours de l’arbre est caché à la caméra ; la caméra ne voit qu’une requête et une réponse.Le serveur DNS met le résultat en cache pour la prochaine fois et renvoie la réponse à la caméra sous forme d’un autre datagramme UDP.
L’échange complet prend généralement quelques millisecondes avec un cache chaud, et jusqu’à une centaine avec un cache froid.
9.15.3. L’interface Python¶
La fonction getaddrinfo() effectue la recherche et renvoie une adresse prête à être passée à un constructeur de socket:
import socket
addr = socket.getaddrinfo("example.com", 80)[0][-1]
print(addr)
# ('93.184.216.34', 80)
La signature est getaddrinfo(host, port). La valeur de retour est une liste de quintuplets (un par adresse résolue) ; le [0] choisit le premier et le [-1] choisit le dernier champ, qui est le tuple (ip, port) que l’on peut transmettre directement à une socket:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(socket.getaddrinfo("example.com", 80)[0][-1])
s.send(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
...
La plupart du code de caméra qui communique avec un serveur distant commence par cette unique ligne. Les utilitaires asyncio (asyncio.open_connection()) effectuent la recherche en interne si un nom est passé au lieu d’une IP numérique, de sorte que le code asynchrone n’appelle généralement pas getaddrinfo() directement.
9.15.4. Ce qui peut mal se passer¶
Aucun serveur DNS joignable. Si le Wi-Fi vient de monter et que la liaison est instable, le premier appel à
getaddrinfo()peut expirer. UneOSErrorest levée ; réessayez une fois la liaison stable.Le nom n’existe pas. Une faute de frappe ou un nom obsolète lève une
OSErroraprès que le serveur DNS a renvoyé « nom inexistant ». Le code d’erreur distingue ce cas de « serveur DNS injoignable », mais pour la plupart des applications de caméra la politique de réessai/abandon est la même.L’adresse renvoyée ne fonctionne pas. Le DNS peut renvoyer une adresse qui n’héberge plus le service. La solution consiste à se rabattre sur l’entrée suivante de la liste de résultats de
getaddrinfo(), ou à rechercher le nom à nouveau plus tard (le cache DNS aura probablement été mis à jour d’ici là).Portails captifs. Certains réseaux Wi-Fi interceptent le DNS et renvoient l’IP de la page du portail captif pour tout. La caméra semblera se connecter, mais les données qu’elle recevra en retour ne correspondront pas à ce que le service réel enverrait. Peu courant dans les environnements déployés, mais cela arrive sur le Wi-Fi des conférences et les réseaux similaires.
9.15.5. Le nom propre de la caméra¶
Les pages précédentes ont recherché les noms d”autres appareils. La caméra possède elle aussi un nom qui lui est propre et qu’elle annonce au réseau local lorsqu’elle demande une adresse. Par défaut, c’est un identifiant générique qui varie selon la carte ; network.hostname() le remplace par quelque chose que le reste du réseau reconnaîtra:
import network
network.hostname("kitchen-cam")
# ... then bring the link up as usual ...
Définissez le nom d’hôte avant d’activer l’interface, afin que le nom parte dans la demande d’adresse initiale de la caméra plutôt qu’après.
Deux choses se produisent désormais une fois que la caméra a rejoint le réseau. Premièrement, la plupart des routeurs domestiques enregistrent les noms d’hôte des appareils auxquels ils attribuent des adresses dans leur propre annuaire local, de sorte que d’autres appareils peuvent joindre la caméra sous le nom kitchen-cam – sans avoir à connaître l’adresse numérique que le routeur a attribuée. (Les réseaux d’entreprise peuvent ou non respecter cela ; le comportement dépend du routeur.) Deuxièmement, la caméra exécute elle-même un répondeur mDNS prêt à l’emploi, de sorte que le même nom est également joignable sous kitchen-cam.local sur tout réseau dont les clients comprennent le mDNS – ce que font la plupart des systèmes d’exploitation de bureau modernes.
Note
Passez le nom d’hôte brut à network.hostname() – simplement "kitchen-cam", sans suffixe .local. La forme .local est ce que le mDNS ajoute au moment de la recherche ; l’intégrer dans le nom d’hôte fait que la caméra annonce kitchen-cam.local comme un nom d’hôte ordinaire, ce qui n’est attendu par aucune des deux extrémités de la recherche.
9.15.6. Quand les noms ne suffisent pas¶
Quelques situations dans lesquelles le DNS n’aide pas :
Découverte sur le réseau local. Le DNS standard répond aux questions sur les noms enregistrés dans l’annuaire global ; il ne sait rien des appareils du segment local. Le Multicast DNS (mDNS) est le système qui comble ce manque. Chaque appareil participant rejoint un groupe multicast spécial sur le réseau local et écoute les requêtes ; lorsqu’un appareil demande un nom se terminant par
.local, l’appareil qui possède ce nom répond directement. Aucun serveur central, aucune configuration DNS. Bonjour sur les appareils Apple, Avahi sous Linux et Windows 10+ parlent tous le même protocole – c’est pourquoi le nomkitchen-cam.localconfiguré dans la section précédente se résout sur un réseau domestique sans rien de plus à configurer.Le côté de cet échange assuré par la caméra est le répondeur, et il fonctionne déjà. Ce dont la caméra ne dispose pas, c’est d’un résolveur – l’autre moitié, qui permettrait à un script de demander au réseau « où est
printer.local? » et d’obtenir une réponse. Le code mDNS fourni est uniquement répondeur (les appareils embarqués sont généralement la chose que l’on cherche, et non celle qui cherche). Lorsque la découverte doit aller dans l’autre sens, la diffusion UDP (voir UDP – envoyer un paquet et espérer pour le mieux) est la réponse la plus simple pour le cas du segment local, ou bien un module purement Python tel que cbrand/micropython-mdns ajoute un résolveur complet.Noms IPv6.
getaddrinfo()renvoie à la fois les résultats IPv4 et IPv6 s’ils sont tous deux disponibles. Choisissez la famille que la socket de l’application peut utiliser.
Pour la plupart du code côté caméra, getaddrinfo tient en une ligne en tête de toute fonction qui ouvre une connexion réseau. Les exemples ailleurs dans cette section qui s’exécutaient contre "192.168.1.20" fonctionneraient tous de la même manière contre un nom public comme "api.example.com" – il suffit de résoudre d’abord.