diff options
Diffstat (limited to 'contrib/unbound/services/authzone.c')
-rw-r--r-- | contrib/unbound/services/authzone.c | 90 |
1 files changed, 56 insertions, 34 deletions
diff --git a/contrib/unbound/services/authzone.c b/contrib/unbound/services/authzone.c index 3c3dc9ad05d9..60ccc8698748 100644 --- a/contrib/unbound/services/authzone.c +++ b/contrib/unbound/services/authzone.c @@ -2413,14 +2413,12 @@ az_find_wildcard(struct auth_zone* z, struct query_info* qinfo, if(!dname_subdomain_c(nm, z->name)) return NULL; /* out of zone */ while((node=az_find_wildcard_domain(z, nm, nmlen))==NULL) { - /* see if we can go up to find the wildcard */ if(nmlen == z->namelen) return NULL; /* top of zone reached */ if(ce && nmlen == ce->namelen) return NULL; /* ce reached */ - if(dname_is_root(nm)) - return NULL; /* cannot go up */ - dname_remove_label(&nm, &nmlen); + if(!dname_remove_label_limit_len(&nm, &nmlen, z->namelen)) + return NULL; /* can't go up */ } return node; } @@ -2442,9 +2440,8 @@ az_find_candidate_ce(struct auth_zone* z, struct query_info* qinfo, n = az_find_name(z, nm, nmlen); /* delete labels and go up on name */ while(!n) { - if(dname_is_root(nm)) - return NULL; /* cannot go up */ - dname_remove_label(&nm, &nmlen); + if(!dname_remove_label_limit_len(&nm, &nmlen, z->namelen)) + return NULL; /* can't go up */ n = az_find_name(z, nm, nmlen); } return n; @@ -2456,8 +2453,7 @@ az_domain_go_up(struct auth_zone* z, struct auth_data* n) { uint8_t* nm = n->name; size_t nmlen = n->namelen; - while(!dname_is_root(nm)) { - dname_remove_label(&nm, &nmlen); + while(dname_remove_label_limit_len(&nm, &nmlen, z->namelen)) { if((n=az_find_name(z, nm, nmlen)) != NULL) return n; } @@ -2771,26 +2767,23 @@ az_change_dnames(struct dns_msg* msg, uint8_t* oldname, uint8_t* newname, } } -/** find NSEC record covering the query */ +/** find NSEC record covering the query, with the given node in the zone */ static struct auth_rrset* az_find_nsec_cover(struct auth_zone* z, struct auth_data** node) { - uint8_t* nm = (*node)->name; - size_t nmlen = (*node)->namelen; + uint8_t* nm; + size_t nmlen; struct auth_rrset* rrset; + log_assert(*node); /* we already have a node when calling this */ + nm = (*node)->name; + nmlen = (*node)->namelen; /* find the NSEC for the smallest-or-equal node */ - /* if node == NULL, we did not find a smaller name. But the zone - * name is the smallest name and should have an NSEC. So there is - * no NSEC to return (for a properly signed zone) */ - /* for empty nonterminals, the auth-data node should not exist, - * and thus we don't need to go rbtree_previous here to find - * a domain with an NSEC record */ - /* but there could be glue, and if this is node, then it has no NSEC. + /* But there could be glue, and then it has no NSEC. * Go up to find nonglue (previous) NSEC-holding nodes */ while((rrset=az_domain_rrset(*node, LDNS_RR_TYPE_NSEC)) == NULL) { - if(dname_is_root(nm)) return NULL; if(nmlen == z->namelen) return NULL; - dname_remove_label(&nm, &nmlen); + if(!dname_remove_label_limit_len(&nm, &nmlen, z->namelen)) + return NULL; /* can't go up */ /* adjust *node for the nsec rrset to find in */ *node = az_find_name(z, nm, nmlen); } @@ -3018,12 +3011,9 @@ az_nsec3_find_ce(struct auth_zone* z, uint8_t** cenm, size_t* cenmlen, struct auth_data* node; while((node = az_nsec3_find_exact(z, *cenm, *cenmlen, algo, iter, salt, saltlen)) == NULL) { - if(*cenmlen == z->namelen) { - /* next step up would take us out of the zone. fail */ - return NULL; - } + if(!dname_remove_label_limit_len(cenm, cenmlen, z->namelen)) + return NULL; /* can't go up */ *no_exact_ce = 1; - dname_remove_label(cenm, cenmlen); } return node; } @@ -3340,7 +3330,8 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo, } else if(ce) { uint8_t* wildup = wildcard->name; size_t wilduplen= wildcard->namelen; - dname_remove_label(&wildup, &wilduplen); + if(!dname_remove_label_limit_len(&wildup, &wilduplen, z->namelen)) + return 0; /* can't go up */ if(!az_add_nsec3_proof(z, region, msg, wildup, wilduplen, msg->qinfo.qname, msg->qinfo.qname_len, 0, insert_ce, 1, 0)) @@ -3399,7 +3390,7 @@ az_generate_answer_with_node(struct auth_zone* z, struct query_info* qinfo, } /** Generate answer without an existing-node that we can use. - * So it'll be a referral, DNAME or nxdomain */ + * So it'll be a referral, DNAME, notype, wildcard or nxdomain */ static int az_generate_answer_nonexistnode(struct auth_zone* z, struct query_info* qinfo, struct regional* region, struct dns_msg* msg, struct auth_data* ce, @@ -3565,14 +3556,17 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, sldns_buffer_read_u16_at(buf, 2), edns); } -int auth_zones_answer(struct auth_zones* az, struct module_env* env, +int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env, struct query_info* qinfo, struct edns_data* edns, - struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp) + struct comm_reply* repinfo, struct sldns_buffer* buf, + struct regional* temp) { struct dns_msg* msg = NULL; struct auth_zone* z; int r; int fallback = 0; + /* Copy the qinfo in case of cname aliasing from local-zone */ + struct query_info zqinfo = *qinfo; lock_rw_rdlock(&az->lock); if(!az->have_downstream) { @@ -3580,6 +3574,7 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, lock_rw_unlock(&az->lock); return 0; } + if(qinfo->qtype == LDNS_RR_TYPE_DS) { uint8_t* delname = qinfo->qname; size_t delnamelen = qinfo->qname_len; @@ -3587,8 +3582,14 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, z = auth_zones_find_zone(az, delname, delnamelen, qinfo->qclass); } else { - z = auth_zones_find_zone(az, qinfo->qname, qinfo->qname_len, - qinfo->qclass); + if(zqinfo.local_alias && !local_alias_shallow_copy_qname( + zqinfo.local_alias, &zqinfo.qname, + &zqinfo.qname_len)) { + lock_rw_unlock(&az->lock); + return 0; + } + z = auth_zones_find_zone(az, zqinfo.qname, zqinfo.qname_len, + zqinfo.qclass); } if(!z) { /* no zone above it */ @@ -3614,7 +3615,7 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, } /* answer it from zone z */ - r = auth_zone_generate_answer(z, qinfo, temp, &msg, &fallback); + r = auth_zone_generate_answer(z, &zqinfo, temp, &msg, &fallback); lock_rw_unlock(&z->lock); if(!r && fallback) { /* fallback to regular answering (recursive) */ @@ -5023,6 +5024,7 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z, xfr->have_zone = 0; xfr->serial = 0; + xfr->soa_zone_acquired = 0; /* insert all RRs in to the zone */ /* insert the SOA only once, skip the last one */ @@ -5124,6 +5126,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z, xfr->have_zone = 0; xfr->serial = 0; + xfr->soa_zone_acquired = 0; chunk = xfr->task_transfer->chunks_first; chunk_pos = 0; @@ -5334,6 +5337,8 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env, " (or malformed RR)", xfr->task_transfer->master->host); return 0; } + z->soa_zone_acquired = *env->now; + xfr->soa_zone_acquired = *env->now; /* release xfr lock while verifying zonemd because it may have * to spawn lookups in the state machines */ @@ -7003,13 +7008,23 @@ xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env, comm_timer_set(xfr->task_nextprobe->timer, &tv); } +void auth_zone_pickup_initial_zone(struct auth_zone* z, struct module_env* env) +{ + /* Set the time, because we now have timestamp in env, + * (not earlier during startup and apply_cfg), and this + * notes the start time when the data was acquired. */ + z->soa_zone_acquired = *env->now; +} + void auth_xfer_pickup_initial_zone(struct auth_xfer* x, struct module_env* env) { /* set lease_time, because we now have timestamp in env, * (not earlier during startup and apply_cfg), and this * notes the start time when the data was acquired */ - if(x->have_zone) + if(x->have_zone) { x->lease_time = *env->now; + x->soa_zone_acquired = *env->now; + } if(x->task_nextprobe && x->task_nextprobe->worker == NULL) { xfr_set_timeout(x, env, 0, 1); } @@ -7020,7 +7035,13 @@ void auth_xfer_pickup_initial(struct auth_zones* az, struct module_env* env) { struct auth_xfer* x; + struct auth_zone* z; lock_rw_wrlock(&az->lock); + RBTREE_FOR(z, struct auth_zone*, &az->ztree) { + lock_rw_wrlock(&z->lock); + auth_zone_pickup_initial_zone(z, env); + lock_rw_unlock(&z->lock); + } RBTREE_FOR(x, struct auth_xfer*, &az->xtree) { lock_basic_lock(&x->lock); auth_xfer_pickup_initial_zone(x, env); @@ -7105,6 +7126,7 @@ auth_xfer_new(struct auth_zone* z) lock_protect(&xfr->lock, &xfr->notify_serial, sizeof(xfr->notify_serial)); lock_protect(&xfr->lock, &xfr->zone_expired, sizeof(xfr->zone_expired)); lock_protect(&xfr->lock, &xfr->have_zone, sizeof(xfr->have_zone)); + lock_protect(&xfr->lock, &xfr->soa_zone_acquired, sizeof(xfr->soa_zone_acquired)); lock_protect(&xfr->lock, &xfr->serial, sizeof(xfr->serial)); lock_protect(&xfr->lock, &xfr->retry, sizeof(xfr->retry)); lock_protect(&xfr->lock, &xfr->refresh, sizeof(xfr->refresh)); |