Login Logout

Howto BIND

BIND (Berkeley Internet Name Daemon) est le serveur DNS historique écrit au début des années 1980, c’est encore le plus utilisé sur Internet. Il est développé par l’ISC qui développe aussi ISC DHCP. BIND peut être à la fois serveur récursif (résoudre n’importe quel enregistrement DNS pour certaines machines) ou serveur faisant autorité (renvoyer au monde entier les enregistrements DNS d’un nom de domaine spécifique).

Installation

# apt install bind9

$ /usr/sbin/named -V
BIND 9.10.3-P4-Debian <id:ebd72b3>
built by make with '--prefix=/usr' '--mandir=/usr/share/man' '--libdir=/usr/lib/x86_64-linux-gnu' '--infodir=/usr/share/info' '--sysconfdir=/etc/bind' '--with-python=python3' '--localstatedir=/' '--enable-threads' '--enable-largefile' '--with-libtool' '--enable-shared' '--enable-static' '--with-gost=no' '--with-openssl=/usr' '--with-gssapi=/usr' '--with-gnu-ld' '--with-geoip=/usr' '--with-atf=no' '--enable-ipv6' '--enable-rrl' '--enable-filter-aaaa' '--enable-native-pkcs11' '--with-pkcs11=/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so' '--with-randomdev=/dev/urandom' 'CFLAGS=-g -O2 -fdebug-prefix-map=/build/bind9-iBGKO7/bind9-9.10.3.dfsg.P4=. -fstack-protector-strong -Wformat -Werror=format-security -fno-strict-aliasing -fno-delete-null-pointer-checks -DNO_VERSION_DATE -DDIG_SIGCHASE' 'LDFLAGS=-Wl,-z,relro -Wl,-z,now' 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2'
compiled by GCC 6.3.0 20170516
compiled with OpenSSL version: OpenSSL 1.0.2l  25 May 2017
linked to OpenSSL version: OpenSSL 1.0.2l  25 May 2017
compiled with libxml2 version: 2.9.4
linked to libxml2 version: 20904

Sous Debian 8, l’unité systemd ne gère pas les options dans /etc/default/bind9, il faut corriger l’unité en copiant :

# cp -a /lib/systemd/system/bind9.service /etc/systemd/system/

et ajuster la section [Service] :

EnvironmentFile=-/etc/default/bind9
ExecStart=/usr/sbin/named -f $OPTIONS

puis :

# systemctl daemon-reload

Configuration

Les options de BIND sont dans /etc/default/bind9.

Fichiers de configuration :

/etc/bind
├── bind.keys
├── db.0
├── db.127
├── db.255
├── db.empty
├── db.local
├── db.root
├── named.conf
├── named.conf.default-zones
├── named.conf.local
├── named.conf.options
├── rndc.key
└── zones.rfc1918

serveur DNS récursif

Lorsque BIND est utilisé en serveur DNS récursif pour une ou plusieurs machines, on conseille d’activer la résolution DNS inverse pour les zones RFC1918 dans le fichier /etc/bind/named.conf.local (c’est important car de nombreux outils vérifient les reverses DNS) :

include "/etc/bind/zones.rfc1918";

Puis ajuster les options via /etc/bind/named.conf.options :

options {
    directory "/var/cache/bind";
    version "Bingo";
    auth-nxdomain no;
    listen-on-v6 { ::1; };
    listen-on { 127.0.0.1; };
    allow-recursion { ::1; 127.0.0.1; };
};

logging {
        category default { default_file; };
        channel default_file {
                file "/var/log/bind.log";
                severity info;
        };
};

Note : dans l’exemple, BIND n’écoute que pour la machine locale. Si l’on veut l’interroger avec d’autres machines, on ajustera les options listen-* et allow-recursion (on pourra notamment utiliser l’ACL localnets

serveur DNS faisant autorité

Lorsque BIND est utilisé en serveur DNS faisant autorité, on conseille de le sécuriser en l’enfermant dans un chroot.

On va ensuite configurer via le fichier /etc/bind/named.conf.options :

acl "foo" {
    ::ffff:192.0.2.21; 192.0.2.21;
    2001:db8::21;
};

options {
      directory "/var/cache/bind";
      version "Bingo";
      auth-nxdomain no;
      masterfile-format text;
      statistics-file "/var/run/named.stats";

      listen-on-v6 { any; };
      listen-on { any; };

      allow-query { localhost; };
      allow-recursion { localhost; };
      allow-transfer { localhost; };
};

logging {
    category default { default_file; };
    category queries { query_logging; };

    channel default_file {
        file "/var/log/bind.log";
        severity info;
    };
    channel query_logging {
        file "/var/log/bind_queries.log" versions 2 size 128M;
        print-category yes;
        print-severity yes;
        print-time yes;
    };
};

On peut ensuite ajouter ses domaines pour lesquels BIND fait autorité dans le fichier /etc/bind/named.conf.local, par exemple pour example.com avec un serveur replica dans l’ACL foo :

zone "example.com" { 
        type master; 
        file "/etc/bind/db.example.com";
        allow-query { any; };
        allow-transfer { "foo"; };
};

Puis enfin les fichiers de zone, exemple avec un /etc/bind/db.example.com simple :

$TTL 1800
@          IN      SOA ns1.example.net. dnsmaster.example.com. (
                   2017072107 ; serial
                   2h         ; rafraichissement replica->master
                   1h         ; en cas d'echec du refraichissement, nouvel essai
                   5w         ; expiration des enregistrements en cache par les serveurs replica
                   10m )      ; TTL negatif

           A 192.0.2.80

           NS ns1.example.net.
           NS ns2.example.org.

           MX 0    .
           TXT "v=spf1 -all"

www        CNAME @
ftp        CNAME ftp.example.net.

Note : on s’assurera que les fichiers de zone sont lisibles par l’utilisateur bind en faisant chown bind:bind /etc/bind/db.example.com

Options de configuration

  • allow-query : spécifie les adresses autorisées à faire des requêtes DNS. Par défaut, toutes les adresses sont autorisées
  • allow-transfer : spécifie les adresses des serveurs replica autorisées à faire des requêtes AXFR (transfert de zone). Par défaut, toutes les adresses sont autorisées, il est impératif de restreindre les autorisations.
  • allow-recursion : spécifie les adresses autorisées à faire des requêtes DNS récursives. À restreindre impérativement également.
  • allow-update : spécifie les adresses autorisées à mettre à jour dynamiquement des informations dans leur zone. Par défaut, aucune adresse n’est autorisée.

chroot

Pour enfermer BIND dans une prison chroot nous utilisons le script chroot-bind.sh :

# cd /root
# wget https://forge.evolix.org/projects/chroot-bind/repository/revisions/master/raw/chroot-bind.sh
# sh chroot-bind.sh

Puis ajoutez -t /var/chroot-bind dans la variable OPTIONS du fichier `/etc/default/bind9 :

RESOLVCONF=no
OPTIONS=" -u bind -t /var/chroot-bind"

Vous devez alors relancer BIND :

# systemctl restart bind9

À chaque mise à jour du paquet bind9 ou de l’une de ses dépendances (libc6, libcap2, libssl, etc.) vous devrez relancer le script chroot-bind.sh et BIND ensuite.

Rotation des logs

On utilise logrotate pour la rotation des logs.

Voici le fichier /etc/logrotate.d/bind que l’on utilise pour un serveur récursif :

/var/log/bind.log {
    weekly
    missingok
    rotate 8
    create 640 bind bind
    sharedscripts
    postrotate
        rndc reload > /dev/null
    endscript
}

Pour un serveur faisant autorité, on doit préciser le path des fichiers dans le chroot :

/var/chroot-bind/var/log/bind.log {
    weekly
    missingok
    rotate 52
    create 640 bind bind
    sharedscripts
    postrotate
        rndc reload > /dev/null
    endscript
}

Note : la rotation du fichier /var/chroot-bind/var/log/bind_queries.log est assurée par BIND sous réserve d’avoir bien précisé l’option versions dans les paramètres de logging

ACL

http://www.zytrax.com/books/dns/ch7/address_match_list.html

Au sein des différentes directives allow-* on peut utiliser des ACLs.

Par défaut, les ACLs suivantes sont prédéfinies :

  • none : aucune adresse IP
  • any : toutes les adresses IP
  • localhost : toutes les adresses IP de la machine (127.0.0.1 mais aussi les adresses configurées sur les différentes interfaces réseau)
  • localnets : tous les sous-réseaux dans lesquels la machine possède une adresse IP

On peut également définir ses propres ACLs :

acl "bar" {
    ::ffff:192.0.2.21; 192.0.2.21;
    ::ffff:192.0.2.42; 192.0.2.42;
    2001:db8::21; 2001:db8::42;
};

master/replica

Dans une configuration comprenant un serveur DNS replica, il réplique tout ou partie de ses fichiers de zone à partir d’un serveur DNS master.

Si l’on reprend le cas de la zone master suivante :

zone "example.com" {
        type master;
        file "/etc/bind/db.example.com";
        allow-query { any; };
        allow-transfer { "foo"; };
};

Sur le serveur DNS replica, on spécifiera l’adresse IP du serveur master ainsi qu’un fichier pour sauvegarder la zone en local :

zone "example.com" {
        type slave;
        file "/etc/bind/bak.example.com";
        allow-query { any; };
        masters { 192.0.2.53; };
};

Note : pour avoir le fichier de zone en clair sur le serveur replica (ce qui est pratique notamment en cas d’incident avec le serveur master), il faut s’assurer d’avoir l’option masterfile-format text dans la configuration de BIND.

Mise à jour dynamique

Il est possible de mettre à jour une zone DNS sans éditer le fichier avec nsupdate. Dans ce cas, BIND génère un ficher de journal binaire contenant l’historique des modifications apportées à la zone.

Note : la synchronisation avec le fichier réel de zone n’est pas faite en temps réel, cela se fait toutes les 15 minutes en général : il faut donc faire attention si l’on veut éditer le fichier de zone, il faudra forcer la synchronisation ainsi :

$ rndc freeze domain.tld
[Modification manuelle de la zone]
$ rndc thaw domain.tld
$ rndc reload domain.tld

Reverse DNS

Un reverse DNS est un nom de domaine associé à une adresse IP. Le nom de cet enregistrement est PTR. Exemples :

$ dig -x 31.170.8.43

;; QUESTION SECTION:
;43.8.170.31.in-addr.arpa.      IN      PTR

;; ANSWER SECTION:
43.8.170.31.in-addr.arpa. 43200 IN      PTR     hosting.evolix.net.

$ dig -x 2a01:9500::3

;; QUESTION SECTION:
;3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.9.1.0.a.2.ip6.arpa. IN PTR

;; ANSWER SECTION:
3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.5.9.1.0.a.2.ip6.arpa. 43200 IN PTR forge.evolix.net.

Cela fonctionne avec un nom de domaine “virtuel” : .in-addr.arpa en IPv4 et .ip6.arpa en IPv6 !

Il est important de configurer les reverses DNS, car ils sont souvent vérifiés par les serveurs SMTP, et certains logiciels les vérifient également (Postfix, MySQL, CUPS, SSH, etc.). Sur un réseau avec des adresses privées, il également important de renvoyer au minimum une réponse DNS NXDOMAIN ce qui peut être fait facilement grâce au fichier /etc/bind/zones.rfc1918.

À noter que les DNS de l’IANA répondent tout de même pour ces demandes… mais sans garantie de bon fonctionnement !

Monitoring

dnstop

L’outil dnstop permet de surveiller en direct l’activité DNS en analysant les paquets réseau qui circulent :

# apt install dnstop
# dnstop -l3 eth0

 s - Sources list
 d - Destinations list
 t - Query types
 o - Opcodes
 r - Rcodes
 1 - 1st level Query Names      ! - with Sources
 2 - 2nd level Query Names      @ - with Sources
 3 - 3rd level Query Names      # - with Sources
 4 - 4th level Query Names      $ - with Sources
 5 - 5th level Query Names      % - with Sources
 6 - 6th level Query Names      ^ - with Sources
 7 - 7th level Query Names      & - with Sources
 8 - 8th level Query Names      * - with Sources
 9 - 9th level Query Names      ( - with Sources
^R - Reset counters
^X - Exit

Munin

Pour activer les plugins Munin pour BIND :

# cd /etc/munin/plugins
# ln -s /usr/share/munin/plugins/bind9_rndc
# ln -s /usr/share/munin/plugins/bind9

Le plugin bind9_rndc s’appuie sur le fichier /var/run/named.stats (option statistics-file de BIND) et bind9 s’appuie un fichier de logs (channel query_logging dans les logs BIND). Il donc s’assurer d’avoir bien configuré ces deux fichiers puis on indique à Munin via /etc/munin/plugin-conf.d/munin-node :

[bind*]
user root
env.logfile /var/chroot-bind/var/log/bind_queries.log
env.querystats /var/chroot-bind/var/run/named.stats
env.MUNIN_PLUGSTATE /var/lib/munin
timeout 120

Log2mail

Pour être alerté en cas de fichiers de zone incorrect, on peut rajouter ceci dans la conf de Log2mail :

file = /var/chroot-bind/var/log/bind.log
  pattern = "not loaded due to errors"
  mailto = alert@example.com

file = /var/log/syslog
  pattern = "fatal error"
  mailto = alert@example.com

  pattern = "loading configuration: failure"
  mailto = alert@example.com

géolocalisation

BIND peut répondre une réponse différente selon l’adresse IP qui l’interroge, on peut faire cela de deux façons :

  • à l’aide de ce patch. Le principe est de faire une recherche suivant un arbre binaire (binary search tree) sur la base de données de MaxMind. Cela n’impacte pas les temps de réponse mais nécessite de maintenir un Bind patché ;
  • en se basant sur le système de vue de Bind. Le principe est de récupérer les plages d’adresses par pays auprès de MaxMind et de générer des fichiers d’ACL à l’aide de ce script. Les performances sont en théorie moins bonnes (mais cette différence n’est pas vraiment constatée dans la pratique), mais l’installation est bien plus simple à maintenir.

À l’aide de vues

  • On récupère le script GeoIP.py et on installe les dépendances nécessaires :
# apt install python-mpmath
  • exécuter le script. Il générera un fichier GeoIP.acl, avec une ACL par pays :
$ ./GeoIP.py MaxMind
  • Configurer Bind pour servir une zone différente en fonction des pays :
include "/etc/bind/GeoIP.acl";

view "europe" {
  match-clients { FR; };
  recursion no;
  zone "example555.com" {
    type master;
    file "/etc/bind/db.example555-europe.db";
    allow-query { any; };
  };
};

view "north_america" {
  match-clients { US; CA; MX; };
  recursion no;
  zone "example555.com" {
    type master;
    file "/etc/bind/db.example555-north-america.db";
    allow-query { any; };
  };
};

view "other" {
  match-clients { any; };
  recursion no;
  zone "example555.com" {
    type master;
    file "/etc/bind/db.example555-other.db";
    allow-query { any; };
  };
};

Le script peut être mis en cron pour conserver des ACL à jour.

FAQ

journal out of sync

Si vous avez une erreur du type :

journal out of sync with zone

Lancer la commande :

# named -g

Voir http://www.thedumbterminal.co.uk/?action=showArticle&articleId=168

ran out of space

Si vous avez une erreur du type (par exemple pour des enregistrements TXT ou SPF) :

ran out of space

Vous devez spliter vos champs, voir http://www.jeoffrey54.com/article144/dns-sous-bind-ran-out-of-space

received control channel command ‘stop’

En lançant votre démon, celui-ci est stoppé immédiatement avec un simple message d’arrêt :

received control channel command 'stop'

…vérifiez si vous n’avez pas oublié l’option -f tout en utilisant systemd.

Zone replica avec Bind 9.9

À partir de Bind 9.9, le stockage des zones répliquées se fait en binaire. Avec une ancienne configuration vous aurez des erreurs :

zone example.com/IN: loading from master file /etc/bind/bak.example.com failed: not implemented
zone example.com/IN: unable to load from '/etc/bind/bak.example.com'; renaming file to '/etc/bind/db-5GoiCpdc' for failure analysis and retransferring.

Pour conserver l’ancien comportement il faut ajouter dans la configuration :

masterfile-format text;

Voir http://geekdom.wesmo.com/2014/06/05/bind9-dns-slave-file-format/

Vérifier la configuration

  • Globalement
# named-checkconf /etc/bind/named.conf
  • Pour une zone en particulier
# named-checkzone example.com /etc/bind/db.example.com

Forcer un transfer sur le replica

Sur le replica :

# rndc reload example.com
zone refresh queued

Pas d’IPv6 ou souci d’IPv6

Si malheureusement vous n’avez pas d’IPv6 sur votre serveur ou alors si la qualité de votre connexion IPv6 est insuffisante, vous devez forcer Bind à ne pas écouter en IPv6 ainsi :

listen-on-v6 { none; };

Et via le fichier /etc/default/bind9 vous allez le forcer à n’effectuer des requêtes qu’en IPv4 :

OPTIONS="-u bind -4 -t /var/chroot-bind"