J’ai depuis quelque temps maintenant un Raspberry pi, qui se trouve chez moi, et sur lequel je souhaite installer un logiciel de backup et d’autres trucs. Il faut donc que mon Raspberry soit accessible depuis internet. Le souci est que je suis chez Orange et j’ai donc une IP dynamique (merci Orange…).
Il existe des sites comme DynDNS ou No-IP qui propose de lier l’IP de votre box à un sous-domaine chez eux afin de connaitre facilement votre IP. Mais je préfère utiliser un système que j’héberge moi-même plutôt que d’utiliser un service tiers. Pour ce faire, je vais créer un sous-domaine, monip.memodugeek.info par exemple, et faire en sorte que mon Raspberry vienne mettre à jour ce nom de domaine pour le faire pointer vers l’IP publique de ma box Orange.
Il faut quand même quelques pré-requis pour cette méthode :
Dans la suite de l’article, je parlerai, pour désigner les machines, de serveur DNS (mon serveur OVH dans mon cas) et de Raspberry (serveur situé derrière ma box Orange).
Commençons par la configuration du Raspberry. Installez les paquets bind9utils et dnsutils
sudo aptitude install bind9utils dnsutils
Comme le Raspberry va devoir communiquer avec le serveur DNS pour mettre à jour le nom de domaine, on va sécuriser cet échange. Pour ce faire, on va utiliser une clé TSIG qui nous servira à générer un HMAC, qui couple une fonction de hachage et une clé secrète afin de vérifier l’intégrité et l’authenticité du message. Pour l’algorithme de hachage, on va utiliser SHA2. On peut utiliser d’autres algorithmes également.
L’utilitaire dnssec-keygen, fournit par Bind, va nous permettre de créer cette clé
dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST iprasp
A la fin de la commande, on indique le nom de clé.
Deux clés ont été générées : Kiprasp.+165+07175.key et Kiprasp.+165+07175.private. Celle qui va surtout nous intéresser est la clé privée. Voici le contenu de la clé :
cat Kiprasp.+165+07175.private Private-key-format: v1.3 Algorithm: 165 (HMAC_SHA512) Key: qIBPc05SV9C6dphFKYWRYop+wRPaA/J1b5Te/Is0HDxYhBpS7qVmDFsDN2W/DeGmCxKnq+nXo+wOoaqJjeywkw== Bits: AAA= Created: 20180523133201 Publish: 20180523133201 Activate: 20180523133201
C’est bien évidemment une clé que j’ai créée uniquement pour les besoins de l’article, il ne faut jamais partager une clé comme je le fais là. Ce qui va nous intéresser est la ligne “Key:”. Copiez la clé dans le presse papier (qIBPc05SV9C6dphFKYWRYop+wRPaA/J1b5Te/Is0HDxYhBpS7qVmDFsDN2W/DeGmCxKnq+nXo+wOoaqJjeywkw== dans notre exemple).
La configuration du Raspberry étant terminée, on va passer à la configuration du serveur DNS.
Créez le fichier /etc/bind/named.conf.keys et ajoutez les lignes suivantes
key iprasp { algorithm HMAC-SHA512; secret "qIBPc05SV9C6dphFKYWRYop+wRPaA/J1b5Te/Is0HDxYhBpS7qVmDFsDN2W/DeGmCxKnq+nXo+wOoaqJjeywkw=="; };
Ces lignes servent à indiquer à Bind, le serveur DNS, la clé à utiliser pour sécuriser les échanges. Après “key” il faut bien évidemment indiquer le nom que vous avez utilisé lors de la génération de la clé TSIG. De même, si vous avez utilisé un autre algorithme que HMAC-SHA512, pensez à le modifier.
Ouvrez le fichier /etc/bind/named.conf.local et ajoutez les lignes suivantes dans la zone souhaitée (memodugeek.info dans notre exemple)
update-policy { grant "iprasp" subdomain monip.memodugeek.info A; };
On indique à Bind, grâce à cette ligne, que toute demande de mise à jour DNS utilisant la clé “iprasp” est autorisée pour le sous-domaine “monip.memodugeek.info” et uniquement ce sous-domaine. Sans la clé TSIG, impossible de mettre à jour ce sous-domaine ou un autre et la clé ne permet de mettre à jour que ce sous-domaine.
Votre zone devrait donc ressembler à ça
zone "memodugeek.info" { type master; allow-transfer {213.186.33.199;}; file "/etc/bind/pri.memodugeek.info"; update-policy { grant "iprasp" subdomain monip.memodugeek.info A; }; };
La ligne “allow-transfer” sert au DNS secondaire et n’a rien à voir avec ce qu’on fait.
Si vous utilisez ISPConfig, la moindre modification de la zone DNS va écraser ce fichier. Malheureusement, ISPConfig ne gère pas “update-policy” mais gère “allow-update” qui permet moins de finesse. Contrairement à “update-policy”, “allow-update” autorise toutes les mise à jour authentifiées avec la clé. Mais au moins vous n’aurez pas besoin de modifier le fichier à chaque changement dans ISPConfig.
Pour configurer ISPConfig, allez dans la zone DNS de votre domaine, et dans le champ “mettre à jour l’ACL” mettre key “nom de la clé”.
Après avoir cliqué sur Enregistrer et attendu qu’ISPConfig mette à jour les fichiers, si vous ouvrez le fichier /etc/bind/named.conf.local, vous devriez avoir ceci :
zone "memodugeek.info" { │ type master; │ allow-transfer {213.186.33.199;}; │ allow-update {key "iprasp";}; │ file "/etc/bind/pri.memodugeek.info"; │ };
Il ne nous reste plus qu’à redémarrer Bind
sudo systemctl restart bind9.service
On n’a plus qu’à tester pour vérifier que ça fonctionne.
Pour mettre à jour le DNS, on va utiliser l’utilitaire nsupdate. Sur le Raspberry, tapez la commande suivante en indiquant votre clé privée à la place de “cléprivée”
nsupdate -k cléprivée
La clé publique (le fichier en .key) doit être situé dans le même dossier.
Ensuite, tapez les commandes suivantes suivies de Entrée
zone memodugeek.info
update add monip.memodugeek.info. 30 A 0.0.0.0
La première ligne sert à indiquer quelle zone DNS on va modifier et la seconde indique qu’on va modifier le sous-domaine monip.memodugeek.info afin de le faire pointer vers l’adresse 0.0.0.0. Évidemment ces lignes sont à modifier en fonction de votre nom de domaine.
Maintenant tapez la commande suivante suivie de Entrée
show
Vous devriez avoir quelque chose de ce type :
> zone memodugeek.info > update add monip.memodugeek.info. 30 A 0.0.0.0 > show Outgoing update query: ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0 ;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 ;; ZONE SECTION: ;memodugeek.info. IN SOA ;; UPDATE SECTION: monip.memodugeek.info. 30 IN A 0.0.0.0
Pour mettre à jour le DNS, tapez la commande suivante suivie de Entrée
send
Si nsupdate vous affiche un message d’erreur, il vous faudra aller éplucher les logs de Bind sur le serveur DNS pour voir où se situe le problème.
Si tout a fonctionné, vous devriez voir ceci dans les logs de Bind sur le serveur DNS:
May 23 16:23:41 ns397819 named[31585]: client 92.167.57.120#58242/key iprasp: updating zone 'memodugeek.info/IN': adding an RR at 'monip.memodugeek.info' A 0.0.0.0 May 23 16:23:41 ns397819 named[31585]: zone memodugeek.info/IN: sending notifies (serial 2018052208)
Et, toujours sur le serveur DNS, lancez la commande suivante
dig +nocmd monip.memodugeek.info +noall +answer
Vous devriez avoir ceci qui s'affiche
rasp.memodugeek.info. 30 IN A 0.0.0.0
Il ne nous reste plus qu’à automatiser tout ça avec un petit script.
Créez le script suivant sur le Raspberry :
#!/bin/bash # Teste si l'IP publique a été modifiée et met à jour l'enregistrement DNS # Utilise la clé TSIG # François Grange 2012 # Modifié par fate 2018 # Inits ADMIN="admin@memodugeek.info" ZONE="memodugeek.info" RR="rasp.$ZONE." TTL=30 LAST_IP="0.0.0.0" LAST_IP_FILE="/home/pi/update_ip/lastip" ERR_FILE="/home/pi/update_ip/dyndns.err" KEY_FILE="/home/pi/update_ip/Kiprasp.+165+07175.private" TMP_FILE="/home/pi/update_ip/dyndns.tmp" CUR_IP=`wget -q -O - memodugeek.info/monip.php` # Fonction de gestion des message d'erreur ou de changement d'IP sortie() { # Si erreur de mise à jour, on envoie un mail indiquant qu'il y a eu une erreur avec le fichier d'erreur en pièce-jointe. if [ $1 -eq 1 ]; then echo "Une erreur est survenue lors de la mise à jour du DNS. Le message d'erreur se trouve en pièce-jointe." | mail -s "Erreur de mise à jour de $RR" -A $ERR_FILE $ADMIN # Si changement d'IP, on envoie un mail avec la nouvelle IP else cat $TMP_FILE | mail -s "Changement d'IP pour $RR La nouvelle IP est $CUR_IP." $ADMIN fi exit } # On supprime l'ancien fichier d'erreur s'il existe if [ -f $ERR_FILE ]; then rm -f $ERR_FILE fi # Si on n'arrive pas à récupérer l'adresse IP publique, on sort en envoyant un mail d'erreur via sortie() if [ "$CUR_IP" = "" ] || [ "$CUR_IP" = "unknown" ]; then echo "Impossible de récupérer l'IP actuelle - Abandon" > $ERR_FILE sortie 1 fi # On récupère la dernière IP connue if [ -f $LAST_IP_FILE ]; then LAST_IP=`cat $LAST_IP_FILE` fi # Si l'adresse a changé, on lance nsupdate en mettant la sortie debug dans le fichier d'erreur. if [ ! "$LAST_IP" = "$CUR_IP" ]; then echo "IP actuelle : $CUR_IP" > $TMP_FILE echo "IP précédente : $LAST_IP" >> $TMP_FILE ( echo "zone $ZONE" echo "update delete $RR A" echo "update add $RR $TTL A $CUR_IP" echo "send" ) | nsupdate -k $KEY_FILE -v -d >/dev/null 2> $ERR_FILE if [ $? -ne 0 ]; then sortie 1 else echo $CUR_IP > $LAST_IP_FILE fi sortie 0 fi
Ce script provient de François Grange, je l’ai juste modifié un peu à ma sauce et l’ai commenté un peu plus, histoire que les néophytes du bash le comprenne.
Tout ce que vous avez besoin de modifier, ce sont les lignes ADMIN, ZONE, RR, LAST_IP_FILE, ERR_FILE, KEY_FILE, TMP_FILE. Voici à quoi correspondent ces variables :
Pour résumer, ce script va récupérer l’adresse IP publique, vérifier si elle est différente de la dernière envoyée au serveur DNS et, si c’est le cas, envoyer la nouvelle IP publique au serveur DNS afin qu’il mette à jour le sous-domaine. Une fois la mise à jour faite avec succès, un mail contenant l’ancienne et la nouvelle IP publique sera envoyé à l’admin. Si la dernière IP envoyée est identique à l’IP publique récupérée, le script se termine sans faire de mise à jour DNS. Si une erreur est détectée lors de la mise à jour, un mail sera envoyé à l’admin avec le fichier d’erreur en pièce jointe.
Pour récupérer l’adresse IP, je passe par un service maison. Je la récupère grâce à une page PHP que j’ai uploadée sur le site et qui contient le code suivant :
<?php print $_SERVER['REMOTE_ADDR'] ?>
Cette page renvoie l’adresse IP publique du PC qui l’affiche. C’est comme ça que je renseigne la variable CUR_IP dans le script avec la commande
wget -q -O - ipv4.memodugeek.info
Vous pouvez soit utiliser la page hébergée sur mon serveur, soit en créer une et l’héberger sur votre serveur. Si vous avez besoin de récupérer l'IP publique IPV6, vous pouvez utiliser la commande suivante
wget -q -O - ipv6.memodugeek.info
On va passer par cron pour lancer automatiquement ce script. Editez cron
crontab -e
Ajoutez la ligne suivante en adaptant le chemin du script
*/10 * * * * /home/pi/update_ip/update_ip.sh
Sauvegardez puis quitter.
Le script va s’exécuter toutes les 10 minutes.
Comme je le disais plus tôt, ce script envoi des mails, il faut donc que votre Raspberry puisse envoyer des mails. Si ce n’est pas le cas, je vous conseille msmtp qui permet d’envoyer des mails en passant par le serveur SMTP de votre choix (le vôtre ou celui de votre FAI par exemple).
Pour l’installer, lancez la commande sudo aptitude install msmtp mailutils mpack . Une fois installé, vous pouvez le configurer en éditant le fichier /etc/msmtprc. Voici à quoi ressemble le mien qui utilise le serveur SMTP installé sur mon serveur OVH :
# Valeurs par défaut pour tous les comptes. defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt #tls_trust_file /etc/letsencrypt/live/rasp.fr/cert.pem logfile ~/.msmtp.log # Exemple account memodugeek.info host memodugeek.info port 587 from rasp@raspberry.fr user identifiantducomptemail password motdepasseducomptemail # Définir le compte par défaut account default : memodugeek.info
J’ai retiré les informations sensibles, mais ça vous permettra de comprendre comment le configurer.
Désormais, votre sous-domaine va pointer vers l’IP publique de votre Raspberry sans que vous ne soyez dépendant d’un service tiers comme no-IP ou dyndns 😉
Sources :
http://tavie.onsenfout.com/2012/04/04/dns-dynamique-securise-avec-nsupdate-et-bind9/
https://jpmens.net/2010/09/28/performing-dynamic-dns-updates-on-your-dns/