bool nsec_update_label_record(zdb_rr_label *label, nsec_node *node, nsec_node *next_node, u8 *name, u32 ttl) { type_bit_maps_context tbmctx; u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */ u32 tbm_size = type_bit_maps_initialize(&tbmctx, label, TRUE, TRUE); type_bit_maps_write(tmp_bitmap, &tbmctx); /* * Get the NSEC record */ zdb_packed_ttlrdata *nsec_record; if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) { /* * has record -> compare the type and the nsec next * if something does not match remove the record and its signature (no record) * */ log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) updating record.", name, node->inverse_relative_name, next_node->inverse_relative_name); /* * If there is more than one record, clean-up */ if(nsec_record->next == NULL) { u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record); u16 dname_len = dnsname_len(rdata); if(dname_len < size) { u8* type_bitmap = &rdata[dname_len]; /* * check the type bitmap */ if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0) { /* * check the nsec next */ if(dnsname_equals(rdata, name)) { /* All good */ return FALSE; } } } } if(zdb_listener_notify_enabled()) { zdb_packed_ttlrdata *nsec_rec = nsec_record; do { zdb_ttlrdata unpacked_ttlrdata; unpacked_ttlrdata.ttl = nsec_rec->ttl; unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec); unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec); zdb_listener_notify_remove_record(name, TYPE_NSEC, &unpacked_ttlrdata); nsec_rec = nsec_rec->next; } while(nsec_rec != NULL); } zdb_record_delete(&label->resource_record_set, TYPE_NSEC); rrsig_delete(name, label, TYPE_NSEC); nsec_record = NULL; } /* * no record -> create one and schedule a signature */ if(nsec_record == NULL) { zdb_packed_ttlrdata *nsec_record; u8 next_name[256]; log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) building new record.", name, node->inverse_relative_name, next_node->inverse_relative_name); u16 dname_len = nsec_inverse_name(next_name, next_node->inverse_relative_name); u16 rdata_size = dname_len + tbm_size; ZDB_RECORD_ZALLOC_EMPTY(nsec_record, ttl, rdata_size); u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); memcpy(rdata, next_name, dname_len); rdata += dname_len; memcpy(rdata, tmp_bitmap, tbm_size); zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record); if(zdb_listener_notify_enabled()) { dnsname_vector name_path; zdb_ttlrdata unpacked_ttlrdata; unpacked_ttlrdata.ttl = ttl; unpacked_ttlrdata.rdata_size = rdata_size; unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); dnsname_to_dnsname_vector(name, &name_path); zdb_listener_notify_add_record(name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata); } /* * Schedule a signature */ } label->flags |= ZDB_RR_LABEL_NSEC; return TRUE; }
ya_result nsec_update_zone(zdb_zone *zone, bool read_only) // read_only a.k.a slave { nsec_node *nsec_tree = NULL; nsec_node *first_node; nsec_node *node; u8 *prev_name; u8 *name; soa_rdata soa; u32 missing_nsec_records = 0; u32 sibling_count = 0; u32 nsec_under_delegation = 0; ya_result return_code; u8 name_buffer[2][MAX_DOMAIN_LENGTH]; u8 inverse_name[MAX_DOMAIN_LENGTH]; u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */ yassert(zdb_zone_islocked_weak(zone)); if(FAIL(return_code = zdb_zone_getsoa(zone, &soa))) // zone is locked (weak) { return return_code; } #ifdef DEBUG memset(name_buffer, 0xde, sizeof(name_buffer)); #endif name = name_buffer[0]; prev_name = name_buffer[1]; zdb_zone_label_iterator label_iterator; zdb_zone_label_iterator_init(&label_iterator, zone); while(zdb_zone_label_iterator_hasnext(&label_iterator)) { zdb_zone_label_iterator_nextname(&label_iterator, name); zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator); if(zdb_rr_label_is_glue(label) || (label->resource_record_set == NULL)) { // we are under a delegation or on an empty (non-terminal) // there should not be an NSEC record here zdb_packed_ttlrdata *nsec_record; if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked { nsec_under_delegation++; log_err("nsec: %{dnsname}: unexpected NSEC record under a delegation", name); } continue; } nsec_inverse_name(inverse_name, name); nsec_node *node = nsec_avl_insert(&nsec_tree, inverse_name); node->label = label; label->nsec.nsec.node = node; } /* * Now that we have the NSEC chain */ type_bit_maps_context tbmctx; nsec_avl_iterator nsec_iter; nsec_avl_iterator_init(&nsec_tree, &nsec_iter); if(nsec_avl_iterator_hasnext(&nsec_iter)) { first_node = nsec_avl_iterator_next_node(&nsec_iter); node = first_node; do { nsec_node *next_node; nsec_update_zone_count++; if(nsec_avl_iterator_hasnext(&nsec_iter)) { next_node = nsec_avl_iterator_next_node(&nsec_iter); } else { next_node = first_node; } /* * Compute the type bitmap */ zdb_rr_label *label = node->label; if(label == NULL) { node = next_node; continue; } u32 tbm_size = type_bit_maps_initialise_from_label(&tbmctx, label, TRUE, TRUE); type_bit_maps_write(&tbmctx, tmp_bitmap); u8 *tmp_name = prev_name; prev_name = name; name = tmp_name; nsec_inverse_name(name, next_node->inverse_relative_name); /* * Get the NSEC record */ zdb_packed_ttlrdata *nsec_record; if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) // zone is locked { /* * has record -> compare the type and the nsec next * if something does not match remove the record and its signature (no record) * */ if(nsec_record->next == NULL) // should only be one record => delete all if not the case (the rrsig is lost anyway) { const u8 *rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); const u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record); const u16 dname_len = dnsname_len(rdata); if(dname_len < size) { const u8 *type_bitmap = &rdata[dname_len]; /* * check the type bitmap */ if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0) { /* * check the nsec next */ if(dnsname_equals(rdata, name)) { /* All good */ label->flags |= ZDB_RR_LABEL_NSEC; node = next_node; continue; } else // else the "next fqdn" do not match (this is irrecoverable for a slave) { rdata_desc nsec_desc = {TYPE_NSEC, size, rdata}; log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name); } } else // else the type bitmap do not match (this is wrong) { rdata_desc nsec_desc = {TYPE_NSEC, size, rdata}; log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} types map do not match expected value", zone->origin, prev_name, &nsec_desc); } } else // else the "next fqdn" do not match (early test, this is irrecoverable for a slave) { rdata_desc nsec_desc = {TYPE_NSEC, size, rdata}; log_debug("nsec: %{dnsname}: src: %{dnsname} %{typerdatadesc} next field do not match expected value (%{dnsname})", zone->origin, prev_name, &nsec_desc, name); } } else { sibling_count++; log_warn("nsec: %{dnsname}: %{dnsname}: multiple NSEC records where only one is expected", zone->origin, prev_name); } // wrong NSEC RRSET zdb_packed_ttlrdata *nsec_rec = nsec_record; do { zdb_ttlrdata unpacked_ttlrdata; unpacked_ttlrdata.ttl = nsec_rec->ttl; unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec); unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec); rdata_desc nsec_desc = {TYPE_NSEC, unpacked_ttlrdata.rdata_size, unpacked_ttlrdata.rdata_pointer}; if(!read_only) { log_warn("nsec: %{dnsname}: del: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc); #if ZDB_CHANGE_FEEDBACK_SUPPORT zdb_listener_notify_remove_record(zone, name, TYPE_NSEC, &unpacked_ttlrdata); #endif } else { log_err("nsec: %{dnsname}: got: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc); } nsec_rec = nsec_rec->next; } while(nsec_rec != NULL); if(!read_only) { zdb_record_delete(&label->resource_record_set, TYPE_NSEC); rrsig_delete(zone, name, label, TYPE_NSEC); nsec_record = NULL; } } /* * no record -> create one and schedule a signature (MASTER ONLY) */ if(nsec_record == NULL) { missing_nsec_records++; zdb_packed_ttlrdata *nsec_record; u16 dname_len = nsec_inverse_name(name, next_node->inverse_relative_name); u16 rdata_size = dname_len + tbm_size; ZDB_RECORD_ZALLOC_EMPTY(nsec_record, soa.minimum, rdata_size); u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); memcpy(rdata, name, dname_len); rdata += dname_len; memcpy(rdata, tmp_bitmap, tbm_size); rdata_desc nsec_desc = {TYPE_NSEC, ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record), ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record)}; if(!read_only) { zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record); #ifdef DEBUG log_debug("nsec: %{dnsname}: add: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc); #endif #if ZDB_CHANGE_FEEDBACK_SUPPORT if(zdb_listener_notify_enabled()) { dnsname_vector name_path; zdb_ttlrdata unpacked_ttlrdata; unpacked_ttlrdata.ttl = nsec_record->ttl; unpacked_ttlrdata.rdata_size = rdata_size; unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); dnsname_to_dnsname_vector(name, &name_path); zdb_listener_notify_add_record(zone, name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata); } #endif /* * Schedule a signature */ } else { log_warn("nsec: %{dnsname}: need: %{dnsname} %{typerdatadesc}", zone->origin, prev_name, &nsec_desc); ZDB_RECORD_ZFREE(nsec_record); } } label->flags |= ZDB_RR_LABEL_NSEC; node = next_node; } while(node != first_node); } zone->nsec.nsec = nsec_tree; if(read_only) { if(missing_nsec_records + sibling_count + nsec_under_delegation) { log_err("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation); //return DNSSEC_ERROR_NSEC_INVALIDZONESTATE; } } else { if(missing_nsec_records + sibling_count + nsec_under_delegation) { log_warn("nsec: missing records: %u, nsec with siblings: %u, nsec under delegation: %u", missing_nsec_records, sibling_count, nsec_under_delegation); } } return SUCCESS; }
ya_result nsec_update_zone(zdb_zone *zone) { nsec_node *nsec_tree = NULL; soa_rdata soa; u8 name[MAX_DOMAIN_LENGTH]; u8 inverse_name[MAX_DOMAIN_LENGTH]; u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */ ya_result return_code; if(FAIL(return_code = zdb_zone_getsoa(zone, &soa))) { return return_code; } zdb_zone_label_iterator label_iterator; zdb_zone_label_iterator_init(zone, &label_iterator); while(zdb_zone_label_iterator_hasnext(&label_iterator)) { zdb_zone_label_iterator_nextname(&label_iterator, name); zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator); if(zdb_rr_label_is_glue(label) || (label->resource_record_set == NULL)) { continue; } nsec_inverse_name(inverse_name, name); nsec_node *node = nsec_avl_insert(&nsec_tree, inverse_name); node->label = label; label->nsec.nsec.node = node; } /* * Now that we have the NSEC chain */ nsec_node *first_node; nsec_node *node; type_bit_maps_context tbmctx; nsec_avl_iterator nsec_iter; nsec_avl_iterator_init(&nsec_tree, &nsec_iter); if(nsec_avl_iterator_hasnext(&nsec_iter)) { first_node = nsec_avl_iterator_next_node(&nsec_iter); node = first_node; do { nsec_node *next_node; nsec_update_zone_count++; if(nsec_avl_iterator_hasnext(&nsec_iter)) { next_node = nsec_avl_iterator_next_node(&nsec_iter); } else { next_node = first_node; } /* * Compute the type bitmap */ zdb_rr_label *label = node->label; u32 tbm_size = type_bit_maps_initialize(&tbmctx, label, TRUE, TRUE); type_bit_maps_write(tmp_bitmap, &tbmctx); nsec_inverse_name(name, next_node->inverse_relative_name); /* * Get the NSEC record */ zdb_packed_ttlrdata *nsec_record; if((nsec_record = zdb_record_find(&label->resource_record_set, TYPE_NSEC)) != NULL) { /* * has record -> compare the type and the nsec next * if something does not match remove the record and its signature (no record) * */ if(nsec_record->next == NULL) { u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); u16 size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_record); u16 dname_len = dnsname_len(rdata); if(dname_len < size) { u8* type_bitmap = &rdata[dname_len]; /* * check the type bitmap */ if(memcmp(tmp_bitmap, type_bitmap, size - dname_len) == 0) { /* * check the nsec next */ if(dnsname_equals(rdata, name)) { /* All good */ label->flags |= ZDB_RR_LABEL_NSEC; node = next_node; continue; } } } } if(zdb_listener_notify_enabled()) { zdb_packed_ttlrdata *nsec_rec = nsec_record; do { zdb_ttlrdata unpacked_ttlrdata; unpacked_ttlrdata.ttl = nsec_rec->ttl; unpacked_ttlrdata.rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec_rec); unpacked_ttlrdata.rdata_pointer = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_rec); zdb_listener_notify_remove_record(name, TYPE_NSEC, &unpacked_ttlrdata); nsec_rec = nsec_rec->next; } while(nsec_rec != NULL); } zdb_record_delete(&label->resource_record_set, TYPE_NSEC); rrsig_delete(name, label, TYPE_NSEC); nsec_record = NULL; } /* * no record -> create one and schedule a signature */ if(nsec_record == NULL) { zdb_packed_ttlrdata *nsec_record; u16 dname_len = nsec_inverse_name(name, next_node->inverse_relative_name); u16 rdata_size = dname_len + tbm_size; ZDB_RECORD_ZALLOC_EMPTY(nsec_record, soa.minimum, rdata_size); u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec_record); memcpy(rdata, name, dname_len); rdata += dname_len; memcpy(rdata, tmp_bitmap, tbm_size); zdb_record_insert(&label->resource_record_set, TYPE_NSEC, nsec_record); /* * Schedule a signature */ } label->flags |= ZDB_RR_LABEL_NSEC; node = next_node; } while(node != first_node); } zone->nsec.nsec = nsec_tree; return SUCCESS; }
ya_result zdb_icmtl_replay_commit(zdb_zone *zone, input_stream *is, u32 *current_serialp) { ya_result ret; /* * 0: DELETE, 1: ADD * The mode is switched every time an SOA is found. */ yassert(zdb_zone_islocked(zone)); #if ZDB_HAS_NSEC3_SUPPORT bool has_nsec3 = zdb_zone_is_nsec3(zone); #endif #if ZDB_HAS_NSEC_SUPPORT bool has_nsec = zdb_zone_is_nsec(zone); #endif #if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT if(has_nsec3 && has_nsec) { log_err("journal: %{dnsname}: zone has both NSEC and NSEC3 status, which is not supported by YADIFA", zone->origin); return ERROR; } #endif u8 mode = 1; // the first SOA will switch the mode to delete s32 changes = 0; zdb_ttlrdata ttlrdata; dns_resource_record rr; dns_resource_record_init(&rr); const u8 *fqdn = rr.name; dnslabel_vector labels; ttlrdata.next = NULL; /* * The plan for NSEC3 : * Store the fqdn + type class ttl rdata in collections * => the delete collection * => the add collection * Then there is the NSEC3 covered labels: keep a reference to them for later * * When a pass of SOA-/SOA+ has finished: * _ replace the NSEC3 in both collections (reading from delete) * _ delete NSEC3 to delete * _ add NSEC3 to add * * _ and finally update the NSEC3 for the labels kept above */ #if ZDB_HAS_NSEC3_SUPPORT chain_replay nsec3replay; nsec3_chain_replay_init(&nsec3replay, zone); #endif #if ZDB_HAS_NSEC_SUPPORT chain_replay nsecreplay; nsec_chain_replay_init(&nsecreplay, zone); #endif #if ZDB_HAS_NSEC3_SUPPORT ptr_set downed_fqdn = PTR_SET_DNSNAME_EMPTY; #endif /* * At this point : the next record, if it exists AND is not an SOA , has to be deleted * */ bool did_remove_soa = FALSE; // something has to be committed for(;;) { /* * read the full record * * == 0 : no record (EOF) * < 0 : failed */ if((ret = dns_resource_record_read(&rr, is)) <= 0) { if(ISOK(ret)) { log_info("journal: %{dnsname}: reached the end of the journal page", zone->origin); } else { log_err("journal: %{dnsname}: broken journal: %r", zone->origin, ret); logger_flush(); // broken journal (bad, keep me) } break; } ttlrdata.ttl = ntohl(rr.tctr.ttl); ttlrdata.rdata_pointer = rr.rdata; ttlrdata.rdata_size = rr.rdata_size; /* * Stop at the SOA */ if(rr.tctr.qtype == TYPE_SOA) { mode ^= 1; if(mode == 0) { /* ADD */ #if ZDB_HAS_NSEC3_SUPPORT // NSEC3 { ret = nsec3replay.vtbl->execute(&nsec3replay); if(FAIL(ret)) { dns_resource_record_clear(&rr); // DO NOT: input_stream_close(is); nsec3replay.vtbl->finalise(&nsec3replay); #if ZDB_HAS_NSEC_SUPPORT nsecreplay.vtbl->finalise(&nsecreplay); #endif // ZDB_HAS_NSEC_SUPPORT return ret; } } #endif #if ZDB_HAS_NSEC_SUPPORT // NSEC ret = nsecreplay.vtbl->execute(&nsecreplay); #endif //ZDB_HAS_NSEC_SUPPORT } } if(!did_remove_soa) { log_info("journal: %{dnsname}: removing obsolete SOA", zone->origin); if(FAIL(ret = zdb_record_delete(&zone->apex->resource_record_set, TYPE_SOA))) { /** * complain */ log_err("journal: %{dnsname}: removing current SOA gave an error: %r", zone->origin, ret); /* That's VERY bad ... */ changes = ret; break; } did_remove_soa = TRUE; } s32 top = dnsname_to_dnslabel_vector(fqdn, labels); if(mode == 0) { /* * "TO DEL" record */ #if ICMTL_DUMP_JOURNAL_RECORDS rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, rr.rdata }; log_debug("journal: del %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata); logger_flush(); #endif bool added_in_chain = FALSE; #if ZDB_HAS_NSEC3_SUPPORT // 0 : proceed // 1 : ignore // ? : error if((added_in_chain = (nsec3replay.vtbl->record_del(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0))) { // add everything up until a non-empty terminal is found (the apex will thus be automatically avoided) // if the record is a delegation, add everything down too /* if((top > zone->origin_vector.size) && (rr.tctr.qtype != TYPE_NSEC3) && ( (rr.tctr.qtype != TYPE_RRSIG) || ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3)) ) ) { } */ ++changes; } else { if(top > zone->origin_vector.size) { const u8 *above_fqdn = fqdn; for(int i = 1; i < top - zone->origin_vector.size; ++i) { zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i); if(above != NULL) { if(btree_notempty(above->resource_record_set)) { break; } } above_fqdn += above_fqdn[0] + 1; nsec3replay.vtbl->record_del(&nsec3replay, above_fqdn, TYPE_NONE, NULL); } zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1); if(rr_label != NULL) { zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_del_cb, &nsec3replay); } } } #endif #if ZDB_HAS_NSEC_SUPPORT // 0 : proceed // 1 : ignore // ? : error if(!added_in_chain && (added_in_chain = nsecreplay.vtbl->record_del(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0)) { ++changes; } //else #endif if(!added_in_chain) switch(rr.tctr.qtype) { case TYPE_SOA: { rdata_desc rdata = {TYPE_SOA, ttlrdata.rdata_size, ttlrdata.rdata_pointer}; log_info("journal: %{dnsname}: SOA: del %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata); s32 m1 = (top - zone->origin_vector.size) - 1; if(m1 == -1) { if(FAIL(ret = zdb_record_delete_exact(&zone->apex->resource_record_set, TYPE_SOA, &ttlrdata))) /* FB done, APEX : no delegation, source is the journal */ { if(!did_remove_soa) { log_err("journal: %{dnsname}: SOA: %r", zone->origin, ret); } } } else { if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal { if(!did_remove_soa) { log_err("journal: %{dnsname}: SOA: (2) %r", zone->origin, ret); } } } break; } default: { #if ZDB_HAS_NSEC3_SUPPORT // NSEC3 if(rr.tctr.qtype != TYPE_NSEC3) { if((rr.tctr.qtype != TYPE_RRSIG) && (rrsig_get_type_covered_from_rdata(rr.rdata, rr.rdata_size) != TYPE_NSEC3)) { if(ptr_set_avl_find(&downed_fqdn, fqdn) == NULL) { ptr_set_avl_insert(&downed_fqdn, dnsname_dup(fqdn)); } } } else { if(!NSEC3_RDATA_IS_OPTOUT(rr.rdata)) { zone->_flags &= ~ZDB_ZONE_HAS_OPTOUT_COVERAGE; } } #endif if(FAIL(ret = zdb_rr_label_delete_record_exact(zone, labels, (top - zone->origin_vector.size) - 1, rr.tctr.qtype, &ttlrdata))) // source is journal { // signatures can be removed automatically by maintenance if((rr.tctr.qtype != TYPE_RRSIG) && (ret != ZDB_ERROR_KEY_NOTFOUND)) { log_err("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr); log_err("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret); } else { log_debug("journal: %{dnsname}: del %{dnsrr}", zone->origin, &rr); log_debug("journal: %{dnsname}: %{dnstype}: %r", zone->origin, &rr.tctr.qtype, ret); } } } } } else { /* * "TO ADD" record */ bool added_in_chain = FALSE; #if ZDB_HAS_NSEC3_SUPPORT // returns the number of changes taken into account (0 or 1) // 0 : proceed // 1 : ignore // ? : error if((added_in_chain = (nsec3replay.vtbl->record_add(&nsec3replay, fqdn, rr.tctr.qtype, &ttlrdata) != 0))) { ++changes; } else { if( (top > zone->origin_vector.size) && (rr.tctr.qtype != TYPE_NSEC3) && ( (rr.tctr.qtype != TYPE_RRSIG) || ((rr.tctr.qtype == TYPE_RRSIG) && (GET_U16_AT_P(ZDB_RECORD_PTR_RDATAPTR(&ttlrdata)) != TYPE_NSEC3)) ) ) { const u8 *above_fqdn = fqdn; for(int i = 1; i < top - zone->origin_vector.size; ++i) { zdb_rr_label *above = zdb_rr_label_find_exact(zone->apex, &labels[i], top - zone->origin_vector.size - 1 - i); if(above != NULL) { if(btree_notempty(above->resource_record_set)) { break; } } above_fqdn += above_fqdn[0] + 1; nsec3replay.vtbl->record_add(&nsec3replay, above_fqdn, TYPE_NONE, NULL); } zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, labels, (top - zone->origin_vector.size) - 1); if(rr_label != NULL) { zdb_rr_label_forall_children_of_fqdn(rr_label, fqdn, zdb_icmtl_replay_commit_label_forall_nsec3_add_cb, &nsec3replay); } } } #endif #if ZDB_HAS_NSEC_SUPPORT // returns the number of changes taken into account (0 or 1) // 0 : proceed // 1 : ignore // ? : error if(!added_in_chain && (added_in_chain = (nsecreplay.vtbl->record_add(&nsecreplay, fqdn, rr.tctr.qtype, &ttlrdata) != 0))) { ++changes; } //else #endif if(!added_in_chain) switch(rr.tctr.qtype) { #if ZDB_HAS_NSEC3_SUPPORT case TYPE_NSEC3CHAINSTATE: { // create chain if missing ... nsec3_zone_add_from_rdata(zone, rr.rdata_size, rr.rdata); // add the record zdb_packed_ttlrdata *packed_ttlrdata; ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size); packed_ttlrdata->next = NULL; MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size); zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified break; } #endif // ZDB_HAS_NSEC3_SUPPORT # default: { zdb_packed_ttlrdata *packed_ttlrdata; ZDB_RECORD_ZALLOC_EMPTY(packed_ttlrdata, ttlrdata.ttl, rr.rdata_size); packed_ttlrdata->next = NULL; MEMCOPY(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), rr.rdata, rr.rdata_size); #if ICMTL_DUMP_JOURNAL_RECORDS rdata_desc type_len_rdata = {rr.tctr.qtype, rr.rdata_size, ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata) }; log_debug("journal: add %{dnsname} %{typerdatadesc}", fqdn, &type_len_rdata); logger_flush(); #endif if(rr.tctr.qtype == TYPE_SOA) { rr_soa_get_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), current_serialp); rdata_desc rdata = {TYPE_SOA, ZDB_PACKEDRECORD_PTR_RDATASIZE(packed_ttlrdata), ZDB_PACKEDRECORD_PTR_RDATAPTR(packed_ttlrdata)}; log_info("journal: %{dnsname}: SOA: add %{dnsname} %{typerdatadesc}", zone->origin, fqdn, &rdata); } zdb_zone_record_add(zone, labels, top, rr.tctr.qtype, packed_ttlrdata); // class is implicit, flow verified } } } // end if ADD changes++; } /* * Yes, I know. If 2^32 changes (add batch + del batch) occurs then it will be seen as an error ... */ if(ISOK(changes)) { #if ZDB_HAS_NSEC3_SUPPORT && ZDB_HAS_NSEC_SUPPORT if(has_nsec3 && has_nsec) { log_warn("journal: %{dnsname}: both NSEC3 and NSEC operations happened, which is not supported by YADIFA. Keeping the original one.", zone->origin); has_nsec3 = zdb_zone_is_nsec3(zone); has_nsec = zdb_zone_is_nsec(zone); } #endif #if ZDB_HAS_NSEC3_SUPPORT nsec3replay.vtbl->execute(&nsec3replay); #endif #if ZDB_HAS_NSEC_SUPPORT nsecreplay.vtbl->execute(&nsecreplay); #endif } #if ZDB_HAS_NSEC3_SUPPORT // has_nsec3 = zdb_zone_is_nsec3(zone); nsec3replay.vtbl->finalise(&nsec3replay); #endif #if ZDB_HAS_NSEC_SUPPORT // has_nsec = zdb_zone_is_nsec(zone); nsecreplay.vtbl->finalise(&nsecreplay); #endif dns_resource_record_clear(&rr); return changes; }