Dgaard
Un collègue en cybersécurité m’a amené à m’intéresser aux listes de blocage DNS — filtrer les publicités, les malwares, la télémétrie — au niveau réseau plutôt que périphérique par périphérique. Le premier problème que je voulais résoudre était celui des domaines générés aléatoirement : les malwares utilisent des noms d’hôtes générés algorithmiquement (canaux C2, botnets) qui tournent si vite qu’aucune liste statique ne peut suivre. On ajoute un domaine à la liste, le malware en génère mille nouveaux dans la nuit.
Cette conversation avec une IA lors de la conception de l’outil a ouvert une image plus large. Les mathématiques de l’entropie et les modèles N-Gram permettent de détecter ces domaines générés en temps réel, avant qu’ils n’apparaissent sur quelque liste publique que ce soit. L’actualité du protocole DNS pointait vers d’autres lacunes : les attaques homographiques (domaines sosies utilisant des caractères Unicode), le DNS rebinding, l’exfiltration de données via les enregistrements TXT, le cloaking CNAME. Chacune est devenue un filtre. Ensuite, en tant que parent, j’avais besoin de quelque chose pouvant également empêcher les enfants de tomber sur des contenus nuisibles — sans la charge de maintenance liée à l’abonnement et à la mise à jour de bases de données de catégories toujours en retard d’un cran.
Le résultat est Dgaard : un proxy DNS de filtrage écrit en Rust qui s’exécute en bordure de réseau (sur un routeur, un Raspberry Pi ou un petit VPS) et combine des listes de blocage statiques avec un moteur heuristique qui détecte les menaces qu’aucune liste n’a encore vues.
Fonctionnement
Chaque requête DNS traverse un pipeline à plusieurs niveaux. Chaque étape peut bloquer la requête ou la laisser passer à la suivante :
- Filtre rapide d’entrée — rejette immédiatement les domaines malformés ou non-ASCII.
- Liste blanche — les domaines de confiance passent toutes les vérifications restantes via une recherche de hachage sans copie.
- Bloqueur IDN intelligent — décode le Punycode et signale les attaques homographiques (ex.
аррlе.comutilisant des caractères cyrilliques). - Liste de blocage hiérarchisée — correspondances exactes et règles de jokers stockées dans des filtres de Bloom et des archives zero-copy rkyv ; des millions d’entrées, des recherches en sous-milliseconde, une RAM minimale.
- Moteur heuristique — calcule l’entropie de Shannon et les scores N-Gram sur le nom de domaine lui-même. Les chaînes à forte aléatoire comme
ajh12-v9z.topsont caractéristiques des domaines générés algorithmiquement et sont bloqués ici sans aucune connaissance préalable. - Analyse comportementale — suit les taux de NXDOMAIN par client (indicateurs de botnet), surveille l’entropie des enregistrements TXT et les chaînes CNAME pour les schémas d’exfiltration de données, et limite la profondeur des labels de domaine pour détecter les outils de tunneling DNS (iodine, dnscat2).
- Score GeoIP — après la résolution en amont, vérifie les IPs retournées dans une base de données locale au format MaxMind. Les réponses provenant de juridictions à haut risque ajoutent des points pondérés au score de menace cumulatif du domaine, amplifiant les autres signaux sans bloquer purement par géographie.
- Indicateurs de renseignement sur les menaces personnalisés — jusqu’à 16 listes de domaines définies par l’utilisateur mappées sur des bitflags nommés, chacun avec son propre poids de suspicion ; utile pour des flux sectoriels (finance, santé) ou des jeux de données de classification générés par IA.
Le pipeline est conçu pour court-circuiter tôt : la plupart des requêtes saines sont répondues depuis le cache LRU ou la liste blanche avant que le moteur heuristique ne s’exécute.
Contrôle parental
Plutôt que de s’abonner à de grandes bases de données de catégories nécessitant des mises à jour constantes, Dgaard utilise une correspondance de mots-clés sensible aux labels, propulsée par un automate Aho-Corasick. Une petite liste de mots-clés (ex. casino, porno, bet) est compilée en un automate qui occupe des kilo-octets, pas des méga-octets. Un mot-clé ne déclenche un blocage que s’il forme un label de domaine complet ou est séparé par un tiret — ainsi casino.com est bloqué mais pas casinon-les-bains.fr. Cela évite le problème classique de Scunthorpe où la correspondance de sous-chaînes bloque des sites légitimes. Les nouveaux domaines dans les catégories bloquées sont détectés dès leur enregistrement, sans aucune mise à jour de liste nécessaire.
Composants
La suite comprend quatre outils installables indépendamment :
dgaard est le proxy DNS lui-même. Il écoute sur le port 5353 (ou 53 directement), reçoit les requêtes UDP/TCP, et transfère les requêtes saines vers un résolveur en amont via DNS-over-TLS. Binaire de moins de 5 Mo ; conçu pour OpenWrt et les routeurs embarqués.
dgaard-engine est le cœur de filtrage extrait en bibliothèque Rust autonome sans runtime asynchrone. N’importe quelle application — un serveur mail, un proxy HTTP, un script personnalisé — peut l’embarquer et appeler resolve_with_score() pour évaluer un domaine contre le pipeline complet.
dgaard-daemon est un démon socket Unix qui encapsule dgaard-engine. Il évalue les domaines contre le pipeline de filtrage complet et retourne un score de suspicion JSON — sans effectuer de résolution DNS. Conçu comme sidecar pour les MTAs (Postfix, Rspamd) ou tout processus local pouvant écrire sur un socket Unix. Supporte SIGHUP pour un rechargement atomique des listes de blocage sans redémarrage.
dgaard-rest est une API REST HTTP qui encapsule dgaard-engine. Elle expose le scoring de domaines en HTTP/JSON pour les tableaux de bord, services web ou tout outil parlant HTTP — sans effectuer de résolution DNS. Points d’accès : GET /api/v1/health (sonde de vivacité), GET /api/v1/blocklists (métadonnées des listes et rechargement asynchrone), et POST /api/v1/check (évaluer un domaine). Supporte SIGHUP pour le rechargement atomique des listes.
dgaard-monitor est un tableau de bord terminal qui se connecte au socket Unix de dgaard et affiche l’activité DNS en temps réel : trafic par client, graphiques chronologiques, domaines les plus bloqués et statistiques de blocage. Linux uniquement.
adblockptimize ingère des listes de blocage standard (fichiers ou URLs) et les divise en une sortie réseau dédupliquée (pour dgaard, Pi-hole, dnsmasq) et une sortie navigateur (règles CSS/JS cosmétiques pour uBlock Origin). Cela supprime le bruit spécifique aux navigateurs de la liste DNS et la réduit considérablement.
Alternatives
Auto-hébergées
Pi-hole est un DNS sinkhole qui intercepte les requêtes et retourne NXDOMAIN pour les domaines bloqués. Il est bien établi, possède une interface web et supporte un large écosystème de listes communautaires. Le filtrage est entièrement basé sur des listes : un domaine doit figurer sur une liste avant d’être bloqué. Pas d’heuristiques, pas de détection DGA. L’utilisation mémoire évolue avec la taille des listes. Conçu pour Raspberry Pi mais nécessite plus de ressources que ce qu’un routeur OpenWrt typique peut offrir.
AdGuard Home est architecturalement similaire à Pi-hole mais ajoute le support des résolveurs DNS-over-HTTPS/TLS en amont, un mode de contrôle parental s’appuyant sur la base de données de catégories cloud d’AdGuard, et un éditeur de règles de filtrage côté client. Toujours entièrement basé sur des listes pour les décisions de blocage. Le contrôle parental nécessite d’envoyer les requêtes à l’API Safe Browsing d’AdGuard, soit un appel cloud. Plus lourd que Pi-hole en termes de ressources.
Pi-hole et AdGuard Home partagent la même lacune fondamentale : ils sont aveugles aux domaines nouvellement enregistrés et générés algorithmiquement jusqu’à ce qu’un humain ajoute une entrée de liste.
DNS cloud
CleanBrowsing Family Filter, OpenDNS FamilyShield, AdGuard Family DNS et Cloudflare 1.1.1.3 fonctionnent tous de la même façon : vous pointez le DNS de votre routeur vers leurs serveurs, et ils filtrent les réponses selon leurs propres catégories. La configuration prend deux minutes. Le filtrage parental est mis à jour en continu par leurs équipes.
Le compromis est structurel. Chaque requête DNS de votre réseau — chaque site visité, chaque connexion d’application, chaque appareil connecté — est résolue via leur infrastructure. Ces données sont journalisées, au minimum à des fins de service et d’abus. Pour un réseau domestique avec des appareils d’enfants, des applications médicales et des machines de travail sur le même sous-réseau, c’est une empreinte de données significative confiée à un tiers.
La latence est un autre facteur. Le DNS cloud ajoute un aller-retour vers un résolveur distant pour chaque requête non mise en cache. Sur une connexion bien connectée, c’est généralement négligeable, mais c’est une dépendance dure : si l’amont est injoignable ou vous limite, la résolution DNS s’arrête pour tout le réseau.
Ces services n’offrent également aucune personnalisation en dessous du niveau catégorie. Vous ne pouvez pas ajuster les scores, ajouter vos propres flux de renseignements, mettre des patterns en liste blanche, ni inspecter ce qui a été bloqué et pourquoi.
Comparaison
| Pi-hole | AdGuard Home | DNS cloud (tous) | Dgaard | |
|---|---|---|---|---|
| Vie privée | Locale | Locale (parental via API cloud) | Toutes les requêtes envoyées au fournisseur | Entièrement locale |
| Détection DGA | Non | Non | Variable, opaque | Oui (entropie + N-Gram) |
| Domaines nouvellement enregistrés | Réactif (liste) | Réactif (liste) | Variable, opaque | Proactif (flux NRD + heuristiques) |
| Contrôle parental | Via listes | Via API AdGuard cloud | Oui, par catégorie | Oui, moteur de mots-clés local |
| Utilisation RAM | Modérée–élevée | Élevée | Aucune (cloud) | Faible (filtres de Bloom + rkyv) |
| OpenWrt / embarqué | Difficile | Non | Non (juste config DNS) | Oui (binaire sous 5 Mo) |
| Supervision | Interface web | Interface web | Tableau de bord fournisseur uniquement | TUI terminal, socket Unix |
| Personnalisation | Listes, regex | Listes, règles | Aucune en dessous de la catégorie | Config par étape, flags TI personnalisés, poids GeoIP |
| Blocage tunneling DNS | Non | Non | Variable, opaque | Oui (limite de profondeur de labels) |
| Dépendance internet | Non | Partielle (parental) | Oui | Non |
Code source : codeberg.org/slundi/dgaard