From: Wouter Wijngaards Date: Tue, 19 Feb 2008 13:12:23 +0000 (+0000) Subject: Faster due to time-sharing. X-Git-Tag: release-0.10~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2710818d4218025224d3f3e03dde6b9c9f43d98;p=thirdparty%2Funbound.git Faster due to time-sharing. git-svn-id: file:///svn/unbound/trunk@966 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 0893ac13f..78eaaad58 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -406,7 +406,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, */ uint16_t udpsize = edns->udp_size; int secure = 0; - uint32_t timenow = (uint32_t)time(0); + uint32_t timenow = *worker->env.now; int must_validate = !(flags&BIT_CD) && worker->env.need_to_validate; struct dns_msg *msg = NULL; struct delegpt *dp; @@ -510,7 +510,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id, { struct msgreply_entry* mrentry = (struct msgreply_entry*)e->key; struct reply_info* rep = (struct reply_info*)e->data; - uint32_t timenow = time(0); + uint32_t timenow = *worker->env.now; uint16_t udpsize = edns->udp_size; int secure; int must_validate = !(flags&BIT_CD) && worker->env.need_to_validate; @@ -1008,6 +1008,9 @@ worker_init(struct worker* worker, struct config_file *cfg, worker->thread_num); alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker); worker->env = *worker->daemon->env; + comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv); + if(worker->thread_num == 0) + log_set_time(worker->env.now); worker->env.worker = worker; worker->env.send_packet = &worker_send_packet; worker->env.send_query = &worker_send_query; @@ -1057,6 +1060,8 @@ worker_delete(struct worker* worker) comm_signal_delete(worker->comsig); comm_point_delete(worker->cmd_com); comm_timer_delete(worker->stat_timer); + if(worker->thread_num == 0) + log_set_time(NULL); comm_base_delete(worker->base); ub_randfree(worker->rndstate); /* close fds after deleting commpoints, to be sure. diff --git a/doc/Changelog b/doc/Changelog index ea84055da..b0134f585 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,10 @@ - applied patch to unbound-host man page from Jan-Piet Mens. - fix donotquery-localhost: yes default (it erroneously was switched to default 'no'). + - time is only gotten once and the value is shared across unbound. + - unittest cleans up crypto, so that it has no memory leaks. + - mini_event shares the time value with unbound this results in + +3% speed for cache responses and +9% for recursions. 18 February 2008: Wouter - patch to unbound-host from Jan-Piet Mens. diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index 76551a144..eedbfcb4d 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -467,7 +467,7 @@ store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env, struct ub_packed_rrset_key* k; struct packed_rrset_data* d; struct rrset_ref ref; - uint32_t now = time(NULL); + uint32_t now = *env->now; k = alloc_special_obtain(env->alloc); if(!k) diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 778580fe0..d0bc3cf1c 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -130,7 +130,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) /** filter out unsuitable targets, return rtt or -1 */ static int iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, - uint8_t* name, size_t namelen, time_t now, struct delegpt_addr* a) + uint8_t* name, size_t namelen, uint32_t now, struct delegpt_addr* a) { int rtt; int lame; @@ -160,7 +160,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, * returns number of best targets (or 0, no suitable targets) */ static int iter_filter_order(struct iter_env* iter_env, struct module_env* env, - uint8_t* name, size_t namelen, time_t now, struct delegpt* dp, + uint8_t* name, size_t namelen, uint32_t now, struct delegpt* dp, int* best_rtt) { int got_num = 0, got_rtt = 0, thisrtt, swap_to_front; @@ -211,12 +211,11 @@ iter_server_selection(struct iter_env* iter_env, struct module_env* env, struct delegpt* dp, uint8_t* name, size_t namelen, int* dnssec_expected) { - time_t now = time(NULL); int sel; int selrtt; struct delegpt_addr* a, *prev; - int num = iter_filter_order(iter_env, env, name, namelen, now, dp, - &selrtt); + int num = iter_filter_order(iter_env, env, name, namelen, + *env->now, dp, &selrtt); if(num == 0) return NULL; diff --git a/iterator/iterator.c b/iterator/iterator.c index 906c59aa3..8e011bb8e 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -759,7 +759,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, * cache needs to be primed for the qclass. */ iq->dp = dns_cache_find_delegation(qstate->env, delname, delnamelen, iq->qchase.qtype, iq->qchase.qclass, - qstate->region, &iq->deleg_msg, (uint32_t)time(NULL)); + qstate->region, &iq->deleg_msg, *qstate->env->now); /* If the cache has returned nothing, then we have a * root priming situation. */ @@ -1336,8 +1336,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, * gotten this from cache, so test to be sure */ if(!infra_set_lame(qstate->env->infra_cache, &qstate->reply->addr, qstate->reply->addrlen, - iq->dp->name, iq->dp->namelen, time(NULL), - dnsseclame)) + iq->dp->name, iq->dp->namelen, + *qstate->env->now, dnsseclame)) log_err("mark host lame: out of memory"); } else log_err("%slame response from cache", dnsseclame?"DNSSEC ":""); diff --git a/libunbound/libworker.c b/libunbound/libworker.c index fa029584b..f04cde4ef 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -172,6 +172,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg) w->env->attach_sub = &mesh_attach_sub; w->env->kill_sub = &mesh_state_delete; w->env->detect_cycle = &mesh_detect_cycle; + comm_base_timept(w->base, &w->env->now, &w->env->now_tv); return w; } diff --git a/services/cache/dns.c b/services/cache/dns.c index a05665f88..854b134b8 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -52,7 +52,7 @@ /** store rrsets in the rrset cache. * @param env: module environment with caches. * @param rep: contains list of rrsets to store. - * @param now: current time(NULL). + * @param now: current time. */ static void store_rrsets(struct module_env* env, struct reply_info* rep, uint32_t now) @@ -73,7 +73,7 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, hashvalue_t hash, struct reply_info* rep) { struct msgreply_entry* e; - uint32_t now = time(NULL), ttl = rep->ttl; + uint32_t ttl = rep->ttl; size_t i; /* store RRsets */ @@ -82,8 +82,8 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, rep->ref[i].id = rep->rrsets[i]->id; } reply_info_sortref(rep); - reply_info_set_ttls(rep, now); - store_rrsets(env, rep, now); + reply_info_set_ttls(rep, *env->now); + store_rrsets(env, rep, *env->now); if(ttl == 0) { /* we do not store the message, but we did store the RRs, * which could be useful for delegation information */ @@ -219,7 +219,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, { struct delegpt_ns* ns; struct ub_packed_rrset_key* akey; - uint32_t now = time(NULL); + uint32_t now = *env->now; for(ns = dp->nslist; ns; ns = ns->next) { if(ns->resolved) continue; @@ -543,7 +543,7 @@ dns_cache_lookup(struct module_env* env, struct lruhash_entry* e; struct query_info k; hashvalue_t h; - uint32_t now = (uint32_t)time(NULL); + uint32_t now = *env->now; struct ub_packed_rrset_key* rrset; /* lookup first, this has both NXdomains and ANSWER responses */ @@ -630,16 +630,15 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, if(is_referral) { /* store rrsets */ struct rrset_ref ref; - uint32_t now = time(NULL); size_t i; for(i=0; irrset_count; i++) { packed_rrset_ttl_add((struct packed_rrset_data*) - rep->rrsets[i]->entry.data, now); + rep->rrsets[i]->entry.data, *env->now); ref.key = rep->rrsets[i]; ref.id = rep->rrsets[i]->id; /*ignore ret: it was in the cache, ref updated */ (void)rrset_cache_update(env->rrset_cache, &ref, - env->alloc, now); + env->alloc, *env->now); } free(rep); return 1; diff --git a/services/cache/infra.c b/services/cache/infra.c index b2b6ada26..149092f03 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -158,7 +158,7 @@ infra_lookup_host_nottl(struct infra_cache* infra, struct infra_host_data* infra_lookup_host(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, int wr, - time_t timenow, struct infra_host_key** key) + uint32_t timenow, struct infra_host_key** key) { struct infra_host_data* data; struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, @@ -186,7 +186,7 @@ infra_lookup_host(struct infra_cache* infra, */ static struct lruhash_entry* new_host_entry(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, time_t tm) + socklen_t addrlen, uint32_t tm) { struct infra_host_data* data; struct infra_host_key* key = (struct infra_host_key*)malloc( @@ -214,7 +214,7 @@ new_host_entry(struct infra_cache* infra, struct sockaddr_storage* addr, int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, time_t timenow, int* edns_vs, int* to) + socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to) { struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, addrlen, 0); @@ -260,7 +260,7 @@ hash_lameness(uint8_t* name, size_t namelen) int infra_lookup_lame(struct infra_host_data* host, - uint8_t* name, size_t namelen, time_t timenow) + uint8_t* name, size_t namelen, uint32_t timenow) { struct lruhash_entry* e; struct infra_lame_key k; @@ -329,7 +329,7 @@ infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg)) int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, time_t timenow, int dnsseclame) + uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame) { struct infra_host_data* data; struct lruhash_entry* e; @@ -422,7 +422,7 @@ infra_update_tcp_works(struct infra_cache* infra, int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - int roundtrip, time_t timenow) + int roundtrip, uint32_t timenow) { struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, addrlen, 1); @@ -452,7 +452,7 @@ infra_rtt_update(struct infra_cache* infra, int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - int edns_version, time_t timenow) + int edns_version, uint32_t timenow) { struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, addrlen, 1); @@ -478,7 +478,7 @@ int infra_get_lame_rtt(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, int* lame, int* dnsseclame, - int* rtt, time_t timenow) + int* rtt, uint32_t timenow) { struct infra_host_data* host; struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, diff --git a/services/cache/infra.h b/services/cache/infra.h index fd5261b74..605396e28 100644 --- a/services/cache/infra.h +++ b/services/cache/infra.h @@ -63,7 +63,7 @@ struct infra_host_key { */ struct infra_host_data { /** TTL value for this entry. absolute time. */ - time_t ttl; + uint32_t ttl; /** round trip times for timeout calculation */ struct rtt_info rtt; /** Names of the zones that are lame. NULL=no lame zones. */ @@ -90,7 +90,7 @@ struct infra_lame_key { */ struct infra_lame_data { /** TTL of this entry. absolute time. */ - time_t ttl; + uint32_t ttl; /** is the host lame (does not serve the zone authoritatively), * or is the host dnssec lame (does not serve DNSSEC data) */ int isdnsseclame; @@ -151,7 +151,7 @@ struct infra_cache* infra_adjust(struct infra_cache* infra, */ struct infra_host_data* infra_lookup_host(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, int wr, - time_t timenow, struct infra_host_key** key); + uint32_t timenow, struct infra_host_key** key); /** * Find host information to send a packet. Creates new entry if not found. @@ -166,7 +166,7 @@ struct infra_host_data* infra_lookup_host(struct infra_cache* infra, * @return: 0 on error. */ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, time_t timenow, int* edns_vs, int* to); + socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to); /** * Check for lameness of this server for a particular zone. @@ -178,7 +178,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, * @return: 0 if not lame or unknown or timed out, 1 if lame, 2 if dnsseclame. */ int infra_lookup_lame(struct infra_host_data* host, - uint8_t* name, size_t namelen, time_t timenow); + uint8_t* name, size_t namelen, uint32_t timenow); /** * Set a host to be lame for the given zone. @@ -194,7 +194,7 @@ int infra_lookup_lame(struct infra_host_data* host, */ int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, time_t timenow, int dnsseclame); + uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame); /** * Update rtt information for the host. @@ -208,7 +208,7 @@ int infra_set_lame(struct infra_cache* infra, */ int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - int roundtrip, time_t timenow); + int roundtrip, uint32_t timenow); /** * Update information for the host, store that a TCP transaction works. @@ -230,7 +230,7 @@ void infra_update_tcp_works(struct infra_cache* infra, */ int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - int edns_version, time_t timenow); + int edns_version, uint32_t timenow); /** * Get Lameness information and average RTT if host is in the cache. @@ -250,7 +250,7 @@ int infra_edns_update(struct infra_cache* infra, int infra_get_lame_rtt(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, int* lame, int* dnsseclame, - int* rtt, time_t timenow); + int* rtt, uint32_t timenow); /** * Get memory used by the infra cache. diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 20c97330a..5034c20b9 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -309,9 +309,8 @@ rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, void rrset_update_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset) + struct ub_packed_rrset_key* rrset, uint32_t now) { - uint32_t now = (uint32_t)time(0); struct packed_rrset_data* updata = (struct packed_rrset_data*)rrset->entry.data; struct lruhash_entry* e; @@ -339,9 +338,8 @@ rrset_update_sec_status(struct rrset_cache* r, void rrset_check_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset) + struct ub_packed_rrset_key* rrset, uint32_t now) { - uint32_t now = (uint32_t)time(0); struct packed_rrset_data* updata = (struct packed_rrset_data*)rrset->entry.data; struct lruhash_entry* e; diff --git a/services/cache/rrset.h b/services/cache/rrset.h index ff3832fae..02241d4bd 100644 --- a/services/cache/rrset.h +++ b/services/cache/rrset.h @@ -192,9 +192,10 @@ void rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, * @param r: the rrset cache. * @param rrset: which rrset to attempt to update. This rrset is left * untouched. The rrset in the cache is updated in-place. + * @param now: current time. */ void rrset_update_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset); + struct ub_packed_rrset_key* rrset, uint32_t now); /** * Looks up security status of an rrset. Looks up the rrset. @@ -203,9 +204,10 @@ void rrset_update_sec_status(struct rrset_cache* r, * @param r: the rrset cache. * @param rrset: This rrset may change security status due to the cache. * But its status will only improve, towards secure. + * @param now: current time. */ void rrset_check_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset); + struct ub_packed_rrset_key* rrset, uint32_t now); /** mark rrset to be deleted, set id=0 */ void rrset_markdel(void* key); diff --git a/services/mesh.c b/services/mesh.c index 16552b04e..c1cc1d53b 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -516,6 +516,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, struct mesh_reply* r) { struct timeval end_time; + struct timeval duration; int secure; /* examine security status */ if(m->s.env->need_to_validate && !(r->qflags&BIT_CD) && rep && @@ -551,18 +552,13 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, } /* account */ m->s.env->mesh->num_reply_addrs--; - if(gettimeofday(&end_time, NULL) < 0) { - log_err("gettimeofday: %s", strerror(errno)); - return; - } else { - struct timeval duration; - timeval_subtract(&duration, &end_time, &r->start_time); - verbose(VERB_ALGO, "query took %d.%6.6d sec", - (int)duration.tv_sec, (int)duration.tv_usec); - m->s.env->mesh->replies_sent++; - timeval_add(&m->s.env->mesh->replies_sum_wait, &duration); - timehist_insert(m->s.env->mesh->histogram, &duration); - } + end_time = *m->s.env->now_tv; + timeval_subtract(&duration, &end_time, &r->start_time); + verbose(VERB_ALGO, "query took %d.%6.6d sec", + (int)duration.tv_sec, (int)duration.tv_usec); + m->s.env->mesh->replies_sent++; + timeval_add(&m->s.env->mesh->replies_sum_wait, &duration); + timehist_insert(m->s.env->mesh->histogram, &duration); } void mesh_query_done(struct mesh_state* mstate) @@ -640,10 +636,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, r->edns = *edns; r->qid = qid; r->qflags = qflags; - if(gettimeofday(&r->start_time, NULL) < 0) { - log_err("addrep: gettimeofday: %s", strerror(errno)); - memset(&r->start_time, 0, sizeof(r->start_time)); - } + r->start_time = *s->s.env->now_tv; r->next = s->reply_list; s->reply_list = r; return 1; diff --git a/services/outside_network.c b/services/outside_network.c index 445547d71..a189dff98 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -430,6 +430,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, log_err("malloc failed"); return NULL; } + comm_base_timept(base, &outnet->now_secs, &outnet->now_tv); outnet->base = base; outnet->num_tcp = num_tcp; outnet->infra = infra; @@ -947,7 +948,7 @@ static int serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff) { int rtt, vs; - time_t now = time(0); + uint32_t now = *sq->outnet->now_secs; if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, now, &vs, &rtt)) @@ -958,10 +959,7 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff) else sq->status = serviced_query_UDP; } serviced_encode(sq, buff, sq->status == serviced_query_UDP_EDNS); - if(gettimeofday(&sq->last_sent_time, NULL) < 0) { - log_err("gettimeofday: %s", strerror(errno)); - return 0; - } + sq->last_sent_time = *sq->outnet->now_tv; verbose(VERB_ALGO, "serviced query UDP timeout=%d msec", rtt); sq->pending = pending_udp_query(sq->outnet, buff, &sq->addr, sq->addrlen, rtt, serviced_udp_callback, sq, sq->outnet->rnd); @@ -1039,7 +1037,7 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error, LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(ldns_buffer_begin( c->buffer)) == LDNS_RCODE_NOTIMPL) ) { if(!infra_edns_update(sq->outnet->infra, &sq->addr, - sq->addrlen, -1, time(0))) + sq->addrlen, -1, *sq->outnet->now_secs)) log_err("Out of memory caching no edns for host"); sq->status = serviced_query_TCP; serviced_tcp_initiate(sq->outnet, sq, c->buffer); @@ -1079,19 +1077,15 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, { struct serviced_query* sq = (struct serviced_query*)arg; struct outside_network* outnet = sq->outnet; - struct timeval now; + struct timeval now = *sq->outnet->now_tv; int fallback_tcp = 0; - if(gettimeofday(&now, NULL) < 0) { - log_err("gettimeofday: %s", strerror(errno)); - /* this option does not need current time */ - error = NETEVENT_CLOSED; - } + sq->pending = NULL; /* removed after callback */ if(error == NETEVENT_TIMEOUT) { int rto = 0; sq->retry++; if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen, - -1, (time_t)now.tv_sec))) + -1, (uint32_t)now.tv_sec))) log_err("out of memory in UDP exponential backoff"); if(sq->retry < OUTBOUND_UDP_RETRY) { log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10, @@ -1115,7 +1109,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) { /* note no EDNS, fallback without EDNS */ if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen, - -1, (time_t)now.tv_sec)) { + -1, (uint32_t)now.tv_sec)) { log_err("Out of memory caching no edns for host"); } sq->status = serviced_query_UDP; @@ -1145,7 +1139,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, verbose(VERB_ALGO, "measured roundtrip at %d msec", roundtime); log_assert(roundtime >= 0); if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen, - roundtime, (time_t)now.tv_sec)) + roundtime, (uint32_t)now.tv_sec)) log_err("out of memory noting rtt."); } serviced_callbacks(sq, error, c, rep); diff --git a/services/outside_network.h b/services/outside_network.h index 3eca8fe2a..97257f287 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -60,6 +60,10 @@ struct infra_cache; struct outside_network { /** Base for select calls */ struct comm_base* base; + /** pointer to time in seconds */ + uint32_t* now_secs; + /** pointer to time in microseconds */ + struct timeval* now_tv; /** buffer shared by UDP connections, since there is only one datagram at any time. */ diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 453b57ab1..4b86dfceb 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -592,6 +592,14 @@ comm_base_delete(struct comm_base* b) free(runtime); } +void +comm_base_timept(struct comm_base* b, uint32_t** tt, struct timeval** tv) +{ + struct replay_runtime* runtime = (struct replay_runtime*)b; + *tt = &runtime->now_secs; + *tv = &runtime->now_tv; +} + void comm_base_dispatch(struct comm_base* b) { diff --git a/testcode/replay.h b/testcode/replay.h index 1f0058574..5873ad029 100644 --- a/testcode/replay.h +++ b/testcode/replay.h @@ -226,6 +226,11 @@ struct replay_runtime { /** user argument for incoming query callback */ void *cb_arg; + /** the current time in seconds */ + uint32_t now_secs; + /** the current time in microseconds */ + struct timeval now_tv; + /** signal handler callback */ void (*sig_cb)(int, void*); /** signal handler user arg */ diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 8a6b0bccb..651859ab4 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -314,7 +314,7 @@ infra_test() size_t zonelen = 13; struct infra_cache* slab; struct config_file* cfg = config_create(); - time_t now = 0; + uint32_t now = 0; int vs, to; struct infra_host_key* k; struct infra_host_data* d; @@ -409,5 +409,7 @@ main(int argc, char* argv[]) msgparse_test(); checklock_stop(); printf("%d checks ok.\n", testcount); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); return 0; } diff --git a/testcode/unitverify.c b/testcode/unitverify.c index 0f89b10ad..4c7eb7160 100644 --- a/testcode/unitverify.c +++ b/testcode/unitverify.c @@ -263,6 +263,7 @@ verifytest_file(const char* fname, const char* at_date) struct entry* list = read_datafile(fname); struct module_env env; struct val_env ve; + uint32_t now = time(NULL); if(!list) fatal_exit("could not read %s: %s", fname, strerror(errno)); @@ -271,6 +272,7 @@ verifytest_file(const char* fname, const char* at_date) memset(&ve, 0, sizeof(ve)); env.scratch = region; env.scratch_buffer = buf; + env.now = &now; ve.date_override = cfg_convert_timeval(at_date); unit_assert(region && buf); dnskey = extract_keys(list, &alloc, region, buf); diff --git a/util/log.c b/util/log.c index 998b4c291..614541e33 100644 --- a/util/log.c +++ b/util/log.c @@ -69,6 +69,8 @@ static const char* ident="unbound"; /** are we using syslog(3) to log to */ static int log_to_syslog = 0; #endif /* HAVE_SYSLOG_H */ +/** time to print in log, if NULL, use time(2) */ +static uint32_t* log_now = NULL; void log_init(const char* filename, int use_syslog, const char* chrootdir) @@ -130,12 +132,18 @@ void log_ident_set(const char* id) ident = id; } +void log_set_time(uint32_t* t) +{ + log_now = t; +} + void log_vmsg(int pri, const char* type, const char *format, va_list args) { char message[MAXSYSLOGMSGLEN]; unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey); + uint32_t now; (void)pri; vsnprintf(message, sizeof(message), format, args); #ifdef HAVE_SYSLOG_H @@ -146,7 +154,10 @@ log_vmsg(int pri, const char* type, } #endif /* HAVE_SYSLOG_H */ if(!logfile) return; - fprintf(logfile, "[%d] %s[%d:%x] %s: %s\n", (int)time(NULL), + if(log_now) + now = *log_now; + else now = (uint32_t)time(NULL); + fprintf(logfile, "[%u] %s[%d:%x] %s: %s\n", (unsigned)now, ident, (int)getpid(), tid?*tid:0, type, message); fflush(logfile); } diff --git a/util/log.h b/util/log.h index 394a20111..04c2577ce 100644 --- a/util/log.h +++ b/util/log.h @@ -105,6 +105,13 @@ void log_thread_set(int* num); */ void log_ident_set(const char* id); +/** + * Set the time value to print in log entries. + * @param t: the point is copied and used to find the time. + * if NULL, time(2) is used. + */ +void log_set_time(uint32_t* t); + /** * Log informational message. * Pass printf formatted arguments. No trailing newline is needed. diff --git a/util/mini_event.c b/util/mini_event.c index 71726277a..ef54d542a 100644 --- a/util/mini_event.c +++ b/util/mini_event.c @@ -67,14 +67,29 @@ int mini_ev_cmp(const void* a, const void* b) return 0; } +/** set time */ +static int +settime(struct event_base* base) +{ + if(gettimeofday(base->time_tv, NULL) < 0) { + return -1; + } +#ifndef S_SPLINT_S + *base->time_secs = (uint32_t)base->time_tv->tv_sec; +#endif + return 0; +} + /** create event base */ -void *event_init(void) +void *event_init(uint32_t* time_secs, struct timeval* time_tv) { struct event_base* base = (struct event_base*)malloc( sizeof(struct event_base)); if(!base) return NULL; memset(base, 0, sizeof(*base)); + base->time_secs = time_secs; + base->time_tv = time_tv; base->times = rbtree_create(mini_ev_cmp); if(!base->times) { event_base_free(base); @@ -165,10 +180,16 @@ static int handle_select(struct event_base* base, struct timeval* wait) memmove(&w, &base->writes, sizeof(fd_set)); if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { - if(errno == EAGAIN || errno == EINTR) + ret = errno; + if(settime(base) < 0) + return -1; + errno = ret; + if(ret == EAGAIN || ret == EINTR) return 0; return -1; } + if(settime(base) < 0) + return -1; for(i=0; imaxfd+1; i++) { short bits = 0; @@ -199,13 +220,13 @@ static int handle_select(struct event_base* base, struct timeval* wait) /** run select in a loop */ int event_base_dispatch(struct event_base* base) { - struct timeval now, wait; + struct timeval wait; + if(settime(base) < 0) + return -1; while(!base->need_to_exit) { - if(gettimeofday(&now, NULL) < 0) - return -1; /* see if timeouts need handling */ - handle_timeouts(base, &now, &wait); + handle_timeouts(base, base->time_tv, &wait); if(base->need_to_exit) return 0; /* do select */ @@ -279,11 +300,9 @@ int event_add(struct event* ev, struct timeval* tv) } if(tv && (ev->ev_events&EV_TIMEOUT)) { #ifndef S_SPLINT_S - struct timeval now; - if(gettimeofday(&now, NULL) < 0) - return -1; - ev->ev_timeout.tv_sec = tv->tv_sec + now.tv_sec; - ev->ev_timeout.tv_usec = tv->tv_usec + now.tv_usec; + struct timeval *now = ev->ev_base->time_tv; + ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec; + ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec; while(ev->ev_timeout.tv_usec > 1000000) { ev->ev_timeout.tv_usec -= 1000000; ev->ev_timeout.tv_sec++; diff --git a/util/mini_event.h b/util/mini_event.h index c537f1394..1abb347b6 100644 --- a/util/mini_event.h +++ b/util/mini_event.h @@ -94,6 +94,10 @@ struct event_base struct event** signals; /** if we need to exit */ int need_to_exit; + /** where to store time in seconds */ + uint32_t* time_secs; + /** where to store time in microseconds */ + struct timeval* time_tv; }; /** @@ -122,7 +126,7 @@ struct event { /* function prototypes as they appear in event.h */ /** create event base */ -void *event_init(void); +void *event_init(uint32_t* time_secs, struct timeval* time_tv); /** get version */ const char *event_get_version(void); /** get polling method, select */ diff --git a/util/module.h b/util/module.h index a70306a1e..43551ef20 100644 --- a/util/module.h +++ b/util/module.h @@ -191,6 +191,10 @@ struct module_env { struct alloc_cache* alloc; /** random table to generate random numbers */ struct ub_randstate* rnd; + /** time in seconds, converted to integer */ + uint32_t* now; + /** time in microseconds. Relatively recent. */ + struct timeval* now_tv; /** is validation required for messages, controls client-facing * validation status (AD bits) and servfails */ int need_to_validate; diff --git a/util/netevent.c b/util/netevent.c index c72dc9d11..0b7995f1e 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -62,6 +62,8 @@ * Possibly other structures (list, tree) this is part of. */ struct internal_event { + /** the comm base */ + struct comm_base* base; /** libevent event type, alloced here */ struct event ev; }; @@ -72,12 +74,18 @@ struct internal_event { struct internal_base { /** libevent event_base type. */ struct event_base* base; + /** seconds time pointer points here */ + uint32_t secs; + /** timeval with current time */ + struct timeval now; }; /** * Internal timer structure, to store timer event in. */ struct internal_timer { + /** the comm base */ + struct comm_base* base; /** libevent event type, alloced here */ struct event ev; /** is timer enabled */ @@ -101,6 +109,20 @@ static struct comm_point* comm_point_create_tcp_handler( /* -------- End of local definitions -------- */ +#ifdef USE_MINI_EVENT +#define comm_base_now(x) /* nothing to do */ +#else /* !USE_MINI_EVENT */ +/** fillup the time values in the event base */ +static void +comm_base_now(struct comm_base* b) +{ + if(gettimeofday(&b->eb->now, NULL) < 0) { + log_err("gettimeofday: %s", strerror(errno)); + } + b->eb->secs = (uint32_t)b->eb->now.tv_sec; +} +#endif /* USE_MINI_EVENT */ + struct comm_base* comm_base_create() { @@ -113,12 +135,18 @@ comm_base_create() free(b); return NULL; } +#ifdef USE_MINI_EVENT + /* use mini event time-sharing feature */ + b->eb->base = event_init(&b->eb->secs, &b->eb->now); +#else b->eb->base = event_init(); +#endif if(!b->eb->base) { free(b->eb); free(b); return NULL; } + comm_base_now(b); verbose(VERB_ALGO, "libevent %s uses %s method.", event_get_version(), event_get_method()); return b; @@ -142,6 +170,13 @@ comm_base_delete(struct comm_base* b) free(b); } +void +comm_base_timept(struct comm_base* b, uint32_t** tt, struct timeval** tv) +{ + *tt = &b->eb->secs; + *tv = &b->eb->now; +} + void comm_base_dispatch(struct comm_base* b) { @@ -335,6 +370,7 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg) if(!(event&EV_READ)) return; log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); + comm_base_now(rep.c->ev->base); ldns_buffer_clear(rep.c->buffer); rep.addrlen = (socklen_t)sizeof(rep.addr); log_assert(fd != -1); @@ -414,6 +450,7 @@ comm_point_udp_callback(int fd, short event, void* arg) if(!(event&EV_READ)) return; log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); + comm_base_now(rep.c->ev->base); ldns_buffer_clear(rep.c->buffer); rep.addrlen = (socklen_t)sizeof(rep.addr); log_assert(fd != -1); @@ -460,6 +497,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg) log_info("ignoring tcp accept event %d", (int)event); return; } + comm_base_now(c->ev->base); /* find free tcp handler. */ if(!c->tcp_free) { log_warn("accepted too many tcp, connections full"); @@ -706,6 +744,7 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg) { struct comm_point* c = (struct comm_point*)arg; log_assert(c->type == comm_tcp); + comm_base_now(c->ev->base); if(event&EV_READ) { if(!comm_point_tcp_handle_read(fd, c, 0)) { @@ -748,6 +787,7 @@ void comm_point_local_handle_callback(int fd, short event, void* arg) { struct comm_point* c = (struct comm_point*)arg; log_assert(c->type == comm_local); + comm_base_now(c->ev->base); if(event&EV_READ) { if(!comm_point_tcp_handle_read(fd, c, 1)) { @@ -765,6 +805,7 @@ void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), { struct comm_point* c = (struct comm_point*)arg; log_assert(c->type == comm_raw); + comm_base_now(c->ev->base); (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL); } @@ -784,6 +825,7 @@ comm_point_create_udp(struct comm_base *base, int fd, ldns_buffer* buffer, free(c); return NULL; } + c->ev->base = base; c->fd = fd; c->buffer = buffer; c->timeout = NULL; @@ -828,6 +870,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, free(c); return NULL; } + c->ev->base = base; c->fd = fd; c->buffer = buffer; c->timeout = NULL; @@ -872,6 +915,7 @@ comm_point_create_tcp_handler(struct comm_base *base, free(c); return NULL; } + c->ev->base = base; c->fd = -1; c->buffer = ldns_buffer_new(bufsize); if(!c->buffer) { @@ -934,6 +978,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, free(c); return NULL; } + c->ev->base = base; c->fd = fd; c->buffer = NULL; c->timeout = NULL; @@ -995,6 +1040,7 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, free(c); return NULL; } + c->ev->base = base; c->fd = -1; c->buffer = ldns_buffer_new(bufsize); if(!c->buffer) { @@ -1046,6 +1092,7 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, free(c); return NULL; } + c->ev->base = base; c->fd = fd; c->buffer = ldns_buffer_new(bufsize); if(!c->buffer) { @@ -1097,6 +1144,7 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing, free(c); return NULL; } + c->ev->base = base; c->fd = fd; c->buffer = NULL; c->timeout = NULL; @@ -1280,6 +1328,7 @@ comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg) free(tm); return NULL; } + tm->ev_timer->base = base; tm->callback = cb; tm->cb_arg = cb_arg; event_set(&tm->ev_timer->ev, -1, EV_PERSIST|EV_TIMEOUT, @@ -1331,6 +1380,7 @@ comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg) struct comm_timer* tm = (struct comm_timer*)arg; if(!(event&EV_TIMEOUT)) return; + comm_base_now(tm->ev_timer->base); tm->ev_timer->enabled = 0; log_assert(fptr_whitelist_comm_timer(tm->callback)); (*tm->callback)(tm->cb_arg); @@ -1371,6 +1421,7 @@ comm_signal_callback(int sig, short event, void* arg) struct comm_signal* comsig = (struct comm_signal*)arg; if(!(event & EV_SIGNAL)) return; + comm_base_now(comsig->base); log_assert(fptr_whitelist_comm_signal(comsig->callback)); (*comsig->callback)(sig, comsig->cb_arg); } diff --git a/util/netevent.h b/util/netevent.h index a023ce2f3..299044a76 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -264,6 +264,15 @@ struct comm_base* comm_base_create(); */ void comm_base_delete(struct comm_base* b); +/** + * Obtain two pointers. The pointers never change (until base_delete()). + * The pointers point to time values that are updated regularly. + * @param b: the communication base that will update the time values. + * @param tt: pointer to time in seconds is returned. + * @param tv: pointer to time in microseconds is returned. + */ +void comm_base_timept(struct comm_base* b, uint32_t** tt, struct timeval** tv); + /** * Dispatch the comm base events. * @param b: the communication to perform. diff --git a/validator/val_kcache.c b/validator/val_kcache.c index 2104eddd9..70267e517 100644 --- a/validator/val_kcache.c +++ b/validator/val_kcache.c @@ -119,9 +119,8 @@ key_cache_search(struct key_cache* kcache, uint8_t* name, size_t namelen, struct key_entry_key* key_cache_obtain(struct key_cache* kcache, uint8_t* name, size_t namelen, - uint16_t key_class, struct regional* region) + uint16_t key_class, struct regional* region, uint32_t now) { - uint32_t now = time(NULL); /* keep looking until we find a nonexpired entry */ while(1) { struct key_entry_key* k = key_cache_search(kcache, name, diff --git a/validator/val_kcache.h b/validator/val_kcache.h index 5d767d405..948353d7d 100644 --- a/validator/val_kcache.h +++ b/validator/val_kcache.h @@ -86,13 +86,14 @@ void key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey); * @param namelen: length of the name. * @param key_class: class of the key. * @param region: a copy of the key_entry is allocated in this region. + * @param now: current time. * @return pointer to a newly allocated key_entry copy in the region, if * a key entry could be found, and allocation succeeded and TTL was OK. * Otherwise, NULL is returned. */ struct key_entry_key* key_cache_obtain(struct key_cache* kcache, uint8_t* name, size_t namelen, uint16_t key_class, - struct regional* region); + struct regional* region, uint32_t now); /** * Get memory in use by the key cache. diff --git a/validator/val_kentry.c b/validator/val_kentry.c index de846c12a..8ba7e1e0b 100644 --- a/validator/val_kentry.c +++ b/validator/val_kentry.c @@ -221,13 +221,14 @@ key_entry_setup(struct regional* region, struct key_entry_key* key_entry_create_null(struct regional* region, - uint8_t* name, size_t namelen, uint16_t dclass, uint32_t ttl) + uint8_t* name, size_t namelen, uint16_t dclass, uint32_t ttl, + uint32_t now) { struct key_entry_key* k; struct key_entry_data* d; if(!key_entry_setup(region, name, namelen, dclass, &k, &d)) return NULL; - d->ttl = time(0) + ttl; + d->ttl = now + ttl; d->isbad = 0; d->rrset_type = LDNS_RR_TYPE_DNSKEY; d->rrset_data = NULL; @@ -237,7 +238,7 @@ key_entry_create_null(struct regional* region, struct key_entry_key* key_entry_create_rrset(struct regional* region, uint8_t* name, size_t namelen, uint16_t dclass, - struct ub_packed_rrset_key* rrset) + struct ub_packed_rrset_key* rrset, uint32_t now) { struct key_entry_key* k; struct key_entry_data* d; @@ -245,7 +246,7 @@ key_entry_create_rrset(struct regional* region, rrset->entry.data; if(!key_entry_setup(region, name, namelen, dclass, &k, &d)) return NULL; - d->ttl = rd->ttl + time(NULL); + d->ttl = rd->ttl + now; d->isbad = 0; d->rrset_type = ntohs(rrset->rk.type); d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region, diff --git a/validator/val_kentry.h b/validator/val_kentry.h index 2b0a12f5a..52d65eaa6 100644 --- a/validator/val_kentry.h +++ b/validator/val_kentry.h @@ -145,10 +145,12 @@ int key_entry_isbad(struct key_entry_key* kkey); * @param namelen: length of name * @param dclass: class of key entry. (host order); * @param ttl: what ttl should the key have. relative. + * @param now: current time (added to ttl). * @return new key entry or NULL on alloc failure */ struct key_entry_key* key_entry_create_null(struct regional* region, - uint8_t* name, size_t namelen, uint16_t dclass, uint32_t ttl); + uint8_t* name, size_t namelen, uint16_t dclass, uint32_t ttl, + uint32_t now); /** * Create a key entry from an rrset, in the given region. @@ -157,11 +159,12 @@ struct key_entry_key* key_entry_create_null(struct regional* region, * @param namelen: length of name * @param dclass: class of key entry. (host order); * @param rrset: data for key entry. This is copied to the region. + * @param now: current time (added to ttl of rrset) * @return new key entry or NULL on alloc failure */ struct key_entry_key* key_entry_create_rrset(struct regional* region, uint8_t* name, size_t namelen, uint16_t dclass, - struct ub_packed_rrset_key* rrset); + struct ub_packed_rrset_key* rrset, uint32_t now); /** * Create a bad entry, in the given region. diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 497e5c7a6..f0c9fc4d2 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -408,7 +408,7 @@ int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey) + struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey) { enum sec_status sec; size_t i, num; @@ -420,8 +420,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, return sec_status_bogus; } for(i=0; inow, rrset, + dnskey, i, &sortree); if(sec == sec_status_secure) return sec; } @@ -454,8 +454,8 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, continue; buf_canon = 0; sec = dnskey_verify_rrset_sig(env->scratch, - env->scratch_buffer, ve, rrset, dnskey, dnskey_idx, i, - &sortree, &buf_canon); + env->scratch_buffer, ve, *env->now, rrset, + dnskey, dnskey_idx, i, &sortree, &buf_canon); if(sec == sec_status_secure) return sec; } @@ -464,9 +464,10 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, } enum sec_status -dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, - size_t sig_idx, struct rbtree_t** sortree) +dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, + uint32_t now, struct ub_packed_rrset_key* rrset, + struct ub_packed_rrset_key* dnskey, size_t sig_idx, + struct rbtree_t** sortree) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -486,8 +487,8 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, numchecked ++; /* see if key verifies */ sec = dnskey_verify_rrset_sig(env->scratch, - env->scratch_buffer, ve, rrset, dnskey, i, sig_idx, - sortree, &buf_canon); + env->scratch_buffer, ve, now, rrset, dnskey, i, + sig_idx, sortree, &buf_canon); if(sec == sec_status_secure) return sec; } @@ -1087,7 +1088,8 @@ sigdate_error(const char* str, int32_t expi, int32_t incep, int32_t now) /** check rrsig dates */ static int -check_dates(struct val_env* ve, uint8_t* expi_p, uint8_t* incep_p) +check_dates(struct val_env* ve, uint32_t unow, + uint8_t* expi_p, uint8_t* incep_p) { /* read out the dates */ int32_t expi, incep, now; @@ -1100,7 +1102,7 @@ check_dates(struct val_env* ve, uint8_t* expi_p, uint8_t* incep_p) if(ve->date_override) { now = ve->date_override; verbose(VERB_ALGO, "date override option %d", (int)now); - } else now = (int32_t)time(0); + } else now = (int32_t)unow; /* check them */ if(incep - expi > 0) { @@ -1123,8 +1125,9 @@ check_dates(struct val_env* ve, uint8_t* expi_p, uint8_t* incep_p) /** adjust rrset TTL for verified rrset, compare to original TTL and expi */ static void -adjust_ttl(struct val_env* ve, struct ub_packed_rrset_key* rrset, - uint8_t* orig_p, uint8_t* expi_p, uint8_t* incep_p) +adjust_ttl(struct val_env* ve, uint32_t unow, + struct ub_packed_rrset_key* rrset, uint8_t* orig_p, + uint8_t* expi_p, uint8_t* incep_p) { struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->entry.data; @@ -1140,7 +1143,7 @@ adjust_ttl(struct val_env* ve, struct ub_packed_rrset_key* rrset, /* get current date */ if(ve->date_override) { now = ve->date_override; - } else now = (int32_t)time(0); + } else now = (int32_t)unow; expittl = expi - now; /* so now: @@ -1273,7 +1276,7 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock, enum sec_status dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf, - struct val_env* ve, + struct val_env* ve, uint32_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, size_t sig_idx, struct rbtree_t** sortree, int* buf_canon) @@ -1357,7 +1360,7 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf, /* original ttl, always ok */ /* verify inception, expiration dates */ - if(!check_dates(ve, sig+2+8, sig+2+12)) { + if(!check_dates(ve, now, sig+2+8, sig+2+12)) { return sec_status_bogus; } @@ -1385,7 +1388,7 @@ dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf, /* check if TTL is too high - reduce if so */ if(sec == sec_status_secure) { - adjust_ttl(ve, rrset, sig+2+4, sig+2+8, sig+2+12); + adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12); } return sec; diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index 38a5d9e77..c3525cb67 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -164,6 +164,7 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, * verify rrset, with dnskey rrset, for a specific rrsig in rrset * @param env: module environment, scratch space is used. * @param ve: validator environment, date settings. + * @param now: current time for validation (can be overridden). * @param rrset: to be validated. * @param dnskey: DNSKEY rrset, keyset to try. * @param sig_idx: which signature to try to validate. @@ -173,7 +174,7 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, * or unchecked on error. */ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, - struct val_env* ve, struct ub_packed_rrset_key* rrset, + struct val_env* ve, uint32_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t sig_idx, struct rbtree_t** sortree); @@ -182,6 +183,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, * @param region: scratch region used for temporary allocation. * @param buf: scratch buffer used for canonicalized rrset data. * @param ve: validator environment, date settings. + * @param now: current time for validation (can be overridden). * @param rrset: to be validated. * @param dnskey: DNSKEY rrset, keyset. * @param dnskey_idx: which key from the rrset to try. @@ -195,7 +197,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, * bogus if it did not validate. */ enum sec_status dnskey_verify_rrset_sig(struct regional* region, - ldns_buffer* buf, struct val_env* ve, + ldns_buffer* buf, struct val_env* ve, uint32_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, size_t sig_idx, struct rbtree_t** sortree, int* buf_canon); diff --git a/validator/val_utils.c b/validator/val_utils.c index f95e8014a..1432a715c 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -322,7 +322,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, return d->security; } /* check in the cache if verification has already been done */ - rrset_check_sec_status(env->rrset_cache, rrset); + rrset_check_sec_status(env->rrset_cache, rrset, *env->now); if(d->security == sec_status_secure) { log_nametypeclass(VERB_ALGO, "verify rrset from cache", rrset->rk.dname, ntohs(rrset->rk.type), @@ -349,7 +349,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, * if RRset timed out and clients see proper value. */ } /* if status updated - store in cache for reuse */ - rrset_update_sec_status(env->rrset_cache, rrset); + rrset_update_sec_status(env->rrset_cache, rrset, *env->now); } return sec; @@ -456,7 +456,8 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, verbose(VERB_ALGO, "DS matched DNSKEY."); return key_entry_create_rrset(region, ds_rrset->rk.dname, ds_rrset->rk.dname_len, - ntohs(ds_rrset->rk.rrset_class), dnskey_rrset); + ntohs(ds_rrset->rk.rrset_class), dnskey_rrset, + *env->now); } } @@ -469,7 +470,7 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, return key_entry_create_null(region, ds_rrset->rk.dname, ds_rrset->rk.dname_len, ntohs(ds_rrset->rk.rrset_class), - rrset_get_ttl(ds_rrset)); + rrset_get_ttl(ds_rrset), *env->now); } /* If any were understandable, then it is bad. */ verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY."); @@ -685,7 +686,7 @@ val_check_nonsecure(struct val_env* ve, struct reply_info* rep) void val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors, - struct rrset_cache* r) + struct rrset_cache* r, struct module_env* env) { size_t i; struct packed_rrset_data* d; @@ -698,14 +699,14 @@ val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors, { /* mark as indeterminate */ d->security = sec_status_indeterminate; - rrset_update_sec_status(r, rep->rrsets[i]); + rrset_update_sec_status(r, rep->rrsets[i], *env->now); } } } void val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey, - struct rrset_cache* r) + struct rrset_cache* r, struct module_env* env) { size_t i; struct packed_rrset_data* d; @@ -716,7 +717,7 @@ val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey, dname_subdomain_c(rep->rrsets[i]->rk.dname, kkey->name)) { /* mark as insecure */ d->security = sec_status_insecure; - rrset_update_sec_status(r, rep->rrsets[i]); + rrset_update_sec_status(r, rep->rrsets[i], *env->now); } } } diff --git a/validator/val_utils.h b/validator/val_utils.h index db1a77a67..e56ecb9c2 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -230,9 +230,11 @@ void val_check_nonsecure(struct val_env* ve, struct reply_info* rep); * @param rep: the reply with rrsets. * @param anchors: the trust anchors. * @param r: rrset cache to store updated security status into. + * @param env: module environment */ void val_mark_indeterminate(struct reply_info* rep, - struct val_anchors* anchors, struct rrset_cache* r); + struct val_anchors* anchors, struct rrset_cache* r, + struct module_env* env); /** * Mark all unchecked rrset entries below a NULL key entry as insecure. @@ -241,9 +243,10 @@ void val_mark_indeterminate(struct reply_info* rep, * @param kkey: key entry, key_entry_isnull() for it. A key entry that marks * the end of secure space into insecure space. * @param r: rrset cache to store updated security status into. + * @param env: module environment */ void val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey, - struct rrset_cache* r); + struct rrset_cache* r, struct module_env* env); /** * Find next unchecked rrset position, return it for skip. diff --git a/validator/validator.c b/validator/validator.c index 2e719f562..d352c7f32 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1118,7 +1118,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, } val_mark_indeterminate(vq->chase_reply, qstate->env->anchors, - qstate->env->rrset_cache); + qstate->env->rrset_cache, qstate->env); vq->key_entry = NULL; vq->empty_DS_name = NULL; vq->ds_rrset = 0; @@ -1176,7 +1176,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, } vq->key_entry = key_cache_obtain(ve->kcache, lookup_name, lookup_len, - vq->qchase.qclass, qstate->region); + vq->qchase.qclass, qstate->region, *qstate->env->now); /* if not key, or if keyentry is *above* the trustanchor, i.e. * the keyentry is based on another (higher) trustanchor */ @@ -1196,7 +1196,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, * essentially proven insecure. */ vq->chase_reply->security = sec_status_insecure; val_mark_insecure(vq->chase_reply, vq->key_entry, - qstate->env->rrset_cache); + qstate->env->rrset_cache, qstate->env); /* go to finished state to cache this result */ vq->state = VAL_FINISHED_STATE; return 1; @@ -1357,7 +1357,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, vq->signer_name?"":"unsigned "); vq->chase_reply->security = sec_status_insecure; val_mark_insecure(vq->chase_reply, vq->key_entry, - qstate->env->rrset_cache); + qstate->env->rrset_cache, qstate->env); return 1; } @@ -1538,7 +1538,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, /* if the result is bogus - set message ttl to bogus ttl to avoid * endless bogus revalidation */ if(vq->orig_msg->rep->security == sec_status_bogus) { - vq->orig_msg->rep->ttl = time(0) + ve->bogus_ttl; + vq->orig_msg->rep->ttl = *qstate->env->now + ve->bogus_ttl; /* If we are in permissive mode, bogus gets indeterminate */ if(ve->permissive_mode) vq->orig_msg->rep->security = sec_status_indeterminate; @@ -1692,7 +1692,8 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta, kkey = key_entry_create_bad(qstate->region, ta->name, ta->namelen, ta->dclass); else kkey = key_entry_create_null(qstate->region, ta->name, - ta->namelen, ta->dclass, NULL_KEY_TTL); + ta->namelen, ta->dclass, NULL_KEY_TTL, + *qstate->env->now); if(!kkey) { log_err("out of memory: allocate fail prime key"); return NULL; @@ -1723,7 +1724,7 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta, if(sec == sec_status_secure) { kkey = key_entry_create_rrset(qstate->region, ta->name, ta->namelen, ta->dclass, - dnskey_rrset); + dnskey_rrset, *qstate->env->now); if(!kkey) { log_err("out of memory: allocate primed key"); return NULL; @@ -1741,7 +1742,8 @@ primeResponseToKE(int rcode, struct dns_msg* msg, struct trust_anchor* ta, kkey = key_entry_create_bad(qstate->region, ta->name, ta->namelen, ta->dclass); else kkey = key_entry_create_null(qstate->region, ta->name, - ta->namelen, ta->dclass, NULL_KEY_TTL); + ta->namelen, ta->dclass, NULL_KEY_TTL, + *qstate->env->now); if(!kkey) { log_err("out of memory: allocate null prime key"); return NULL; @@ -1816,14 +1818,15 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, * there was no DS. */ *ke = key_entry_create_null(qstate->region, qinfo->qname, qinfo->qname_len, qinfo->qclass, - ub_packed_rrset_ttl(ds)); + ub_packed_rrset_ttl(ds), *qstate->env->now); return (*ke) != NULL; } /* Otherwise, we return the positive response. */ log_query_info(VERB_DETAIL, "validated DS", qinfo); *ke = key_entry_create_rrset(qstate->region, - qinfo->qname, qinfo->qname_len, qinfo->qclass, ds); + qinfo->qname, qinfo->qname_len, qinfo->qclass, ds, + *qstate->env->now); return (*ke) != NULL; } else if(subtype == VAL_CLASS_NODATA || subtype == VAL_CLASS_NAMEERROR) { @@ -1846,7 +1849,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, "referral proved no DS."); *ke = key_entry_create_null(qstate->region, qinfo->qname, qinfo->qname_len, - qinfo->qclass, proof_ttl); + qinfo->qclass, proof_ttl, + *qstate->env->now); return (*ke) != NULL; case sec_status_insecure: verbose(VERB_DETAIL, "NSEC RRset for the " @@ -1872,7 +1876,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, "referral proved no DS."); *ke = key_entry_create_null(qstate->region, qinfo->qname, qinfo->qname_len, - qinfo->qclass, proof_ttl); + qinfo->qclass, proof_ttl, + *qstate->env->now); return (*ke) != NULL; case sec_status_indeterminate: verbose(VERB_DETAIL, "NSEC3s for the "