}
labs = dname_count_size_labels(rr_name, &len);
lock_rw_rdlock(&zones->lock);
- z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
+ z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1);
if(!z) {
lock_rw_unlock(&zones->lock);
fatal_exit("internal error: no zone for rr %s", rr);
labs = dname_count_size_labels(rr_name, &len);
lock_rw_rdlock(&zones->lock);
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
- rr_type)) {
+ rr_type, 1)) {
/* Check if there is a zone that this could go
* under but for different class; created zones are
* always for LDNS_RR_CLASS_IN. Create the zone with
* a different class but the same configured
* local_zone_type. */
struct local_zone* z = local_zones_lookup(zones,
- rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
+ rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type,
+ 1);
if(z) {
uint8_t* name = memdup(z->name, z->namelen);
size_t znamelen = z->namelen;
struct local_zone*
local_zones_lookup(struct local_zones* zones,
- uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype)
+ uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
+ int foradd)
{
return local_zones_tags_lookup(zones, name, len, labs,
- dclass, dtype, NULL, 0, 1);
+ dclass, dtype, NULL, 0, 1, foradd);
}
struct local_zone*
local_zones_tags_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
- uint8_t* taglist, size_t taglen, int ignoretags)
+ uint8_t* taglist, size_t taglen, int ignoretags, int foradd)
{
rbnode_type* res = NULL;
struct local_zone *result;
struct local_zone key;
int m;
+ key.node.key = &key;
+ key.dclass = dclass;
/* for type DS use a zone higher when on a zonecut */
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
- dname_remove_label(&name, &len);
- labs--;
+ /* If this is at a zone cut, of a local-zone, and it is
+ * of type always_refuse. Then also refuse the type DS
+ * for it. That could make it DNSSEC bogus, but it is
+ * REFUSED anyway. It stops CNAME type answers in the
+ * type DS lookup. */
+ key.name = name;
+ key.namelen = len;
+ key.namelabs = labs;
+ /* For additions and removals, use the ordinary rule,
+ * to remove a label for type DS to locate the parent zone.
+ * That is where the DS RR needs to be put. */
+ if(!foradd &&
+ (result=(struct local_zone*)rbtree_search(
+ &zones->ztree, &key)) != NULL &&
+ result->type == local_zone_always_refuse) {
+ /* The type DS does not go up one label. */
+ return result;
+ } else {
+ dname_remove_label(&name, &len);
+ labs--;
+ }
}
- key.node.key = &key;
- key.dclass = dclass;
key.name = name;
key.namelen = len;
key.namelabs = labs;
if(view->local_zones &&
(z = local_zones_lookup(view->local_zones,
qinfo->qname, qinfo->qname_len, labs,
- qinfo->qclass, qinfo->qtype))) {
+ qinfo->qclass, qinfo->qtype, 0))) {
lock_rw_rdlock(&z->lock);
lzt = z->type;
}
lock_rw_rdlock(&zones->lock);
if(!(z = local_zones_tags_lookup(zones, qinfo->qname,
qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype,
- taglist, taglen, 0))) {
+ taglist, taglen, 0, 0))) {
lock_rw_unlock(&zones->lock);
return 0;
}
/* could first try readlock then get writelock if zone does not exist,
* but we do not add enough RRs (from multiple threads) to optimize */
lock_rw_wrlock(&zones->lock);
- z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
+ z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type,
+ 1);
if(!z) {
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
local_zone_transparent);
/* remove DS */
lock_rw_rdlock(&zones->lock);
- z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
+ z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS,
+ 1);
if(z) {
lock_rw_wrlock(&z->lock);
d = local_zone_find_data(z, name, len, labs);
/* remove other types */
lock_rw_rdlock(&zones->lock);
- z = local_zones_lookup(zones, name, len, labs, dclass, 0);
+ z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1);
if(!z) {
/* no such zone, we're done */
lock_rw_unlock(&zones->lock);
* @param taglen: length of taglist.
* @param ignoretags: lookup zone by name and class, regardless the
* local-zone's tags.
+ * @param foradd: if the lookup is for addition or removal of the type.
+ * Used for type DS. The lookup for answers turns this off.
* @return closest local_zone or NULL if no covering zone is found.
*/
struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
- uint8_t* taglist, size_t taglen, int ignoretags);
+ uint8_t* taglist, size_t taglen, int ignoretags, int foradd);
/**
* Lookup zone that contains the given name, class.
* @param dclass: class to lookup.
* @param dtype: type of the record, if type DS then a zone higher up is found
* pass 0 to just plain find a zone for a name.
+ * @param foradd: if the lookup is for addition or removal of the type.
+ * Used for type DS. The lookup for answers turns this off.
* @return closest local_zone or NULL if no covering zone is found.
*/
struct local_zone* local_zones_lookup(struct local_zones* zones,
- uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype);
+ uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
+ int foradd);
/**
* Debug helper. Print all zones