static void journal_ix_link_zone(journal *jh, zdb_zone *zone) { yassert(jh->zone == NULL); #if ZDB_ZONE_HAS_JNL_REFERENCE yassert(zone->journal == NULL); #endif journal_ix *jix = (journal_ix*)jh; journal_ix_writelock(jix); jix->zone = zone; #if ZDB_ZONE_HAS_JNL_REFERENCE zone->journal = jh; #endif journal_ix_writeunlock(jix); }
void buffer_input_stream_init(input_stream* stream, input_stream* filtered, int buffer_size) { buffer_input_stream_data* data; if(buffer_size == 0) { buffer_size = BUFFER_INPUT_STREAM_DEFAULT_BUFFER_SIZE; } yassert(filtered->vtbl != NULL); MALLOC_OR_DIE(buffer_input_stream_data*, data, sizeof(buffer_input_stream_data) + buffer_size - 1, BUFFER_INPUT_STREAM_TAG); data->filtered.data = filtered->data; data->filtered.vtbl = filtered->vtbl; filtered->data = NULL; filtered->vtbl = NULL; data->buffer_maxsize = buffer_size; data->buffer_size = 0; data->buffer_offset = 0; stream->data = data; stream->vtbl = &buffer_input_stream_vtbl; }
ya_result tsig_register(const u8 *name, const u8 *mac, u16 mac_size, u8 mac_algorithm) { ya_result return_code = SUCCESS; tsig_node *node = tsig_avl_insert(&tsig_tree, name); if(node != NULL) { if(node->item.mac != NULL) { bool same = (node->item.mac_size == mac_size) && (node->item.mac_algorithm == mac_algorithm) && (memcmp((u8*)node->item.mac, mac, mac_size) == 0); if(node->item.load_serial != tsig_serial) { node->item.load_serial = tsig_serial; // else every 256 updates will see a duplicate if(same) { // same key, different instances ... nothing to do return SUCCESS; } else { // this is an old version of the key free((void*)node->item.mac); node->item.mac = NULL; } } else { // it's a dup in the config file return TSIG_DUPLICATE_REGISTRATION; /* dup */ } } yassert(node->item.mac == NULL); MALLOC_OR_DIE(u8*, node->item.mac, mac_size, TSIGMAC_TAG); MEMCOPY((u8*)node->item.mac, mac, mac_size); node->item.evp_md = tsig_get_EVP_MD(mac_algorithm); node->item.mac_algorithm_name = tsig_get_algorithm_name(mac_algorithm); node->item.name_len = dnsname_len(name); node->item.mac_algorithm_name_len = dnsname_len(node->item.mac_algorithm_name); node->item.mac_size = mac_size; node->item.mac_algorithm = mac_algorithm; node->item.load_serial = tsig_serial; tsig_tree_count++; } else {
static void test_ivar(void) { int i; double vs0[] = {1}; double vs1[] = {1, 2, 3, 4, 5, 6, 7}; double vs2[] = {1, 2, 3, 4, 5, 6, 7, 8}; struct ysm_ivar *iv, *iv0, *iv1, *iv2; iv = ysm_ivar_create(); for (i = 0; i < yut_arrsz(vs0); i++) ysm_ivar_add(iv, vs0[i]); yassert(0 == ysm_ivar(iv)); ysm_ivar_destroy(iv); iv = ysm_ivar_create(); for (i = 0; i < yut_arrsz(vs1); i++) ysm_ivar_add(iv, vs1[i]); yassert(4 == ysm_ivar(iv)); ysm_ivar_destroy(iv); iv = ysm_ivar_create(); iv0 = ysm_ivar_create(); iv1 = ysm_ivar_create(); iv2 = ysm_ivar_create(); for (i = 0; i < yut_arrsz(vs2); i++) ysm_ivar_add(iv, vs2[i]); yassert(5.25f == ysm_ivar(iv)); for (i = 0; i < yut_arrsz(vs2) / 2; i++) ysm_ivar_add(iv0, vs2[i]); for (; i < yut_arrsz(vs2); i++) ysm_ivar_add(iv1, vs2[i]); ysm_ivar_combine(iv2, iv0, iv1); yassert(ysm_ivar(iv) == ysm_ivar(iv2)); ysm_ivar_destroy(iv); ysm_ivar_destroy(iv0); ysm_ivar_destroy(iv1); ysm_ivar_destroy(iv2); iv = ysm_ivar_create(); yassert(isnan(ysm_ivar(iv))); ysm_ivar_destroy(iv); }
void nsec_zone_label_detach(zdb_rr_label *rr_label) { yassert((rr_label != NULL) && (rr_label->flags & ZDB_RR_LABEL_NSEC) != 0); if((rr_label->nsec.dnssec != NULL) && (rr_label->nsec.nsec.node != NULL)) { rr_label->nsec.nsec.node->label = NULL; rr_label->nsec.nsec.node = NULL; } }
void tsig_hmac_free(tsig_hmac_t t) { HMAC_CTX *hmac = (HMAC_CTX*)t; yassert(hmac != NULL); #if SSL_API_LT_110 HMAC_CTX_cleanup(hmac); ZFREE(t, HMAC_CTX); #else HMAC_CTX_free(hmac); #endif }
static void tc3(struct ymsghandler *mh) { struct ythreadex *yt; struct targ *ta; struct tres *tr; void *retval; /* Normal successful thread */ ta = ymalloc(sizeof(*ta)); memset(ta, 0, sizeof(*ta)); ta->s = ymalloc(16); ta->sleep_cnt = 10 + rand() % 20; ta->sleep_interval = 10; strcpy(ta->s, "ok:arg"); yt = ythreadex_create("ok", mh, YTHREADEX_NORMAL, &_lis, ta, &free_arg, &free_result, &thread_run); yassert(ythreadex_destroy(yt)); yassert(!ythreadex_start(yt)); yassert(!ythreadex_cancel(yt, FALSE)); ythreadex_join(yt, &retval); yassert(YTHREADEX_TERMINATED_CANCELLED == ythreadex_get_state(yt)); tr = ythreadex_get_result(yt); yassert(!tr); yassert(!ythreadex_destroy(yt)); }
struct ylistl_link * ypool_get(struct ypool *p) { struct ylistl_link *lk = NULL; lock(p); if (unlikely(ylistl_is_empty(&p->hd))) goto done_unlock; lk = ylistl_remove_first(&p->hd); yassert(p->sz > 0); p->sz--; done_unlock: unlock(p); return lk; }
static void nsec3_free_node(nsec3_zone_item* node) { /* * This assert is wrong because this is actually the payload that has just overwritten our node * assert(node->rc == 0 && node->sc == 0 && node->label.owners == NULL && node->star_label.owners == NULL & node->type_bit_maps == NULL); */ #ifdef DEBUG yassert((node->rc == 0) && (node->sc == 0)); #endif u32 node_size = NSEC3_NODE_SIZE(node); ZFREE_ARRAY(node, node_size); }
int ymsglooper_loop(void) { int r __unused; struct ymsglooper *ml = ymsglooper_get(); if (unlikely(!ml)) return -EPERM; dfpr("start LOOP!"); lock_state(ml); if (YMSGLOOPER_READY != get_state_locked(ml)) { unlock_state(ml); goto skip_loop; } set_state_locked(ml, YMSGLOOPER_LOOP); unlock_state(ml); while (TRUE) { struct ymsg *m = ymsgq_de(ml->mq); struct ymsg_ *m_ = msg_mutate(m); /* Operation is NOT locked intentionally. * See comment for 'struct ymsglooper'. */ if (YMSGLOOPER_STOPPING == get_state(ml)) { if (likely(m)) ymsg_destroy(m); dfpr("break!!!! from loop!"); break; } if (unlikely(!m)) continue; /* Handler code here! */ yassert(m_->handler && m_->handler->handle); (*m_->handler->handle)(m); ymsg_destroy(m); } skip_loop: r = pthread_setspecific(_tkey, NULL); yassert(!r); set_state(ml, YMSGLOOPER_TERMINATED); return 0; }
static void tc2(struct ymsghandler *mh) { struct ythreadex *yt; struct targ *ta; struct tres *tr; void *retval; /* Normal successful thread */ ta = ymalloc(sizeof(*ta)); memset(ta, 0, sizeof(*ta)); ta->s = ymalloc(16); strcpy(ta->s, "ok:arg"); yt = ythreadex_create("ok", mh, YTHREADEX_NORMAL, &_lis, ta, &free_arg, &free_result, &thread_run); yassert(ythreadex_destroy(yt)); yassert(!ythreadex_start(yt)); ythreadex_join(yt, &retval); tr = ythreadex_get_result(yt); /* STARTED, DONE. And PROGRESS_INIT */ ylogv("%d, %d, %d, %d, %d, %c\n", ta->sti, ta->st[0], ta->st[1], ta->progcnt, tr->r, tr->s[0]); yassert(2 == ta->sti && YTHREADEX_STARTED == ta->st[0] && YTHREADEX_DONE == ta->st[1] && 1000 == ta->progcnt && 0 == tr->r && 'r' == tr->s[0]); yassert(!ythreadex_destroy(yt)); }
static void test_imean(void) { int i; double vs0[] = {1}; double vs1[] = {1, 2, 3, 4, 5, 6, 7}; double vs2[] = {1, 2, 3, 4, 5, 6, 7, 8}; struct ysm_imean *im, *im0, *im1, *im2; im = ysm_imean_create(); for (i = 0; i < yut_arrsz(vs0); i++) ysm_imean_add(im, vs0[i]); yassert(1 == ysm_imean(im)); ysm_imean_destroy(im); im = ysm_imean_create(); for (i = 0; i < yut_arrsz(vs1); i++) ysm_imean_add(im, vs1[i]); yassert(4 == ysm_imean(im)); ysm_imean_destroy(im); im0 = ysm_imean_create(); im1 = ysm_imean_create(); im2 = ysm_imean_create(); im = ysm_imean_create(); for (i = 0; i < yut_arrsz(vs2); i++) ysm_imean_add(im, vs2[i]); yassert(4.5f == ysm_imean(im)); for (i = 0; i < yut_arrsz(vs2) / 2; i++) ysm_imean_add(im0, vs2[i]); for (; i < yut_arrsz(vs2); i++) ysm_imean_add(im1, vs2[i]); ysm_imean_combine(im2, im0, im1); yassert(ysm_imean(im) == ysm_imean(im2)); ysm_imean_destroy(im); ysm_imean_destroy(im0); ysm_imean_destroy(im1); ysm_imean_destroy(im2); }
static struct ymsglooper * create_msglooper(pthread_t thread, int msgq_capacity) { struct ymsglooper *ml = ymalloc(sizeof(*ml)); if (unlikely(!ml)) return NULL; ml->mq = ymsgq_create(msgq_capacity); if (unlikely(!ml->mq)) goto free_ml; yassert(thread); /* NOT NULL */ ml->thread = thread; if (unlikely(pthread_mutex_init(&ml->state_lock, NULL))) goto free_mq; return ml; free_mq: ymsgq_destroy(ml->mq); free_ml: yfree(ml); return NULL; }
/* * get one block from pool. */ void * ymempool_get(struct ymempool *mp) { struct blk *b; lock(mp); if (mp->fbi >= sz(mp)) { if (expand(mp)) { unlock(mp); return NULL; } } b = fbpblk(mp, mp->fbi); yassert(b->i == mp->fbi); mp->fbi++; unlock(mp); return (void*)(&b->d); }
struct ymempool * ymempool_create(int grpsz, int elemsz, int opt) { struct ymempool *mp; yassert(grpsz > 0 && elemsz > 0); if (unlikely(!(mp = ycalloc(1, sizeof(*mp))))) return NULL; if (unlikely(!(mp->fbp = ymalloc(sizeof(*mp->fbp))))) goto nomem; #ifndef CONFIG_MEMPOOL_DYNAMIC if (unlikely(!(mp->grp = ymalloc(sizeof(*mp->grp))))) goto nomem; #endif mp->grpsz = grpsz; mp->nrgrp = 0; mp->esz = elemsz; mp->fbi = 0; mp->opt = opt; init_lock(mp); /* allocate 1-block-group for initial state */ if (expand(mp)) goto nomem; return mp; nomem: #ifndef CONFIG_MEMPOOL_DYNAMIC if (mp->grp) yfree(mp->grp); #endif if (mp->fbp) yfree(mp->fbp); yfree(mp); return NULL; }
/* * return block to pool. */ void ymempool_put(struct ymempool *mp, void *block) { struct blk *b; struct blk *ub; /* used block */ int ti; b = containerof(block, struct blk, d); lock(mp); yassert(mp->fbi > 0 && b->i < mp->fbi); mp->fbi--; ub = fbpblk(mp, mp->fbi); /* swap free block pointer */ ti = b->i; setfbp(mp, ub->i, b); setfbp(mp, ti, ub); if (need_shrink(mp)) shrink(mp, 1); unlock(mp); }
static void test_etc(void) { int n; n = 0; unroll16(-2, n++); yassert(!n); n = 0; unroll16(0, n++); yassert(!n); n = 0; unroll16(2, n++); yassert(2 == n); n = 0; unroll16(18, n++); yassert(18 == n); n = 0; unroll16(16, n++); yassert(16 == n); n = 0; unroll16(32, n++); yassert(32 == n); }
static void tc4(struct ymsghandler *mh) { #define NR_THREADS 10 int i; struct ythreadex *yt[NR_THREADS]; struct targ *ta; struct tres *tr; void *retval[NR_THREADS]; for (i = 0; i < NR_THREADS; i++) { /* Normal successful thread */ ta = ymalloc(sizeof(*ta)); memset(ta, 0, sizeof(*ta)); /* sleep enough to get 'cancel' message after start */ ta->sleep_cnt = 10 + rand() % 20; ta->sleep_interval = 10; ta->s = ymalloc(16); strcpy(ta->s, "ok:arg"); yt[i] = ythreadex_create("ok", mh, YTHREADEX_NORMAL, &_lis, ta, &free_arg, &free_result, &thread_run); } for (i = 0; i < NR_THREADS; i++) yassert(!ythreadex_start(yt[i])); for (i = 0; i < NR_THREADS; i++) { if (i % 3) ythreadex_cancel(yt[i], i % 2); } for (i = 0; i < NR_THREADS; i++) ythreadex_join(yt[i], &retval[i]); for (i = 0; i < NR_THREADS; i++) { if (i % 3) { /* This is cancelled thread */ ylogv("state: %d\n", ythreadex_get_state(yt[i])); yassert(YTHREADEX_TERMINATED_CANCELLED == ythreadex_get_state(yt[i])); } else { yassert(YTHREADEX_TERMINATED == ythreadex_get_state(yt[i])); tr = ythreadex_get_result(yt[i]); ta = ythreadex_get_arg(yt[i]); /* STARTED, DONE. And PROGRESS_INIT */ ylogv("%d, %d, %d, %d, %d, %c\n", ta->sti, ta->st[0], ta->st[1], ta->progcnt, tr->r, tr->s[0]); yassert(2 == ta->sti && YTHREADEX_STARTED == ta->st[0] && YTHREADEX_DONE == ta->st[1] && 1000 == ta->progcnt && 0 == tr->r && 'r' == tr->s[0]); } yassert(!ythreadex_destroy(yt[i])); } #undef NR_THREADS }
/* * i : index of fbp (ex. fbi) */ static INLINE struct blk * fbpblk(struct ymempool *mp, int i) { struct blk *b = *(mp->fbp[i / mp->grpsz] + i % mp->grpsz); yassert(b->i == i); return b; }
void database_load_zone_desc(zone_desc_s *zone_desc) { yassert(zone_desc != NULL); log_debug1("database_load_zone_desc(%{dnsname}@%p=%i)", zone_desc->origin, zone_desc, zone_desc->rc); s32 err = zone_register(&database_zone_desc, zone_desc); if(ISOK(err)) { log_info("zone: %{dnsname}: %p: config: registered", zone_desc->origin, zone_desc); zone_lock(zone_desc, ZONE_LOCK_LOAD_DESC); zone_set_status(zone_desc, ZONE_STATUS_REGISTERED); zone_clear_status(zone_desc, ZONE_STATUS_DROP_AFTER_RELOAD); zone_unlock(zone_desc, ZONE_LOCK_LOAD_DESC); // newly registered zone // used to be message->origin if(database_service_started()) { database_zone_load(zone_desc->origin); // before this I should set the file name #if HAS_MASTER_SUPPORT if(zone_desc->type == ZT_MASTER) { if(!host_address_empty(zone_desc->slaves)) { log_info("zone: %{dnsname}: %p: config: notifying slaves", zone_desc->origin, zone_desc); host_address *slaves = host_address_copy_list(zone_desc->slaves); notify_host_list(zone_desc, slaves, CLASS_CTRL); } } else #endif { } } } else { switch(err) { case DATABASE_ZONE_MISSING_DOMAIN: { log_err("zone: ?: %p: config: no domain set (not loaded)", zone_desc); if(zone_get_status(zone_desc) & ZONE_STATUS_PROCESSING) { log_err("zone: ?: %p: is processed by %s (releasing)", zone_desc, database_service_operation_get_name(zone_desc->last_processor)); } zone_release(zone_desc); break; } case DATABASE_ZONE_MISSING_MASTER: { log_err("zone: %{dnsname}: %p: config: slave but no master setting (not loaded)", zone_desc->origin, zone_desc); if(zone_get_status(zone_desc) & ZONE_STATUS_PROCESSING) { log_err("zone: ?: %p: is processed by %s (releasing)", zone_desc, database_service_operation_get_name(zone_desc->last_processor)); } zone_release(zone_desc); break; } case DATABASE_ZONE_CONFIG_CLONE: // Exact copy { log_debug("zone: %{dnsname}: %p: config: has already been set (same settings)", zone_desc->origin, zone_desc); zone_desc_s* current = zone_acquirebydnsname(zone_desc->origin); zone_lock(current, ZONE_LOCK_REPLACE_DESC); zone_clear_status(current, ZONE_STATUS_DROP_AFTER_RELOAD); zone_unlock(current, ZONE_LOCK_REPLACE_DESC); zone_release(current); // whatever has been decided above, loading the zone file (if it changed) should be queued database_zone_load(zone_desc->origin); zone_release(zone_desc); break; } case DATABASE_ZONE_CONFIG_DUP: // Not an exact copy { log_debug("zone: %{dnsname}: %p: config: has already been set (different settings)", zone_desc->origin, zone_desc); // basically, most of the changes require a stop, restart of // any task linked to the zone // so let's make this a rule, whatever changed notify_clear(zone_desc->origin); zone_desc_s *current = zone_acquirebydnsname(zone_desc->origin); #if HAS_DYNAMIC_PROVISIONING host_address *notify_slaves_then_delete = NULL; host_address *notify_slaves = NULL; #endif if(current != zone_desc) { zone_lock(current, ZONE_LOCK_REPLACE_DESC); if(zone_get_status(current) & ZONE_STATUS_PROCESSING) { log_err("zone: ?: %p: is processed by %s (overwriting)", zone_desc, database_service_operation_get_name(zone_desc->last_processor)); } // what happens if the change is on : // domain: impossible /// @todo 20131203 edf -- compare before replace // file_name : try to load the new file (will happen anyway) if((current->file_name != NULL) && (zone_desc->file_name != NULL)) { if(strcmp(current->file_name, zone_desc->file_name) != 0) { zone_set_status(current, ZONE_STATUS_MODIFIED); } } else if(current->file_name != zone_desc->file_name) // at least one of them is NULL { zone_set_status(current, ZONE_STATUS_MODIFIED); } free(current->file_name); current->file_name = zone_desc->file_name; zone_desc->file_name = NULL; // masters : log_debug7("updating %p (%u) with %p (%u): masters", current, current->lock_owner, zone_desc, zone_desc->lock_owner); if(host_address_list_equals(current->masters, zone_desc->masters)) { host_address_delete_list(zone_desc->masters); } else { host_address_delete_list(current->masters); current->masters = zone_desc->masters; } zone_desc->masters = NULL; // notifies : log_debug7("updating %p (%u) with %p (%u): notifies", current, current->lock_owner, zone_desc, zone_desc->lock_owner); if(host_address_list_equals(current->notifies, zone_desc->notifies)) { host_address_delete_list(zone_desc->notifies); } else { host_address_delete_list(current->notifies); current->notifies = zone_desc->notifies; } zone_desc->notifies = NULL; #if HAS_DYNAMIC_PROVISIONING log_debug7("updating %p (%u) with %p (%u): slaves", current, current->lock_owner, zone_desc, zone_desc->lock_owner); if(host_address_list_equals(current->slaves, zone_desc->slaves)) { #if HAS_MASTER_SUPPORT if((current->type == ZT_MASTER) || (zone_desc->type == ZT_MASTER)) { notify_slaves_then_delete = zone_desc->slaves; } else #endif { host_address_delete_list(zone_desc->slaves); } } else { #if HAS_MASTER_SUPPORT if(current->type == ZT_MASTER) { notify_slaves_then_delete = current->slaves; } else { host_address_delete_list(current->slaves); } if(zone_desc->type == ZT_MASTER) { notify_slaves = zone_desc->slaves; } #else host_address_delete_list(current->slaves); #endif current->slaves = zone_desc->slaves; } zone_desc->slaves = NULL; #endif // type : ? log_debug7("updating %p (%u) with %p (%u): type", current, current->lock_owner, zone_desc, zone_desc->lock_owner); current->type = zone_desc->type; #if HAS_ACL_SUPPORT // ac : apply the new one, update the zone access log_debug7("updating %p (%u) with %p (%u): ac@%p with ac@%p", current, current->lock_owner, zone_desc, zone_desc->lock_owner, ¤t->ac, &zone_desc->ac); #ifdef DEBUG log_debug7("old@%p:", current); log_debug7(" notify@%p",current->ac.allow_notify.ipv4.items); log_debug7(" query@%p",current->ac.allow_query.ipv4.items); log_debug7(" transfer@%p",current->ac.allow_transfer.ipv4.items); log_debug7(" update@%p",current->ac.allow_update.ipv4.items); log_debug7("forwarding@%p",current->ac.allow_update_forwarding.ipv4.items); log_debug7(" control@%p",current->ac.allow_control.ipv4.items); log_debug7("new@%p:", zone_desc); log_debug7(" notify@%p",zone_desc->ac.allow_notify.ipv4.items); log_debug7(" query@%p",zone_desc->ac.allow_query.ipv4.items); log_debug7(" transfer@%p",zone_desc->ac.allow_transfer.ipv4.items); log_debug7(" update@%p",zone_desc->ac.allow_update.ipv4.items); log_debug7("forwarding@%p",zone_desc->ac.allow_update_forwarding.ipv4.items); log_debug7(" control@%p",zone_desc->ac.allow_control.ipv4.items); #endif acl_unmerge_access_control(¤t->ac, &g_config->ac); acl_empties_access_control(¤t->ac); memcpy(¤t->ac, &zone_desc->ac, sizeof(access_control)); ZEROMEMORY(&zone_desc->ac, sizeof(access_control)); #endif // notify : reset, restart log_debug7("updating %p (%u) with %p (%u): notify", current, current->lock_owner, zone_desc, zone_desc->lock_owner); memcpy(¤t->notify, &zone_desc->notify, sizeof(zone_notify_s)); #if HAS_DNSSEC_SUPPORT #if HAS_RRSIG_MANAGEMENT_SUPPORT // signature : reset, restart log_debug7("updating %p (%u) with %p (%u): signature", current, current->lock_owner, zone_desc, zone_desc->lock_owner); memcpy(¤t->signature, &zone_desc->signature, sizeof(zone_signature_s)); #endif // dnssec_mode : drop everything related to the zone, load the new config log_debug7("updating %p (%u) with %p (%u): dnssec_mode", current, current->lock_owner, zone_desc, zone_desc->lock_owner); current->dnssec_mode = zone_desc->dnssec_mode; #endif // refresh : update the "alarms" log_debug7("updating %p (%u) with %p (%u): refresh", current, current->lock_owner, zone_desc, zone_desc->lock_owner); memcpy(¤t->refresh, &zone_desc->refresh, sizeof(zone_refresh_s)); // dynamic_provisioning : ? log_debug7("updating %p (%u) with %p (%u): dynamic_provisioning", current, current->lock_owner, zone_desc, zone_desc->lock_owner); memcpy(¤t->dynamic_provisioning, &zone_desc->dynamic_provisioning, sizeof(dynamic_provisioning_s)); // slaves : update the list zone_unlock(current, ZONE_LOCK_REPLACE_DESC); } // whatever has been decided above, loading the zone file should be queued database_zone_load(zone_desc->origin); #if HAS_DYNAMIC_PROVISIONING // if asking for a load of the zone_data on a master should trigger a notify of its slaves log_debug7("handling dynamic provisioning"); if(!host_address_empty(notify_slaves_then_delete)) { log_info("zone load desc: %{dnsname}: notifying slaves: %{hostaddrlist}", zone_desc->origin, notify_slaves_then_delete); notify_host_list(current, notify_slaves_then_delete, CLASS_CTRL); notify_slaves_then_delete = NULL; } if(!host_address_empty(notify_slaves)) { log_info("zone load desc: %{dnsname}: notifying slaves: %{hostaddrlist}", zone_desc->origin, notify_slaves); host_address *notify_slaves_copy = host_address_copy_list(notify_slaves); notify_host_list(current, notify_slaves_copy, CLASS_CTRL); notify_slaves = NULL; } #endif #if HAS_MASTER_SUPPORT && HAS_DNSSEC_SUPPORT && HAS_RRSIG_MANAGEMENT_SUPPORT if(current->dnssec_policy != zone_desc->dnssec_policy) { log_info("zone: %{dnsname}: %p: config: dnssec-policy modified", zone_desc->origin, zone_desc); if(zone_desc->dnssec_policy != NULL) { if(current->dnssec_policy != NULL) { log_warn("zone: %{dnsname}: %p: config: changing dnssec-policy at runtime (%s to %s)", zone_desc->origin, zone_desc, current->dnssec_policy->name, zone_desc->dnssec_policy->name); if(current->dnssec_policy->denial != zone_desc->dnssec_policy->denial) { log_warn("zone: %{dnsname}: %p: config: modifications of the dnssec-policy denial setting may be ignored", zone_desc->origin, zone_desc); } dnssec_policy_release(current->dnssec_policy); current->dnssec_policy = dnssec_policy_acquire_from_name(zone_desc->dnssec_policy->name); } else { log_info("zone: %{dnsname}: %p: config: dnssec-policy %s enabled", zone_desc->origin, zone_desc, zone_desc->dnssec_policy->name); current->dnssec_policy = dnssec_policy_acquire_from_name(zone_desc->dnssec_policy->name); } } else { log_warn("zone: %{dnsname}: %p: config: removing policy at runtime", zone_desc->origin, zone_desc); dnssec_policy_release(current->dnssec_policy); current->dnssec_policy = NULL; } } #endif if(current != zone_desc) { log_debug7("destroying temporary zone descriptor @%p", zone_desc); zone_release(zone_desc); } zone_clear_status(zone_desc, ZONE_STATUS_DROP_AFTER_RELOAD); zone_release(current); break; } // DUP default: { log_err("zone: %{dnsname}: %p: failed to register", zone_desc->origin, zone_desc); break; } } // switch } log_debug1("database_load_zone_desc(%p) done", zone_desc); }
static void tc0(struct ymsghandler *mh0, struct ymsghandler *mh1) { struct ytaskmanager *tm; struct targ *ta; struct ytask *tsk; int nrtasks; struct ytask *ptsks[2 * NR_TEST_TASKS]; int ptski = 0; tm = ytaskmanager_create(mh0, 3); yassert(tm); nrtasks = NR_TEST_TASKS; while (nrtasks--) { usleep((rand() % 50) * 100); /* Normal successful thread */ ta = ycalloc(1, sizeof(*ta)); ta->s = ymalloc(16); strcpy(ta->s, "TC0"); ta->sleep_cnt = rand() % 10; ta->sleep_interval = rand() % 10; tsk = ytask_create3("TC0-0", mh0, rand() % YTHREADEX_NUM_PRIORITY, NULL, ta, &free_arg, NULL, &task_runnable, TRUE); ytaskmanager_add_task(tm, tsk); ptsks[ptski++] = tsk; } nrtasks = NR_TEST_TASKS; while (nrtasks--) { usleep((rand() % 50) * 100); /* Normal successful thread */ ta = ycalloc(1, sizeof(*ta)); ta->s = ymalloc(16); strcpy(ta->s, "TC0"); ta->sleep_cnt = rand() % 10; ta->sleep_interval = rand() % 10; tsk = ytask_create3("TC0-1", mh1, rand() % YTHREADEX_NUM_PRIORITY, NULL, ta, &free_arg, NULL, &task_runnable, TRUE); ytaskmanager_add_task(tm, tsk); ptsks[ptski++] = tsk; } while (ytaskmanager_destroy(tm)) usleep(10 * 1000); while (ptski--) yassert(!ytask_destroy(ptsks[ptski])); }
static void mexit(void) { int r __unused; r = pthread_key_delete(_tkey); yassert(!r); }
struct ymsglooper * ymsglooper_start_looper_thread(bool destroy_on_exit) { int r __unused; int r0 __unused; pthread_t thread; struct looper_thread_share ts; dfpr("Enter"); memset(&ts, 0, sizeof(ts)); r = pthread_cond_init(&ts.cond, NULL); if (unlikely(r)) goto done; r = pthread_mutex_init(&ts.lock, NULL); if (unlikely(r)) goto free_cond; ts.destroy_on_exit = destroy_on_exit; r = pthread_create(&thread, NULL, &looper_thread, &ts); if (unlikely(r)) { yassert(0); ylogf("Fail to create thread: %s\n", yerrno_str(r)); goto free_cond; } r = pthread_mutex_lock(&ts.lock); if (unlikely(r)) goto free_lock; if (!ts.result) { r = pthread_cond_wait(&ts.cond, &ts.lock); if (unlikely(r)) { r0 = pthread_mutex_unlock(&ts.lock); yassert(!r0); goto free_lock; } } yassert(ts.result); r = pthread_mutex_unlock(&ts.lock); yassert(!r); if (ts.result < 0) r = -ts.result; /* error ! */ else yassert(ts.ml); free_lock: r0 = pthread_mutex_destroy(&ts.lock); yassert(!r0); free_cond: r0 = pthread_cond_destroy(&ts.cond); yassert(!r0); done: if (unlikely(r)) { dfpr("%s", yerrno_str(r)); return NULL; } return ts.ml; }
AVL_NODE_TYPE* AVL_PREFIXED(avl_find_prev_mod)(AVL_CONST_TREE_TYPE* root, const AVL_REFERENCE_TYPE obj_hash) { AVL_NODE_TYPE* node = *root; AVL_NODE_TYPE* lower_bound = NULL; AVL_REFERENCE_TYPE h; yassert(node != NULL); /* This is one of the parts I could try to optimize * I've checked the assembly, and it sucks ... */ /* Both the double-test while/ternary and the current one * are producing the same assembly code. */ /** * Get a key that */ while(node != NULL) { h = AVL_REFERENCE(node); /* * [0] is the length of the obj_hash * * The obj_hashs starts at [1] * */ #ifdef DEBUG if(h[0] != obj_hash[0]) { DIE_MSG("NSEC3 corrupted NSEC3 node"); } #endif int cmp = memcmp(&obj_hash[1], &h[1], h[0]); /* equals */ if(cmp == 0) { // want the prev mod return nsec3_avl_node_mod_prev(node); } /* bigger */ if(cmp > 0) { lower_bound = node; node = AVL_CHILD(node, DIR_RIGHT); } else { node = AVL_CHILD(node, DIR_LEFT); } } if(lower_bound == NULL) { lower_bound = *root; yassert(lower_bound != NULL); while((node = AVL_CHILD(lower_bound, DIR_RIGHT)) != NULL) { lower_bound = node; } } return lower_bound; }
/** * Linked list test. */ static void test_list(void) { int i; int *p; struct ylist *lst; struct ylisti *itr; lst = ylist_create(0, &yfree); ylist_destroy(lst); lst = ylist_create(0, &yfree); p = (int *)ymalloc(sizeof(*p)); *p = 3; ylist_add_last(lst, p); itr = ylisti_create(lst, YLISTI_FORWARD); yassert(ylisti_has_next(itr)); p = (int *)ylisti_next(itr); yassert(3 == *p); yassert(!ylisti_has_next(itr)); ylisti_destroy(itr); itr = ylisti_create(lst, YLISTI_FORWARD); yassert(ylisti_has_next(itr)); ylisti_next(itr); ylist_remove_current(lst, itr, 1); yassert(0 == ylist_size(lst)); ylisti_destroy(itr); for (i = 0; i < 10; i++) { p = (int *)ymalloc(sizeof(*p)); *p = i; ylist_add_last(lst, p); } yassert(10 == ylist_size(lst)); yassert(ylist_has(lst, p)); yassert(!ylist_has(lst, lst)); /* simple iteration */ i = 0; itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); yassert(ylist_has(lst, p)); yassert(i == *p); i++; } ylisti_destroy(itr); i = 9; itr = ylisti_create(lst, YLISTI_BACKWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); yassert(i == *p); i--; } ylisti_destroy(itr); /* remove odd numbers - tail is removed. */ itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); if (*p % 2) ylist_remove_current(lst, itr, 1); } ylisti_destroy(itr); i = 0; itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); yassert(i == *p); i += 2; } ylisti_destroy(itr); ylist_destroy(lst); lst = ylist_create(0, &yfree); /* remove even numbers - head is removed. */ for (i = 0; i < 10; i++) { p = (int *)ymalloc(sizeof(*p)); *p = i; ylist_add_last(lst, p); } itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); if (!(*p % 2)) ylist_remove_current(lst, itr, 1); } ylisti_destroy(itr); i = 1; itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { p = ylisti_next(itr); yassert(i == *p); i += 2; } ylisti_destroy(itr); ylist_destroy(lst); { /* Just Scope */ struct dummy *dum; lst = ylist_create(0, free_dummycb); for (i = 0; i < 10; i++) { dum = (struct dummy *)ymalloc(sizeof(*dum)); dum->id = i; dum->mem = (int *)ymalloc(sizeof(*dum->mem)); *(dum->mem) = i; ylist_add_last(lst, dum); } yassert(10 == ylist_size(lst)); itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { dum = ylisti_next(itr); if (5 == dum->id) ylist_remove_current(lst, itr, 1); } ylisti_destroy(itr); yassert(9 == ylist_size(lst)); itr = ylisti_create(lst, YLISTI_FORWARD); while (ylisti_has_next(itr)) { dum = ylisti_next(itr); yassert(5 != dum->id); } ylisti_destroy(itr); ylist_destroy(lst); } lst = ylist_create(1, &yfree); p = (int *)ymalloc(sizeof(*p)); *p = 0; ylist_add_last(lst, p); yassert(1 == ylist_size(lst)); p = (int *)ymalloc(sizeof(*p)); *p = 1; yassert(ylist_add_last(lst, p)); yassert(1 == ylist_size(lst)); yfree(p); /* p is fail to insert to the list */ p = (int *)ylist_peek_last(lst); yassert(0 == *p && 1 == ylist_size(lst)); p = ylist_remove_last(lst, FALSE); yassert(ylist_is_empty(lst)); yfree(p); ylist_destroy(lst); }
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; }
static INLINE void unlock(struct ymempool *mp) { if (opt_is_mt_safe(mp)) if (pthread_mutex_unlock(&mp->m)) yassert(0); }
bool nsec_update_label_record(zdb_zone *zone, zdb_rr_label *label, nsec_node *item, nsec_node *next_item, u8 *name) { yassert(zdb_zone_islocked(zone)); type_bit_maps_context tbmctx; u8 tmp_bitmap[256 * (1 + 1 + 32)]; /* 'max window count' * 'max window length' */ u32 tbm_size = type_bit_maps_initialise_from_label(&tbmctx, label, TRUE, TRUE); u32 ttl = zone->min_ttl; type_bit_maps_write(&tbmctx, tmp_bitmap); /* * 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) * */ log_debug("nsec_update_label_record: [%{dnsname}] %{dnsname} (=> %{dnsname}) updating record.", name, item->inverse_relative_name, next_item->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 */ u8 tmp_name[MAX_DOMAIN_LENGTH]; nsec_inverse_name(tmp_name, next_item->inverse_relative_name); if(dnsname_equals(rdata, tmp_name)) { /* All good */ return FALSE; } } } } #if ZDB_CHANGE_FEEDBACK_SUPPORT 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(zone, name, TYPE_NSEC, &unpacked_ttlrdata); nsec_rec = nsec_rec->next; } while(nsec_rec != NULL); } #endif 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 */ 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, item->inverse_relative_name, next_item->inverse_relative_name); u16 dname_len = nsec_inverse_name(next_name, next_item->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_CHANGE_FEEDBACK_SUPPORT 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(zone, name_path.labels, name_path.size, TYPE_NSEC, &unpacked_ttlrdata); } #endif /* * Schedule a signature */ } label->flags |= ZDB_RR_LABEL_NSEC; return TRUE; }
ya_result xfr_input_stream_init(input_stream* filtering_stream, const u8 *origin, input_stream *xfr_source_stream, message_data *message, u32 current_serial, xfr_copy_flags flags) { yassert(filtering_stream != NULL && origin != NULL && xfr_source_stream != NULL && message != NULL); input_stream *is = xfr_source_stream; packet_unpack_reader_data reader; u8 *buffer; u8 *record; u8 *ptr; #if DNSCORE_HAS_TSIG_SUPPORT const tsig_item *tsig; #endif ya_result record_len; ya_result return_value; u32 origin_len; u32 last_serial = 0; u16 tcplen; u16 qtype; u16 qclass; u16 old_mac_size; bool last_message_had_tsig; bool need_cleanup_tsig = FALSE; #if DNSCORE_HAS_TSIG_SUPPORT u8 old_mac[64]; #endif /* * ensure the stream will be unusable if the initialisation fails */ input_stream_set_void(filtering_stream); /* * Start by reading the first packet, and determine if it's an AXFR or an IXFR (for the name) * note: it's read and converted to the host endianness */ if(!is_fd_input_stream(is)) { // expected file input stream return INVALID_ARGUMENT_ERROR; } //buffer_input_stream_init(is, is, 4096); /* TCP length */ if(FAIL(return_value = input_stream_read_nu16(is, &tcplen))) { return return_value; } if(return_value != 2) { return UNEXPECTED_EOF; } /* if the length is not enough, return the most appropriate error code */ origin_len = dnsname_len(origin); if(tcplen < DNS_HEADER_LENGTH + origin_len + 4) { return_value = UNEXPECTED_EOF; if(tcplen >= DNS_HEADER_LENGTH) { if(ISOK(return_value = input_stream_read_fully(is, message->pool_buffer, DNS_HEADER_LENGTH))) { return_value = MAKE_DNSMSG_ERROR(MESSAGE_RCODE(message->pool_buffer)); } } return return_value; } /* read the whole message */ buffer = &message->buffer[0]; record = &message->pool_buffer[0]; assert(sizeof(message->pool_buffer) >= 255 + 10 + 65535); if(FAIL(return_value = input_stream_read_fully(is, buffer, tcplen))) { return return_value; } #if DEBUG_XFR_INPUT_STREAM log_memdump(g_system_logger, MSG_DEBUG1, &message->buffer[0], tcplen, 32); #endif message->received = return_value; /* check the message makes sense */ const u64 *h64 = (u64*)buffer; u64 m64 = AXFR_MESSAGE_HEADER_MASK; u64 r64 = AXFR_MESSAGE_HEADER_RESULT; if(((*h64&m64) != r64) || (MESSAGE_NS(message->buffer) != 0)) { u8 code = MESSAGE_RCODE(message->buffer); if(code != 0) { return_value = MAKE_DNSMSG_ERROR(code); } else { return_value = UNPROCESSABLE_MESSAGE; } return return_value; } //m64 = AXFR_NEXT_MESSAGE_HEADER_MASK; //r64 = AXFR_NEXT_MESSAGE_HEADER_RESULT; packet_reader_init(&reader, buffer, tcplen); reader.offset = DNS_HEADER_LENGTH; packet_reader_read_fqdn(&reader, record, RDATA_MAX_LENGTH + 1); if(!dnsname_equals(record, origin)) { return INVALID_PROTOCOL; } if(FAIL(return_value = packet_reader_read_u16(&reader, &qtype))) { return return_value; } if(return_value != 2) { return UNEXPECTED_EOF; } /* * check that we are allowed to process this particular kind of transfer * note : this does not determine what is REALLY begin transferred */ switch(qtype) { case TYPE_AXFR: { if((flags & XFR_ALLOW_AXFR) == 0) { return INVALID_PROTOCOL; } break; } case TYPE_IXFR: { if((flags & XFR_ALLOW_IXFR) == 0) { return INVALID_PROTOCOL; } break; } default: { return INVALID_PROTOCOL; } } if(FAIL(return_value = packet_reader_read_u16(&reader, &qclass))) { return return_value; } if(qclass != CLASS_IN) { /** wrong answer */ return INVALID_PROTOCOL; } /* check for TSIG and verify */ u16 ancount = ntohs(MESSAGE_AN(buffer)); #if DNSCORE_HAS_TSIG_SUPPORT if((last_message_had_tsig = ((tsig = message->tsig.tsig) != NULL))) { /* verify the TSIG * * AR > 0 * skip ALL the records until the last AR * it MUST be a TSIG * It's the first TSIG answering to our query * verify it * */ message->tsig.tsig = NULL; old_mac_size = message->tsig.mac_size; memcpy(old_mac, message->tsig.mac, old_mac_size); if(FAIL(return_value = tsig_message_extract(message))) { log_debug("xfr_input_stream: error extracting the signature"); return return_value; } if(return_value == 0) { log_debug("xfr_input_stream: no signature when one was requested"); return TSIG_BADSIG; /* no signature, when one was requested, is a bad signature */ } if(message->tsig.tsig != tsig) { /* This is not the one we started with */ log_debug("xfr_input_stream: signature key does not match"); return TSIG_BADSIG; } /// check that the tsig in the message matches the one that was sent if(FAIL(return_value = tsig_verify_tcp_first_message(message, old_mac, old_mac_size))) { return return_value; } reader.packet_size = message->received; need_cleanup_tsig = TRUE; } #endif log_debug("xfr_input_stream: expecting %5d answer records", ancount); /* * read the SOA (it MUST be an SOA) */ if(FAIL(record_len = packet_reader_read_record(&reader, record, RDATA_MAX_LENGTH + 1))) { return record_len; } if(!dnsname_equals(record, origin)) { return INVALID_PROTOCOL; } ptr = &record[origin_len]; if(GET_U16_AT(*ptr) != TYPE_SOA) { return INVALID_PROTOCOL; } ptr += 8; /* type class ttl */ u16 rdata_size = ntohs(GET_U16_AT(*ptr)); if(rdata_size < 22) { return INVALID_PROTOCOL; } rdata_size -= 16; ptr += 2; /* rdata size */ s32 len = dnsname_len(ptr); if(len >= rdata_size) { return INVALID_PROTOCOL; } rdata_size -= len; ptr += len; len = dnsname_len(ptr); if(len >= rdata_size) { return INVALID_PROTOCOL; } rdata_size -= len; if(rdata_size != 4) { return INVALID_PROTOCOL; } ptr += len; // if the serial of the SOA is the same one as we know, then there is no // need to download the zone last_serial = ntohl(GET_U32_AT(*ptr)); if(last_serial == current_serial) { //args->out_loaded_serial = args->current_serial; return ZONE_ALREADY_UP_TO_DATE; } xfr_input_stream_data *data; ZALLOC_OR_DIE(xfr_input_stream_data*, data, xfr_input_stream_data, XFRISDTA_TAG); ZEROMEMORY(data, sizeof(xfr_input_stream_data)); /* * We have got the first SOA * Next time we find this SOA (second next time for IXFR) the stream, it will be the end of the stream */ /* * The stream can be AXFR or IXFR. * The only way to know this is to look at the records, maybe on many packets. * If there are two SOA (different serial numbers) for the start, then it's an IXFR, else it's an AXFR. * * OPEN A PIPE STREAM "XFRs" * * Save the first SOA */ MALLOC_OR_DIE(u8*, data->first_soa_record, record_len, XFRISSOA_TAG); MEMCOPY(data->first_soa_record, record, record_len); data->first_soa_record_size = record_len; filtering_stream->vtbl = &xfr_input_stream_vtbl; filtering_stream->data = data; pipe_stream_init(&data->pipe_stream_output, &data->pipe_stream_input, 65536); MEMCOPY(&data->reader, &reader, sizeof(packet_unpack_reader_data)); data->origin = origin; data->message = message; data->ancount = ancount - 1; data->record_index++; data->last_serial = last_serial; data->xfr_mode = TYPE_ANY; data->ixfr_mark = FALSE; data->last_message_had_tsig = last_message_had_tsig; data->source_stream = *is; data->need_cleanup_tsig = need_cleanup_tsig; /* * Then we read all records for all packets * If we find an SOA ... * AXFR: it has to be the last serial and it is the end of the stream. * IXFR: if it's not the last serial it has to go from step to step * AND once we have reached the "last serial" once, the next hit is the end of the stream. */ data->eos = FALSE; /* * In order to know what the type is, read the first packet. */ return_value = xfr_input_stream_read_packet(data); if(FAIL(return_value)) { xfr_input_stream_close(filtering_stream); } return return_value; }
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; }