Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Ève

Le serveur DNS Knot

Première rédaction de cet article le 4 janvier 2014


Curieusement, des tas d'endroits où tourne un serveur DNS faisant autorité, font tourner BIND. Ce qui est curieux, ce n'est pas ce choix (BIND est un excellent logiciel), c'est le fait qu'aucune alternative n'a été considérée. Peut-on vraiment se dire administrateur système si on ne se pose même pas la question « y a-t-il d'autres possibilités ? ». Parmi les alternatives sérieuses, pour cette fonction de serveur DNS faisant autorité, le logiciel Knot.

J'ai déjà présenté ici une autre alternative, le logiciel NSD. NSD est extrêmement rapide et fiable mais sa principale faiblesse (qui a été corrigée en version 4) était que l'ajout ou le retrait d'une zone à sa configuration nécessitait le redémarrage du serveur. NSD est donc très bien pour les gérants de TLD ou d'autres grandes zones mais il ne convient pas forcément au cas d'un hébergeur gérant des milliers de zones, avec ajouts et retraits fréquents. Autre manque, NSD ne gère pas les mises à jour dynamiques du RFC 2136. NSD est conçu pour deux choses, vitesse et fiabilité. Si on veut la richesse fonctionnelle, Knot mérite un coup d'œil.

Les tests ci-dessous ont été faits avec la version 1.4rc2, la 1.4 définitive devrait sortir « bientôt ». Voici la configuration minimale d'un serveur Knot gérant example.com :

interfaces {
  my-iface { address 0.0.0.0;}
}

zones {
  storage "/var/knot";
  example.com {
    file "./example.com"; # Relative to "zones / storage"
  }
}

Indiquer au moins une interface est obligatoire, Knot est sourd, autrement. On peut alors démarrer le serveur (ici, à la main, pour des tests mais, en production, cela serait fait par un script de démarrage) :

# knotd -c ultra-simple.conf -v
2014-01-03T14:46:31 Reading configuration '/home/stephane/System/DNS/Knot-tests/ultra-simple.conf' ...
2014-01-03T14:46:31 Knot DNS 1.4.0-rc2 starting.
2014-01-03T14:46:31 Binding to interface 0.0.0.0 port 53.
2014-01-03T14:46:31 Configured 1 interfaces and 1 zones.
2014-01-03T14:46:31 Server started in foreground, PID = 12472
2014-01-03T14:46:31 Server running without PID file.
2014-01-03T14:46:31 Zone 'example.com.' loaded (serial 2013122101)
2014-01-03T14:46:31 Loaded 1 out of 1 zones.
2014-01-03T14:46:31 Starting server...
2014-01-03T14:46:31 Binding remote control interface to /usr/local/var/run/knot/knot.sock

Et on peut tester que le serveur répond bien :


% dig @192.168.2.7 SOA example.com

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

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;example.com.		IN SOA

;; ANSWER SECTION:
example.com.		600 IN SOA ns1.example.com. root.example.com. (
				2013122101 ; serial
				604800     ; refresh (1 week)
				86400      ; retry (1 day)
				2419200    ; expire (4 weeks)
				86400      ; minimum (1 day)
				)

...

;; Query time: 1 msec
;; SERVER: 192.168.2.7#53(192.168.2.7)
;; WHEN: Fri Jan  3 15:46:35 2014
;; MSG SIZE  rcvd: 127

Knot dispose, comme BIND et contrairement à NSD (avant la version 4) d'un canal de contrôle. Par défaut, ce canal passe par une prise locale, ici /usr/local/var/run/knot/knot.sock. Le programme knotc permet de parler au serveur (knotd) :

# knotc  status               
OK

# knotc  zonestatus
example.com.	type=master | serial=2013122101 |  busy |  

Contrairement à NSD (avant la version 4), on peut ajouter des zones « en vol ». Ajoutons dans le fichier de configuration :

  example.net {
    file "./example.net";
  }

Et un simple :

# knotc  reload 
OK

sera suffisant pour charger la nouvelle zone :

2014-01-03T14:54:02 Reloading configuration...
2014-01-03T14:54:02 Zone 'example.com.' is up-to-date (serial 2013122101)
2014-01-03T14:54:02 Zone 'example.net.' loaded (serial 2013122101)
2014-01-03T14:54:02 Loaded 2 out of 2 zones.
2014-01-03T14:54:02 Configuration reloaded.

Le canal de contrôle peut être mis sur autre chose qu'une prise locale :

remotes {
        ctl { address 127.0.0.1;}
}

control {
	listen-on { address 127.0.0.1@5533;}
        allow ctl;
}

Et le serveur répond alors sur cette prise réseau :

% knotc -s localhost -p 5533 status
OK

% knotc -s localhost -p 5533 zonestatus
example.com.	type=master | serial=2013122101 |  busy |  

Autre fonction intéressante, la mise à jour dynamique. Si on configure une zone avec update-in  :

remotes {
        updater { address 127.0.0.1;}
}

zones {
  storage "/var/knot";
  example.com {
    file "./example.com"; 
   update-in {
	  updater;
   } 
  }
}

Et qu'on utilise, par exemple, ce script (qui utilise le nsupdate livré avec BIND) pour les mises à jour :


#!/bin/sh

nsupdate  -d <<EOF
  server 127.0.0.1 
  zone example.com
  update delete monportable.example.com
  update add monportable.example.com 300 A 192.0.2.42
  send
EOF

La mise à jour est bien faite :

2014-01-03T15:04:58 UPDATE of 'example.com.' from '127.0.0.1@22672' Started.
2014-01-03T15:04:58 UPDATE of 'example.com.' from '127.0.0.1@22672' Finished.

Ce qu'on peut vérifier avec dig :

% dig -p 5353 @127.0.0.1 A monportable.example.com
...
;; ANSWER SECTION:
monportable.example.com. 300	IN	A	192.0.2.42

Maintenant, si je me mets dans la peau de l'hébergeur qui gère plein de zones, est-ce Knot va tenir le coup ? Testons sur une petite machine, un Raspberry Pi sous Arch Linux avec mille zones (c'est peu, mais c'est vraiment une petite machine). En cinq secondes, les mille zones sont chargées et Knot répond. 50 Mo de RAM sont utilisés dont 20 en résident. Et si on bombarde le serveur de requêtes avec queryperf ? On atteint 3 800 requêtes par seconde, sans aucune perte.

Et si on compare avec BIND ? Un BIND 9.9.4-P1 sur le même Raspberry Pi consomme effectivement deux fois moins de mémoire mais ses performances avec queryperf sont bien moins bonnes, avec 1 000 requêtes par seconde (en débrayant la journalisation des requêtes refusées, qui est faite par défaut et ralentit beaucoup BIND). Rien d'étonnant (BIND a toujours été très lent dans tous les tests de performance, l'accent est mis par ses développeurs sur la richesse fonctionnelle).

Knot gère évidemment les trucs modernes : DNSSEC (si le fichier de zone est signé, il active automatiquement le mode DNSSEC), NSID (RFC 5001) et RRL (limitation du rythme des réponses). Pour NSID, on met :

system {
  identity "ns1.example.com"; # For the old CH TXT hostname.bind trick
  nsid "ns1.example.com";
}

Et on obtient le résultat attendu :

% dig +nsid -p 5353 @127.0.0.1 SOA example.com     
...
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; NSID: 6e 73 31 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d  (n) (s) (1) (.) (e) (x) (a) (m) (p) (l) (e) (.) (c) (o) (m)
...

Knot dispose également évidemment de la fonction RRL (Response-Rate Limiting) qui permet de limiter la contribution du serveur aux attaques par réflexion. Par exemple, on configure avec :

system {
  ...
  rate-limit 20;
}

Et on limite le serveur à 20 réponses par seconde pour la même question depuis la même adresse IP. Sur le graphique, on voit bien la différence : le premier pic correspond à une attaque par réflexion sans RRL (autant de paquets sortants qu'entrants), le second pic au cas où la RRL est activée (le nombre de paquets sortants chute). knot-rrl-reflector.png

Si vous voulez en apprendre plus sur Knot en français, vous pouvez lire l'article de ses auteurs à JRES.

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)