Commit 12a5fabc authored by Jan Kadlec's avatar Jan Kadlec
Browse files

DNSSEC/chain fix: Chain fixing preparations.

- Storing dnames to trie using sortable format
- Updating sorted changes with nonterminal changes

Refs #196
parent 14264785
......@@ -225,20 +225,24 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
return ret;
}
// Fix NSEC(3) chain
ret = knot_zone_create_nsec_chain(zone, out_ch, &zone_keys, &policy);
// Sign added and removed RRSets in changeset
hattrie_t *sorted_changes = NULL;
ret = knot_zone_sign_changeset(zone, in_ch, out_ch, &sorted_changes,
&zone_keys, &policy);
if (ret != KNOT_EOK) {
log_zone_error("Failed to fix NSEC(3) chain (%s)\n",
log_zone_error("Failed to sign changeset (%s)\n",
knot_strerror(ret));
free_zone_keys(&zone_keys);
return ret;
}
// Sign added and removed RRSets in changeset
ret = knot_zone_sign_changeset(zone, in_ch, out_ch, &zone_keys,
&policy);
// Fix NSEC(3) chain
ret = knot_zone_fix_chain(zone, sorted_changes, out_ch, &zone_keys,
&policy);
knot_zone_clear_sorted_changes(sorted_changes);
hattrie_free(sorted_changes);
if (ret != KNOT_EOK) {
log_zone_error("Failed to sign changeset (%s)\n",
log_zone_error("Failed to fix NSEC(3) chain (%s)\n",
knot_strerror(ret));
free_zone_keys(&zone_keys);
return ret;
......@@ -247,8 +251,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone,
// Update SOA RRSIGs
ret = knot_zone_sign_update_soa(knot_node_rrset(zone->apex,
KNOT_RRTYPE_SOA),
&zone_keys, &policy,
out_ch);
&zone_keys, &policy, out_ch);
if (ret != KNOT_EOK) {
log_zone_error("Failed to sign SOA RR (%s)\n",
knot_strerror(ret));
......
......@@ -30,6 +30,7 @@
#include "libknot/rdata.h"
#include "libknot/util/debug.h"
#include "libknot/util/utils.h"
#include "libknot/util/wire.h"
#include "libknot/zone/zone-contents.h"
#include "libknot/zone/zone-diff.h"
......@@ -857,6 +858,50 @@ static bool get_zone_soa_min_ttl(const knot_zone_contents_t *zone,
return true;
}
static int walk_dname_and_store_empty_nonterminals(knot_dname_t *dname,
const knot_zone_contents_t *zone, ahtable_t *t)
{
assert(dname);
assert(zone);
assert(t);
if (knot_dname_size(dname) == 1) {
// Root dname
assert(*dname == '\0');
return KNOT_EOK;
}
// Start after the first cut
const knot_dname_t *cut = knot_wire_next_label(dname, NULL);
while (*cut != '\0') {
// Search for name in the zone
const knot_node_t *n = knot_zone_contents_find_node(zone, cut);
if (n == NULL || n->rrset_count == 0) {
/*!
* n == NULL:
* This means that RR *removal* caused non-terminal
* deletion - NSEC3 has to be dropped.
*
* n->rrset_count == 0:
* This means that RR *addition* created new empty
* non-terminal - NSEC3 has to be added.
*/
// Convert dname to sortable format
uint8_t lf[KNOT_DNAME_MAXLEN];
knot_dname_lf(lf, n->owner, NULL);
// Store into trie (duplicates 'rewritten')
*ahtable_get(t, (char *)lf+1, *lf) = (void *)0x1;
}
cut = knot_wire_next_label(dname, NULL);
}
return KNOT_EOK;
}
/*!
* \brief Cuts labels and looks for nodes in zone, if an empty node is found
* adds it into trie. There may be multiple nodes. Not all nodes
* have to be checked, but doing that would bloat the code.
*/
static int update_changes_with_non_terminals(const knot_zone_contents_t *zone,
hattrie_t *sorted_changes)
{
......@@ -865,30 +910,76 @@ static int update_changes_with_non_terminals(const knot_zone_contents_t *zone,
assert(sorted_changes);
/*!
* Cut labels and look for nodes in zone, if an empty node is found
* add it into trie. There may be multiple nodes. Not all nodes
* have to be checked, but doing that would bloat the code.
* Create table with newly created nonterminals, as we cannot
* insert to the trie in the middle of iteration. Also useful
* because it will filter duplicated added nonterminals.
*/
ahtable_t *nterminal_t = ahtable_create();
if (nterminal_t == NULL) {
return KNOT_ENOMEM;
}
// Start trie iteration
const bool sort = false;
hattrie_iter_t *it = hattrie_iter_begin(sorted_changes, sort);
if (it == NULL) {
hattrie_iter_t *itt = hattrie_iter_begin(sorted_changes, sort);
if (itt == NULL) {
return KNOT_ERROR;
}
for (; !hattrie_iter_finished(it); hattrie_iter_next(it)) {
signing_info_t *owner = knot_dname_parse(*hattrie_iter_val(it);
for (int i = 0; i < node->rrset_count; i++) {
// referenced RRSIGs from old NSEC3 tree
node->rrset_tree[i]->rrsigs = NULL;
// newly allocated NSEC3 nodes
knot_rrset_deep_free(&node->rrset_tree[i], 1);
for (; !hattrie_iter_finished(itt); hattrie_iter_next(itt)) {
signed_info_t *info = (signed_info_t *)*hattrie_iter_val(itt);
knot_dname_t *node_dname = info->dname;
assert(node_dname);
int ret = walk_dname_and_store_empty_nonterminals(node_dname,
zone,
nterminal_t);
if (ret != KNOT_EOK) {
ahtable_free(nterminal_t);
return ret;
}
knot_node_free(&node);
}
hattrie_iter_free(itt);
// Reinsert ahtable values into trie (dname already converted)
ahtable_iter_t ith = { '\0'};
ahtable_iter_begin(nterminal_t, &ith, sort);
for (; !ahtable_iter_finished(&ith); ahtable_iter_next(&ith)) {
// Store keys from table directly to trie
size_t key_size = 0;
const char *k = ahtable_iter_key(&ith, &key_size);
assert(k && key_size > 0);
// Create dummy value
signed_info_t *info = malloc(sizeof(signed_info_t));
if (info == NULL) {
ERR_ALLOC_FAILED;
ahtable_free(nterminal_t);
ahtable_iter_free(&ith);
return KNOT_ENOMEM;
}
memset(info, 0, sizeof(signed_info_t));
*hattrie_get(sorted_changes, k, key_size) = info;
}
hattrie_iter_free(it);
ahtable_iter_free(&ith);
return KNOT_EOK;
}
static int fix_nsec_chain_using_changes(const knot_zone_contents_t *zone,
const hattrie_t *sorted_changes,
knot_changeset_t *out_ch,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy)
{
return KNOT_EOK;
}
static int fix_nsec3_chain_using_changes(const knot_zone_contents_t *zone,
const hattrie_t *sorted_changes,
knot_changeset_t *out_ch,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy)
{
return KNOT_EOK;
}
/* - public API ------------------------------------------------------------ */
......@@ -897,7 +988,7 @@ static int update_changes_with_non_terminals(const knot_zone_contents_t *zone,
* \brief Create NSEC3 owner name from regular owner name.
*/
knot_dname_t *create_nsec3_owner(const knot_dname_t *owner,
const knot_dname_t *zone_apex,
const knot_dname_t *zone_apex,
const knot_nsec3_params_t *params)
{
if (owner == NULL || zone_apex == NULL || params == NULL) {
......@@ -912,7 +1003,8 @@ knot_dname_t *create_nsec3_owner(const knot_dname_t *owner,
return NULL;
}
if (knot_nsec3_hash(params, owner, owner_size, &hash, &hash_size) != KNOT_EOK) {
if (knot_nsec3_hash(params, owner, owner_size, &hash, &hash_size)
!= KNOT_EOK) {
return NULL;
}
......@@ -962,9 +1054,28 @@ int knot_zone_create_nsec_chain(const knot_zone_contents_t *zone,
int knot_zone_fix_chain(const knot_zone_contents_t *zone,
hattrie_t *sorted_changes,
knot_changeset_t *out_ch,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy)
{
if (zone == NULL || sorted_changes == NULL || zone_keys == NULL ||
policy == NULL) {
return KNOT_EOK;
}
int ret = KNOT_EOK;
if (is_nsec3_enabled(zone)) {
ret = update_changes_with_non_terminals(zone, sorted_changes);
if (ret != KNOT_EOK) {
return ret;
}
ret = fix_nsec3_chain_using_changes(zone, sorted_changes,
out_ch, zone_keys, policy);
} else {
ret = fix_nsec_chain_using_changes(zone, sorted_changes,
out_ch, zone_keys, policy);
}
return ret;
}
......@@ -62,6 +62,8 @@ knot_dname_t *create_nsec3_owner(const knot_dname_t *owner,
*
* \param zone Zone for which the NSEC(3) chain will be created.
* \param changeset Changeset into which the changes will be added.
* \param zone_keys Zone keys used for NSEC(3) creation.
* \param policy DNSSEC signing policy.
*
* \return Error code, KNOT_EOK if successful.
*/
......@@ -70,6 +72,23 @@ int knot_zone_create_nsec_chain(const knot_zone_contents_t *zone,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy);
/*!
* \brief Create NSEC or NSEC3 chain in the zone.
*
* \param zone Zone for which the NSEC(3) chain will be created.
* \param sorted_changes Sorted changes created by 'sign_changeset' function.
* \param out_ch Changeset into which the changes will be added.
* \param zone_keys Zone keys used for NSEC(3) creation.
* \param policy DNSSEC signing policy.
*
* \return Error code, KNOT_EOK if successful.
*/
int knot_zone_fix_chain(const knot_zone_contents_t *zone,
hattrie_t *sorted_changes,
knot_changeset_t *out_ch,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy);
#endif // _KNOT_DNSSEC_ZONE_NSEC_H_
/*! @} */
......@@ -936,7 +936,8 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data)
if (knot_zone_sign_rr_should_be_signed(node, zone_rrset,
args->signed_tree)) {
return force_resign_rrset(zone_rrset, args->zone_keys,
args->policy, args->changeset);
args->policy,
args->changeset);
} else if (zone_rrset && zone_rrset->rrsigs != NULL) {
/*!
* If RRSet in zone DOES have RRSIGs although we
......@@ -949,16 +950,6 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data)
return KNOT_EOK;
}
typedef struct type_node {
node_t n;
uint16_t type;
} type_node_t;
typedef struct signed_info {
knot_dname_t *dname;
list_t *type_list;
} signed_info_t;
static bool rr_type_in_list(const knot_rrset_t *rr, const list_t *l)
{
if (l == NULL) {
......@@ -1013,7 +1004,8 @@ static bool rr_already_signed(const knot_rrset_t *rrset, hattrie_t *t)
knot_dname_lf(lf, rrset->owner, NULL);
signed_info_t *info = (signed_info_t *)hattrie_tryget(t, (char *)lf+1,
*lf);
if (rr_type_in_list(rrset, type_list)) {
assert(info);
if (rr_type_in_list(rrset, info->type_list)) {
return true;
}
......@@ -1032,13 +1024,13 @@ static bool rr_already_signed(const knot_rrset_t *rrset, hattrie_t *t)
}
// Create new list to insert as a value
info->type_list = malloc(sizeof(list_t));
if (type_list == NULL) {
if (info->type_list == NULL) {
free(info->dname);
free(info);
ERR_ALLOC_FAILED;
return false;
}
init_list(*(info->type_list));
init_list(info->type_list);
// Insert type to list
int ret = add_rr_type_to_list(rrset, info->type_list);
if (ret != KNOT_EOK) {
......@@ -1064,22 +1056,19 @@ static bool rr_already_signed(const knot_rrset_t *rrset, hattrie_t *t)
return false;
}
static int free_list(value_t *val, void *d)
static int free_helper_trie_node(value_t *val, void *d)
{
UNUSED(d);
signed_info_t *info = (signed_info_t *)*val;
WALK_LIST_FREE(*(info->l));
free(info->l);
if (info->type_list && !EMPTY_LIST(*(info->type_list))) {
WALK_LIST_FREE(*(info->type_list));
}
free(info->type_list);
knot_dname_free(&info->dname);
free(info);
return KNOT_EOK;
}
static void clear_helper_trie(hattrie_t *t)
{
hattrie_apply_rev(t, free_list, NULL);
}
/*- public API ---------------------------------------------------------------*/
/*!
......@@ -1233,6 +1222,7 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa,
int knot_zone_sign_changeset(const knot_zone_contents_t *zone,
const knot_changeset_t *in_ch,
knot_changeset_t *out_ch,
hattrie_t **sorted_changes,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy)
{
......@@ -1256,11 +1246,13 @@ int knot_zone_sign_changeset(const knot_zone_contents_t *zone,
ret = knot_changeset_apply((knot_changeset_t *)in_ch,
KNOT_CHANGESET_REMOVE,
sign_changeset_wrap, &args);
} else {
knot_zone_clear_sorted_changes(args.signed_tree);
hattrie_free(args.signed_tree);
args.signed_tree = NULL;
}
clear_helper_trie(args.signed_tree);
hattrie_free(args.signed_tree);
*sorted_changes = args.signed_tree;
return ret;
}
......@@ -1331,3 +1323,8 @@ bool knot_zone_sign_rr_should_be_signed(const knot_node_t *node,
return true;
}
void knot_zone_clear_sorted_changes(hattrie_t *t)
{
hattrie_apply_rev(t, free_helper_trie_node, NULL);
}
......@@ -35,6 +35,16 @@
#include "libknot/dnssec/zone-keys.h"
#include "libknot/dnssec/policy.h"
typedef struct type_node {
node_t n;
uint16_t type;
} type_node_t;
typedef struct signed_info {
knot_dname_t *dname;
list_t *type_list;
} signed_info_t;
/*!
* \brief Update zone signatures and store performed changes in changeset.
*
......@@ -88,6 +98,7 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone,
* \param zone Contents of the updated zone (AFTER zone is switched).
* \param in_ch Changeset created bvy DDNS or zone-diff
* \param out_ch New records will be added to this changeset.
* \param sorted_changes Sorted representation of changes.
* \param zone_keys Keys to use for signing.
* \param policy DNSSEC signing policy.
*
......@@ -96,6 +107,7 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone,
int knot_zone_sign_changeset(const knot_zone_contents_t *zone,
const knot_changeset_t *in_ch,
knot_changeset_t *out_ch,
hattrie_t **sorted_changes,
const knot_zone_keys_t *zone_keys,
const knot_dnssec_policy_t *policy);
......@@ -127,6 +139,8 @@ bool knot_zone_sign_rr_should_be_signed(const knot_node_t *node,
const knot_rrset_t *rrset,
hattrie_t *trie);
void knot_zone_clear_sorted_changes(hattrie_t *t);
#endif // _KNOT_DNSSEC_ZONE_SIGN_H_
/*! @} */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment