Par défaut, la résolution DNS est faite en utilisant la couche transport UDP. J'ai cependant remarqué que sur un certain réseau avec connexion WiFi, cela aboutit souvent à un timeout de 5 secondes avant que la résolution soit automatiquement réessayée, quel que soit les serveurs DNS, y compris le serveur DNS fourni par le modem-routeur ADSL. J'obtenais parfois deux timeout à la suite, si bien que la résolution DNS pouvait prendre 10 secondes! Ce problème est aggravé par le fait que GNU/Linux n'utilise pas de cache DNS local par défaut.
J'ai donc voulu essayer le DNS avec la couche transport TCP. Pour cela, on peut utiliser l'option use-vc, non documentée. Cependant tous les serveurs DNS ne supportent pas TCP, et en particulier, cela ne marchait pas avec le serveur DNS du modem-routeur ou ceux du FAI. Heureusement, cela marche avec Google Public DNS. Voici le fichier /etc/resolv.conf correspondant:
options use-vc
nameserver 8.8.8.8
nameserver 8.8.4.4
Ensuite, on peut vouloir utiliser cette configuration (ou une autre) uniquement sur certains réseaux donnés. Alors que certains outils de gestion réseau permettent de spécifier les serveurs de noms pour des réseaux donnés, je n'ai pas vu de façon de donner des options comme use-vc. Il y a plusieurs solutions alternatives. Sauf mention contraire, on suppose que resolvconf n'est pas utilisé, sinon il peut y avoir des conflits. Même chose pour les caches DNS locaux.
Pour ifupdown et son fichier de configuration /etc/network/interfaces: On peut utiliser une section mapping avec l'outil guessnet (/usr/sbin/guessnet-ifupdown comme script de mapping), par exemple pour tester l'adresse MAC du routeur. Pour les réseaux sélectionnés, on peut générer la configuration /etc/resolv.conf spécifique via une commande up (a.k.a. post-up). Ou si resolvconf est utilisé, dans les cas les plus simples, on peut définir une commande pre-up pour créer le fichier /etc/resolvconf/resolv.conf.d/head contenant la configuration ci-dessus, et une commande down pour enlever cette configuration (pour éviter qu'elle soit réutilisée sur un autre réseau).
Pour wicd et les connexions WiFi: On peut ajouter un script dans le répertoire /etc/wicd/scripts/postconnect. On peut y tester $3, dont la valeur est le BSSID, qui est l'adresse MAC du point d'accès WiFi, typiquement la même que ci-dessus. C'était ce que je faisais initialement (mais j'ai maintenant une meilleure solution, voir plus bas):
#!/bin/sh logger "wicd script postconnect/dns-with-tcp $*" if [ "x$3" = x00:1F:33:89:73:4E ] && [ ! -L /etc/resolv.conf ]; then logger "Google Public DNS with TCP to avoid recurrent timeout" cat > /etc/resolv.conf <<EOF options use-vc nameserver 8.8.8.8 nameserver 8.8.4.4 EOF fi
Note: La fonctionnalité de scripts locaux de wicd pourrait disparaître. C'est pourquoi je n'utilise pas de tels scripts. Leur statut et leur documentation ne sont toujours pas clairs. Voir le bug 537198 de Debian.
Si DHCP est utilisé, comme c'est habituellement le cas: Avec le client DHCP de l'Internet Software Consortium (je n'ai pas essayé d'autres clients DHCP), on peut utiliser un enter hook script pour BOUND. C'est une meilleure solution car le fichier /etc/resolv.conf est normalement recréé ici et un enter hook script est de toute façon nécessaire (voir ci-dessous). Mais l'adresse MAC du routeur n'est pas fournie et elle n'est pas encore dans la table ARP (/proc/net/arp ne contient aucune entrée). De plus, un lookup ARP avec la commande arping échoue. L'idée que j'ai eue à partir de ce message est de pinger le routeur pour remplir la table ARP. C'est un peu plus délicat ici car l'interface n'a pas encore été configurée; on doit donc dire à la commande ping quelle interface utiliser:
ping -n -c 1 -I "$interface" "$new_routers"
Le paquet est perdu, mais ça fait ce que l'on veut. Bon… Cela marchait pour moi en 2015-08, mais en 2016-08, cela ne marche plus. Une solution alternative est de faire ceci dans un exit hook script: un fichier /etc/resolv.conf incorrect va d'abord être créé, mais il va être réécrit dans cet exit hook script, si bien que ce n'est pas vraiment un problème, mais le mieux est de s'assurer que ce script est le premier exit hook script.
Maintenant, pour DHCP (cas habituel), il y a un autre problème: le fichier /etc/resolv.conf est normalement réécrit quand le bail est renouvelé, ce qui signifie que la configuration de l'utilisateur faite ci-dessus est écrasée. Pour le client DHCP de l'Internet Software Consortium, une solution est d'empêcher ceci sur les réseaux concernés en redéfinissant la fonction shell make_resolv_conf
dans un enter hook script pour RENEW.
Voici un exemple de hook script DHCP pour BOUND et RENEW (il est peut-être nécessaire d'ajouter d'autres raisons, mais elles ne se produisent pas chez moi, si bien que je n'ai pas pu les tester), à utiliser à la fois en tant qu'enter hook script et exit hook script. La fonction make_resolv_conf
est exécutée par dhclient-script juste après les enter hook scripts; pour BOUND, quand ce script est exécuté en tant qu'exit hook script, on fait la même chose et on exécute cette fonction.
#!/bin/sh if [ ! -L /etc/resolv.conf ]; then logger "$1 with reason=$reason" # the MAC address of the router mac=00:1f:33:89:73:4e case "$reason" in BOUND) # The ping has an effect to fill the ARP table "/proc/net/arp". # This trick is inspired by: # https://www.debian-fr.org/serveur-dns-timout-resolv-conf-et-dhclient-t24401.html # In 2015-08, this was working as an enter hook, but in 2016-08, # the ping fails (ditto with arping, after trying various options). # So, this script should be used as an exit hook too. ping -n -c 1 -I "$interface" "$new_routers" > /dev/null if grep -i -q $mac /proc/net/arp; then logger "Google Public DNS with TCP to avoid recurrent timeout" make_resolv_conf() { logger "creating /etc/resolv.conf (Google Public DNS with TCP)" cat > /etc/resolv.conf <<EOF options use-vc nameserver 8.8.8.8 nameserver 8.8.4.4 EOF } case $1 in */dhclient-exit-hooks.d/*) make_resolv_conf;; esac fi ;; RENEW) case $1 in */dhclient-enter-hooks.d/*) if grep -i -q $mac /proc/net/arp; then logger "do not overwrite /etc/resolv.conf" make_resolv_conf() { : ; } fi;; esac ;; esac fi
Note: pour le cas RENEW, au lieu de tester l'adresse MAC, on peut aussi tester la présence d'un certain texte dans le fichier /etc/resolv.conf, e.g. do not overwrite on lease renewal
, si un tel texte a été écrit à la création du fichier.