From: Libor Peltan Date: Mon, 30 Aug 2021 12:15:32 +0000 (+0200) Subject: bugfix: fix answering with opt-outed NSEC3 on empty-non-terminal X-Git-Tag: v3.1.2~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4e885cc16b0077f7a04f45416ebd33ec2a404055;p=thirdparty%2Fknot-dns.git bugfix: fix answering with opt-outed NSEC3 on empty-non-terminal --- diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c index c23f2863d5..93e47ffc21 100644 --- a/src/knot/nameserver/nsec_proofs.c +++ b/src/knot/nameserver/nsec_proofs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. +/* Copyright (C) 2021 CZ.NIC, z.s.p.o. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ static bool wildcard_expanded(const zone_node_t *node, const knot_dname_t *qname */ static bool ds_optout(const zone_node_t *node) { - return node_nsec3_get(node) == NULL && node->flags & NODE_FLAGS_DELEG; + return node_nsec3_get(node) == NULL && !(node->flags & NODE_FLAGS_SUBTREE_AUTH); } /*! diff --git a/src/knot/zone/adjust.c b/src/knot/zone/adjust.c index ba53c48884..b5006ad19c 100644 --- a/src/knot/zone/adjust.c +++ b/src/knot/zone/adjust.c @@ -21,19 +21,47 @@ #include "knot/zone/measure.h" #include "libdnssec/error.h" +static bool node_non_dnssec_exists(const zone_node_t *node) +{ + assert(node); + + for (uint16_t i = 0; i < node->rrset_count; ++i) { + switch (node->rrs[i].type) { + case KNOT_RRTYPE_NSEC: + case KNOT_RRTYPE_NSEC3: + case KNOT_RRTYPE_RRSIG: + continue; + default: + return true; + } + } + + return false; +} + int adjust_cb_flags(zone_node_t *node, adjust_ctx_t *ctx) { zone_node_t *parent = node_parent(node); uint16_t flags_orig = node->flags; + bool set_subt_auth = false; assert(!(node->flags & NODE_FLAGS_DELETED)); - node->flags &= ~(NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH); + node->flags &= ~(NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH | NODE_FLAGS_SUBTREE_AUTH); if (parent && (parent->flags & NODE_FLAGS_DELEG || parent->flags & NODE_FLAGS_NONAUTH)) { node->flags |= NODE_FLAGS_NONAUTH; } else if (node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != ctx->zone->apex) { node->flags |= NODE_FLAGS_DELEG; + if (node_rrtype_exists(node, KNOT_RRTYPE_DS)) { + set_subt_auth = true; + } + } else if (node_non_dnssec_exists(node)) { + set_subt_auth = true; + } + + if (set_subt_auth) { + node_set_flag_hierarch(node, NODE_FLAGS_SUBTREE_AUTH); } if (node->flags != flags_orig && ctx->changed_nodes != NULL) { diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h index 42c756170c..045eea534d 100644 --- a/src/knot/zone/node.h +++ b/src/knot/zone/node.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. +/* Copyright (C) 2021 CZ.NIC, z.s.p.o. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -100,6 +100,8 @@ enum node_flags { NODE_FLAGS_SECOND = 1 << 9, // this value shall be fixed /*! \brief The node shall be deleted. It's just not because it's a bi-node and the counterpart still exists. */ NODE_FLAGS_DELETED = 1 << 10, + /*! \brief The node or some node in subtree has some authoritative data in it (possibly also DS at deleg). */ + NODE_FLAGS_SUBTREE_AUTH = 1 << 11, }; typedef void (*node_addrem_cb)(zone_node_t *, void *); @@ -296,6 +298,16 @@ inline static const zone_node_t *glue_node(const glue_t *glue, const zone_node_t return binode_node_as((zone_node_t *)glue->node, another_zone_node); } +/*! + * \brief Add a flag to this node and all (grand-)parents until the flag is present. + */ +inline static void node_set_flag_hierarch(zone_node_t *node, uint16_t fl) +{ + for (zone_node_t *i = node; i != NULL && (i->flags & fl) != fl; i = node_parent(i)) { + i->flags |= fl; + } +} + /*! * \brief Checks whether node contains any RRSIG for given type. * diff --git a/tests-extra/data/flags.zone b/tests-extra/data/flags.zone index 92b6970007..01b89506d5 100644 --- a/tests-extra/data/flags.zone +++ b/tests-extra/data/flags.zone @@ -23,6 +23,9 @@ sub NS sub sub A 192.0.0.1 ns.sub A 192.0.2.4 +; Opt-outable delegation below empty-non-terminal +deleg.ent NS sub + ; CNAME to A record cname CNAME dns1 diff --git a/tests-extra/tests/basic/query/test.py b/tests-extra/tests/basic/query/test.py index 19f8c96312..4dd90e4f1f 100644 --- a/tests-extra/tests/basic/query/test.py +++ b/tests-extra/tests/basic/query/test.py @@ -69,6 +69,11 @@ def query_test(knot, bind, dnssec): resp.check(rcode="NOERROR", flags="QR AA", noflags="TC AD RA") resp.cmp(bind, additional=True) + # Positive (NODATA, at delegation, DS type, below empty-non-terminal) + resp = knot.dig("deleg.ent.flags", "DS", udp=True, dnssec=dnssec) + resp.check(rcode="NOERROR", flags="QR AA", noflags="TC AD RA") + resp.cmp(bind, additional=True) + # Positive (REFERRAL, below delegation, DS type) resp = knot.dig("net.ds-sub.flags", "DS", udp=True, dnssec=dnssec) resp.check(rcode="NOERROR", flags="QR", noflags="AA TC AD RA") @@ -348,6 +353,15 @@ query_test(knot, bind, False) knot.dnssec(zone[0]).enable = True knot.dnssec(zone[0]).nsec3 = False +knot.dnssec(zone[0]).nsec3_opt_out = False +knot.gen_confile() +knot.reload() + +serial = bind.zone_wait(zone, serial) +query_test(knot, bind, True) + +knot.dnssec(zone[0]).nsec3 = True +knot.dnssec(zone[0]).nsec3_opt_out = False knot.gen_confile() knot.reload() @@ -355,6 +369,7 @@ serial = bind.zone_wait(zone, serial) query_test(knot, bind, True) knot.dnssec(zone[0]).nsec3 = True +knot.dnssec(zone[0]).nsec3_opt_out = True knot.gen_confile() knot.reload()