====== IP dynamique et DNS ======
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 :
* Un serveur DNS Bind configuré, relié à internet, et étant maître de la zone qui sera modifiée (memodugeek.info dans mon cas). Je vais utiliser mon serveur OVH (sur lequel est hébergé ce site) dans mon cas.
* Un serveur Linux situé derrière la box, qui va récupérer l’IP publique et la transmettre au serveur DNS. Dans mon cas c’est mon Raspberry qui va se charger de ça.
* Avoir un sous-domaine.
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).
===== Configuration du Raspberry =====
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é [[https://fr.wikipedia.org/wiki/TSIG|TSIG]] qui nous servira à générer un [[https://fr.wikipedia.org/wiki/Keyed-hash_message_authentication_code|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 [[https://fr.wikipedia.org/wiki/SHA-2|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 HMAC-SHA512 : indique l’algorithme utilisé pour le hachage, SHA-512 qui fait partie de la famille SHA2
* -b 512 : indique le nombre de bit de la clé, 512 ici.
* -n HOST : j’ai pas vraiment compris la différence entre tous les choix possibles de -n (USER, ZONE, ENTITY, etc) mais dans notre cas il faut choisir HOST.
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.
===== 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.
===== Test de mise à jour du DNS =====
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.
===== Automatisation de la mise à jour =====
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 [[http://tavie.onsenfout.com/2012/04/04/dns-dynamique-securise-avec-nsupdate-et-bind9/|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 :
* ADMIN : adresse mail de l’administrateur
* ZONE : nom de domaine principal. Ne pas indiquer le sous-domaine ici.
* RR : le sous-domaine. On récupère le nom de domaine principal via la variable “$ZONE”, vous n’avez donc besoin de modifier que le début du sous-domaine.
* LAST_IP_FILE, ERR_FILE, KEY_FILE, TMP_FILE : chemin complet, respectivement, du fichier de la dernière IP envoyée, du fichier d’erreur, de la clé privée et du fichier de log temporaire. J’ai mis tous ces fichiers dans mon home car je souhaite que ce soit mon utilisateur qui exécute ce script, mais vous pouvez mettre ces fichiers là où vous le souhaitez (il faut quand même que l’utilisateur qui va exécuter le script y ait accès). Ces fichiers seront créés lors de l’exécution du script, pas besoin de les créer vous-même.
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 :
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/|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/|https://jpmens.net/2010/09/28/performing-dynamic-dns-updates-on-your-dns/]]
[[https://doc.ubuntu-fr.org/msmtp|https://doc.ubuntu-fr.org/msmtp]]