void schedule_purge(schedule_type* schedule) { ldns_rbnode_t* node; if (!schedule || !schedule->tasks) return; pthread_mutex_lock(&schedule->schedule_lock); /* don't attempt to free payload, still referenced by other tree*/ while ((node = ldns_rbtree_first(schedule->tasks)) != LDNS_RBTREE_NULL) { node = ldns_rbtree_delete(schedule->tasks, node->data); if (node == 0) break; free(node); } /* also clean up name tree */ while ((node = ldns_rbtree_first(schedule->tasks_by_name)) != LDNS_RBTREE_NULL) { node = ldns_rbtree_delete(schedule->tasks_by_name, node->data); if (node == 0) break; task_cleanup((task_type*) node->data); free(node); } pthread_mutex_unlock(&schedule->schedule_lock); }
static ldns_rbnode_t * ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) { ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names); ldns_dnssec_name *current_name; ldns_rdf *hashed_name; hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); while (current_node != LDNS_RBTREE_NULL) { current_name = (ldns_dnssec_name *) current_node->data; if (!current_name->hashed_name) { current_name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name); } if (ldns_dname_compare(hashed_name, current_name->hashed_name) == 0) { ldns_rdf_deep_free(hashed_name); return current_node; } current_node = ldns_rbtree_next(current_node); } ldns_rdf_deep_free(hashed_name); return NULL; }
static void ldns_dnssec_zone_hashed_names_from_nsec3( ldns_dnssec_zone* zone, ldns_rr* nsec3rr) { ldns_rbnode_t* current_node; ldns_dnssec_name* current_name; assert(zone != NULL); assert(nsec3rr != NULL); if (zone->hashed_names) { ldns_traverse_postorder(zone->hashed_names, ldns_hashed_names_node_free, NULL); LDNS_FREE(zone->hashed_names); } zone->_nsec3params = nsec3rr; /* So this is a NSEC3 zone. * Calculate hashes for all names already in the zone */ zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); if (zone->hashed_names == NULL) { return; } for ( current_node = ldns_rbtree_first(zone->names) ; current_node != LDNS_RBTREE_NULL ; current_node = ldns_rbtree_next(current_node) ) { current_name = (ldns_dnssec_name *) current_node->data; ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr); } }
/** * Get the first scheduled task. As long as return value is used * caller should hold schedule->schedule_lock. * * \param[in] schedule schedule * \return task_type* first scheduled task, NULL on no task or error. */ static task_type* get_first_task(schedule_type* schedule) { ldns_rbnode_t* first_node; if (!schedule || !schedule->tasks) return NULL; first_node = ldns_rbtree_first(schedule->tasks); if (!first_node) return NULL; return (task_type*) first_node->data; }
static int run(int sockfd, cmdhandler_ctx_type* context, const char *cmd) { struct tm strtime_struct; char strtime[64]; /* at least 26 according to docs plus a long integer */ char* taskdescription; size_t i = 0; int count; time_t now; time_t nextFireTime; ldns_rbnode_t* node = LDNS_RBTREE_NULL; task_type* task = NULL; int num_waiting; engine_type* engine = getglobalcontext(context); (void)cmd; ods_log_debug("[%s] list tasks command", module_str); ods_log_assert(engine); if (!engine->taskq || !engine->taskq->tasks) { client_printf(sockfd, "There are no tasks scheduled.\n"); return 0; } schedule_info(engine->taskq, &nextFireTime, &num_waiting, &count); if (num_waiting == engine->config->num_worker_threads) { client_printf(sockfd, "All worker threads idle.\n"); } /* how many tasks */ client_printf(sockfd, "There %s %i %s scheduled.\n", (count==1)?"is":"are", (int) count, (count==1)?"task":"tasks"); now = time_now(); strftime(strtime, sizeof(strtime), "%c", localtime_r(&now, &strtime_struct)); client_printf(sockfd, "It is now %s (%ld seconds since epoch)\n", (strtime[0]?strtime:"(null)"), (long)now); if (nextFireTime > now) { strftime(strtime, sizeof(strtime), "%c", localtime_r(&nextFireTime, &strtime_struct)); client_printf(sockfd, "Next task scheduled %s (%ld seconds since epoch)\n", strtime, (long)nextFireTime); } else if (nextFireTime >= 0) { client_printf(sockfd, "Next task scheduled immediately\n"); } /* else: no tasks scheduled at all. */ /* list tasks */ pthread_mutex_lock(&engine->taskq->schedule_lock); node = ldns_rbtree_first(engine->taskq->tasks); while (node && node != LDNS_RBTREE_NULL) { task = (task_type*) node->data; taskdescription = schedule_describetask(task); client_printf(sockfd, "%s", taskdescription); free(taskdescription); node = ldns_rbtree_next(node); } pthread_mutex_unlock(&engine->taskq->schedule_lock); return 0; }
void MV_SHM_Dump_Node(ldns_rbtree_t *shm_root) { ldns_rbnode_t *node; shm_address_t *tmp; dump_stack_android(); node = ldns_rbtree_first(shm_root); while (node != LDNS_RBTREE_NULL) { tmp = (shm_address_t *)(node->key); node = ldns_rbtree_next(node); MV_SHM_Print("SHM:DUMP:N:0x%x,PA:0x%x,VA=0x%x,SZ=0x%x", \ tmp, tmp->m_phyaddress, tmp->m_virtaddress, tmp->m_size); } }
void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_rbtree_t *tree, bool print_soa) { ldns_rbnode_t *node; ldns_dnssec_name *name; node = ldns_rbtree_first(tree); while (node != LDNS_RBTREE_NULL) { name = (ldns_dnssec_name *) node->data; ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa); if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, ";\n"); node = ldns_rbtree_next(node); } }
int schedule_flush_type(schedule_type* schedule, task_id id) { ldns_rbnode_t *node, *nextnode; int nflushed = 0; ods_log_debug("[%s] flush task", schedule_str); if (!schedule || !schedule->tasks) return 0; pthread_mutex_lock(&schedule->schedule_lock); node = ldns_rbtree_first(schedule->tasks); while (node && node != LDNS_RBTREE_NULL) { nextnode = ldns_rbtree_next(node); if (node->data && ((task_type*)node->data)->what == id) { /* Merely setting flush is not enough. We must set it * to the front of the queue as well. */ node = ldns_rbtree_delete(schedule->tasks, node->data); if (!node) break; /* stange, bail out */ if (node->data) { /* task */ ((task_type*)node->data)->flush = 1; /* This is important for our tests only. If a task is * set to flush it should not affect the current time. * Otherwise timeleap will advance time. */ ((task_type*)node->data)->when = time_now(); if (!ldns_rbtree_insert(schedule->tasks, node)) { ods_log_crit("[%s] Could not reschedule task " "after flush. A task has been lost!", schedule_str); free(node); /* Do not free node->data it is still in use * by the other rbtree. */ break; } nflushed++; } } node = nextnode; } /* wakeup! work to do! */ pthread_cond_signal(&schedule->schedule_cond); pthread_mutex_unlock(&schedule->schedule_lock); return nflushed; }
bool ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone) { ldns_rr* nsec3; ldns_rbnode_t* node; if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) { node = ldns_rbtree_first(zone->names); while (node != LDNS_RBTREE_NULL) { nsec3 = ((ldns_dnssec_name*)node->data)->nsec; if (nsec3 &&ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3 && ldns_nsec3_optout(nsec3)) { return true; } node = ldns_rbtree_next(node); } } return false; }
/** * pop the first scheduled task. Caller must hold * schedule->schedule_lock. Result is safe to use outside lock. * * \param[in] schedule schedule * \return task_type* first scheduled task, NULL on no task or error. */ static task_type* pop_first_task(schedule_type* schedule) { ldns_rbnode_t *node, *delnode; task_type *task; if (!schedule || !schedule->tasks) return NULL; node = ldns_rbtree_first(schedule->tasks); if (!node) return NULL; delnode = ldns_rbtree_delete(schedule->tasks, node->data); /* delnode == node, but we don't free it just yet, data is shared * with tasks_by_name tree */ if (!delnode) return NULL; delnode = ldns_rbtree_delete(schedule->tasks_by_name, node->data); free(node); if (!delnode) return NULL; task = (task_type*) delnode->data; free(delnode); /* this delnode != node */ set_alarm(schedule); return task; }
/** * Queue zone for signing. * */ static void worker_queue_zone(worker_type* worker, fifoq_type* q, zone_type* zone) { ldns_rbnode_t* node = LDNS_RBTREE_NULL; domain_type* domain = NULL; ods_log_assert(worker); ods_log_assert(q); ods_log_assert(zone); worker_clear_jobs(worker); if (!zone->db || !zone->db->domains) { return; } if (zone->db->domains->root != LDNS_RBTREE_NULL) { node = ldns_rbtree_first(zone->db->domains); } while (node && node != LDNS_RBTREE_NULL) { domain = (domain_type*) node->data; worker_queue_domain(worker, q, domain); node = ldns_rbtree_next(node); } return; }
/** * Make sure that all zones have been worked on at least once. * */ static int engine_all_zones_processed(engine_type* engine) { ldns_rbnode_t* node = LDNS_RBTREE_NULL; zone_type* zone = NULL; ods_log_assert(engine); ods_log_assert(engine->zonelist); ods_log_assert(engine->zonelist->zones); node = ldns_rbtree_first(engine->zonelist->zones); while (node && node != LDNS_RBTREE_NULL) { zone = (zone_type*) node->key; ods_log_assert(zone); ods_log_assert(zone->db); if (!zone->db->is_processed) { return 0; } node = ldns_rbtree_next(node); } return 1; }
ldns_status ldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone) { ldns_rbnode_t *cur_node; ldns_dnssec_name *cur_name; ldns_rdf *cur_owner, *cur_parent; cur_node = ldns_rbtree_first(zone->names); while (cur_node != LDNS_RBTREE_NULL) { cur_name = (ldns_dnssec_name *) cur_node->data; cur_node = ldns_rbtree_next(cur_node); if (ldns_dnssec_name_has_only_a(cur_name)) { /* assume glue XXX check for zone cur */ cur_owner = ldns_rdf_clone(ldns_rr_owner( cur_name->rrsets->rrs->rr)); while (ldns_dname_label_count(cur_owner) > ldns_dname_label_count(zone->soa->name)) { if (ldns_dnssec_zone_find_rrset(zone, cur_owner, LDNS_RR_TYPE_NS)) { /* fprintf(stderr, "[XX] Marking as glue: "); ldns_rdf_print(stderr, cur_name->name); fprintf(stderr, "\n"); */ cur_name->is_glue = true; } cur_parent = ldns_dname_left_chop(cur_owner); ldns_rdf_deep_free(cur_owner); cur_owner = cur_parent; } ldns_rdf_deep_free(cur_owner); } } return LDNS_STATUS_OK; }
void schedule_flush(schedule_type* schedule) { ldns_rbnode_t* node; task_type* task; ods_log_debug("[%s] flush all tasks", schedule_str); if (!schedule || !schedule->tasks) return; pthread_mutex_lock(&schedule->schedule_lock); node = ldns_rbtree_first(schedule->tasks); while (node && node != LDNS_RBTREE_NULL) { task = (task_type*) node->data; /* * TODO BUG? schedule_flush_type() sets when to zero, this does not. * Whos right and whos wrong? */ task->flush = 1; node = ldns_rbtree_next(node); } /* wakeup! work to do! */ pthread_cond_signal(&schedule->schedule_cond); pthread_mutex_unlock(&schedule->schedule_lock); }
ldns_status ldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs) { ldns_rbnode_t *first_node, *cur_node, *next_node; ldns_dnssec_name *cur_name, *next_name; ldns_rr *nsec_rr; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf( soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } first_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); cur_node = first_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } else { next_node = NULL; } while (cur_node && next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)next_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(cur_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); cur_node = next_node; if (cur_node) { next_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(cur_node)); } } if (cur_node && !next_node) { cur_name = (ldns_dnssec_name *)cur_node->data; next_name = (ldns_dnssec_name *)first_node->data; nsec_rr = ldns_dnssec_create_nsec(cur_name, next_name, LDNS_RR_TYPE_NSEC); ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(cur_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); } else { printf("error\n"); } return LDNS_STATUS_OK; }
/** * Marks the names in the zone that are occluded. Those names will be skipped * when walking the tree with the ldns_dnssec_name_node_next_nonglue() * function. But watch out! Names that are partially occluded (like glue with * the same name as the delegation) will not be marked and should specifically * be taken into account separately. * * When glue_list is given (not NULL), in the process of marking the names, all * glue resource records will be pushed to that list, even glue at delegation names. * * \param[in] zone the zone in which to mark the names * \param[in] glue_list the list to which to push the glue rrs * \return LDNS_STATUS_OK on success, an error code otherwise */ ldns_status ldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone, ldns_rr_list *glue_list) { ldns_rbnode_t *node; ldns_dnssec_name *name; ldns_rdf *owner; ldns_rdf *cut = NULL; /* keeps track of zone cuts */ /* When the cut is caused by a delegation, below_delegation will be 1. * When caused by a DNAME, below_delegation will be 0. */ int below_delegation = -1; /* init suppresses comiler warning */ ldns_status s; if (!zone || !zone->names) { return LDNS_STATUS_NULL; } for (node = ldns_rbtree_first(zone->names); node != LDNS_RBTREE_NULL; node = ldns_rbtree_next(node)) { name = (ldns_dnssec_name *) node->data; owner = ldns_dnssec_name_name(name); if (cut) { /* The previous node was a zone cut, or a subdomain * below a zone cut. Is this node (still) a subdomain * below the cut? Then the name is occluded. Unless * the name contains a SOA, after which we are * authoritative again. * * FIXME! If there are labels in between the SOA and * the cut, going from the authoritative space (below * the SOA) up into occluded space again, will not be * detected with the contruct below! */ if (ldns_dname_is_subdomain(owner, cut) && !ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_SOA)) { if (below_delegation && glue_list) { s = ldns_dnssec_addresses_on_glue_list( name->rrsets, glue_list); if (s != LDNS_STATUS_OK) { return s; } } name->is_glue = true; /* Mark occluded name! */ continue; } else { cut = NULL; } } /* The node is not below a zone cut. Is it a zone cut itself? * Everything below a SOA is authoritative of course; Except * when the name also contains a DNAME :). */ if (ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_SOA)) { cut = owner; below_delegation = 1; if (glue_list) { /* record glue on the zone cut */ s = ldns_dnssec_addresses_on_glue_list( name->rrsets, glue_list); if (s != LDNS_STATUS_OK) { return s; } } } else if (ldns_dnssec_rrsets_contains_type( name->rrsets, LDNS_RR_TYPE_DNAME)) { cut = owner; below_delegation = 0; } } return LDNS_STATUS_OK; }
static ldns_status ldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt, ldns_rbtree_t **map) { ldns_rbnode_t *first_name_node; ldns_rbnode_t *current_name_node; ldns_dnssec_name *current_name; ldns_status result = LDNS_STATUS_OK; ldns_rr *nsec_rr; ldns_rr_list *nsec3_list; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; ldns_rbnode_t *hashmap_node; if (!zone || !new_rrs || !zone->names) { return LDNS_STATUS_ERR; } /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr && ldns_rr_rdf(soa->rrs->rr, 6) != NULL) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } if (zone->hashed_names) { ldns_traverse_postorder(zone->hashed_names, ldns_hashed_names_node_free, NULL); LDNS_FREE(zone->hashed_names); } zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); if (zone->hashed_names && map) { *map = zone->hashed_names; } first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; while (current_name_node && current_name_node != LDNS_RBTREE_NULL && result == LDNS_STATUS_OK) { current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, zone->soa->name, algorithm, flags, iterations, salt_length, salt); /* by default, our nsec based generator adds rrsigs * remove the bitmap for empty nonterminals */ if (!current_name->rrsets) { ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr)); } ldns_rr_set_ttl(nsec_rr, nsec_ttl); result = ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); if (ldns_rr_owner(nsec_rr)) { hashmap_node = LDNS_MALLOC(ldns_rbnode_t); if (hashmap_node == NULL) { return LDNS_STATUS_MEM_ERR; } current_name->hashed_name = ldns_dname_label(ldns_rr_owner(nsec_rr), 0); if (current_name->hashed_name == NULL) { LDNS_FREE(hashmap_node); return LDNS_STATUS_MEM_ERR; } hashmap_node->key = current_name->hashed_name; hashmap_node->data = current_name; if (! ldns_rbtree_insert(zone->hashed_names , hashmap_node)) { LDNS_FREE(hashmap_node); } } current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } if (result != LDNS_STATUS_OK) { return result; } /* Make sorted list of nsec3s (via zone->hashed_names) */ nsec3_list = ldns_rr_list_new(); if (nsec3_list == NULL) { return LDNS_STATUS_MEM_ERR; } for ( hashmap_node = ldns_rbtree_first(zone->hashed_names) ; hashmap_node != LDNS_RBTREE_NULL ; hashmap_node = ldns_rbtree_next(hashmap_node) ) { current_name = (ldns_dnssec_name *) hashmap_node->data; nsec_rr = ((ldns_dnssec_name *) hashmap_node->data)->nsec; if (nsec_rr) { ldns_rr_list_push_rr(nsec3_list, nsec_rr); } } result = ldns_dnssec_chain_nsec3_list(nsec3_list); ldns_rr_list_free(nsec3_list); return result; }
static int MV_SHM_free_all_node(shm_free_t *shm) { int i = 0; int frist = 0; ldns_rbnode_t *node; shm_address_t *tmp; uint middle1, middle2, middle_size; shm->flag = 0; shm->node = NULL; MV_SHM_Print("SHM:FREE:START:%d\n", __LINE__); MV_SHM_Dump_Node(&shm->shm_root->m_phyaddr_root); MV_SHM_Dump_Node(&shm->shm_root->m_virtaddr_root); node = ldns_rbtree_first(&shm->shm_root->m_phyaddr_root); while (node != LDNS_RBTREE_NULL) { tmp = (shm_address_t *)(node->key); node = ldns_rbtree_next(node); middle1 = tmp->m_phyaddress + tmp->m_size/2; middle2 = shm->address + shm->size/2; middle_size = (tmp->m_size + shm->size)/2; if (middle1 > middle2) middle1 = middle1 - middle2; else middle1 = middle2 - middle1; if (middle1 < middle_size) { MV_SHM_Print("MV_SHM_free_all_node No.[%d], root[%p]" " Node_phys[%08x] Node_virt[%08x] Node_size[%08x]" " address[%08x] size[%08x]\n", i, tmp, tmp->m_phyaddress, tmp->m_virtaddress, tmp->m_size, shm->address, shm->size); i++; if ((tmp->m_phyaddress == shm->address) && (tmp->m_size == shm->size) && (shm->flag == 0)) { shm->flag = 1; if ((shm->node != NULL) && (frist == 1)) free(shm->node); shm->node = tmp; } else { if (MV_SHM_Munmap_Base(tmp->m_virtaddress, tmp->m_size, shm->mem_type) == 0) { MV_SHM_delete_phyaddress_node( &shm->shm_root->m_phyaddr_root, tmp); MV_SHM_delete_virtaddress_node( &shm->shm_root->m_virtaddr_root, tmp); if ((frist == 0) && (shm->flag == 0)) { frist = 1; shm->node = tmp; } else { free(tmp); } } } } } MV_SHM_Print("SHM:FREE:END:%d\n", __LINE__); MV_SHM_Dump_Node(&shm->shm_root->m_phyaddr_root); MV_SHM_Dump_Node(&shm->shm_root->m_virtaddr_root); return 0; }
ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone) { ldns_dnssec_name *new_name; ldns_rdf *cur_name; ldns_rdf *next_name; ldns_rbnode_t *cur_node, *next_node, *new_node; /* for the detection */ uint16_t i, cur_label_count, next_label_count; uint16_t soa_label_count = 0; ldns_rdf *l1, *l2; int lpos; if (!zone) { return LDNS_STATUS_ERR; } if (zone->soa && zone->soa->name) { soa_label_count = ldns_dname_label_count(zone->soa->name); } cur_node = ldns_rbtree_first(zone->names); while (cur_node != LDNS_RBTREE_NULL) { next_node = ldns_rbtree_next(cur_node); /* skip glue */ while (next_node != LDNS_RBTREE_NULL && next_node->data && ((ldns_dnssec_name *)next_node->data)->is_glue ) { next_node = ldns_rbtree_next(next_node); } if (next_node == LDNS_RBTREE_NULL) { next_node = ldns_rbtree_first(zone->names); } if (! cur_node->data || ! next_node->data) { return LDNS_STATUS_ERR; } cur_name = ((ldns_dnssec_name *)cur_node->data)->name; next_name = ((ldns_dnssec_name *)next_node->data)->name; cur_label_count = ldns_dname_label_count(cur_name); next_label_count = ldns_dname_label_count(next_name); /* Since the names are in canonical order, we can * recognize empty non-terminals by their labels; * every label after the first one on the next owner * name is a non-terminal if it either does not exist * in the current name or is different from the same * label in the current name (counting from the end) */ for (i = 1; i < next_label_count - soa_label_count; i++) { lpos = (int)cur_label_count - (int)next_label_count + (int)i; if (lpos >= 0) { l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos); } else { l1 = NULL; } l2 = ldns_dname_clone_from(next_name, i); if (!l1 || ldns_dname_compare(l1, l2) != 0) { /* We have an empty nonterminal, add it to the * tree */ new_name = ldns_dnssec_name_new(); if (!new_name) { return LDNS_STATUS_MEM_ERR; } new_name->name = ldns_dname_clone_from(next_name, i); if (!new_name->name) { ldns_dnssec_name_free(new_name); return LDNS_STATUS_MEM_ERR; } new_name->name_alloced = true; new_node = LDNS_MALLOC(ldns_rbnode_t); if (!new_node) { ldns_dnssec_name_free(new_name); return LDNS_STATUS_MEM_ERR; } new_node->key = new_name->name; new_node->data = new_name; (void)ldns_rbtree_insert(zone->names, new_node); ldns_dnssec_name_make_hashed_name( zone, new_name, NULL); } ldns_rdf_deep_free(l1); ldns_rdf_deep_free(l2); } /* we might have inserted a new node after * the current one so we can't just use next() */ if (next_node != ldns_rbtree_first(zone->names)) { cur_node = next_node; } else { cur_node = LDNS_RBTREE_NULL; } } return LDNS_STATUS_OK; }
ldns_status ldns_dnssec_zone_create_rrsigs_flg( ldns_dnssec_zone *zone , ldns_rr_list *new_rrs , ldns_key_list *key_list , int (*func)(ldns_rr *, void*) , void *arg , int flags ) { ldns_status result = LDNS_STATUS_OK; ldns_rbnode_t *cur_node; ldns_rr_list *rr_list; ldns_dnssec_name *cur_name; ldns_dnssec_rrsets *cur_rrset; ldns_dnssec_rrs *cur_rr; ldns_rr_list *siglist; size_t i; int on_delegation_point = 0; /* handle partially occluded names */ ldns_rr_list *pubkey_list = ldns_rr_list_new(); for (i = 0; i<ldns_key_list_key_count(key_list); i++) { ldns_rr_list_push_rr( pubkey_list , ldns_key2rr(ldns_key_list_key( key_list, i)) ); } /* TODO: callback to see is list should be signed */ /* TODO: remove 'old' signatures from signature list */ cur_node = ldns_rbtree_first(zone->names); while (cur_node != LDNS_RBTREE_NULL) { cur_name = (ldns_dnssec_name *) cur_node->data; if (!cur_name->is_glue) { on_delegation_point = ldns_dnssec_rrsets_contains_type( cur_name->rrsets, LDNS_RR_TYPE_NS) && !ldns_dnssec_rrsets_contains_type( cur_name->rrsets, LDNS_RR_TYPE_SOA); cur_rrset = cur_name->rrsets; while (cur_rrset) { /* reset keys to use */ ldns_key_list_set_use(key_list, true); /* walk through old sigs, remove the old, and mark which keys (not) to use) */ cur_rrset->signatures = ldns_dnssec_remove_signatures(cur_rrset->signatures, key_list, func, arg); if(!(flags&LDNS_SIGN_DNSKEY_WITH_ZSK) && cur_rrset->type == LDNS_RR_TYPE_DNSKEY) ldns_key_list_filter_for_dnskey(key_list); if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY) ldns_key_list_filter_for_non_dnskey(key_list); /* TODO: just set count to zero? */ rr_list = ldns_rr_list_new(); cur_rr = cur_rrset->rrs; while (cur_rr) { ldns_rr_list_push_rr(rr_list, cur_rr->rr); cur_rr = cur_rr->next; } /* only sign non-delegation RRsets */ /* (glue should have been marked earlier, * except on the delegation points itself) */ if (!on_delegation_point || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_DS || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_NSEC || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_NSEC3) { siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_rrset->signatures) { result = ldns_dnssec_rrs_add_rr(cur_rrset->signatures, ldns_rr_list_rr(siglist, i)); } else { cur_rrset->signatures = ldns_dnssec_rrs_new(); cur_rrset->signatures->rr = ldns_rr_list_rr(siglist, i); } if (new_rrs) { ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); } ldns_rr_list_free(rr_list); cur_rrset = cur_rrset->next; } /* sign the nsec */ ldns_key_list_set_use(key_list, true); cur_name->nsec_signatures = ldns_dnssec_remove_signatures(cur_name->nsec_signatures, key_list, func, arg); ldns_key_list_filter_for_non_dnskey(key_list); rr_list = ldns_rr_list_new(); ldns_rr_list_push_rr(rr_list, cur_name->nsec); siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_name->nsec_signatures) { result = ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures, ldns_rr_list_rr(siglist, i)); } else { cur_name->nsec_signatures = ldns_dnssec_rrs_new(); cur_name->nsec_signatures->rr = ldns_rr_list_rr(siglist, i); } if (new_rrs) { ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); ldns_rr_list_free(rr_list); } cur_node = ldns_rbtree_next(cur_node); } ldns_rr_list_deep_free(pubkey_list); return result; }
ldns_status ldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt) { ldns_rbnode_t *first_name_node; ldns_rbnode_t *current_name_node; ldns_dnssec_name *current_name; ldns_status result = LDNS_STATUS_OK; ldns_rr *nsec_rr; ldns_rr_list *nsec3_list; uint32_t nsec_ttl; ldns_dnssec_rrsets *soa; if (!zone || !new_rrs || !zone->names) { return LDNS_STATUS_ERR; } /* the TTL of NSEC rrs should be set to the minimum TTL of * the zone SOA (RFC4035 Section 2.3) */ soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA); /* did the caller actually set it? if not, * fall back to default ttl */ if (soa && soa->rrs && soa->rrs->rr) { nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf( soa->rrs->rr, 6)); } else { nsec_ttl = LDNS_DEFAULT_TTL; } nsec3_list = ldns_rr_list_new(); first_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_first(zone->names)); current_name_node = first_name_node; while (current_name_node && current_name_node != LDNS_RBTREE_NULL) { current_name = (ldns_dnssec_name *) current_name_node->data; nsec_rr = ldns_dnssec_create_nsec3(current_name, NULL, zone->soa->name, algorithm, flags, iterations, salt_length, salt); /* by default, our nsec based generator adds rrsigs * remove the bitmap for empty nonterminals */ if (!current_name->rrsets) { ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr)); } ldns_rr_set_ttl(nsec_rr, nsec_ttl); ldns_dnssec_name_add_rr(current_name, nsec_rr); ldns_rr_list_push_rr(new_rrs, nsec_rr); ldns_rr_list_push_rr(nsec3_list, nsec_rr); current_name_node = ldns_dnssec_name_node_next_nonglue( ldns_rbtree_next(current_name_node)); } ldns_rr_list_sort_nsec3(nsec3_list); ldns_dnssec_chain_nsec3_list(nsec3_list); if (result != LDNS_STATUS_OK) { return result; } ldns_rr_list_free(nsec3_list); return result; }
/** * Try to recover from the backup files. * */ static ods_status engine_recover(engine_type* engine) { ldns_rbnode_t* node = LDNS_RBTREE_NULL; zone_type* zone = NULL; ods_status status = ODS_STATUS_OK; ods_status result = ODS_STATUS_UNCHANGED; if (!engine || !engine->zonelist || !engine->zonelist->zones) { ods_log_error("[%s] cannot recover zones: no engine or zonelist", engine_str); return ODS_STATUS_ERR; /* no need to update zones */ } ods_log_assert(engine); ods_log_assert(engine->zonelist); ods_log_assert(engine->zonelist->zones); lock_basic_lock(&engine->zonelist->zl_lock); /* [LOCK] zonelist */ node = ldns_rbtree_first(engine->zonelist->zones); while (node && node != LDNS_RBTREE_NULL) { zone = (zone_type*) node->data; ods_log_assert(zone->zl_status == ZONE_ZL_ADDED); status = zone_recover2(zone); if (status == ODS_STATUS_OK) { ods_log_assert(zone->task); ods_log_assert(zone->db); ods_log_assert(zone->signconf); /* notify nameserver */ if (engine->config->notify_command && !zone->notify_ns) { set_notify_ns(zone, engine->config->notify_command); } /* schedule task */ lock_basic_lock(&engine->taskq->schedule_lock); /* [LOCK] schedule */ status = schedule_task(engine->taskq, (task_type*) zone->task, 0); /* [UNLOCK] schedule */ lock_basic_unlock(&engine->taskq->schedule_lock); if (status != ODS_STATUS_OK) { ods_log_crit("[%s] unable to schedule task for zone %s: %s", engine_str, zone->name, ods_status2str(status)); task_cleanup((task_type*) zone->task); zone->task = NULL; result = ODS_STATUS_OK; /* will trigger update zones */ } else { ods_log_debug("[%s] recovered zone %s", engine_str, zone->name); /* recovery done */ zone->zl_status = ZONE_ZL_OK; } } else { if (status != ODS_STATUS_UNCHANGED) { ods_log_warning("[%s] unable to recover zone %s from backup," " performing full sign", engine_str, zone->name); } result = ODS_STATUS_OK; /* will trigger update zones */ } node = ldns_rbtree_next(node); } /* [UNLOCK] zonelist */ lock_basic_unlock(&engine->zonelist->zl_lock); return result; }
/** * Update zones. * */ void engine_update_zones(engine_type* engine, ods_status zl_changed) { ldns_rbnode_t* node = LDNS_RBTREE_NULL; zone_type* zone = NULL; zone_type* delzone = NULL; task_type* task = NULL; ods_status status = ODS_STATUS_OK; unsigned wake_up = 0; int warnings = 0; time_t now = 0; if (!engine || !engine->zonelist || !engine->zonelist->zones) { return; } now = time_now(); ods_log_debug("[%s] commit zone list changes", engine_str); lock_basic_lock(&engine->zonelist->zl_lock); node = ldns_rbtree_first(engine->zonelist->zones); while (node && node != LDNS_RBTREE_NULL) { zone = (zone_type*) node->data; task = NULL; /* reset task */ if (zone->zl_status == ZONE_ZL_REMOVED) { node = ldns_rbtree_next(node); lock_basic_lock(&zone->zone_lock); delzone = zonelist_del_zone(engine->zonelist, zone); if (delzone) { lock_basic_lock(&engine->taskq->schedule_lock); task = unschedule_task(engine->taskq, (task_type*) zone->task); lock_basic_unlock(&engine->taskq->schedule_lock); } task_cleanup(task); task = NULL; lock_basic_unlock(&zone->zone_lock); netio_remove_handler(engine->xfrhandler->netio, &zone->xfrd->handler); zone_cleanup(zone); zone = NULL; continue; } else if (zone->zl_status == ZONE_ZL_ADDED) { lock_basic_lock(&zone->zone_lock); ods_log_assert(!zone->task); /* set notify nameserver command */ if (engine->config->notify_command && !zone->notify_ns) { set_notify_ns(zone, engine->config->notify_command); } /* create task */ task = task_create(TASK_SIGNCONF, now, zone); lock_basic_unlock(&zone->zone_lock); if (!task) { ods_log_crit("[%s] unable to create task for zone %s: " "task_create() failed", engine_str, zone->name); node = ldns_rbtree_next(node); continue; } } /* load adapter config */ status = adapter_load_config(zone->adinbound); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to load config for inbound adapter " "for zone %s: %s", engine_str, zone->name, ods_status2str(status)); } status = adapter_load_config(zone->adoutbound); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to load config for outbound adapter " "for zone %s: %s", engine_str, zone->name, ods_status2str(status)); } /* for dns adapters */ warnings += dnsconfig_zone(engine, zone); if (zone->zl_status == ZONE_ZL_ADDED) { ods_log_assert(task); lock_basic_lock(&zone->zone_lock); zone->task = task; lock_basic_unlock(&zone->zone_lock); lock_basic_lock(&engine->taskq->schedule_lock); status = schedule_task(engine->taskq, task, 0); lock_basic_unlock(&engine->taskq->schedule_lock); } else if (zl_changed == ODS_STATUS_OK) { /* always try to update signconf */ lock_basic_lock(&zone->zone_lock); status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF); lock_basic_unlock(&zone->zone_lock); } if (status != ODS_STATUS_OK) { ods_log_crit("[%s] unable to schedule task for zone %s: %s", engine_str, zone->name, ods_status2str(status)); } else { wake_up = 1; zone->zl_status = ZONE_ZL_OK; } node = ldns_rbtree_next(node); } lock_basic_unlock(&engine->zonelist->zl_lock); if (engine->dnshandler) { dnshandler_fwd_notify(engine->dnshandler, (uint8_t*) ODS_SE_NOTIFY_CMD, strlen(ODS_SE_NOTIFY_CMD)); } else if (warnings) { ods_log_warning("[%s] no dnshandler/listener configured, but zones " "are configured with dns adapters: notify and zone transfer " "requests will not work properly", engine_str); } if (wake_up) { engine_wakeup_workers(engine); } return; }
ldns_status ldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone, ldns_rr_list *new_rrs, ldns_key_list *key_list, int (*func)(ldns_rr *, void*), void *arg) { ldns_status result = LDNS_STATUS_OK; ldns_rbnode_t *cur_node; ldns_rr_list *rr_list; ldns_dnssec_name *cur_name; ldns_dnssec_rrsets *cur_rrset; ldns_dnssec_rrs *cur_rr; ldns_rr_list *siglist; size_t i; ldns_rr_list *pubkey_list = ldns_rr_list_new(); zone = zone; new_rrs = new_rrs; key_list = key_list; for (i = 0; i<ldns_key_list_key_count(key_list); i++) { ldns_rr_list_push_rr(pubkey_list, ldns_key2rr(ldns_key_list_key(key_list, i))); } /* TODO: callback to see is list should be signed */ /* TODO: remove 'old' signatures from signature list */ cur_node = ldns_rbtree_first(zone->names); while (cur_node != LDNS_RBTREE_NULL) { cur_name = (ldns_dnssec_name *) cur_node->data; if (!cur_name->is_glue) { cur_rrset = cur_name->rrsets; while (cur_rrset) { /* reset keys to use */ ldns_key_list_set_use(key_list, true); /* walk through old sigs, remove the old, and mark which keys (not) to use) */ cur_rrset->signatures = ldns_dnssec_remove_signatures(cur_rrset->signatures, key_list, func, arg); /* TODO: just set count to zero? */ rr_list = ldns_rr_list_new(); cur_rr = cur_rrset->rrs; while (cur_rr) { ldns_rr_list_push_rr(rr_list, cur_rr->rr); cur_rr = cur_rr->next; } /* only sign non-delegation RRsets */ /* (glue should have been marked earlier) */ if ((ldns_rr_list_type(rr_list) != LDNS_RR_TYPE_NS || ldns_dname_compare(ldns_rr_list_owner(rr_list), zone->soa->name) == 0) && /* OK, there is also the possibility that the record * is glue, but at the same owner name as other records that * are not NS nor A/AAAA. Bleh, our current data structure * doesn't really support that... */ !((ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_A || ldns_rr_list_type(rr_list) == LDNS_RR_TYPE_AAAA) && !ldns_dname_compare(ldns_rr_list_owner(rr_list), zone->soa->name) == 0 && ldns_dnssec_zone_find_rrset(zone, ldns_rr_list_owner(rr_list), LDNS_RR_TYPE_NS) )) { siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_rrset->signatures) { ldns_dnssec_rrs_add_rr(cur_rrset->signatures, ldns_rr_list_rr(siglist, i)); } else { cur_rrset->signatures = ldns_dnssec_rrs_new(); cur_rrset->signatures->rr = ldns_rr_list_rr(siglist, i); ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); } ldns_rr_list_free(rr_list); cur_rrset = cur_rrset->next; } /* sign the nsec */ cur_name->nsec_signatures = ldns_dnssec_remove_signatures(cur_name->nsec_signatures, key_list, func, arg); rr_list = ldns_rr_list_new(); ldns_rr_list_push_rr(rr_list, cur_name->nsec); siglist = ldns_sign_public(rr_list, key_list); for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) { if (cur_name->nsec_signatures) { ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures, ldns_rr_list_rr(siglist, i)); } else { cur_name->nsec_signatures = ldns_dnssec_rrs_new(); cur_name->nsec_signatures->rr = ldns_rr_list_rr(siglist, i); ldns_rr_list_push_rr(new_rrs, ldns_rr_list_rr(siglist, i)); } } ldns_rr_list_free(siglist); ldns_rr_list_free(rr_list); } cur_node = ldns_rbtree_next(cur_node); } ldns_rr_list_deep_free(pubkey_list); return result; }
/** * Merge zone lists. * */ static void zonelist_merge(zonelist_type* zl1, zonelist_type* zl2) { zone_type* z1 = NULL; zone_type* z2 = NULL; ldns_rbnode_t* n1 = LDNS_RBTREE_NULL; ldns_rbnode_t* n2 = LDNS_RBTREE_NULL; int ret = 0; ods_log_assert(zl1); ods_log_assert(zl2); ods_log_assert(zl1->zones); ods_log_assert(zl2->zones); ods_log_debug("[%s] merge two zone lists", zl_str); n1 = ldns_rbtree_first(zl1->zones); n2 = ldns_rbtree_first(zl2->zones); while (n2 && n2 != LDNS_RBTREE_NULL) { z2 = (zone_type*) n2->data; if (n1 && n1 != LDNS_RBTREE_NULL) { z1 = (zone_type*) n1->data; } else { z1 = NULL; } if (!z2) { /* no more zones to merge into zl1 */ return; } else if (!z1) { /* just add remaining zones from zl2 */ z2 = zonelist_add_zone(zl1, z2); if (!z2) { ods_log_crit("[%s] merge failed: z2 not added", zl_str); return; } n2 = ldns_rbtree_next(n2); } else { /* compare the zones z1 and z2 */ ret = zone_compare(z1, z2); if (ret < 0) { /* remove zone z1, it is not present in the new list zl2 */ z1->zl_status = ZONE_ZL_REMOVED; zl1->just_removed++; n1 = ldns_rbtree_next(n1); } else if (ret > 0) { /* add the new zone z2 */ z2 = zonelist_add_zone(zl1, z2); if (!z2) { ods_log_crit("[%s] merge failed: z2 not added", zl_str); return; } n2 = ldns_rbtree_next(n2); } else { /* just update zone z1 */ n1 = ldns_rbtree_next(n1); n2 = ldns_rbtree_next(n2); zone_merge(z1, z2); zone_cleanup(z2); if (z1->zl_status == ZONE_ZL_UPDATED) { zl1->just_updated++; } z1->zl_status = ZONE_ZL_UPDATED; } } } /* remove remaining zones from z1 */ while (n1 && n1 != LDNS_RBTREE_NULL) { z1 = (zone_type*) n1->data; z1->zl_status = ZONE_ZL_REMOVED; zl1->just_removed++; n1 = ldns_rbtree_next(n1); } zl1->last_modified = zl2->last_modified; return; }