aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/services/authzone.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/services/authzone.c')
-rw-r--r--contrib/unbound/services/authzone.c90
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));