Warda-DNSDocs Warda: from ward — to protect, guardian
v0.9.3

Warda asks the upstream servers with the AD bit (RFC 6840): a validating resolver says whether it checked the signatures, without sending them. The answers validated are counted. A minute after the start, then every 6 hours (task dnssec.check), each upstream is asked isc.org (signed: AD expected) and dnssec-failed.org (signed wrong: SERVFAIL expected): it validates, or not. With Only ask the upstream servers that validate DNSSEC (PUT /api/v1/dns-services/dnssec, meta dnssec_require), only those are asked while at least one is known to validate; the others only when none of them answers (names never stop resolving). POST /api/v1/dns-services/dnssec/check checks at once.

Validation by Warda itself (beta)#

With Check the signatures in Warda itself (PUT /api/v1/dns-services/dnssec/native {"enabled": true}, meta dnssec_validate, off by default), Warda asks each name with the DO bit and validates the answer itself, from the trust anchors of the root (KSK-2017 20326 and KSK-2024 38696): the keys (DNSKEY) and delegations (DS) of each zone are asked to the same upstreams and kept in memory (a minute to an hour, 4096 zones at most). Algorithms 8 and 10 (RSA/SHA-256 and SHA-512), 13 and 14 (ECDSA P-256 and P-384) and 15 (Ed25519); digests SHA-1, SHA-256 and SHA-384; the proofs of denial NSEC and NSEC3 (150 iterations at most; closest encloser and wildcard proofs; opt-out read as unsigned). The result of each answer:

  • secure: every record verified up to the root: the AD flag is set;
  • insecure: the zone is proven unsigned (or signed only with other algorithms): passed, without AD;
  • bogus: a signed zone whose answer does not verify, an unsigned answer in a signed zone, a signature by a name that is no signed zone, or a name under a signed zone whose absence of DS is not proven: refused with SERVFAIL (not cached, not counted as an error of the upstream);
  • indeterminate: Warda could not tell (an answer made from a wildcard, a denial signed but not proven, the types ANY and RRSIG): passed without AD, as insecure.

It fails open only when the keys of the root cannot be verified (upstreams that remove the signatures, no network): everything is then indeterminate for 5 minutes and the page says so (dnssec.status.working false). Below the root, a key query that fails costs the answer (SERVFAIL, asked again at the next query): only a proven unsigned delegation makes a name insecure. It protects from answers forged or changed on the way; a forged denial of existence that replays real signed records passes without AD. Not to use with a filtering upstream (Quad9, AdGuard, NextDNS, Cloudflare 1.1.1.2 or 1.1.1.3): its unsigned blocks of signed names become SERVFAIL. A resolver that answers the DS query of a zone from the zone itself (a local authoritative zone) makes it bogus: such zones belong in WARDA_FORWARD, which is never validated. The signatures are removed from the answer of a client that did not ask them (no DO); a client that sets CD is not validated; the local zones (WARDA_FORWARD) are never validated. The counts (secure, insecure, bogus) are on the page; turning it on empties the cache, and Restart the resolver forgets the keys.