Jacques Foucry bio photo

Jacques Foucry

IT, râleur, faiseur de pain et d’autres choses

Email

Où l’on va voir comment se passer (sous certaines conditions) des fournisseurs de DNS dynamique.



Note : ce billet ne concerne que des configurations qui utilisent IPv4

Note : Merci aux copains qui m’ont aidé dans la compréhension et de déverminage de cette fonctionnalité.

Je suis possédé par une maison de campagne. Celle-ci est mal reliée aux Internets par une connexion ADSL fournie par Orange.

À chaque reboot de la « Livebox », celle-ci change d’adresse IP et le peu d’équipement que j’ai derrière devient inaccessible.

J’ai essayé les services de type DynDNS pour mettre à jour un enregistrement DNS. Malheureusement, celui-ci ne correspond en rien avec mon domaine à moi que j’ai.

Mais je loue une machine reliée aux Internets et équipée d’une adresse IP fixe. Celle-ci héberge un serveur DNS animé par Bind9.

C’est donc lui qui va gérer la zone dynamique de mon domaine avec l’adresse IP de ma « livebox » campagnarde.

Prérequis

Vous aurez besoin de quelques prérequis pour mettre en place cette solution :

  • un serveur DNS en état de marche ;
  • savoir vous en servir (éditer une zone) ;
  • savoir vous débrouiller avec le shell.

Sur le serveur

Nous devons créer une nouvelle zone (en fait un sous-domaine de celui qui existe déjà). La mienne sera externe.example.com.

Ajout de la gestion de la nouvelle zone

Nous allons ajouter la gestion de cette zone dans la configuration de Bind9. Cela se fait à la suite des zones existantes, dans le fichier /usr/local/etc/namedb/named.conf.local1.

1
2
3
4
5
zone "externe.example.com" {
    type master;
    file "/usr/local/etc/namedb/working/db.externe.example.com";
    allow-update { key externe.example.com.key ;};
};

Ce qui signifie :

  • définition de la zone “externe.example.com“ ;
  • de type master ;
  • le fichier de définition est celui-ci ;
  • la mise à jour est autorisée avec cette clef.

Génération de la clef

Cette clef, qui sera présente sur le serveur et le client, devra demeurer secrète, est utilisée pour certifier les échanges. Seules les machines disposant cette clef pourront mettre à jour la zone.

1
2
3
4
5
$ sudo  ddns-confgen -r /dev/urandom -q -a hmac-md5 -k externe.example.com -s externe.example.com. | tee /usr/local/etc/namedb/externe.example.com.key
key "externe.example.com" {
    algorithm hmac-md5;
    secret "RXGQ0vVzbKJVxrXneLLf/w==";
};

Création du fichier de la zone externe.exanple.com

Ce fichier de zone ne comporte que le SOA et un enregistrement de type NS. Il va perdre à Bind9 de connaître la zone. Vous devriez être capable de lire et comprendre ce fichier. Ce fichier se nomme db.externe.example.com

1
2
3
4
5
6
7
8
9
10
11
$ORIGIN .
$TTL 28800      ; 8 hours
externe.example.com      IN SOA  ns.example.com. root.example.com. (
                                1          ; serial
                                3600       ; refresh (1 hour)
                                600        ; retry (10 minutes)
                                604800     ; expire (1 week)
                                300        ; minimum (5 minutes)
                                )
                        NS      ns.example.com.
$ORIGIN externe.example.com.

Vérification de la prise en compte de nos modifications

Nous allons vérifier que notre fichier de zone est correct, que la configuration l’est aussi et nous allons redémarrer Bind pour que nos modifications soient prises en compte.

Vérification de la configuration

Pour vérifier la configuration, nous allons utiliser named-checkconf :

1
2
3
4
$ sudo named-checkconf -z named.conf
...
zone externe.example.com/IN: loaded serial 1
...

Vérification de la zone

Nous avons, pour vérifier la zone, à notre disposition l’utilitaire named-checkzone :

1
2
3
$ sudo named-checkzone externem.example.com db.externem.example.com
zone externem.example.com/IN: loaded serial 1
OK

Redémarrage de Bind et test de la résolution de la zone

Nous redémarrons Bind le plus simplement du monde :

1
2
3
4
5
$ udo service named restart
Password:
Stopping named.
Waiting for PIDS: 60500.
Starting named.

Et nous testons la résolution de la zone. Cela se fait de préférence depuis une autre machine que le serveur.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
dig @ns.example.com externe.example.com

; <<>> DiG 9.8.3-P1 <<>> @ns.example.com externe.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6102
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;externe.example.com.        IN  A

;; AUTHORITY SECTION:
externe.example.com. 300 IN  SOA ns.example.com. root.example.com. 3 3600 600 604800 300

;; Query time: 41 msec
;; SERVER: 198.51.100.78#53(198.51.100.78)
;; WHEN: Fri Dec 25 21:48:27 2015
;; MSG SIZE  rcvd: 86

On dirait que la zone est connue.

Copie de la clef sur la machine cliente

Il nous reste à copier la clef sur la machine cliente.

1
$ scp externe.example.com.key 172.16.234.98

Sur la machine cliente

Ma machine cliente est une RaspBerryPi2. Doivent être installé les utilitaires DNS afin de disposer de la commande nsupdate.

1
$ sudo apt-get install dnsutils

Première mise à jour avec nsupdate

Nous allons commencer par utiliser le mode interactif de nsupdate pour comprendre comment fonctionne l’outil.

1
2
3
4
5
6
$ nsupdate -k externe.example.com.key
> server ns.example.com
> zone externe.example.com
> update add raspi.externe.example.com 60 A 172.16.234.98
> send
> exit

En interrogeant le DNS nous devrions voir apparaître notre machine dans la zone :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ dig @ns.example.com pi.arquian.example.com

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @ns.example.com pi.arquian.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65285
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;raspi.externe.example.com.     IN  A

;; ANSWER SECTION:
raspi.externe.example.com.  60  IN  A  172.16.234.98

;; AUTHORITY SECTION:
externe.example.com. 28800   IN  NS  ns.example.com.

;; ADDITIONAL SECTION:
ns.example.com.    300 IN  A   198.51.100.78

;; Query time: 36 msec
;; SERVER: 198.51.100.78#53(198.51.100.78)
;; WHEN: Sat Dec 26 11:07:06 2015
;; MSG SIZE  rcvd: 94

Houra, ça marche. Toutes vos machines qui utilisent ns.example.com comme resolveur peuvent connaître la RaspberryPI.

Automatisation

Il faut maintenant automatiser cette mise à jour. Il va nous falloir déterminer la fréquence de mise à jour. Est-ce qu’une semaine, une jour ou une heure sans pouvoir joindre la machine est handicapant ? J’ai choisi une journée, mais libre à vous de changer ce réglage.

Nous allons faire un script shell qui va devoir vérifier quelques petites choses avant de faire la mise à jour. En effet, celle-ci est inutile si l’adresse IP n’a pas changé. Inutile aussi si le serveur DNS est injoignable.

Nous allons également devoir supprimer l’enregistrement avant de l’ajouter à nouveau.

Voici mon script :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/bin/sh

# --- Script de mise à jour de l’enregistrement DNS de ma Raspi
# --- Ce script ne fonctionne qu’avec des IPv4

# -- Définiton de fonctions

valid_ip ()
{
    local ip=$1
    dummy=$(echo $ip | grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")
    if [ $dummy ] ;
    then
        echo $ip | awk -F. '{
            if ( (($1>=0) && ($1<=255)) &&
                 (($2>=0) && ($2<=255)) &&  
                 (($3>=0) && ($3<=255)) &&  
                 (($4>=0) && ($4<=255)) ) {
                exit 0;
            } else {
                exit 255;
            }
        }'
    else
        return 255
    fi

}


# -- Définition de variables

# Ajout d'un point (.) à la fin de la zone.
# Erreur classique dans la gestion du DNS

ZONE="externe.example.com."
SERVER="ns.example.com"
IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
DATUM=$(date +"%Y%m%d-%T")
LOG="/var/log/update-dns.$(DATUM).log"
# Modification de la variable host en fonction de ce qui est
# retourné par la commande _hostname_

# HOST=$(hostname).$ZONE
HOST=$(hostname).

KEYFILE=/root/externe.example.com.key


# Le serveur DNS est-il joinable ?
ping -c 2 $SERVER
if [ $? = 255 ] ; then
    echo "Serveur DNS injoinable. Fin" >> $LOG
    exit 255
fi

# Test adresse IP

valid $IP
if [ $? = 255 ] ; then
    echo "$IP n\'est pas une adresse IP valide. Fin" >> $LOG
    exit 255
fi

# L’adresse IP a-t-elle changé ?

oldIP=$(dig @$SERVER $HOST  | grep "^$HOST" | awk '{print $5}')

if [ $oldIP = $IP] ; then
    echo "Rien à faire. Fin" >> $LOG
    exit 0
fi

# Tout semble OK, faisons la mise à jour

cat <<EOF | nsupdate -k $KEYFILE
server $SERVER
zone $ZONE
update delete $HOST
update add $HOST 60 IN A $IP
send
EOF
>> $LOG 2>&1

exit 0

Il reste à tester le script et à le mettre en production avec cron.

Attention : la commande hostname retourne chez moi un nom pleinement qualifié (pi.externe.example.com) parce que j’avais déjà renseigné cette valeur dans le fichier /etc/hostname. Il est donc inutile d’y ajouter la zone.

Mettre le script dans cron

Nous allons le mettre dans la crontab de l’utilisateur root.

1
2
3
$ sudo crontab -e

10 4 * * * /root/updatedns.sh

Le script est lancé automatiquement tous les jours à 4 heures 10 du matin.

Conclusion

Il n’est pas très difficile de mettre en place une zone dynamique avec Bind9 et nsupdate. Cette technique peut être utilisé en conjonction avec un serveur DHCP pour que toutes les machines qui obtiennent une adresse via ce protocole soit enregistré dans une zone spécifique du DNS.

  1. les chemins vers mes fichiers sont ceux d’une installation FreeBSD. Ils différent sur une installation Linux, mais je suis sûr que vous saurez faire la convertion. 


Laisser un commentaire

Les commentaires sont soumis à modération.