Installer Unbound en complément de Pi-Hole

Après l'installation de mon serveur homelab, voici l'installation d'une autre brique logiciel, celle d'Unbound, un résolveur DNS validateur, cache, récursif développé par NLnet Labs. Ce logiciel, écrit en C, est distribué sous licence BSD ce qui permet d'auditer régulièrement son code source. Il prend en charge les protocoles de sécurité DNSSEC, DNS-over-TLS (DoT) et DNS-over-HTTPS (DoH) pour augmenter la sécurité et la confidentialité de l'utilisation d'un serveur DNS de confiance.

Logo d'Unbound

Installer Unbound#

Nous allons principalement suivre la documentation d'installation d'Unbound par Pi-Hole, car elle est bien faite, mais adaptée à la distribution Fedora.

Installation via le gestionnaire de paquet DNF#

Sur une distribution Fedora, Unbound est présent dans les dépôts principaux. Il s’installe donc via le gestionnaire de paquets avec la commande :

$ sudo dnf install unbound

Vue de l'installation d'Unbound par Dnf

Copie du fichier de zone des serveurs DNS racine#

Si vous deviez utiliser ce serveur Unbound en tant que serveur DNS faisant autorité, vous devriez également vous assurer que vous disposez d'un fichier root.hints, qui est le fichier de zone pour les serveurs DNS racine, c'est-à-dire les serveurs racine primaires qui desservent le domaine "." (le domaine racine).

Vous pouvez obtenir ce fichier auprès d'InterNIC. Le plus simple est de le télécharger directement à l'endroit où vous le souhaitez. Nous allons le placer là où se trouvent les autres fichiers liés à unbound, dans /etc/unbound :

$ sudo wget https://www.internic.net/domain/named.root -O /etc/unbound/root.hints

Si vous faites cette étape optionnelle, vous devrez décommenter la ligne de configuration root-hints dans le fichier de configuration (cf ci-dessous).

Par la suite, il faudra mettre à jour ce fichier tous les 6 mois, car il change rarement. Ceci peut être fait manuellement ou en utilisant un timer systemd (cf. Automatiser la copie du fichier de zone des serveurs DNS racine).

Configurer Unbound#

Le fichier principal, avec lequel nous allons travailler pour configurer Unbound, est le fichier unbound.conf, qui se trouve dans /etc/unbound/unbound.conf.

Nous allons garder le fichier original unbound.conf généré à l'installation, décommenter les lignes qui nous intéresse et modifier les options décrites dans la documentation de Pi-Hole. Pour l'éditer :

$ sudo nano /etc/unbound/unbound.conf

Voici les options principales, les autres sont laissées par défaut :

server:
    # verbosity number, 0 is least verbose. 1 is default.
    verbosity: 1

    # number of threads to create. 1 disables threading.
    num-threads: 1

    # specify the interfaces to answer queries from by ip-address.
    # The default is to listen to localhost (127.0.0.1 and ::1).
    # specify 0.0.0.0 and ::0 to bind to all available interfaces.
    # specify every interface[@port] on a new 'interface:' labelled line.
    # The listen interfaces are not changed on reload, only on restart.
    interface: 127.0.0.1

    # port to answer queries from
    port: 5335

    # Specify a netblock to use remainder 64 bits as random bits for
    # upstream queries.  Uses freebind option (Linux).
    # outgoing-interface: 2001:DB8::/64
    # Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo
    # And: ip -6 route add local 2001:db8::/64 dev lo
    # And set prefer-ip6: yes to use the ip6 randomness from a netblock.
    # Set this to yes to prefer ipv6 upstream servers over ipv4.
    prefer-ip6: no

    # buffer size for UDP port 53 incoming (SO_RCVBUF socket option).
    # 0 is system default.  Use 4m to catch query spikes for busy servers.
    so-rcvbuf: 1m

    # EDNS reassembly buffer to advertise to UDP peers (the actual buffer
    # is set with msg-buffer-size).
    edns-buffer-size: 1232

    # Enable IPv4, "yes" or "no".
    do-ip4: yes

    # Enable IPv6, "yes" or "no".
    do-ip6: yes

    # Enable UDP, "yes" or "no".
    # NOTE: if setting up an Unbound on tls443 for public use, you might want to
    # disable UDP to avoid being used in DNS amplification attacks.
    do-udp: yes

    # Enable TCP, "yes" or "no".
    do-tcp: yes

    # file to read root hints from.
    # get one from https://www.internic.net/domain/named.cache
    root-hints: "/etc/unbound/root.hints"

    # Harden against out of zone rrsets, to avoid spoofing attempts.
    harden-glue: yes

    # Harden against receiving dnssec-stripped data. If you turn it
    # off, failing to validate dnskey data for a trustanchor will
    # trigger insecure mode for that zone (like without a trustanchor).
    # Default on, which insists on dnssec data for trust-anchored zones.
    harden-dnssec-stripped: yes

    # Use 0x20-encoded random bits in the query to foil spoof attempts.
    # This feature is an experimental implementation of draft dns-0x20.
    use-caps-for-id: no

    # Enforce privacy of these addresses. Strips them away from answers.
    # It may cause DNSSEC validation to additionally mark it as bogus.
    # Protects against 'DNS Rebinding' (uses browser as network proxy).
    # Only 'private-domain' and 'local-data' names are allowed to have
    # these private addresses. No default.
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: fd00::/8
    private-address: fe80::/10
    private-address: ::ffff:0:0/96

    # if yes, perform prefetching of almost expired message cache entries.
    prefetch: yes

    # File with trusted keys for validation. Specify more than one file
    # with several entries, one file per entry. Like trust-anchor-file
    # but has a different file format. Format is BIND-9 style format,
    # the trusted-keys { name flag proto algo "key"; }; clauses are read.
    # you need external update procedures to track changes in keys.
    # trusted-keys-file: ""
    #
    trusted-keys-file: /etc/unbound/keys.d/*.key
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

Vous pouvez télécharger ce fichier unbound.conf.

Les options principales#

L’ensemble des options sont détaillées dans la documentation officielle unbound.conf(5). Voyons les options recommandées par Pi-Hole :

verbosity#

Valeur de la verbosité, 0 est le moins verbeux. 1 est la valeur par défaut.

num-threads#

nombre de threads à créer. 1 désactive le threading. Un seul thread devrait suffire, mais ce nombre peut être augmenté sur les machines plus puissantes. En réalité, pour la plupart des utilisateurs travaillant sur de petits réseaux ou sur une seule machine, il est inutile de chercher à améliorer les performances en augmentant le nombre de threads au-delà de 1.

interface#

Spécifier les interfaces à partir desquelles répondre aux requêtes par adresse IP. Par défaut, l'écoute se fait sur localhost (127.0.0.1 et ::1). Spécifier 0.0.0.0 et ::0 pour se lier à toutes les interfaces disponibles. Spécifier chaque interface[@port] sur une nouvelle ligne étiquetée 'interface:'. Les interfaces d'écoute ne sont pas modifiées lors du rechargement, mais seulement lors du redémarrage.

port#

Le numéro de port sur lequel le serveur répond aux requêtes. Par défaut, le port est 53. Dans le cas d'une utilisation conjointe avec Pi-Hole, le port 53 est déjà utilisé par FTLDNS (Pi-Hole) qui sert de serveur DNS/DHCP/TFTP/... intégré à Pi-Hole.

prefer-ip6#

Si cette option est activée, le transport IPv6 est privilégié pour l'envoi des requêtes DNS aux serveurs de noms Internet.

so-rcvbuf#

Taille du tampon pour le port UDP 53 entrant (option de socket SO_RCVBUF). 0 est la valeur par défaut du système. Utilisez 4m pour capturer les pics de requêtes pour les serveurs occupés.

edns-buffer-size#

Nombre d'octets à annoncer comme taille du tampon de réassemblage EDNS. Le tampon réel est défini avec msg-buffer-size Valeur par défaut : 1232 (Cette valeur a également été suggérée dans le DNS Flag Day 2020.)

do-ip4#

Activer ou désactiver la réponse ou l'émission de requêtes IPv4.

do-ip6#

Permet d'activer ou de désactiver la réponse ou l'émission de requêtes IPv6. Peut être réglé sur "yes" si vous disposez d'une connectivité IPv6. Si cette option est désactivée, les requêtes ne reçoivent pas de réponse sur IPv6 et les requêtes ne sont pas envoyées sur IPv6 aux serveurs de noms Internet. Cette option permet de désactiver le transport IPv6 pour l'envoi du trafic DNS. Elle n'a aucune incidence sur le contenu du trafic DNS, qui peut contenir des adresses IPv4 (A) et IPv6 (AAAA).

do-udp#

Permet d'activer ou de désactiver la réponse ou l'émission de requêtes UDP.

do-tcp#

Permet d'activer ou de désactiver la réponse ou l'émission de requêtes TCP.

root-hints#

Chemin vers le fichier root.hints. N'utilisez ceci que lorsque vous avez téléchargé la liste des serveurs racine primaires !

harden-glue#

Ne fera confiance à la "glue" que si elle relève de l'autorité du serveur, afin d'éviter les tentatives d'usurpation d'identité (spoofing).

harden-dnssec-stripped#

Exiger des données DNSSEC pour les zones de confiance, si ces données sont absentes, la zone devient BOGUS. La valeur par défaut est "on", ce qui insiste sur les données dnssec pour les zones de confiance.

use-caps-for-id#

Utiliser des bits aléatoires codés en 0x20 dans la requête pour déjouer les tentatives d'usurpation. Cette fonctionnalité est une implémentation expérimentale de l'ébauche dns-0x20. Par exemple, en utilisant cette fonctionnalité, une requête pour www.mathdatech.fr pourrait apparaître dans la demande comme www.mathdatech.fr ou Www.Mathdatech.Fr ou WWW.MaTHdaTEcH.fR ou toute autre combinaison de majuscules et de minuscules. Le serveur faisant autorité doit répondre avec la même casse. Cela permet d'éviter l'usurpation d'adresse DNS.

N'utilisez pas la randomisation des majuscules car elle est connue pour causer parfois des problèmes DNSSEC (voir https://discourse.pi-hole.net/t/unbound-stubby-or-dnscrypt-proxy/9378 pour plus de détails)

private-address#

Donner des adresses IPv4 ou IPv6 ou des sous-réseaux sans classe. Il s'agit d'adresses de votre réseau privé, qui ne sont pas autorisées à être renvoyées pour des noms internet publics. Toute occurrence de ces adresses est supprimée des réponses DNS. En outre, le validateur DNSSEC peut marquer les réponses comme fausses (BOGUS). Cela permet de se protéger contre ce que l'on appelle le DNS Rebinding, où le navigateur d'un utilisateur est transformé en proxy de réseau, ce qui permet d'accéder à distance, par le biais du navigateur, à d'autres parties de votre réseau privé.

prefetch#

Si activé, les éléments de la mémoire cache des messages sont traités avant d'expirer afin de maintenir la mémoire cache à jour. L'activation de cette fonction entraîne une augmentation d'environ 10 % du trafic et de la charge sur la machine, mais les éléments les plus populaires n'expirent pas du cache.

auto-trust-anchor-file#

La variable auto-trust-anchor-file permet d'indiquer à unbound le fichier de clé nécessaire à la gestion de DNSSEC. Si ce fichier n'existe pas, vous pouvez l'ajouter à votre fichier de configuration personnelle, ou créer ledit fichier qui sera pris en charge lors du (re)démarrage lié au service unbound.

Vérifier le fichier de configuration#

Une fois le fichier de configuration enregistré, pour détecter d'éventuelle erreur de syntaxe, une vérification s'impose avec :

$ unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

Créer le fichier de clé pour la gestion DNSSEC#

En plus de la variable auto-trust-anchor-file, la gestion DNSSEC se fait par l'usage de l'outil 'unbound-anchor' qui crée le fichier de clé nécessaire

$ unbound-anchor -a "/var/lib/unbound/root.key"

Démarrer le serveur local#

Démarrer le serveur Unbound avec les commandes suivantes :

$ sudo systemctl start unbound
$ sudo systemctl enable unbound
Created symlink /etc/systemd/system/multi-user.target.wants/unbound.service → /usr/lib/systemd/system/unbound.service.

Tester le bon fonctionnement#

Le serveur étant actif, on peut désormais faire un test avec la commande dig. Nous allons interroger unbound pour nous donner la résolution du domaine nasa.gov :

$ dig nasa.gov @127.0.0.1 -p 5335

; <<>> DiG 9.18.12 <<>> nasa.gov @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50471
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;nasa.gov.                      IN      A

;; ANSWER SECTION:
nasa.gov.               600     IN      A       23.22.39.120
nasa.gov.               600     IN      A       52.0.14.116

;; Query time: 84 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Mon Mar 13 21:23:27 CET 2023
;; MSG SIZE  rcvd: 69

Premier test satisfaisant, la réponse a eu lieu puisque l'ANSWER SECTION donne la réponse à notre requête dans un délai "Query time" de 84 msec.

Refaisons le même test pour vérifier le délai de réponse sachant d'Unbound met en cache les réponses précédentes :

$ dig nasa.gov @127.0.0.1 -p 5335

; <<>> DiG 9.18.12 <<>> nasa.gov @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41522
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;nasa.gov.                      IN      A

;; ANSWER SECTION:
nasa.gov.               592     IN      A       52.0.14.116
nasa.gov.               592     IN      A       23.22.39.120

;; Query time: 0 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Mon Mar 13 21:23:34 CET 2023
;; MSG SIZE  rcvd: 69

On obtiens donc la même réponse mais en 0 msec (= Query time), ce qui valide bien la mise en cache de la réponse, et ce qui apporte un intérêt à installer Unbound sur son réseau.

Pour vérifier que la gestion DNSSEC est bien prise en compte, il faut repérer dans la sortie complète de la commande dig, sur la ligne 'flags:', la présence du drapeau 'ad' (Authentic Data).

Paramétrer Pi-Hole#

Maintenant, il va falloir paramétrer Pi-hole pour qu'il utilise le serveur local Unbound en tant que serveur DNS dans l'interface d'administration accessible à l'adresse http://<ip-du-pihole>/admin/index.php.

Ensuite dans le menu Settings puis l'onglet DNS, on ajoute dans les 'Upstream DNS Servers' personnalisés, l'adresse IP du serveur local dans le champs "Custom 1 (IPv4)". Comme le serveur Unbound est sur la machine locale, l'IP et le port à renseigner sont 127.0.0.1#5335, puis un clic sur Save pour enregistrer.

Upstream DNS Servers de Pi-Hole

Astuces#

Supprimer Unbound#

Pour supprimer le serveur Unbound, il faudra exécuter la commande suivante :

$ sudo dns remove unbound

Puis il faudra reparamétrer un serveur DNS tiers dans Pi-Hole.

Automatiser la copie du fichier de zone des serveurs DNS racine#

L'automatisation de la copie du fichier de zone des serveurs DNS racine peut se faire :

via le système de service et de timer de SystemD#

Pour télécharger tous les mois le dernier fichier root.hints à jour, il faut créer un fichier roothints.service:

$ sudo nano /etc/systemd/system/roothints.service

Puis y copier ces informations :

[Unit]
Description=Update root hints for unbound
After=network.target

[Service]
ExecStart=/usr/bin/wget https://www.internic.net/domain/named.root -O /etc/unbound/root.hints

Puis, il faut créer un fichier roothints.timer:

$ sudo nano /etc/systemd/system/roothints.timer

Puis y copier ces informations :

[Unit]
Description=Run root.hints monthly

[Timer]
OnCalendar=monthly
Persistent=true

[Install]
WantedBy=timers.target

Et enfin il faut démarrer et activer le service :

$ sudo systemctl start roothints.timer
$ sudo systemctl enable roothints.timer
Created symlink /etc/systemd/system/timers.target.wants/roothints.timer → /etc/systemd/system/roothints.timer.

via cron#

Pour télécharger tous les 6 mois le dernier fichier root.hints à jour, on ajoute une nouvelle entrée dans la table de cron :

crontab -e

et on y ajoute la commande suivante :

1 0 1 */6 * wget https://www.internic.net/domain/named.root -O /etc/unbound/root.hints

Pour en savoir plus#

Voici d'autres liens utiles :

Liens spécifiques à la gestion DNSSEC :

links

social