static void rr_canonize_nsec3param(zdb_packed_ttlrdata* rr, ptr_vector* v) { while(rr != NULL) { zdb_canonized_packed_ttlrdata* c_rr; u32 c_rr_size = sizeof (zdb_canonized_packed_ttlrdata) - 1 + ZDB_PACKEDRECORD_PTR_RDATASIZE(rr); MALLOC_OR_DIE(zdb_canonized_packed_ttlrdata*, c_rr, c_rr_size, RR_CANONIZE_NOP_TAG); ZDB_PACKEDRECORD_PTR_RDATASIZE(c_rr) = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr); c_rr->rdata_canonized_size = htons(ZDB_PACKEDRECORD_PTR_RDATASIZE(rr)); MEMCOPY(&c_rr->rdata_start[0], ZDB_PACKEDRECORD_PTR_RDATAPTR(rr), ZDB_PACKEDRECORD_PTR_RDATASIZE(rr)); c_rr->rdata_start[1] = 0; /* The signed NSEC3PARAM has its flags to 0 */ ptr_vector_append(v, c_rr); rr = rr->next; } }
static void rr_canonize_nop(zdb_packed_ttlrdata* rr, ptr_vector* v) { while(rr != NULL) { zdb_canonized_packed_ttlrdata* c_rr; u32 c_rr_size = sizeof (zdb_canonized_packed_ttlrdata) - 1 + ZDB_PACKEDRECORD_PTR_RDATASIZE(rr); MALLOC_OR_DIE(zdb_canonized_packed_ttlrdata*, c_rr, c_rr_size, RR_CANONIZE_NOP_TAG); ZDB_PACKEDRECORD_PTR_RDATASIZE(c_rr) = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr); c_rr->rdata_canonized_size = htons(ZDB_PACKEDRECORD_PTR_RDATASIZE(rr)); /** @todo CHECK: If we don't lo-case anymore maybe I could grab some * more cycles here. Not for the A-records on a 64bits arch, * but for any case where the rdata is (much) bigger than 8 bytes */ MEMCOPY(&c_rr->rdata_start[0], ZDB_PACKEDRECORD_PTR_RDATAPTR(rr), ZDB_PACKEDRECORD_PTR_RDATASIZE(rr)); ptr_vector_append(v, c_rr); rr = rr->next; } }
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) { 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 nsec3_icmtl_replay_execute(nsec3_icmtl_replay *replay) { bool nsec3param_added = FALSE; if(!treeset_avl_isempty(&replay->nsec3param_add)) { treeset_avl_iterator n3p_avl_iter; treeset_avl_iterator_init(&replay->nsec3param_add, &n3p_avl_iter); while(treeset_avl_iterator_hasnext(&n3p_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&n3p_avl_iter); zdb_ttlrdata* nsec3param = (zdb_ttlrdata*)node->data; nsec3_zone* n3 = nsec3_zone_get_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer); if(n3 == NULL) { /* * add the record */ zdb_packed_ttlrdata *packed_ttlrdata; ZDB_RECORD_ZALLOC(packed_ttlrdata, 0, nsec3param->rdata_size ,nsec3param->rdata_pointer); zdb_record_insert(&replay->zone->apex->resource_record_set, TYPE_NSEC3PARAM, packed_ttlrdata); nsec3_zone_add_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer); //nsec3_load_chain_init(nsec3param->rdata_pointer, nsec3param->rdata_size); nsec3param_added = TRUE; } zdb_ttlrdata_delete(nsec3param); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3param_add); } if(!treeset_avl_isempty(&replay->nsec3_del)) { /* stuff to delete */ treeset_avl_iterator ts_avl_iter; treeset_avl_iterator_init(&replay->nsec3_del, &ts_avl_iter); while(treeset_avl_iterator_hasnext(&ts_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter); u8 *fqdn = (u8*)node->key; zdb_ttlrdata *ttlrdata = (zdb_ttlrdata*)node->data; #ifndef NDEBUG log_debug("journal: NSEC3: post/del %{dnsname}", fqdn); #endif treeset_node *add_node; if((add_node = treeset_avl_find(&replay->nsec3_add, fqdn)) != NULL) { /* replace */ #ifndef NDEBUG log_debug("journal: NSEC3: upd %{dnsname}", fqdn); rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer }; log_debug("journal: NSEC3: - %{typerdatadesc}", &type_len_rdata); #endif zdb_ttlrdata *add_ttlrdata = (zdb_ttlrdata *)add_node->data; #ifndef NDEBUG rdata_desc add_type_len_rdata = {TYPE_NSEC3, add_ttlrdata->rdata_size, add_ttlrdata->rdata_pointer }; log_debug("journal: NSEC3: + %{typerdatadesc}", &add_type_len_rdata); #endif /* * The node may need an update of the type bitmap * After all changes (del/upd/add) all the added records should be matched again (check) * * nsec3_zone_item_get_by_name(); * nsec3_zone_item_update_bitmap(item, rdata, rdata_len) */ nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer); if(add_item != NULL) { nsec3_zone_item_update_bitmap(add_item, add_ttlrdata->rdata_pointer, add_ttlrdata->rdata_size); u8* add_key = add_node->key; treeset_avl_delete(&replay->nsec3_add, fqdn); zdb_ttlrdata_delete(add_ttlrdata); free(add_key); } else { log_err("journal: NSEC3: %{dnsname} has not been found in the NSEC3 database (del/add)", fqdn); return ERROR; } } else { #ifndef NDEBUG log_debug("journal: NSEC3: del %{dnsname}", fqdn); rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer }; log_debug("journal: NSEC3: - %{typerdatadesc}", &type_len_rdata); #endif /* delete */ nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer); if(add_item != NULL) { nsec3_remove_nsec3_by_name(replay->zone, fqdn, ttlrdata->rdata_pointer); } else { log_err("journal: NSEC3: %{dnsname} has not been found in the NSEC3 database (del)", fqdn); } /* * The node has to be deleted */ } zdb_ttlrdata_delete(ttlrdata); free(fqdn); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3_del); } if(!treeset_avl_isempty(&replay->nsec3_add)) { /* stuff to add */ treeset_avl_iterator ts_avl_iter; treeset_avl_iterator_init(&replay->nsec3_add, &ts_avl_iter); while(treeset_avl_iterator_hasnext(&ts_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter); u8 *fqdn = (u8*)node->key; #ifndef NDEBUG log_debug("journal: NSEC3: post/add %{dnsname}", fqdn); #endif zdb_ttlrdata *ttlrdata = (zdb_ttlrdata*)node->data; #ifndef NDEBUG log_debug("journal: NSEC3: add %{dnsname}", fqdn); rdata_desc type_len_rdata = {TYPE_NSEC3, ttlrdata->rdata_size, ttlrdata->rdata_pointer }; log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata); #endif /* * The node must be added. It should not exist already. * After all changes (del/upd/add) all the added records should be matched again (check) */ nsec3_zone_item *add_item = nsec3_zone_item_find_by_record(replay->zone, fqdn, ttlrdata->rdata_size, ttlrdata->rdata_pointer); if(add_item != NULL) { log_err("journal: NSEC3: already exists"); nsec3_zone *n3 = replay->zone->nsec.nsec3; if(n3 != NULL ) { zdb_packed_ttlrdata *nsec3; zdb_packed_ttlrdata *nsec3_rrsig; u8 owner[256]; nsec3_zone_item_to_zdb_packed_ttlrdata(n3, add_item, replay->zone->origin, owner, 600, &nsec3, &nsec3_rrsig); #ifndef NDEBUG rdata_desc type_len_rdata = {TYPE_NSEC3, nsec3->rdata_size, nsec3->rdata_start }; log_debug("journal: NSEC3: ? %{typerdatadesc}", &type_len_rdata); #endif free(nsec3); nsec3_remove_nsec3_by_digest(replay->zone, add_item->digest, ttlrdata->rdata_pointer); } } nsec3_add_nsec3_by_name(replay->zone, fqdn, ttlrdata->rdata_pointer, ttlrdata->rdata_size); zdb_ttlrdata_delete(ttlrdata); free(fqdn); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3_add); } if(!treeset_avl_isempty(&replay->nsec3rrsig_del)) { /* stuff to add */ treeset_avl_iterator ts_avl_iter; treeset_avl_iterator_init(&replay->nsec3rrsig_del, &ts_avl_iter); while(treeset_avl_iterator_hasnext(&ts_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter); u8 *fqdn = (u8*)node->key; #ifndef NDEBUG log_debug("journal: NSEC3: post/add %{dnsname}", fqdn); #endif zdb_ttlrdata *nsec3_rrsig = (zdb_ttlrdata*)node->data; #ifndef NDEBUG log_debug("journal: NSEC3: add %{dnsname}", fqdn); rdata_desc type_len_rdata = {TYPE_RRSIG, ZDB_RECORD_PTR_RDATASIZE(nsec3_rrsig), ZDB_RECORD_PTR_RDATAPTR(nsec3_rrsig) }; log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata); #endif /* * The node must be added. It should not exist already. * After all changes (del/upd/add) all the added records should be matched again (check) */ nsec3_zone_item *item = nsec3_zone_item_find_by_name_ext(replay->zone, fqdn, NULL); if(item != NULL) { nsec3_zone_item_rrsig_del(item, nsec3_rrsig); } zdb_ttlrdata_delete(nsec3_rrsig); free(fqdn); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3rrsig_del); } if(!treeset_avl_isempty(&replay->nsec3rrsig_add)) { /* stuff to add */ treeset_avl_iterator ts_avl_iter; treeset_avl_iterator_init(&replay->nsec3rrsig_add, &ts_avl_iter); while(treeset_avl_iterator_hasnext(&ts_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter); u8 *fqdn = (u8*)node->key; #ifndef NDEBUG log_debug("journal: NSEC3: post/add %{dnsname}", fqdn); #endif zdb_packed_ttlrdata *nsec3_rrsig = (zdb_packed_ttlrdata*)node->data; #ifndef NDEBUG log_debug("journal: NSEC3: add %{dnsname}", fqdn); rdata_desc type_len_rdata = {TYPE_RRSIG, ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec3_rrsig), ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec3_rrsig) }; log_debug("journal: NSEC3: + %{typerdatadesc}", &type_len_rdata); #endif /* * The node must be added. It should not exist already. * After all changes (del/upd/add) all the added records should be matched again (check) */ nsec3_zone_item *item = nsec3_zone_item_find_by_name_ext(replay->zone, fqdn, NULL); if(item != NULL) { nsec3_zone_item_rrsig_add(item, nsec3_rrsig); } else { ZDB_RECORD_ZFREE(nsec3_rrsig); } free(fqdn); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3rrsig_add); } if(!treeset_avl_isempty(&replay->nsec3_labels)) { /* labels to update */ treeset_avl_iterator ts_avl_iter; treeset_avl_iterator_init(&replay->nsec3_labels, &ts_avl_iter); while(treeset_avl_iterator_hasnext(&ts_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&ts_avl_iter); u8 *fqdn = (u8*)node->key; zdb_rr_label *rr_label = (zdb_rr_label*)node->data; #ifndef NDEBUG log_debug("journal: NSEC3: lbl %{dnsname} (%{dnslabel})", fqdn, rr_label->name); #endif /* * The fqdn/label should be updated for self & star match. */ if(rr_label->nsec.nsec3 == NULL) { nsec3_label_link(replay->zone, rr_label, fqdn); } free(fqdn); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3_labels); } /**/ if(nsec3param_added) { /* * ALL the labels of the zone have to be linked again. */ zdb_zone_label_iterator label_iterator; u8 fqdn[MAX_DOMAIN_LENGTH]; zdb_zone_label_iterator_init(replay->zone, &label_iterator); while(zdb_zone_label_iterator_hasnext(&label_iterator)) { zdb_zone_label_iterator_nextname(&label_iterator, fqdn); zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator); nsec3_label_link(replay->zone, label, fqdn); } } if(!treeset_avl_isempty(&replay->nsec3param_del)) { treeset_avl_iterator n3p_avl_iter; treeset_avl_iterator_init(&replay->nsec3param_del, &n3p_avl_iter); while(treeset_avl_iterator_hasnext(&n3p_avl_iter)) { treeset_node *node = treeset_avl_iterator_next_node(&n3p_avl_iter); zdb_ttlrdata* nsec3param = (zdb_ttlrdata*)node->data; nsec3_zone* n3 = nsec3_zone_get_from_rdata(replay->zone, nsec3param->rdata_size, nsec3param->rdata_pointer); if(n3 == NULL) { nsec3_zone_destroy(replay->zone, n3); zdb_record_delete_exact(&replay->zone->apex->resource_record_set, TYPE_NSEC3PARAM, nsec3param); } zdb_ttlrdata_delete(nsec3param); node->key = NULL; node->data = NULL; } treeset_avl_destroy(&replay->nsec3param_del); } return SUCCESS; }
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 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; }
ya_result zdb_zone_update_ixfr(zdb* db, input_stream* is) { u8 rname[MAX_DOMAIN_LENGTH]; u16 rtype; u16 rclass; u32 rttl; u16 rdata_size; u8* rdata; zdb_packed_ttlrdata* soa_ttlrdata; zdb_packed_ttlrdata* tmp_ttlrdata; zdb_packed_ttlrdata* ttlrdata; dnsname_vector name; dnsname_vector entry_name; ya_result err; /* Get the first SOA */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { return err; } if(rtype != TYPE_SOA) { return ZDB_ERROR_GENERAL; } DEBUG_RESET_dnsname(name); dnsname_to_dnsname_vector(rname, &name); ZDB_RECORD_ZALLOC_EMPTY(soa_ttlrdata, rttl, rdata_size); if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size))) { return err; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr H: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, ZDB_PACKEDRECORD_PTR_RDATAPTR(soa_ttlrdata), rdata_size); println(""); } #endif #endif u32 serial_first; if(FAIL(err = rr_soa_get_serial(soa_ttlrdata->rdata_start, soa_ttlrdata->rdata_size, &serial_first))) { return err; } zdb_zone_label* zone_label = zdb_zone_label_find(db, &name, rclass); if((zone_label == NULL) || (zone_label->zone == NULL)) { /* Not loaded */ return ZDB_ERROR_GENERAL; } zdb_zone* zone = zone_label->zone; u32 serial_current; if(FAIL(err = zdb_zone_getserial(zone, &serial_current))) { return err; } #if ZDB_NSEC3_SUPPORT != 0 nsec3_load_context nsec3_context; nsec3_load_init(&nsec3_context, zone); #endif MALLOC_OR_DIE(zdb_packed_ttlrdata*, tmp_ttlrdata, sizeof (zdb_ttlrdata) + RDATA_MAX_LENGTH, ZDB_RDATABUF_TAG); /* We do not need tmp_ttlrdata and rdata at the same time, let's spare memory */ rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(tmp_ttlrdata); /* Read the next SOA (sub or end) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { return err; } if(rtype != TYPE_SOA) { return ZDB_ERROR_GENERAL; } for(;;) { if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr F: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* The SOA serial is supposed to match our current one or the first one * * If it's the first one, then the task is done * * If it's the current one, we are moving forward * * If it's something else, there is an error * */ u32 serial_from; if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_from))) { break; } /* Check the serial */ if(serial_from != serial_current) { if(serial_from == serial_first) { /* IXFR done */ err = SUCCESS; break; } /* Serial sequence is not right */ err = ZDB_ERROR_GENERAL; break; } tmp_ttlrdata->ttl = rttl; tmp_ttlrdata->rdata_size = rdata_size; zdb_zone_record_delete(zone, NULL, -1, TYPE_SOA, tmp_ttlrdata); for(;;) { /* Load the next record without the data (sub) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { break; } /* If we got an SOA, it's the one that starts the "add" sequence */ if(rtype == TYPE_SOA) { break; } /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr R: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif tmp_ttlrdata->ttl = rttl; tmp_ttlrdata->rdata_size = rdata_size; /* The vector is not always required, but it's so much easier to * read putting it here */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); #if ZDB_NSEC3_SUPPORT != 0 if(rtype == TYPE_NSEC3PARAM) { /* Remove it from the zone */ zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata); /* Destroy the whole NSEC3 collection associated to the NSEC3PARAM */ nsec3_remove_nsec3param_by_record(zone, tmp_ttlrdata); continue; } if(rtype == TYPE_NSEC3) { /* Remove the NSEC3 label (and its signature) * * The previous record will have its signature changed, no doubt. * But I cannot edit the previous one about this. * Since we are in an IXFR, the previous NSEC3 is supposed to be * removed too, until one of the previous is also added in the * next section (soa add) * * zdb_zone_record_delete is not the right call, it's * * nsec3_... * */ nsec3_remove_nsec3(zone, tmp_ttlrdata); continue; } if(rtype == TYPE_RRSIG) { if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */ { /* Remove the RRSIG from the NSEC3 label * * zdb_zone_record_delete is not the right call, it's * * nsec3_... * */ nsec3_remove_rrsig(zone, tmp_ttlrdata); continue; } } #endif /* Remove from the zone */ zdb_zone_record_delete(zone, name.labels, (entry_name.size - name.size) - 1, rtype, tmp_ttlrdata); } /* Remove records */ /* The current header is the "ADD" SOA */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr T: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* The SOA serial is supposed to be bigger than the previous one */ u32 serial_to; if(FAIL(err = rr_soa_get_serial(rdata, rdata_size, &serial_to))) { break; } /* * After the "add" sequence is done, serial_current will be serial_to */ do { /* Load the record without the data (add) */ if(FAIL(err = input_stream_read_rr_header(is, rname, sizeof (rname), &rtype, &rclass, &rttl, &rdata_size))) { break; } #if ZDB_NSEC3_SUPPORT != 0 if(rtype == TYPE_NSEC3PARAM) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* Add it to the nsec3 context */ nsec3_load_add_nsec3param(&nsec3_context, rdata, rdata_size); /* Add it to the zone */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); } else if(rtype == TYPE_NSEC3) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif #endif /* Add it to the nsec3 context */ if(FAIL(err = nsec3_load_add_nsec3(&nsec3_context, rname, rttl, rdata, rdata_size))) { break; } } else if(rtype == TYPE_RRSIG) { /* Load the data */ if(FAIL(err = input_stream_read_fully(is, rdata, rdata_size))) { break; } #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, rdata, rdata_size); println(""); } #endif if((GET_U16_AT(*rdata)) == TYPE_NSEC3) /** @note : NATIVETYPE */ { /* Add it to the nsec3 context */ if(FAIL(err = nsec3_load_add_rrsig(&nsec3_context, rname, rttl, rdata, rdata_size))) { break; } } else { /* Add it to the zone */ DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); ZDB_RECORD_ZALLOC(ttlrdata, rttl, rdata_size, rdata); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); } } else { #endif /* Add it to the zone */ ZDB_RECORD_ZALLOC_EMPTY(ttlrdata, rttl, rdata_size); if(FAIL(err = input_stream_read_fully(is, ZDB_PACKEDRECORD_PTR_RDATAPTR(ttlrdata), rdata_size))) { break; } #ifndef NDEBUG #if DUMP_ICMTL_UPDATE != 0 if(err != 0) { format("zdb_zone_update_ixfr A: %{dnsname} %d %{dnsclass} %{dnstype} ", rname, rttl, &rclass, &rtype); print_rdata(rtype, ttlrdata->rdata_start, rdata_size); println(termout, ""); } #endif #endif DEBUG_RESET_dnsname(entry_name); dnsname_to_dnsname_vector(rname, &entry_name); zdb_zone_record_add(zone, entry_name.labels, (entry_name.size - name.size) - 1, rtype, ttlrdata); /* class is implicit */ #if ZDB_NSEC3_SUPPORT != 0 } #endif } while(rtype != TYPE_SOA); /* * The record is either the first of another SOA pair (sub, add) * Either the final one. */ /* Update the current serial */ serial_current = serial_to; break; } free(tmp_ttlrdata); if(ISOK(err)) { /* * soa_ttlrdata is the new SOA */ zdb_zone_record_add(zone, NULL, -1, TYPE_SOA, soa_ttlrdata); #if ZDB_NSEC3_SUPPORT != 0 /** * Check if there is both NSEC & NSEC3. Reject if yes. * compile NSEC if any * compile NSEC3 if any * * @todo: I'm only doing NSEC3 here. Do NSEC as well */ err = nsec3_load_compile(&nsec3_context); if((nsec3_context.nsec3_rejected > 0)||(nsec3_context.nsec3_discarded > 0)) { err = DNSSEC_ERROR_NSEC3_INVALIDZONESTATE; } if(ISOK(err)) { nsec3_load_destroy(&nsec3_context); #endif zone_label->zone = zone; return err; #if ZDB_NSEC3_SUPPORT != 0 } #endif } #if ZDB_NSEC3_SUPPORT != 0 nsec3_load_destroy(&nsec3_context); #endif /** * @note : do NOT use these to unload a zone. * zdb_zone_label_delete(db, &name, zone->zclass); * zdb_zone_destroy(zone); */ zdb_zone_unload(db, &name, zdb_zone_getclass(zone)); return err; }
static bool write_label(zdb_resourcerecord* rr, u32* countp, packet_writer* pc) { u32 count = 0; bool fully_written = TRUE; while(rr != NULL) { /* Store the name */ const u8* name = rr->name; u16 rdata_size = ZDB_PACKEDRECORD_PTR_RDATASIZE(rr->ttl_rdata); u32 offset_backup = pc->packet_offset; /* copy the name */ #if ANSWER_DO_COMPRESSION == 0 packet_writer_add_fqdn_uncompressed(pc, name); #else packet_writer_add_fqdn(pc, name); #endif /* copy the TYPE + CLASS + RDATA SIZE */ packet_writer_add_u16(pc, (rr->rtype)); /** @note: NATIVETYPE */ packet_writer_add_u16(pc, (rr->zclass)); /** @note: NATIVECLASS */ packet_writer_add_u32(pc, htonl(rr->ttl)); /* Here we do compression (or not) */ #if ANSWER_DO_COMPRESSION == 0 /* Store the RDATA len (16 bits) */ u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(rr->ttl_rdata); packet_writer_add_u16(pc, htons(rdata_size)); /* copy the RDATA */ packet_writer_add_bytes(pc, rdata, rdata_size); #else u32 offset = pc->packet_offset; u8* rdata = ZDB_PACKEDRECORD_PTR_RDATAPTR(rr->ttl_rdata); pc->packet_offset += 2; switch(rr->rtype) { case TYPE_MX: packet_writer_add_bytes(pc, rdata, 2); rdata += 2; /* Fallthrough */ case TYPE_NS: case TYPE_CNAME: case TYPE_DNAME: case TYPE_PTR: case TYPE_MB: case TYPE_MD: case TYPE_MF: case TYPE_MG: case TYPE_MR: /* ONE NAME record */ { packet_writer_add_fqdn(pc, rdata); packet_writer_set_u16(pc, htons(pc->packet_offset - offset - 2), offset); break; } case TYPE_SOA: { u32 len1 = dnsname_len(rdata); packet_writer_add_fqdn(pc, rdata); rdata += len1; u32 len2 = dnsname_len(rdata); packet_writer_add_fqdn(pc, rdata); rdata += len2; packet_writer_add_bytes(pc, rdata, 20); packet_writer_set_u16(pc, htons(pc->packet_offset - offset - 2), offset); break; } default: { packet_writer_set_u16(pc, htons(rdata_size), offset); packet_writer_add_bytes(pc, rdata, rdata_size); break; } } /* switch(type) */ #endif /* * If we are beyond the limit, we restore the offset and stop here. */ if(pc->packet_offset > pc->packet_limit) { pc->packet_offset = offset_backup; fully_written = FALSE; break; } count++; rr = rr->next; } *countp = count; /* stores the count */ return fully_written; /* returns the offset of the next writable byte */ }