Skip to content
Snippets Groups Projects
Commit c4c32bef authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman
Browse files

adjust nsec3 ptr: pointing either at node or owner if no node

this shall speed-up adjusting with nsec3-opt-out
because the dead nsec3 pointers are not recalculated every time
parent 4fc38ff1
No related branches found
No related tags found
No related merge requests found
......@@ -83,6 +83,71 @@ int knot_create_nsec3_owner(uint8_t *out, size_t out_size,
return ret;
}
knot_dname_t *node_nsec3_hash(zone_node_t *node, const zone_contents_t *zone)
{
if (node->nsec3_hash == NULL && knot_is_nsec3_enabled(zone)) {
assert(!(node->flags & NODE_FLAGS_NSEC3_NODE));
size_t hash_size = zone_nsec3_name_len(zone);
knot_dname_t *hash = malloc(hash_size);
if (hash == NULL) {
return NULL;
}
if (knot_create_nsec3_owner(hash, hash_size, node->owner, zone->apex->owner,
&zone->nsec3_params) != KNOT_EOK) {
free(hash);
return NULL;
}
node->nsec3_hash = hash;
}
if (node->flags & NODE_FLAGS_NSEC3_NODE) {
return node->nsec3_node->owner;
} else {
return node->nsec3_hash;
}
}
zone_node_t *node_nsec3_node(zone_node_t *node, const zone_contents_t *zone)
{
if (!(node->flags & NODE_FLAGS_NSEC3_NODE) && knot_is_nsec3_enabled(zone)) {
knot_dname_t *hash = node_nsec3_hash(node, zone);
zone_node_t *nsec3 = zone_tree_get(zone->nsec3_nodes, hash);
if (nsec3 != NULL) {
if (node->nsec3_hash != binode_counterpart(node)->nsec3_hash) {
free(node->nsec3_hash);
}
node->nsec3_node = nsec3;
node->flags |= NODE_FLAGS_NSEC3_NODE;
}
}
return node_nsec3_get(node);
}
int binode_fix_nsec3_pointer(zone_node_t *node, const zone_contents_t *zone)
{
zone_node_t *counter = binode_counterpart(node);
if (counter->nsec3_hash == NULL) {
(void)node_nsec3_node(node, zone);
return KNOT_EOK;
}
zone_node_t *nsec3_counter = (counter->flags & NODE_FLAGS_NSEC3_NODE) ?
binode_counterpart(counter->nsec3_node) : NULL;
if (nsec3_counter != NULL && !(nsec3_counter->flags & NODE_FLAGS_DELETED)) {
node->nsec3_node = nsec3_counter;
} else {
node->flags &= ~NODE_FLAGS_NSEC3_NODE;
if (counter->flags & NODE_FLAGS_NSEC3_NODE) {
// downgrade the NSEC3 node pointer to NSEC3 name
node->nsec3_hash = knot_dname_copy(counter->nsec3_node->owner, NULL);
} else {
node->nsec3_hash = counter->nsec3_hash;
}
(void)node_nsec3_node(node, zone);
}
return KNOT_EOK;
}
static bool nsec3param_valid(const knot_rdataset_t *rrs,
const dnssec_nsec3_params_t *params)
{
......
......@@ -74,6 +74,40 @@ int knot_create_nsec3_owner(uint8_t *out, size_t out_size,
const knot_dname_t *owner, const knot_dname_t *zone_apex,
const dnssec_nsec3_params_t *params);
/*!
* \brief Return (and compute of needed) the corresponding NSEC3 node's name.
*
* \param node Normal node.
* \param zone Optional: zone contents with NSEC3 params.
*
* \return NSEC3 node owner.
*
* \note The result is also stored in (node), unless zone == NULL;
*/
knot_dname_t *node_nsec3_hash(zone_node_t *node, const zone_contents_t *zone);
/*!
* \brief Return (and compute if needed) the corresponding NSEC3 node.
*
* \param node Normal node.
* \param zone Optional: zone contents with NSEC3 params and NSEC3 tree.
*
* \return NSEC3 node.
*
* \note The result is also stored in (node), unless zone == NULL;
*/
zone_node_t *node_nsec3_node(zone_node_t *node, const zone_contents_t *zone);
/*!
* \brief Update node's NSEC3 pointer (or hash), taking it from bi-node counterpart if possible.
*
* \param node Bi-node with this node to be updated.
* \param zone Zone contents the node is in.
*
* \return KNOT_EOK :)
*/
int binode_fix_nsec3_pointer(zone_node_t *node, const zone_contents_t *zone);
/*!
* \brief Create NSEC or NSEC3 chain in the zone.
*
......
......@@ -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_node == NULL && node->flags & NODE_FLAGS_DELEG;
return node_nsec3_get(node) == NULL && node->flags & NODE_FLAGS_DELEG;
}
/*!
......@@ -273,7 +273,7 @@ static int put_closest_encloser_proof(const knot_dname_t *qname,
{
// An NSEC3 RR that matches the closest (provable) encloser.
int ret = put_nsec3_from_node(cpe->nsec3_node, qdata, resp);
int ret = put_nsec3_from_node(node_nsec3_get(cpe), qdata, resp);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -530,8 +530,9 @@ static int put_nsec3_nodata(const knot_dname_t *qname,
// NSEC3 matching QNAME is always included.
if (match->nsec3_node) {
ret = put_nsec3_from_node(match->nsec3_node, qdata, resp);
zone_node_t *nsec3_match = node_nsec3_get(match);
if (nsec3_match != NULL) {
ret = put_nsec3_from_node(nsec3_match, qdata, resp);
if (ret != KNOT_EOK) {
return ret;
}
......
......@@ -42,33 +42,14 @@ int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone)
return KNOT_EOK; // always returns this value :)
}
int adjust_cb_point_to_nsec3(zone_node_t *node, const zone_contents_t *zone)
{
if (!knot_is_nsec3_enabled(zone)) {
node->nsec3_node = NULL;
return KNOT_EOK;
}
if (node->nsec3_node != NULL) {
zone_node_t *real_nsec3 = binode_node(node->nsec3_node, node->flags & NODE_FLAGS_SECOND);
if ((real_nsec3->flags & NODE_FLAGS_IN_NSEC3_CHAIN) &&
!(real_nsec3->flags & NODE_FLAGS_DELETED)) {
node->nsec3_node = real_nsec3;
return KNOT_EOK;
}
}
uint8_t nsec3_name[KNOT_DNAME_MAXLEN];
int ret = knot_create_nsec3_owner(nsec3_name, sizeof(nsec3_name), node->owner,
zone->apex->owner, &zone->nsec3_params);
if (ret == KNOT_EOK) {
node->nsec3_node = zone_tree_get(zone->nsec3_nodes, nsec3_name);
}
return ret;
}
int unadjust_cb_point_to_nsec3(zone_node_t *node, const zone_contents_t *zone)
{
UNUSED(zone);
node->nsec3_node = NULL;
// downgrade the NSEC3 node pointer to NSEC3 name
if (node->flags & NODE_FLAGS_NSEC3_NODE) {
node->nsec3_hash = knot_dname_copy(node->nsec3_node->owner, NULL);
node->flags &= ~NODE_FLAGS_NSEC3_NODE;
}
return KNOT_EOK;
}
......@@ -243,14 +224,14 @@ int adjust_cb_flags_and_nsec3(zone_node_t *node, const zone_contents_t *zone)
{
int ret = adjust_cb_flags(node, zone);
if (ret == KNOT_EOK) {
ret = adjust_cb_point_to_nsec3(node, zone);
ret = binode_fix_nsec3_pointer(node, zone);
}
return ret;
}
int adjust_cb_nsec3_and_additionals(zone_node_t *node, const zone_contents_t *zone)
{
int ret = adjust_cb_point_to_nsec3(node, zone);
int ret = binode_fix_nsec3_pointer(node, zone);
if (ret == KNOT_EOK) {
ret = adjust_cb_wildcard_nsec3(node, zone);
}
......@@ -401,7 +382,7 @@ int zone_adjust_incremental_update(zone_update_t *update)
ret = zone_adjust_update(update, adjust_cb_wildcard_nsec3, adjust_cb_void, true);
}
if (ret == KNOT_EOK) {
ret = zone_adjust_contents(update->new_cont, adjust_cb_point_to_nsec3, NULL, false);
ret = zone_adjust_contents(update->new_cont, binode_fix_nsec3_pointer, NULL, false);
}
if (ret == KNOT_EOK) {
ret = additionals_tree_update_from_binodes(
......
......@@ -166,6 +166,9 @@ void binode_unify(zone_node_t *node, bool free_deleted, knot_mm_t *mm)
if (counter->nsec3_wildcard_name != node->nsec3_wildcard_name) {
free(counter->nsec3_wildcard_name);
}
if (!(counter->flags & NODE_FLAGS_NSEC3_NODE) && node->nsec3_hash != counter->nsec3_hash) {
free(counter->nsec3_hash);
}
assert(((node->flags ^ counter->flags) & NODE_FLAGS_SECOND));
memcpy(counter, node, sizeof(*counter));
counter->flags ^= NODE_FLAGS_SECOND;
......@@ -254,6 +257,9 @@ void node_free(zone_node_t *node, knot_mm_t *mm)
binode_counterpart(node)->nsec3_wildcard_name == node->nsec3_wildcard_name);
free(node->nsec3_wildcard_name);
if (!(node->flags & NODE_FLAGS_NSEC3_NODE)) {
free(node->nsec3_hash);
}
if (node->rrs != NULL) {
mm_free(mm, node->rrs);
......
......@@ -41,7 +41,10 @@ typedef struct zone_node {
* nodes or delegation points are referenced by this.
*/
struct zone_node *prev;
struct zone_node *nsec3_node; /*! NSEC3 node corresponding to this node. */
union {
knot_dname_t *nsec3_hash; /*! Name of the NSEC3 corresponding to this node. */
struct zone_node *nsec3_node; /*! NSEC3 node corresponding to this node. */
};
knot_dname_t *nsec3_wildcard_name; /*! Name of NSEC3 node proving wildcard nonexistence. */
uint32_t children; /*!< Count of children nodes in DNS hierarchy. */
uint16_t rrset_count; /*!< Number of RRSets stored in the node. */
......@@ -85,6 +88,8 @@ enum node_flags {
NODE_FLAGS_IN_NSEC3_CHAIN = 1 << 5,
/*! \brief Node is the zone Apex. */
NODE_FLAGS_APEX = 1 << 6,
/*! \brief The nsec3_node pointer is valid and and nsec3_hash pointer invalid. */
NODE_FLAGS_NSEC3_NODE = 1 << 7,
/*! \brief Is this i bi-node? */
NODE_FLAGS_BINODE = 1 << 8, // this value shall be fixed
/*! \brief Is this the second half of bi-node? */
......@@ -355,3 +360,16 @@ static inline knot_rrset_t node_rrset_at(const zone_node_t *node, size_t pos)
rrset.additional = rr_data->additional;
return rrset;
}
/*!
* \brief Return the relevant NSEC3 node (if specified by adjusting), or NULL.
*/
static inline zone_node_t *node_nsec3_get(const zone_node_t *node)
{
if (!(node->flags & NODE_FLAGS_NSEC3_NODE) || node->nsec3_node == NULL) {
return NULL;
} else {
assert((node->nsec3_node->flags & NODE_FLAGS_SECOND) == (node->flags & NODE_FLAGS_SECOND));
return node->nsec3_node;
}
}
......@@ -750,10 +750,12 @@ static int check_nsec_bitmap(const zone_node_t *node, semchecks_data_t *data)
bool nsec = data->level & NSEC;
knot_rdataset_t *nsec_rrs = NULL;
zone_node_t *nsec3_node = node_nsec3_get(node);
if (nsec) {
nsec_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC);
} else if (node->nsec3_node != NULL) {
nsec_rrs = node_rdataset(node->nsec3_node, KNOT_RRTYPE_NSEC3);
} else if (nsec3_node != NULL) {
nsec_rrs = node_rdataset(nsec3_node, KNOT_RRTYPE_NSEC3);
}
if (nsec_rrs == NULL) {
return KNOT_EOK;
......@@ -789,7 +791,7 @@ static int check_nsec_bitmap(const zone_node_t *node, semchecks_data_t *data)
if (node_wire_size != nsec_wire_size ||
memcmp(node_wire, nsec_wire, node_wire_size) != 0) {
char buff[50 + KNOT_DNAME_TXT_MAXLEN];
char *info = nsec ? NULL : nsec3_info(node->nsec3_node->owner,
char *info = nsec ? NULL : nsec3_info(nsec3_node->owner,
buff, sizeof(buff));
data->handler->cb(data->handler, data->zone, node,
(nsec ? SEM_ERR_NSEC_RDATA_BITMAP : SEM_ERR_NSEC3_RDATA_BITMAP),
......@@ -866,7 +868,7 @@ static int check_nsec3_presence(const zone_node_t *node, semchecks_data_t *data)
bool deleg = (node->flags & NODE_FLAGS_DELEG) != 0;
if ((deleg && node_rrtype_exists(node, KNOT_RRTYPE_DS)) || (auth && !deleg)) {
if (node->nsec3_node == NULL) {
if (node_nsec3_get(node) == NULL) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_NSEC3_NONE, NULL);
}
......@@ -883,7 +885,7 @@ static int check_nsec3_presence(const zone_node_t *node, semchecks_data_t *data)
*/
static int check_nsec3_opt_out(const zone_node_t *node, semchecks_data_t *data)
{
if (!(node->nsec3_node == NULL && node->flags & NODE_FLAGS_DELEG)) {
if (!(node_nsec3_get(node) == NULL && node->flags & NODE_FLAGS_DELEG)) {
return KNOT_EOK;
}
/* Insecure delegation, check whether it is part of opt-out span. */
......@@ -930,7 +932,9 @@ static int check_nsec3(const zone_node_t *node, semchecks_data_t *data)
if (!auth && !deleg) {
return KNOT_EOK;
}
if (node->nsec3_node == NULL) {
zone_node_t *nsec3_node = node_nsec3_get(node);
if (nsec3_node == NULL) {
return KNOT_EOK;
}
......@@ -938,9 +942,9 @@ static int check_nsec3(const zone_node_t *node, semchecks_data_t *data)
int ret = KNOT_EOK;
char buff[50 + KNOT_DNAME_TXT_MAXLEN];
char *info = nsec3_info(node->nsec3_node->owner, buff, sizeof(buff));
char *info = nsec3_info(nsec3_node->owner, buff, sizeof(buff));
knot_rrset_t nsec3_rrs = node_rrset(node->nsec3_node, KNOT_RRTYPE_NSEC3);
knot_rrset_t nsec3_rrs = node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3);
if (knot_rrset_empty(&nsec3_rrs)) {
data->handler->cb(data->handler, data->zone, node,
SEM_ERR_NSEC3_NONE, info);
......@@ -1007,7 +1011,7 @@ static int check_nsec3(const zone_node_t *node, semchecks_data_t *data)
const zone_node_t *next_nsec3 = zone_contents_find_nsec3_node(data->zone,
next_dname);
if (next_nsec3 == NULL || node_prev(next_nsec3) != node->nsec3_node) {
if (next_nsec3 == NULL || node_prev(next_nsec3) != nsec3_node) {
uint8_t *next = NULL;
int32_t next_len = base32hex_encode_alloc(next_dname_str,
next_dname_str_size,
......@@ -1022,17 +1026,17 @@ static int check_nsec3(const zone_node_t *node, semchecks_data_t *data)
free(hash_info);
}
ret = check_rrsig(node->nsec3_node, data);
ret = check_rrsig(nsec3_node, data);
if (ret != KNOT_EOK) {
goto nsec3_cleanup;
}
// Check that the node only contains NSEC3 and RRSIG.
for (int i = 0; ret == KNOT_EOK && i < node->nsec3_node->rrset_count; i++) {
knot_rrset_t rrset = node_rrset_at(node->nsec3_node, i);
for (int i = 0; ret == KNOT_EOK && i < nsec3_node->rrset_count; i++) {
knot_rrset_t rrset = node_rrset_at(nsec3_node, i);
uint16_t type = rrset.type;
if (type != KNOT_RRTYPE_NSEC3 && type != KNOT_RRTYPE_RRSIG) {
data->handler->cb(data->handler, data->zone, node->nsec3_node,
data->handler->cb(data->handler, data->zone, nsec3_node,
SEM_ERR_NSEC3_EXTRA_RECORD, NULL);
}
}
......@@ -1101,7 +1105,7 @@ static int check_dname(const zone_node_t *node, semchecks_data_t *data)
}
/* RFC 6672 Section 2.4 Paragraph 1 */
/* If the NSEC3 node of the apex is present, it is counted as apex's child. */
unsigned allowed_children = (is_apex && node->nsec3_node != NULL) ? 1 : 0;
unsigned allowed_children = (is_apex && node_nsec3_get(node) != NULL) ? 1 : 0;
if (node->children > allowed_children) {
data->handler->fatal_error = true;
data->handler->cb(data->handler, data->zone, node,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment