lalahop

Table des matières

Comme vous le savez si vous suivez ce blog, j'ai installé un résolveur DNS sur mon WRT54GL équipé d'OpenWRT. Néanmoins, je rencontre un souci.

Problème

Dés qu'une déconnexion d'internet survient, dnscache n'est plus en mesure de résoudre les noms de domaine : il tourne encore, mais ne répond plus aux requêtes. Bien sûr, ce comportement est normal durant la coupure mais plus dès que la connexion a été rétablie. Mon routeur obtient son adresse IP WAN auprès de mon modem via le protocole DHCP.

Si vous êtes sur votre LAN quand la déconnexion survient, pas de problèmes : il suffit de se connecter au routeur via SSH et de lancer la commande suivante pour que dnscache reprenne son service :

/etc/init.d/dnscache restart

C'est déjà très ennuyeux de faire cette manipulation à chaque fois, même si on n'a pas non plus une déconnexion du net tous les jours. Mais imaginez maintenant que vous ne soyez pas sur votre LAN et que votre FAI vous attribue une IP dynamique... Hé oui, le plantage de dnscache entraine les scripts de dynamic DNS dans sa chute. En effet, ceux-ci utilisent une résolution DNS pour comparer l'IP attribuée actuellement à l'interface WAN et celle enregistrée dans le nom de domaine afin de la mettre à jour éventuellement. Cela provoque un blocage total : l'IP n'étant plus à jour dans le nom de domaine, vous ne pouvez plus vous connecter à votre routeur depuis l'extérieur.

Chercher une solution à ce problème est sur ma TODO list depuis un moment ... Vous connaissez la suite. Quoi qu'il en soit, je me suis enfin attaqué à ce problème et voici la solution que je vous propose.

Recherche d'une solution

Vous pensez à une cron qui relancerait dnscache à intervalle régulier ? Ce n'est pas une bonne idée : outre les ressources que cela consommerait, cela provoquerait la perte des associations nom de domaine <=> IP enregistré en mémoire et obligerait donc dnscache à refaire les résolutions des noms de domaine que vous avez pourtant déjà demandés. Vous perdrez ainsi un peu de réactivité.

Vous pensez à une cron qui lancerait un script qui vérifierait (avec nslookup ou dig) que le serveur ne répond plus avant de le relancer ? On progresse : vous avez éliminé le problème le plus important. Mais il reste encore le problème des ressources consommé inutilement par chaque vérification.

En fait, ce qu'il nous faudrait, c'est quelque chose qui relance le résolveur dès qu'une déconnexion est détectée. Ha ! On tient une piste. Sur OpenWRT, comme sur d'autres OS, il existe un démon qui est capable d'effectuer des actions dès qu'il capte un événement matériel (un bouton est pressé, un périphérique USB est branché, ...). Il se nomme hotplugd et il est également capable de lancer une action quand une interface réseau est activée (ifpup) ou désactivée (ifdown). "Et alors ?" vous demandez vous. La déconnexion du net provoquera un changement d'IP de l'interface WAN du routeur. Celui-ci est assimilé à une désactivation puis à une activation de la carte réseau. C'est d'ailleurs avec cette méthode qu'est lancé le script pour le dynamic dns (ddns) ou bien encore ntpclient.

Mise en place d'une solution

Vous l'avez compris, il suffit de créer un script qui relance le résolveur dns avec la commande /etc/init.d/dnscache restart dès que le statut de l'interface WAN change.

Deux méthodes sont possibles :

  • On lance la commande /etc/init.d/dnscache restart dès que le statut de l'interface passe à "activée".
  • On lance la commande /etc/init.d/dnscache stop dès que le statut de l'interface WAN devient "désactivée" puis on lance la commande /etc/init.d/dnscache start dès que l'interface WAN est réactivée

Il n'y a probablement aucune différence entre ces deux méthodes. Mais pour ma part, j'ai choisi la deuxième méthode.

Il suffit de placer le script suivant dans le dossier /etc/hotplug.d/iface/ :

#!/bin/sh
 
if [ "$INTERFACE" = "wan" ] 
then
	DNS_RUNNING=`ps  | grep dnscache | grep -v grep`

 
	case "${ACTION:-ifup}" in
        	ifup)
                	[ -z "$DNS_RUNNING" ] && /etc/init.d/dnscache start
       		;;

 
		ifdown)
               		[ -n "$DNS_RUNNING" ] && /etc/init.d/dnscache stop
        	;;

	esac
fi

Ce script est un mélange entre celui proposé par/pour ntpclient et celui proposé par/pour le script ddns.

Lecture : si l'interface ayant provoqué l'appel à ce script est bien l'interface WAN, alors on vérifie que le processus dnscache est bien présent sur la machine. Si l'interface vient de s'activer et que la chaine $DNS_RUNNING est vide (sous-entendu que le processus dnscache n'est pas présent sur le routeur), alors on lance le résolveur DNS. Si l'interface vient d'être désactivée, et que la chaine $DNS_RUNNING n'est pas vide (sous-entendu le processus tourne), alors on stoppe le résolveur DNS.

Quel nom donner à ce script ? Cela dépend de votre configuration. En effet, le nom du script détermine l'ordre dans lequel il sera appelé par hotplugd. Il est nécessaire de relancer le résolveur avant qu'un programme dépendant de lui ne soit relancé. Dans mon cas, ntpclient et ddns ont besoin de lui. ntpclient est relancé vers la fin ("20-ntpclient") et ddns est relancé en dernier ("25-ddns"). C'est pour cela que j'ai appelé mon script "15-dnsd".

Attention à ne pas appeler votre script "15-dnscache" par exemple. Sinon, $DNS_RUNNING contiendra toujours quelque chose puisque la commande "grep dnscache" retournera toujours au moins un élément : votre script. Ainsi, les conditions ne fonctionneront pas et dnscache ne sera pas relancé.

ÉDIT du 11/08/2011 à 23h17 : Le fait d'avoir créé un script pour que le démon hotplug démarre et arrête dnscache en fonction des déconnexions survenant sur l'interface WAN provoque le fait que dnscache sera lancé par hotplug au démarrage du routeur. Mais, étant donné qu'un lien est toujours présent dans le dossier /etc/rc.d, dnscache pourrait être lancé une deuxième fois. En effet, notre script hotplug vérifie que le démon n'est pas déjà lancé mais le script d'init ne le vérifie pas. Il suffit donc que dnscache soit démarré par hotplug puis par init pour risquer de voir apparaître des problèmes. Pour l'instant, je n'ai eu aucun problème mais il vaut mieux prévenir que guérir. Plusieurs solutions sont possibles, la plus simple étant :

/etc/init.d/dnscache disable

Ainsi, dnscache ne sera lancé que par hotplugd.

Fin de l'édit

ÉDIT du 13/08/2011 à 19h30 : Si vous voulez modifier ce script et que vous souhaitez le tester sans provoquer une déconnexion physique de l'interface WAN, vous pouvez simuler l'action de hotplugd de la manière suivante :

~# ACTION=ifdown
~# INTERFACE=wan
~# export ACTION
~# export INTERFACE
~# /bin/sh /etc/hotplug.d/iface/15-dnsd
~# ACTION=ifup
~# /bin/sh /etc/hotplug.d/iface/15-dnsd

Fin de l'édit

Bonus : faire en sorte que dnscache inscrive ses démarrages et ses arrêts dans le journal système

Certains démons (ntpclient par exemple) écrivent des informations dans le journal du système (accessible via la commande "logread" ou depuis l'interface web LuCI ("Status -> Journal système")) afin d'indiquer leur lancement/arrêt. Cela est pratique en cas de problème. dnscache ne fait pas ceci : il affiche un message uniquement lors de son premier lancement par le système. Nous allons remédier à cela.

Pour écrire un message dans le journal système, il suffit d'utiliser la commande "logger". Exemple :

root@OpenWRT:~# logger test de l\'écriture dans le journal système
root@OpenWRT:~# logread
[...]
Aug  8 09:54:04 OpenWRT user.notice root: test de l'écriture dans le journal système

Il suffit donc de modifier le script de démarrage de dnscache (/etc/init.d/dnscache) pour faire inscrire un message dans le journal système.
À la fin de la fonction start(), il suffit de rajouter :

logger starting dnscache

Et à la fin de la fonction stop(), il suffit de rajouter :

logger stopping dnscache

Cette modification m'a été inspirée par le script de démarrage/arrêt de ntpclient.

Enjoy 8)