/** * Remove NSEC records between start and end points. * By walking the tree, the tree is sorted canonically. * @param neg: negative cache. * @param zone: the zone * @param el: element to start walking at. * @param nsec: the nsec record with the end point */ static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone, struct val_neg_data* el, struct ub_packed_rrset_key* nsec) { struct packed_rrset_data* d = (struct packed_rrset_data*)nsec-> entry.data; uint8_t* end; size_t end_len; int end_labs, m; rbnode_t* walk, *next; struct val_neg_data* cur; uint8_t buf[257]; /* get endpoint */ if(!d || d->count == 0 || d->rr_len[0] < 2+1) return; if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC) { end = d->rr_data[0]+2; end_len = dname_valid(end, d->rr_len[0]-2); end_labs = dname_count_labels(end); } else { /* NSEC3 */ if(!nsec3_get_nextowner_b32(nsec, 0, buf, sizeof(buf))) return; end = buf; end_labs = dname_count_size_labels(end, &end_len); } /* sanity check, both owner and end must be below the zone apex */ if(!dname_subdomain_c(el->name, zone->name) || !dname_subdomain_c(end, zone->name)) return; /* detect end of zone NSEC ; wipe until the end of zone */ if(query_dname_compare(end, zone->name) == 0) { end = NULL; } walk = rbtree_next(&el->node); while(walk && walk != RBTREE_NULL) { cur = (struct val_neg_data*)walk; /* sanity check: must be larger than start */ if(dname_canon_lab_cmp(cur->name, cur->labs, el->name, el->labs, &m) <= 0) { /* r == 0 skip original record. */ /* r < 0 too small! */ walk = rbtree_next(walk); continue; } /* stop at endpoint, also data at empty nonterminals must be * removed (no NSECs there) so everything between * start and end */ if(end && dname_canon_lab_cmp(cur->name, cur->labs, end, end_labs, &m) >= 0) { break; } /* this element has to be deleted, but we cannot do it * now, because we are walking the tree still ... */ /* get the next element: */ next = rbtree_next(walk); /* now delete the original element, this may trigger * rbtree rebalances, but really, the next element is * the one we need. * But it may trigger delete of other data and the * entire zone. However, if that happens, this is done * by deleting the *parents* of the element for deletion, * and maybe also the entire zone if it is empty. * But parents are smaller in canonical compare, thus, * if a larger element exists, then it is not a parent, * it cannot get deleted, the zone cannot get empty. * If the next==NULL, then zone can be empty. */ if(cur->in_use) neg_delete_data(neg, cur); walk = next; } }
/** remove a random item */ static void remove_item(struct val_neg_cache* neg) { int n, i; struct val_neg_data* d; rbnode_t* walk; struct val_neg_zone* z; lock_basic_lock(&neg->lock); if(neg->tree.count == 0) { lock_basic_unlock(&neg->lock); return; /* nothing to delete */ } /* pick a random zone */ walk = rbtree_first(&neg->tree); /* first highest parent, big count */ z = (struct val_neg_zone*)walk; n = random() % (int)(z->count); if(negverbose) printf("neg stress delete zone %d\n", n); i=0; walk = rbtree_first(&neg->tree); z = (struct val_neg_zone*)walk; while(i!=n+1 && walk && walk != RBTREE_NULL && !z->in_use) { walk = rbtree_next(walk); z = (struct val_neg_zone*)walk; if(z->in_use) i++; } if(!walk || walk == RBTREE_NULL) { lock_basic_unlock(&neg->lock); return; } if(!z->in_use) { lock_basic_unlock(&neg->lock); return; } if(negverbose) log_nametypeclass(0, "delete zone", z->name, 0, 0); /* pick a random nsec item. - that is in use */ walk = rbtree_first(&z->tree); /* first is highest parent */ d = (struct val_neg_data*)walk; n = random() % (int)(d->count); if(negverbose) printf("neg stress delete item %d\n", n); i=0; walk = rbtree_first(&z->tree); d = (struct val_neg_data*)walk; while(i!=n+1 && walk && walk != RBTREE_NULL && !d->in_use) { walk = rbtree_next(walk); d = (struct val_neg_data*)walk; if(d->in_use) i++; } if(!walk || walk == RBTREE_NULL) { lock_basic_unlock(&neg->lock); return; } if(d->in_use) { if(negverbose) log_nametypeclass(0, "neg delete item:", d->name, 0, 0); neg_delete_data(neg, d); } lock_basic_unlock(&neg->lock); }