diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 7c027acef1b2209e7f27be9ebf2123c9e913541c..8a0df1d01ea1da3300fa612eff06d746ef088750 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -48,6 +48,37 @@ static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100; static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; static const size_t XFRIN_BOOTSTRAP_DELAY = 2000; /*!< AXFR bootstrap avg. delay */ + +#include "libknot/rrset-dump.h" + +static void knot_zone_diff_dump_changeset(knot_changeset_t *ch) +{ + if (ch == NULL) { + return; + } + printf("Changeset FROM: %d\n", ch->serial_from); + knot_rrset_dump(ch->soa_from); + printf("\n"); + printf("Changeset TO: %d\n", ch->serial_to); + knot_rrset_dump(ch->soa_to); + printf("\n"); + + printf("ADD section:\n"); + printf("**********************************************\n"); + char buf[1024]; + knot_rr_ln_t *rr_node; + WALK_LIST(rr_node, ch->add) { + knot_rrset_txt_dump(rr_node->rr, buf, 1024, &KNOT_DUMP_STYLE_DEFAULT); + printf("%s\n", buf); + } + printf("REMOVE section:\n"); + printf("**********************************************\n"); + WALK_LIST(rr_node, ch->remove) { + knot_rrset_txt_dump(rr_node->rr, buf, 1024, &KNOT_DUMP_STYLE_DEFAULT); + printf("%s\n", buf); + } +} + /* Forward declarations. */ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *zf); @@ -442,6 +473,9 @@ static int zones_ixfrdb_sync_apply(journal_t *j, journal_node_t *n) static int zones_store_changesets_to_disk(knot_zone_t *zone, knot_changesets_t *chgsets) { + if (EMPTY_LIST(chgsets->sets)) { + return KNOT_EOK; + } journal_t *journal = zones_store_changesets_begin(zone); if (journal == NULL) { dbg_zones("zones: create_changesets: " @@ -1042,9 +1076,14 @@ static int zones_merge_and_store_changesets(knot_zone_t *zone, return KNOT_EOK; } if (diff_chs != NULL && sec_chs == NULL) { + + printf("storing diff:\n"); + knot_zone_diff_dump_changeset(knot_changesets_get_last(diff_chs)); return zones_store_changesets_to_disk(zone, diff_chs); } if (diff_chs == NULL && sec_chs != NULL) { + printf("storing sec:\n"); + knot_zone_diff_dump_changeset(knot_changesets_get_last(sec_chs)); return zones_store_changesets_to_disk(zone, sec_chs); } @@ -1052,12 +1091,45 @@ static int zones_merge_and_store_changesets(knot_zone_t *zone, * Merge changesets (only one in each 'changesets_t' structure), * use serial from diff (it's user supplied). */ + printf("storing merge:\n"); int ret = knot_changeset_merge(knot_changesets_get_last(diff_chs), knot_changesets_get_last(sec_chs)); if (ret != KNOT_EOK) { return ret; } + /* Rewrite SOAs in 'sec_chs' - we need to use SOAs from 'diff_chs' */ + /* SOA to */ + knot_rrset_deep_free(&knot_changesets_get_last(diff_chs)->soa_to, 1, 1); + knot_rrset_t *soa_copy = NULL; + ret = knot_rrset_deep_copy_no_sig( + knot_changesets_get_last(diff_chs)->soa_to, &soa_copy, 1); + if (ret != KNOT_EOK) { + return ret; + } + knot_changeset_add_soa(knot_changesets_get_last(sec_chs), soa_copy, + KNOT_CHANGESET_ADD); + + /* SOA from */ + knot_rrset_deep_free(&knot_changesets_get_last(diff_chs)->soa_from, 1, 1); + ret = knot_rrset_deep_copy_no_sig( + knot_changesets_get_last(diff_chs)->soa_from, &soa_copy, 1); + if (ret != KNOT_EOK) { + return ret; + } + knot_changeset_add_soa(knot_changesets_get_last(sec_chs), soa_copy, + KNOT_CHANGESET_REMOVE); + + /* First SOA */ + knot_rrset_deep_free(&sec_chs->first_soa, 1, 1); + ret = knot_rrset_deep_copy_no_sig(sec_chs->first_soa, &soa_copy, 1); + if (ret != KNOT_EOK) { + return ret; + } + sec_chs->first_soa = soa_copy; + knot_zone_diff_dump_changeset(knot_changesets_get_last(diff_chs)); + + /* Store ALL changes to disk. */ ret = zones_store_changesets_to_disk(zone, diff_chs); if (ret != KNOT_EOK) { return ret; @@ -1323,6 +1395,7 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, /* Run DNSSEC signing if enabled (no zone change needed) */ knot_changesets_t *sec_chs = NULL; + knot_changeset_t *sec_ch = NULL; knot_zone_contents_t *new_contents = NULL; if (z->dnssec_enable) { sec_chs = @@ -1333,8 +1406,15 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, return KNOT_ENOMEM; } /* Extra changeset is needed. */ - knot_changeset_t *sec_ch = - knot_changesets_create_changeset(sec_chs); + sec_ch = knot_changesets_create_changeset(sec_chs); + if (sec_ch == NULL) { + knot_changesets_free(&diff_chs); + knot_changesets_free(&sec_chs); + rcu_read_unlock(); + return KNOT_ENOMEM; + } + + /* Sign the zone. */ int ret = knot_dnssec_zone_sign(zone, sec_ch); if (ret != KNOT_EOK) { knot_changesets_free(&diff_chs); @@ -1342,20 +1422,6 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, rcu_read_unlock(); return ret; } - - if (!knot_changeset_is_empty(sec_ch)) { - /* Apply DNSSEC changeset. */ - ret = xfrin_apply_changesets(zone, sec_chs, - &new_contents); - if (ret != KNOT_EOK) { - knot_changesets_free(&diff_chs); - knot_changesets_free(&sec_chs); - rcu_read_unlock(); - return ret; - } - /* If server dies now, we have to resign. */ - assert(new_contents); - } } /* Merge changesets created by diff and sign. */ @@ -1368,20 +1434,29 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, rcu_read_unlock(); return ret; } + + /* Apply DNSSEC changeset. */ + if (!knot_changeset_is_empty(sec_ch)) { + ret = xfrin_apply_changesets(zone, sec_chs, + &new_contents); + if (ret != KNOT_EOK) { + knot_changesets_free(&diff_chs); + knot_changesets_free(&sec_chs); + rcu_read_unlock(); + return ret; + } + assert(new_contents); + } + /* Switch zone contents. */ rcu_read_unlock(); // TODO isn't this unlock too soon? if (new_contents) { ret = xfrin_switch_zone(zone, new_contents, XFR_TYPE_UPDATE); if (ret != KNOT_EOK) { - rcu_read_unlock(); return ret; } } - knot_changesets_free(&diff_chs); - knot_changesets_free(&sec_chs); - xfrin_cleanup_successful_update(diff_chs ? diff_chs->changes : NULL); - xfrin_cleanup_successful_update(sec_chs ? sec_chs->changes : NULL); } knot_dname_free(&dname); @@ -3298,6 +3373,8 @@ static int zones_dnssec_ev(event_t *event) return ret; } + knot_zone_diff_dump_changeset(ch); + knot_zone_contents_t *new_c = NULL; ret = zones_store_and_apply_chgsets(chs, zone, &new_c, "DNSSEC", XFR_TYPE_UPDATE); diff --git a/src/libknot/dnssec/zone-events.c b/src/libknot/dnssec/zone-events.c index 4c6b1260b375e04958194d4494b3a7bc08cd99d7..9bec8074f015b7134a218aa4ff136603744aba32 100644 --- a/src/libknot/dnssec/zone-events.c +++ b/src/libknot/dnssec/zone-events.c @@ -121,6 +121,7 @@ static int zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch, bool force) free(zname); free_sign_contexts(&zone_keys); free_zone_keys(&zone_keys); + assert(knot_changeset_is_empty(out_ch)); return KNOT_EOK; } @@ -141,7 +142,7 @@ static int zone_sign(knot_zone_t *zone, knot_changeset_t *out_ch, bool force) free_sign_contexts(&zone_keys); free_zone_keys(&zone_keys); - printf("%d %d\n", list_size(&out_ch->add), list_size(&out_ch->remove)); + printf("OK:%d %d\n", list_size(&out_ch->add), list_size(&out_ch->remove)); return KNOT_EOK; } diff --git a/src/libknot/dnssec/zone-sign.c b/src/libknot/dnssec/zone-sign.c index 1f69f4a349984663cfdc24506edffaaf2fd50188..d5e2b88bcfcd801882b4b63b5ef247ed87243514 100644 --- a/src/libknot/dnssec/zone-sign.c +++ b/src/libknot/dnssec/zone-sign.c @@ -123,7 +123,7 @@ static int sign_rrset_one(knot_rrset_t *rrsigs, rrsig_write_rdata(rdata, key, knot_rrset_owner(covered), covered, sig_incept, sig_expire); - // RFC 4034: The signature coveres RRSIG RDATA field (excluding the + // RFC 4034: The signature covers RRSIG RDATA field (excluding the // signature) and all matching RR records, which are ordered // canonically. @@ -202,7 +202,10 @@ static bool full_sig_check(const knot_rrset_t *covered, knot_dnssec_sign_context_t *ctx, const knot_dnssec_policy_t *policy) { - assert(rrsigs && covered && ctx && policy); + assert(rrsigs && covered && policy); + if (key == NULL || ctx == NULL) { + return false; + } // Do cheaper check first if (!is_valid_signature(rrsigs, pos, policy)) { return false; @@ -277,7 +280,30 @@ static bool all_signatures_valid(const knot_rrset_t *covered, return true; } -static int remove_expired_rrsigs(const knot_rrset_t *rrsigs, +static void get_matching_signing_data(const knot_rrset_t *rrsigs, + size_t pos, + const knot_zone_keys_t *keys, + const knot_dnssec_key_t **key, + knot_dnssec_sign_context_t **ctx) +{ + uint16_t keytag = knot_rrset_rdata_rrsig_key_tag(rrsigs, pos); + for (int i = 0; i < keys->count; i++) { + const knot_dnssec_key_t *found_key = &keys->keys[i]; + if (keytag != found_key->keytag) + continue; + *ctx = keys->contexts[i]; + *key = &keys->keys[i]; + return; + } + + *ctx = NULL; + *key = NULL; + return; +} + +static int remove_expired_rrsigs(const knot_rrset_t *covered, + const knot_rrset_t *rrsigs, + const knot_zone_keys_t *zone_keys, const knot_dnssec_policy_t *policy, knot_changeset_t *changeset) { @@ -292,8 +318,13 @@ static int remove_expired_rrsigs(const knot_rrset_t *rrsigs, int result = KNOT_EOK; for (int i = 0; i < rrsigs->rdata_count; i++) { - if (is_valid_signature(rrsigs, i, policy)) + // Get key that matches RRSIGs' + const knot_dnssec_key_t *key = NULL; + knot_dnssec_sign_context_t *ctx = NULL; + get_matching_signing_data(rrsigs, i, zone_keys, &key, &ctx); + if (full_sig_check(covered, rrsigs, i, key, ctx, policy)) continue; + assert(key && ctx); if (to_remove == NULL) { to_remove = create_empty_rrsigs_for(rrsigs); @@ -377,7 +408,6 @@ static int remove_rrset_rrsigs(const knot_rrset_t *rrset, assert(rrset && rrset->rrsigs); knot_rrset_t *to_remove = NULL; int res = knot_rrset_deep_copy(rrset->rrsigs, &to_remove, 1); - if (res != KNOT_EOK) { return res; } @@ -408,7 +438,8 @@ static int resign_rrset(const knot_rrset_t *rrset, const knot_dnssec_policy_t *policy, knot_changeset_t *ch) { - int ret = remove_expired_rrsigs(rrset->rrsigs, policy, ch); + int ret = remove_expired_rrsigs(rrset, rrset->rrsigs, zone_keys, + policy, ch); if (ret != KNOT_EOK) { return ret; } diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c index 845315241c23cb1025dac59ef7f7615230bdd11b..4322a1a2954c34dbff9cafda55304a1649c8f977 100644 --- a/src/libknot/updates/changesets.c +++ b/src/libknot/updates/changesets.c @@ -293,10 +293,6 @@ int knot_changeset_merge(knot_changeset_t *ch1, knot_changeset_t *ch2) add_tail(&ch1->add, HEAD(ch2->add)); add_tail(&ch1->remove, HEAD(ch2->remove)); - // Destroy the lists in the second changeset - init_list(&ch2->add); - init_list(&ch2->remove); - return KNOT_EOK; } diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h index 7d5a203bb62d0df2885cd5e52bb0caf9240de086..b19a09ffb4134005560b6408946b32f4caa21b63 100644 --- a/src/libknot/updates/changesets.h +++ b/src/libknot/updates/changesets.h @@ -277,8 +277,7 @@ int knot_changes_add_node(knot_changes_t *ch, knot_node_t *kn_node, knot_changes_part_t part); /*! - * \brief Merges two changesets together, second changeset's lists are nilled. - * + * \brief Merges two changesets together, second changeset's lists are kept. * * \param ch1 Changeset to merge into * \param ch2 Changeset to merge diff --git a/src/libknot/zone/zone-diff.c b/src/libknot/zone/zone-diff.c index a13532db5ed6c4357f38c7955997bbf767bb7e23..507c0c78c743103d5a3c518084814e296c016d3b 100644 --- a/src/libknot/zone/zone-diff.c +++ b/src/libknot/zone/zone-diff.c @@ -971,7 +971,7 @@ int knot_zone_contents_create_diff(const knot_zone_contents_t *z1, dbg_zonediff("Changesets created successfully!\n"); dbg_zonediff_detail("Changeset dump:\n"); dbg_zonediff_exec_detail( - knot_zone_diff_dump_changeset(HEAD((*changeset)->sets)); + knot_zone_diff_dump_changeset(changeset); ); return KNOT_EOK;