---
categories: openbsd network DNS
title: Howto Unbound
---

* Documentation : <https://www.unbound.net/documentation/>
* Rôle Ansible : <https://forge.evolix.org/projects/ansible-roles/repository/show/unbound>
* Man pages : <https://man.openbsd.org/unbound> ou <https://manpages.debian.org/stretch/unbound/unbound.8.en.html>

[Unbound](https://www.unbound.net/) est un serveur DNS récursif. Il gère notamment du cache et la validation DNSSEC. Par rapport à [Bind](HowtoBind) il est léger et sécurisé, mais il ne sait pas faire autorité pour un nom de domaine. Il a été écrit et est maintenu par [NLnet Labs](https://www.nlnetlabs.nl/).

## Installation

### Debian

~~~
# apt install unbound

$ /usr/sbin/unbound -h | tail -5
Version 1.6.0
linked libs: libevent 2.0.21-stable (it uses epoll), OpenSSL 1.1.0f  25 May 2017
linked modules: dns64 python validator iterator
BSD licensed, see LICENSE in source package for details.
Report bugs to unbound-bugs@nlnetlabs.nl
~~~

### OpenBSD

Unbound est intégré dans la base d'OpenBSD, il est donc déjà présent.


## Configuration

<https://manpages.debian.org/stretch/unbound/unbound.conf.5.en.html> ou <https://man.openbsd.org/unbound.conf>

Fichiers de configuration sous Debian :

~~~
/etc/unbound/
├── unbound.conf
├── unbound.conf.d
│   ├── qname-minimisation.conf
│   └── root-auto-trust-anchor-file.conf
├── unbound_control.key
├── unbound_control.pem
├── unbound_server.key
└── unbound_server.pem
~~~

Fichiers de configuration sous OpenBSD (Unbound est dans un chroot) :

~~~
/var/unbound/etc/
└── unbound.conf
~~~

Par défaut, Unbound écoute uniquement sur _localhost_, la configuration minimale consiste surtout à le sécuriser :

Exécuter la commande `sudo -u _unbound unbound-anchor` pour créer le fichier .key.

~~~
server:
  hide-identity: yes
  hide-version: yes
  auto-trust-anchor-file: "/var/unbound/db/root.key"
~~~

Si l'on veut le faire écouter sur un réseau local, il faut ajuster les directives `interface` et `access-control` :

~~~
server:
  interface: 192.0.2.254
  interface: 127.0.0.1
  interface: ::1

  access-control: 0.0.0.0/0 refuse
  access-control: 127.0.0.0/8 allow
  access-control: 192.0.2.0/24 allow
  access-control: ::0/0 refuse
  access-control: ::1 allow
~~~

### Configuration spécifique sous OpenBSD

Avant d'activer Unbound sous OpenBSD, il faut configurer le nombre maximum de file descriptor qu'il peut ouvrir.
En effet, 2 fd sont ouverts pour chaque IP sur laquelle Unbound écoute, puis 1 fd est ouvert pour chaque requête active.
Dans le cas d'une instabilité réseau, les fd ouverts peuvent s'accumuler et atteindre la limite, bloquant toute nouvelle requête :

~~~
unbound: [12503:0] error: can't create socket: Too many open files
~~~

Par défaut, cette limite est configurée à 512 dans `/etc/login.conf`. Nous conseillons de l'augmenter à 2048 :

~~~
unbound:\
    :openfiles=2048:\
    :tc=daemon:
~~~

Si cette modification est faite alors qu'unbound est déjà démarré, il faudra le redémarrer pour que la modification soit prise en compte.

Si nécessaire, augmenter également le nombre de file descriptor pouvant être ouverts globalement au système :

~~~
# sysctl kern.maxfiles                                                                                                                                                                                                                                                                                         
kern.maxfiles=7030
# sysctl kern.maxfiles=20480
# echo kern.maxfiles=20480 >> /etc/sysctl.conf
~~~

### Activation sous OpenBSD

On active Unbound dans `rc.conf.local` et on démarre le daemon :

~~~
# rcctl enable unbound
# rcctl start unbound
~~~

## Monitoring

### Avoir des statistiques

On peut accéder à des statistiques avec [unbound-control(8)](https://man.openbsd.org/unbound-control).

Pour cela, le `remote-control` doit être activé :

~~~
remote-control:
    control-enable: yes
    control-use-cert: no
    control-interface: /var/run/unbound.sock
~~~

Sous Debian :

~~~
# unbound-control stats
~~~

Sous OpenBSD :

~~~
$ doas -u _unbound unbound-control stats
~~~

Si l'on veut avoir des statistiques plus détaillées, avec notamment le type de requêtes, on peut ajouter à la configuration :

~~~
extended-statistics: yes
~~~

Enfin, les statistiques peuvent régulièrement être affichées dans les logs avec cette configuration :

~~~
statistics-interval: 300
~~~

### dnstop

Voir [HowtoBind#dnstop]()

## Bloquer des domaines indésirables

Unbound peut être utilisé pour renvoyer une réponse `NXDOMAIN` pour des domaines spécifiques.

Le script [unbound-adblock](https://www.geoghegan.ca/unbound-adblock.html) est un script personnalisable, qui se lance périodiquement, et qui permet de bloquer les publicités et autres domaines indésirables à partir de sources URL de fichiers `hosts`, que le script parse et rend compatible au format d'unbound.

### Installation de unbound-adblock

Sous Debian ou OpenBSD :

* Avoir unbound configuré et fonctionnel en tant que serveur DNS récursif local
* Télécharger le script : `wget https://geoghegan.ca/pub/unbound-adblock/0.4/unbound-adblock.sh`
* Créer un utilisateur "_adblock" : ` useradd -s /sbin/nologin _adblock`
* Installer le script avec les permissions appropriées : `install -m 755 -o root -g bin unbound-adblock.sh /usr/local/bin/unbound-adblock.sh`
* Apporter une correction au script pour préciser l'emplacement de la commande unbound-checkconf : `sed -i "s/^unbound-checkconf/\/usr\/sbin\/unbound-checkconf/" /usr/local/bin/unbound-adblock.sh` 
* Créer le fichier "/etc/unbound/adblock.conf" : 
    * Sous Debian : `install -m 640 -o _adblock /dev/null /etc/unbound/adblock.conf`
    * Sous OpenBSD : `install -m 640 -o _adblock -g wheel /dev/null /var/unbound/etc/adblock.conf`
* Donner les permissions nécessaires à l'utilisateur "_adblock" :
    * Sous Debian avec `visudo` : `_adblock    ALL=(root) NOPASSWD: /bin/systemctl restart unbound`
    * Sous OpenBSD en éditant `/etc/doas.conf` : `permit nopass _adblock cmd rcctl args reload unbound`
* Ajouter l'inclusion de la configuration dans "unbound.conf" (**avant** la section de forward s'il en existe une) : `include: /etc/unbound/adblock.conf`
* Éditer la crontab de l'utilisateur "_adblock" pour lancer quotidiennement le script, avec `crontab -u _adblock -e` :
    * Sous Debian : `@midnight  /bin/sh /usr/local/bin/unbound-adblock.sh -linux`
    * Sous OpenBSD : `@midnight /bin/sh /usr/local/bin/unbound-adblock.sh`
* Lancer une première fois le script manuellement :
    * Sous Debian : `sudo -u _adblock sh /usr/local/bin/unbound-adblock.sh -linux`
    * Sous OpenBSD : `doas -u _adblock sh /usr/local/bin/unbound-adblock.sh`

### Configuration supplémentaire optionnelle sous OpenBSD

Google impose l'utilisation de ses propres serveurs DNS dans de nombreuses applications et services. De nombreux appareils utilisent également des DNS Google codés en dur et qui ne peuvent pas être modifiés.

Il est possible de contourner ça avec [HowtoOpenBSD/PacketFilter]() en rajoutant la règle suivante dans `/etc/pf.conf` pour forcer l'utilisation de notre résolveur DNS :

~~~
# Remplacer $adblock_server par l'adresse IP de la machine qui heberge le service unbound
pass in quick to {8.8.8.8, 8.8.4.4} rdr-to $adblock_server

# Ou, de façon plus globale
pass in quick proto {tcp udp} to port 53 rdr-to $adblock_server
~~~

Puis recharger la configuration : `# pfctl -f /etc/pf.conf`.

### Liste de sources de fichiers hosts

Les listes doivent obligatoirement être dans un format de fichier `hosts` pour fonctionner.

Par défaut, l'URL <https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts> est fournie comme seule source.
Des versions plus complètes provenant du même projet peuvent être trouvées sur le README du github (bloquant par exemple tous les réseaux sociaux, les sites de fake news, …) : <https://github.com/StevenBlack/hosts>.

L'URL <https://raw.githubusercontent.com/jerryn70/GoodbyeAds/master/Hosts/GoodbyeAds.txt> peut être rajoutée comme seconde source, plus complète et plus agressive.

### Whitelister des domaines bloqués

Si un domaine présent dans une des listes a besoin d'être autorisé, il peut être whitelisté. Pour cela, il faut éditer le script, et ajouter dans la fonction whitelist(), à l'intérieur du grep, le domaine en question :

~~~
whitelist() {
    grep -E -v 'example\.com|example\.org'
}
~~~

Attention : Il ne faut pas ajouter une commande grep mais bien ajouter le domaine à la liste actuelle. Une nouvelle commande grep ne sera pas prise en compte.

### Bloquer des domaines personnalisés

Il est tout à fait possible de bloquer n'importe quel domaine souhaité sans forcément utiliser le script ci-dessus, ou même en complément du script.

Pour cela, il suffit d'ajouter un autre fichier de configuration à inclure à `unbound.conf`, et d'y ajouter manuellement les entrées à bloquer souhaitées, en respectant ce format, avec un domaine par ligne :

~~~
local-zone: "example.com" always_nxdomain
~~~

À noter que l'ensemble des sous-domaines (*.example.com ; www.example.com par exemple) seront bloqués.

## FAQ

### Vider le cache pour un domaine particulier

~~~
unbound-control flush_zone foo.local
~~~

### Vider tout le cache

~~~
unbound-control flush_infra all
~~~

*Si l'on spécifie une IP à la place de "all", alors l'entrée pour cette adresse est supprimée du cache*

### Utiliser un serveur DNS particulier pour un nom de domaine

On pourra forwarder certaines requêtes vers un serveur différent en rajoutant les directives ci-dessous :

~~~
forward-zone:
  name: "foo.local."
  forward-addr: 192.0.2.1
  forward-first: yes
~~~

Dans le cas présent, les requêtes concernent une zone locale, ainsi afin d'éviter une vérification DNSSEC pour ces dernières on ajoutera la directive suivante dans la configuration de unbound :

~~~
domain-insecure: "foo.local."
~~~

### Rajouter / modifier un enregistrement DNS

Parfois on veut pouvoir modifier un enregistrement DNS, par exemple
quand on a un VPN. On peut utiliser `/etc/hosts` pour les champs A
mais pas pour les MX. On peut donc utiliser unbound pour mentir :

~~~
  local-zone: "example.com." typetransparent
  local-data: "example.com. IN MX 10 fakemx.example.com."
  local-data: "fakemx.example.com. IN A 192.168.1.3"
~~~

### Configuration sur un routeur

Il NE faut JAMAIS mettre une configuration de type :

~~~
  interface: 0.0.0.0
~~~

…car Unbound ne va pas forcément répondre avec la bonne interface et on peut avoir des erreurs du type :

~~~
$ dig @IP-routeur
;; reply from unexpected source: autre.ip.du.routeur#53, expected ipdurouteur#53
~~~

Il faut lister explicitement toutes les interfaces sur lesquelles on souhaite qu'Unbound écoute.

### dig +trace ne fonctionne pas

C'est certainement parce que le client a une autorisation insuffisante
pour ce type de requête particulière. Il faut donc remplacer dans la
directive `access-control:` le mot-clé `allow` par `allow_snoop`.

### Mentir sur le TTL

On peut vouloir mettre un TTL minimum pour ne pas respecter le TTL quand il est mis à des valeurs anormalement basses. Pour mettre le TTL minimum à 600 :

~~~
cache-min-ttl: 600
~~~

### Diminuer le cache des réponses négatives

Si on veut diminuer à 30s la durée de mise en cache des résolutions n'ayant pas de réponse :

~~~
cache-max-negative-ttl: 30
~~~
