+26 March 2020: Ralph
+ - Fix RPZ concurrency issue when using auth_zone_reload.
+
25 March 2020: George
- Merge PR #201 from noloader: Fix OpenSSL cross-compaile warnings.
- Fix on #201.
int ret = 1;
struct ub_packed_rrset_key* redirect_rrset = NULL;
struct rpz* r;
+ struct auth_zone* a;
struct ub_packed_rrset_key* data = NULL;
int rpz_used = 0;
int rpz_log = 0;
}
if(!raddr && !view->isfirst)
goto done;
+ if(!raddr && view->isfirst) {
+ lock_rw_unlock(&view->lock);
+ view = NULL;
+ }
}
if(!raddr && (raddr = respip_addr_lookup(rep, ipset,
&rrset_id))) {
ipset->tagname, ipset->num_tags);
}
lock_rw_rdlock(&az->rpz_lock);
- for(r = az->rpz_first; r && !raddr; r = r->next) {
+ for(a = az->rpz_first; a && !raddr; a = a->rpz_az_next) {
+ lock_rw_rdlock(&a->lock);
+ r = a->rpz;
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, ctaglist, ctaglen)) {
if((raddr = respip_addr_lookup(rep,
region, &rpz_used)) {
log_err("out of memory");
lock_rw_unlock(&raddr->lock);
+ lock_rw_unlock(&a->lock);
lock_rw_unlock(&az->rpz_lock);
return 0;
}
- if(!rpz_used) {
- lock_rw_unlock(&raddr->lock);
- raddr = NULL;
- actinfo->rpz_disabled++;
+ if(rpz_used) {
+ /* break to make sure 'a' stays pointed
+ * to used auth_zone, and keeps lock */
+ break;
}
+ lock_rw_unlock(&raddr->lock);
+ raddr = NULL;
+ actinfo->rpz_disabled++;
}
- }
+ }
+ lock_rw_unlock(&a->lock);
}
lock_rw_unlock(&az->rpz_lock);
if(raddr && !search_only) {
if(raddr) {
lock_rw_unlock(&raddr->lock);
}
+ if(rpz_used) {
+ lock_rw_unlock(&a->lock);
+ }
return ret;
}
if(az && z->rpz) {
/* keep RPZ linked list intact */
lock_rw_wrlock(&az->rpz_lock);
- if(z->rpz->prev)
- z->rpz->prev->next = z->rpz->next;
+ if(z->rpz_az_prev)
+ z->rpz_az_prev->rpz_az_next = z->rpz_az_next;
else
- az->rpz_first = z->rpz->next;
- if(z->rpz->next)
- z->rpz->next->prev = z->rpz->prev;
+ az->rpz_first = z->rpz_az_next;
+ if(z->rpz_az_next)
+ z->rpz_az_next->rpz_az_prev = z->rpz_az_prev;
lock_rw_unlock(&az->rpz_lock);
}
if(z->rpz)
}
rbtree_init(&z->data, &auth_data_cmp);
lock_rw_init(&z->lock);
- lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type));
+ lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)-
+ sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev));
lock_rw_wrlock(&z->lock);
- /* z lock protects all, except rbtree itself, which is az->lock */
+ /* z lock protects all, except rbtree itself and the rpz linked list
+ * pointers, which are protected using az->lock */
if(!rbtree_insert(&az->ztree, &z->node)) {
lock_rw_unlock(&z->lock);
auth_zone_delete(z, NULL);
fatal_exit("Could not setup RPZ zones");
return 0;
}
+ lock_protect(&z->lock, &z->rpz->local_zones, sizeof(*z->rpz));
lock_rw_wrlock(&az->rpz_lock);
- z->rpz->next = az->rpz_first;
+ z->rpz_az_next = az->rpz_first;
if(az->rpz_first)
- az->rpz_first->prev = z->rpz;
- az->rpz_first = z->rpz;
+ az->rpz_first->rpz_az_prev = z;
+ az->rpz_first = z;
lock_rw_unlock(&az->rpz_lock);
}
size_t num_query_up;
/** number of queries downstream */
size_t num_query_down;
- /** first rpz item in linked list */
- struct rpz* rpz_first;
+ /** first auth zone containing rpz item in linked list */
+ struct auth_zone* rpz_first;
/** rw lock for rpz linked list, needed when iterating or editing linked
* list. */
lock_rw_type rpz_lock;
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
struct auth_zone* delete_next;
+ /* not protected by auth_zone lock, must be last items in struct */
+ /** next auth zone containing RPZ data, or NULL */
+ struct auth_zone* rpz_az_next;
+ /** previous auth zone containing RPZ data, or NULL */
+ struct auth_zone* rpz_az_prev;
};
/**
delete_zone = rpz_data_delete_rr(z, dname,
dnamelen, rr_type, rdatawl, rdatalen);
else if(a != localzone_type_to_rpz_action(z->type)) {
+ lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&r->local_zones->lock);
return;
}
lock_rw_unlock(&z->lock);
struct regional* temp, struct comm_reply* repinfo,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats)
{
- struct rpz* r;
+ struct rpz* r = NULL;
+ struct auth_zone* a;
int ret;
enum localzone_type lzt;
struct local_zone* z = NULL;
struct local_data* ld = NULL;
lock_rw_rdlock(&az->rpz_lock);
- for(r = az->rpz_first; r; r = r->next) {
+ for(a = az->rpz_first; a; a = a->rpz_az_next) {
+ lock_rw_rdlock(&a->lock);
+ r = a->rpz;
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, taglist, taglen)) {
z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len,
}
if(z)
break;
- }
+ }
+ lock_rw_unlock(&a->lock); /* not found in this auth_zone */
}
lock_rw_unlock(&az->rpz_lock);
if(!z)
- return 0;
+ return 0; /* not holding auth_zone.lock anymore */
-
+ log_assert(r);
if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
lzt = z->type;
else
regional_alloc_zero(temp, sizeof(struct local_rrset));
if(!qinfo->local_alias) {
lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
return 0; /* out of memory */
}
qinfo->local_alias->rrset =
sizeof(*r->cname_override));
if(!qinfo->local_alias->rrset) {
lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo, repinfo, r->log_name);
stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
return 0;
}
repinfo, r->log_name);
stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
return !qinfo->local_alias;
}
qinfo, repinfo, r->log_name);
stats->rpz_action[localzone_type_to_rpz_action(lzt)]++;
lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
return ret;
}
/**
* RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
* linked list to keep configuration order. Iterating or changing the linked
- * list requires the rpz_lock from struct auth_zones.
+ * list requires the rpz_lock from struct auth_zones. Changing items in this
+ * struct require the lock from struct auth_zone.
*/
struct rpz {
struct local_zones* local_zones;
struct ub_packed_rrset_key* cname_override;
int log;
char* log_name;
- struct rpz* next;
- struct rpz* prev;
struct regional* region;
};