-- GENERE par Set-OPS (role serveur_dns_public). Ne pas editer a la main. -- -- LE FRONTAL PUBLIC DU SERVEUR DNS DU SITE — ce que l'Internet frappe, avant PowerDNS. -- -- PowerDNS repond ; dnsdist decide QUI a droit a une reponse, et combien. Un autoritatif -- expose sans frontal est un amplificateur offert : une requete de 60 octets, adresse source -- usurpee, rend 1 a 3 Ko signes DNSSEC a la victime. -- -- Chaque regle ci-dessous a ete eprouvee le 2026-09-16 sur cette machine, dans l'unite -- `dnsdist.service`, avec le vrai PowerDNS derriere. -- AUCUN APPEL VERS L'EDITEUR (meme raison que `security-poll-suffix=` de PowerDNS). setSecurityPollSuffix("") setLocal("{{ serveur_dns_public_ecoute }}:{{ serveur_dns_public_frontal_port }}") -- TOUT LE MONDE PEUT DEMANDER : c'est un serveur de noms public. Ce qui est borne, c'est -- ce qu'on demande (regles) et a quel rythme (debit). setACL({"0.0.0.0/0", "::/0"}) -- LE SEUL AMONT : le PowerDNS de cette machine. Sonde par le SOA d'une zone qu'il DOIT servir -- — un PowerDNS vivant mais vide serait declare en panne, et c'est juste. newServer({address="{{ serveur_dns_public_ecoute }}:{{ serveur_dns_public_port }}", name="pdns", checkName="{{ (serveur_dns_public_relations | map(attribute='zones') | flatten | first) | default('.') }}.", checkType="SOA", mustResolve={{ 'true' if (serveur_dns_public_relations | map(attribute='zones') | flatten | length) > 0 else 'false' }}}) setServerPolicy(firstAvailable) -- NI TRANSFERT, NI NOTIFICATION, NI MISE A JOUR DEPUIS DEHORS. Les NOTIFY des primaires -- arrivent directement a PowerDNS, par le reseau du site ; par ici, ils seraient ceux de -- n'importe qui. (Eprouve : NOTIFY -> REFUSED, AXFR -> « Transfer failed ».) addAction(NotRule(OpcodeRule(DNSOpcode.Query)), RCodeAction(DNSRCode.REFUSED)) addAction(OrRule({QTypeRule(DNSQType.AXFR), QTypeRule(DNSQType.IXFR)}), RCodeAction(DNSRCode.REFUSED)) -- ANY EN UDP : TRONQUE (RFC 8482). La reponse ANY est la plus grosse qu'une zone puisse -- rendre ; tronquee, elle ne pese que l'en-tete, et un vrai client repasse en TCP — ce qu'un -- attaquant a adresse usurpee ne peut pas faire. -- -- PIEGE DE MESURE (2026-09-16) : `dig` envoie ANY en TCP par defaut. Le premier essai a donc -- « montre » une regle inoperante ; `dig +notcp` montre la troncature, et le compteur de la -- regle le confirme. addAction(AndRule({QTypeRule(DNSQType.ANY), NotRule(TCPRule(true))}), TCAction()) -- LE DEBIT, PAR /{{ serveur_dns_public_debit_masque_v4 }} (et /{{ serveur_dns_public_debit_masque_v6 }} en IPv6). En UDP, au-dela : reponse tronquee — le -- client legitime passe en TCP, la victime d'une reflexion ne recoit qu'un en-tete. En TCP, -- au-dela : abandon ; la poignee de main prouve deja l'adresse, le debit borne l'abus. addAction(AndRule({MaxQPSIPRule({{ serveur_dns_public_debit_udp }}, {{ serveur_dns_public_debit_masque_v4 }}, {{ serveur_dns_public_debit_masque_v6 }}, {{ serveur_dns_public_debit_udp * 2 }}), NotRule(TCPRule(true))}), TCAction()) addAction(AndRule({MaxQPSIPRule({{ serveur_dns_public_debit_tcp }}, {{ serveur_dns_public_debit_masque_v4 }}, {{ serveur_dns_public_debit_masque_v6 }}, {{ serveur_dns_public_debit_tcp * 2 }}), TCPRule(true)}), DropAction())