-/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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
*/
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);
}
/*!
#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) {
-/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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
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 *);
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.
*
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
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")
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()
query_test(knot, bind, True)
knot.dnssec(zone[0]).nsec3 = True
+knot.dnssec(zone[0]).nsec3_opt_out = True
knot.gen_confile()
knot.reload()