From 632c1e83f8fe0a9103fa5862dbee3306e837d2e1 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Tue, 23 May 2017 15:36:17 +0000 Subject: [PATCH] save about 90 bytes per rrset and fix NSEC cover finding. git-svn-id: file:///svn/unbound/trunk@4188 be551aaa-1e26-0410-a405-d3ace91eadb9 --- services/authzone.c | 366 +++++++++++++++++++++++--------------------- services/authzone.h | 6 +- 2 files changed, 195 insertions(+), 177 deletions(-) diff --git a/services/authzone.c b/services/authzone.c index d33dfe60b..a63b86126 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -121,6 +121,23 @@ get_rrset_ttl(struct ub_packed_rrset_key* k) return d->ttl; } +/** Copy rrset into region from domain-datanode and packet rrset */ +static struct ub_packed_rrset_key* +auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node, + struct auth_rrset* rrset, struct regional* region, time_t adjust) +{ + struct ub_packed_rrset_key key; + memset(&key, 0, sizeof(key)); + key.entry.key = &key; + key.entry.data = rrset->data; + key.rk.dname = node->name; + key.rk.dname_len = node->namelen; + key.rk.type = htons(rrset->type); + key.rk.rrset_class = htons(z->dclass); + key.entry.hash = rrset_key_hash(&key.rk); + return packed_rrset_copy_region(&key, region, adjust); +} + /** fix up msg->rep TTL and prefetch ttl */ static void msg_ttl(struct dns_msg* msg) @@ -139,8 +156,8 @@ msg_ttl(struct dns_msg* msg) /** add rrset to answer section (no auth, add rrsets yet) */ static int -msg_add_rrset_an(struct regional* region, struct dns_msg* msg, - struct auth_rrset* rrset) +msg_add_rrset_an(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) { log_assert(msg->rep->ns_numrrsets == 0); log_assert(msg->rep->ar_numrrsets == 0); @@ -151,7 +168,7 @@ msg_add_rrset_an(struct regional* region, struct dns_msg* msg, return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - packed_rrset_copy_region(rrset->rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) return 0; msg->rep->rrset_count++; msg->rep->an_numrrsets++; @@ -161,8 +178,8 @@ msg_add_rrset_an(struct regional* region, struct dns_msg* msg, /** add rrset to authority section (no additonal section rrsets yet) */ static int -msg_add_rrset_ns(struct regional* region, struct dns_msg* msg, - struct auth_rrset* rrset) +msg_add_rrset_ns(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) { log_assert(msg->rep->ar_numrrsets == 0); if(!rrset) @@ -172,7 +189,7 @@ msg_add_rrset_ns(struct regional* region, struct dns_msg* msg, return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - packed_rrset_copy_region(rrset->rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) return 0; msg->rep->rrset_count++; msg->rep->ns_numrrsets++; @@ -182,8 +199,8 @@ msg_add_rrset_ns(struct regional* region, struct dns_msg* msg, /** add rrset to additional section */ static int -msg_add_rrset_ar(struct regional* region, struct dns_msg* msg, - struct auth_rrset* rrset) +msg_add_rrset_ar(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) { if(!rrset) return 1; @@ -192,7 +209,7 @@ msg_add_rrset_ar(struct regional* region, struct dns_msg* msg, return 0; /* copy it */ if(!(msg->rep->rrsets[msg->rep->rrset_count] = - packed_rrset_copy_region(rrset->rrset, region, 0))) + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) return 0; msg->rep->rrset_count++; msg->rep->ar_numrrsets++; @@ -246,9 +263,7 @@ static void auth_rrset_delete(struct auth_rrset* rrset) { if(!rrset) return; - free(rrset->rrset->entry.data); /* struct packed_rrset_data */ - free(rrset->rrset->rk.dname); - free(rrset->rrset); /* struct ub_packed_rrset_key */ + free(rrset->data); free(rrset); } @@ -486,13 +501,6 @@ az_domain_find_or_create(struct auth_zone* z, uint8_t* dname, return n; } -/** return rr type of rrset */ -static uint16_t -az_rrset_type(struct auth_rrset* entry) -{ - return ntohs(entry->rrset->rk.type); -} - /** find rrset of given type in the domain */ static struct auth_rrset* az_domain_rrset(struct auth_data* n, uint16_t t) @@ -501,7 +509,7 @@ az_domain_rrset(struct auth_data* n, uint16_t t) if(!n) return NULL; rrset = n->rrsets; while(rrset) { - if(az_rrset_type(rrset) == t) + if(rrset->type == t) return rrset; rrset = rrset->next; } @@ -517,7 +525,7 @@ domain_remove_rrset(struct auth_data* node, uint16_t rr_type) prev = NULL; rrset = node->rrsets; while(rrset) { - if(az_rrset_type(rrset) == rr_type) { + if(rrset->type == rr_type) { /* found it, now delete it */ if(prev) prev->next = rrset->next; else node->rrsets = rrset->next; @@ -531,10 +539,8 @@ domain_remove_rrset(struct auth_data* node, uint16_t rr_type) /** see if rdata is duplicate */ static int -rdata_duplicate(struct ub_packed_rrset_key* k, uint8_t* rdata, size_t len) +rdata_duplicate(struct packed_rrset_data* d, uint8_t* rdata, size_t len) { - struct packed_rrset_data* d = (struct packed_rrset_data*) - k->entry.data; size_t i; for(i=0; icount + d->rrsig_count; i++) { if(d->rr_len[i] != len) @@ -564,9 +570,7 @@ static int rrset_add_rr(struct auth_rrset* rrset, uint32_t rr_ttl, uint8_t* rdata, size_t rdatalen, int insert_sig) { - struct packed_rrset_data* old = (struct packed_rrset_data*)rrset-> - rrset->entry.data; - struct packed_rrset_data* d; + struct packed_rrset_data* d, *old = rrset->data; size_t total, old_total; d = (struct packed_rrset_data*)calloc(1, packed_rrset_sizeof(old) @@ -626,7 +630,7 @@ rrset_add_rr(struct auth_rrset* rrset, uint32_t rr_ttl, uint8_t* rdata, memmove(d->rr_data[total-1], rdata, rdatalen); } - rrset->rrset->entry.data = d; + rrset->data = d; free(old); return 1; } @@ -634,51 +638,28 @@ rrset_add_rr(struct auth_rrset* rrset, uint32_t rr_ttl, uint8_t* rdata, /** Create new rrset for node with packed rrset with one RR element */ static struct auth_rrset* rrset_create(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl, - uint8_t* rdata, size_t rdatalen, uint16_t dclass) + uint8_t* rdata, size_t rdatalen) { struct auth_rrset* rrset = (struct auth_rrset*)calloc(1, sizeof(*rrset)); struct auth_rrset* p, *prev; - struct ub_packed_rrset_key* k; struct packed_rrset_data* d; if(!rrset) { log_err("out of memory"); return NULL; } - - /* the rrset key structure */ - k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k)); - if(!k) { - free(rrset); - log_err("out of memory"); - return NULL; - } - rrset->rrset = k; - k->entry.key = k; - k->rk.dname = memdup(node->name, node->namelen); - if(!k->rk.dname) { - free(rrset); - free(k); - log_err("out of memory"); - return NULL; - } - k->rk.dname_len = node->namelen; - k->rk.type = htons(rr_type); - k->rk.rrset_class = htons(dclass); - k->entry.hash = rrset_key_hash(&k->rk); + rrset->type = rr_type; /* the rrset data structure, with one RR */ d = (struct packed_rrset_data*)calloc(1, sizeof(struct packed_rrset_data) + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t) + rdatalen); if(!d) { - free(k->rk.dname); - free(k); free(rrset); log_err("out of memory"); return NULL; } - k->entry.data = d; + rrset->data = d; d->ttl = rr_ttl; d->trust = rrset_trust_prim_noglue; d->rr_len = (size_t*)((uint8_t*)d + sizeof(struct packed_rrset_data)); @@ -696,7 +677,7 @@ rrset_create(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl, /* find sorted place to link the rrset into the list */ prev = NULL; p = node->rrsets; - while(p && az_rrset_type(p)<=rr_type) { + while(p && p->type<=rr_type) { prev = p; p = p->next; } @@ -711,11 +692,10 @@ rrset_create(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl, static size_t rrsig_num_that_cover(struct auth_rrset* rrsig, uint16_t rr_type, size_t* sigsz) { - struct packed_rrset_data* d = (struct packed_rrset_data*)rrsig-> - rrset->entry.data; + struct packed_rrset_data* d = rrsig->data; size_t i, num = 0; *sigsz = 0; - log_assert(d && az_rrset_type(rrsig) == LDNS_RR_TYPE_RRSIG); + log_assert(d && rrsig->type == LDNS_RR_TYPE_RRSIG); for(i=0; icount+d->rrsig_count; i++) { if(rrsig_rdata_get_type_covered(d->rr_data[i], d->rr_len[i]) == rr_type) { @@ -732,14 +712,12 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, struct auth_rrset* rrset, struct auth_rrset* rrsig) { size_t sigs, sigsz, i, j, total; - struct packed_rrset_data* sigold = (struct packed_rrset_data*)rrsig-> - rrset->entry.data; - struct packed_rrset_data* old = (struct packed_rrset_data*)rrset-> - rrset->entry.data; + struct packed_rrset_data* sigold = rrsig->data; + struct packed_rrset_data* old = rrset->data; struct packed_rrset_data* d, *sigd; - log_assert(az_rrset_type(rrset) == rr_type); - log_assert(az_rrset_type(rrsig) == LDNS_RR_TYPE_RRSIG); + log_assert(rrset->type == rr_type); + log_assert(rrsig->type == LDNS_RR_TYPE_RRSIG); sigs = rrsig_num_that_cover(rrsig, rr_type, &sigsz); if(sigs == 0) { /* 0 rrsigs to move over, done */ @@ -801,7 +779,7 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, } /* put it in and deallocate the old rrset */ - rrset->rrset->entry.data = d; + rrset->data = d; free(old); /* now make rrsig set smaller */ @@ -856,7 +834,7 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, } /* put it in and deallocate the old rrset */ - rrsig->rrset->entry.data = sigd; + rrsig->data = sigd; free(sigold); return 1; @@ -865,8 +843,8 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, /** Add rr to node, ignores duplicate RRs, * rdata points to buffer with rdatalen octets, starts with 2bytelength. */ static int -az_domain_add_rr(struct auth_zone* z, struct auth_data* node, - uint16_t rr_type, uint32_t rr_ttl, uint8_t* rdata, size_t rdatalen) +az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl, + uint8_t* rdata, size_t rdatalen) { struct auth_rrset* rrset; /* packed rrsets have their rrsigs along with them, sort them out */ @@ -875,27 +853,27 @@ az_domain_add_rr(struct auth_zone* z, struct auth_data* node, if((rrset=az_domain_rrset(node, ctype))!= NULL) { /* a node of the correct type exists, add the RRSIG * to the rrset of the covered data type */ - if(rdata_duplicate(rrset->rrset, rdata, rdatalen)) + if(rdata_duplicate(rrset->data, rdata, rdatalen)) return 1; if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 1)) return 0; } else if((rrset=az_domain_rrset(node, rr_type))!= NULL) { /* add RRSIG to rrset of type RRSIG */ - if(rdata_duplicate(rrset->rrset, rdata, rdatalen)) + if(rdata_duplicate(rrset->data, rdata, rdatalen)) return 1; if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 0)) return 0; } else { /* create rrset of type RRSIG */ if(!rrset_create(node, rr_type, rr_ttl, rdata, - rdatalen, z->dclass)) + rdatalen)) return 0; } } else { /* normal RR type */ if((rrset=az_domain_rrset(node, rr_type))!= NULL) { /* add data to existing node with data type */ - if(rdata_duplicate(rrset->rrset, rdata, rdatalen)) + if(rdata_duplicate(rrset->data, rdata, rdatalen)) return 1; if(!rrset_add_rr(rrset, rr_ttl, rdata, rdatalen, 0)) return 0; @@ -903,7 +881,7 @@ az_domain_add_rr(struct auth_zone* z, struct auth_data* node, struct auth_rrset* rrsig; /* create new node with data type */ if(!(rrset=rrset_create(node, rr_type, rr_ttl, rdata, - rdatalen, z->dclass))) + rdatalen))) return 0; /* see if node of type RRSIG has signatures that @@ -943,7 +921,7 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len, log_err("cannot create domain"); return 0; } - if(!az_domain_add_rr(z, node, rr_type, rr_ttl, rdata, rdatalen)) { + if(!az_domain_add_rr(node, rr_type, rr_ttl, rdata, rdatalen)) { log_err("cannot add RR to domain"); return 0; } @@ -1093,14 +1071,21 @@ write_out(FILE* out, const char* str) /** write rrset to file */ static int -auth_zone_write_rrset(struct auth_rrset* r, FILE* out) +auth_zone_write_rrset(struct auth_zone* z, struct auth_data* node, + struct auth_rrset* r, FILE* out) { - size_t i, count = ((struct packed_rrset_data*)r->rrset->entry.data) - ->count +((struct packed_rrset_data*)r->rrset->entry.data) - ->rrsig_count; + size_t i, count = r->data->count + r->data->rrsig_count; char buf[LDNS_RR_BUF_SIZE]; for(i=0; irrset, i, 0, buf, sizeof(buf))) { + struct ub_packed_rrset_key key; + memset(&key, 0, sizeof(key)); + key.entry.key = &key; + key.entry.data = r->data; + key.rk.dname = node->name; + key.rk.dname_len = node->namelen; + key.rk.type = htons(r->type); + key.rk.rrset_class = htons(z->dclass); + if(!packed_rr_to_string(&key, i, 0, buf, sizeof(buf))) { verbose(VERB_ALGO, "failed to rr2str rr %d", (int)i); continue; } @@ -1119,16 +1104,16 @@ auth_zone_write_domain(struct auth_zone* z, struct auth_data* n, FILE* out) if(z->namelen == n->namelen) { struct auth_rrset* soa = az_domain_rrset(n, LDNS_RR_TYPE_SOA); if(soa) { - if(!auth_zone_write_rrset(soa, out)) + if(!auth_zone_write_rrset(z, n, soa, out)) return 0; } } /* write all the RRsets for this domain */ for(r = n->rrsets; r; r = r->next) { if(z->namelen == n->namelen && - az_rrset_type(r) == LDNS_RR_TYPE_SOA) + r->type == LDNS_RR_TYPE_SOA) continue; /* skip SOA here */ - if(!auth_zone_write_rrset(r, out)) + if(!auth_zone_write_rrset(z, n, r, out)) return 0; } return 1; @@ -1258,9 +1243,9 @@ domain_has_only_nsec3(struct auth_data* n) struct auth_rrset* rrset = n->rrsets; int nsec3_seen = 0; while(rrset) { - if(az_rrset_type(rrset) == LDNS_RR_TYPE_NSEC3) { + if(rrset->type == LDNS_RR_TYPE_NSEC3) { nsec3_seen = 1; - } else if(az_rrset_type(rrset) != LDNS_RR_TYPE_RRSIG) { + } else if(rrset->type != LDNS_RR_TYPE_RRSIG) { return 0; } rrset = rrset->next; @@ -1419,8 +1404,7 @@ static int az_add_additionals_from(struct auth_zone* z, struct regional* region, struct dns_msg* msg, struct auth_rrset* rrset, size_t offset) { - struct packed_rrset_data* d = (struct packed_rrset_data*) - rrset->rrset->entry.data; + struct packed_rrset_data* d = rrset->data; size_t i; if(!d) return 0; for(i=0; icount; i++) { @@ -1436,27 +1420,17 @@ az_add_additionals_from(struct auth_zone* z, struct regional* region, if(!domain) continue; if((ref=az_domain_rrset(domain, LDNS_RR_TYPE_A)) != NULL) { - if(!msg_add_rrset_ar(region, msg, ref)) + if(!msg_add_rrset_ar(z, region, msg, domain, ref)) return 0; } if((ref=az_domain_rrset(domain, LDNS_RR_TYPE_AAAA)) != NULL) { - if(!msg_add_rrset_ar(region, msg, ref)) + if(!msg_add_rrset_ar(z, region, msg, domain, ref)) return 0; } } return 1; } -/** find SOA rrset (if any) for this zone */ -static struct auth_rrset* -az_find_soa(struct auth_zone* z) -{ - struct auth_data* node = az_find_name(z, z->name, z->namelen); - if(!node) - return NULL; - return az_domain_rrset(node, LDNS_RR_TYPE_SOA); -} - /** add negative SOA record (with negative TTL) */ static int az_add_negative_soa(struct auth_zone* z, struct regional* region, @@ -1465,12 +1439,15 @@ az_add_negative_soa(struct auth_zone* z, struct regional* region, uint32_t minimum; struct packed_rrset_data* d; struct auth_rrset* soa; - if(!(soa = az_find_soa(z))) return 0; + struct auth_data* apex = az_find_name(z, z->name, z->namelen); + if(!apex) return 0; + soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA); + if(!soa) return 0; /* must be first to put in message; we want to fix the TTL with * one RRset here, otherwise we'd need to loop over the RRs to get * the resulting lower TTL */ log_assert(msg->rep->rrset_count == 0); - if(!msg_add_rrset_ns(region, msg, soa)) return 0; + if(!msg_add_rrset_ns(z, region, msg, apex, soa)) return 0; /* fixup TTL */ d = (struct packed_rrset_data*)msg->rep->rrsets[msg->rep->rrset_count-1]->entry.data; /* last 4 bytes are minimum ttl in network format */ @@ -1538,20 +1515,27 @@ synth_cname_buf(uint8_t* qname, size_t qname_len, size_t dname_len, * false on alloc failure, cname==NULL when name too long. */ static int create_synth_cname(struct query_info* qinfo, struct regional* region, - struct ub_packed_rrset_key* dname, struct ub_packed_rrset_key** cname) + struct auth_data* node, struct auth_rrset* dname, uint16_t dclass, + struct ub_packed_rrset_key** cname) { uint8_t buf[LDNS_MAX_DOMAINLEN]; uint8_t* dtarg; size_t dtarglen, newlen; struct packed_rrset_data* d; + + /* get DNAME target name */ + if(dname->data->count < 1) return 0; + if(dname->data->rr_len[0] < 3) return 0; /* at least rdatalen +1 */ + dtarg = dname->data->rr_data[0]+2; + dtarglen = dname->data->rr_len[0]-2; + if(sldns_read_uint16(dname->data->rr_data[0]) != dtarglen) + return 0; /* rdatalen in DNAME rdata is malformed */ + if(dname_valid(dtarg, dtarglen) != dtarglen) + return 0; /* DNAME RR has malformed rdata */ + /* synthesize a CNAME */ - get_cname_target(dname, &dtarg, &dtarglen); - if(!dtarg) { - /* DNAME RR has malformed rdata */ - return 0; - } newlen = synth_cname_buf(qinfo->qname, qinfo->qname_len, - dname->rk.dname_len, dtarg, dtarglen, buf, sizeof(buf)); + node->namelen, dtarg, dtarglen, buf, sizeof(buf)); if(newlen == 0) { /* YXDOMAIN error */ *cname = NULL; @@ -1564,7 +1548,7 @@ create_synth_cname(struct query_info* qinfo, struct regional* region, memset(&(*cname)->entry, 0, sizeof((*cname)->entry)); (*cname)->entry.key = (*cname); (*cname)->rk.type = htons(LDNS_RR_TYPE_CNAME); - (*cname)->rk.rrset_class = dname->rk.rrset_class; + (*cname)->rk.rrset_class = htons(dclass); (*cname)->rk.flags = 0; (*cname)->rk.dname = regional_alloc_init(region, qinfo->qname, qinfo->qname_len); @@ -1611,22 +1595,28 @@ az_change_dnames(struct dns_msg* msg, uint8_t* oldname, uint8_t* newname, /** find NSEC record covering the query */ static struct auth_rrset* -az_find_nsec_cover(struct auth_zone* z, struct auth_data* node) +az_find_nsec_cover(struct auth_zone* z, struct auth_data** node) { + uint8_t* nm = (*node)->name; + size_t nmlen = (*node)->namelen; struct auth_rrset* rrset; - /* either the NSEC for the smallest-or-equal node */ - if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_NSEC)) != NULL) - return rrset; - /* or node == NULL, we did not find any smaller name, but the last - * name NSEC wraps around, find the last NSEC in the zone */ - if(node == NULL) { - struct auth_data* last = (struct auth_data*)rbtree_last( - &z->data); - if(!last || (rbnode_type*)last == RBTREE_NULL) - return NULL; - return az_domain_rrset(last, LDNS_RR_TYPE_NSEC); + /* 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. + * 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); + /* adjust *node for the nsec rrset to find in */ + *node = az_find_name(z, nm, nmlen); } - return NULL; + return rrset; } /** Find NSEC and add for wildcard denial */ @@ -1652,8 +1642,8 @@ az_nsec_wildcard_denial(struct auth_zone* z, struct regional* region, qinfo.qtype = 0; qinfo.qclass = 0; az_find_domain(z, &qinfo, &node_exact, &node); - if((nsec=az_find_nsec_cover(z, node)) != NULL) { - if(!msg_add_rrset_ns(region, msg, nsec)) return 0; + if((nsec=az_find_nsec_cover(z, &node)) != NULL) { + if(!msg_add_rrset_ns(z, region, msg, node, nsec)) return 0; } return 1; } @@ -1665,17 +1655,35 @@ az_nsec3_param(struct auth_zone* z, int* algo, size_t* iter, uint8_t** salt, { struct auth_data* apex; struct auth_rrset* param; + size_t i; apex = az_find_name(z, z->name, z->namelen); if(!apex) return 0; param = az_domain_rrset(apex, LDNS_RR_TYPE_NSEC3PARAM); - if(!param || !param->rrset || ((struct packed_rrset_data*)param-> - rrset->entry.data)->count==0) + if(!param || param->data->count==0) return 0; /* no RRset or no RRs in rrset */ - if(!nsec3_get_params(param->rrset, 0, algo, iter, salt, saltlen)) - return 0; /* malformed NSEC3PARAM */ - if(!nsec3_hash_algo_size_supported(*algo)) - return 0; /* unsupported NSEC3 algo */ - return 1; + /* find out which NSEC3PARAM RR has supported parameters */ + /* skip unknown flags (dynamic signer is recalculating nsec3 chain) */ + for(i=0; idata->count; i++) { + uint8_t* rdata = param->data->rr_data[i]+2; + size_t rdatalen = param->data->rr_len[i]; + if(rdatalen < 2+5) + continue; /* too short */ + if(!nsec3_hash_algo_size_supported(rdata[0])) + continue; /* unsupported algo */ + if(rdatalen < (size_t)(2+5+(size_t)rdata[4])) + continue; /* salt missing */ + if((rdata[1]&NSEC3_UNKNOWN_FLAGS)!=0) + continue; /* unknown flags */ + *algo = rdata[0]; + *iter = sldns_read_uint16(rdata+2); + *saltlen = rdata[4]; + if(*saltlen == 0) + *salt = NULL; + else *salt = rdata+5; + return 1; + } + /* no supported params */ + return 0; } /** Hash a name with nsec3param into buffer, it has zone name appended. @@ -1842,14 +1850,14 @@ az_nsec3_find_ce(struct auth_zone* z, uint8_t** cenm, size_t* cenmlen, /* Insert NSEC3 record in authority section, if NULL does nothing */ static int -az_nsec3_insert(struct regional* region, struct dns_msg* msg, - struct auth_data* node) +az_nsec3_insert(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node) { struct auth_rrset* nsec3; if(!node) return 1; /* no node, skip this */ nsec3 = az_domain_rrset(node, LDNS_RR_TYPE_NSEC3); if(!nsec3) return 1; /* if no nsec3 RR, skip it */ - if(!msg_add_rrset_ns(region, msg, nsec3)) return 0; + if(!msg_add_rrset_ns(z, region, msg, node, nsec3)) return 0; return 1; } @@ -1883,7 +1891,7 @@ az_add_nsec3_proof(struct auth_zone* z, struct regional* region, node = az_nsec3_find_ce(z, &cenm, &cenmlen, &no_exact_ce, algo, iter, salt, saltlen); if(no_exact_ce) nxproof = 1; - if(!az_nsec3_insert(region, msg, node)) + if(!az_nsec3_insert(z, region, msg, node)) return 0; if(nxproof) { @@ -1894,7 +1902,7 @@ az_add_nsec3_proof(struct auth_zone* z, struct regional* region, /* find nsec3 that matches or covers it */ node = az_nsec3_find_cover(z, nx, nxlen, algo, iter, salt, saltlen); - if(!az_nsec3_insert(region, msg, node)) + if(!az_nsec3_insert(z, region, msg, node)) return 0; } if(wcproof) { @@ -1910,7 +1918,7 @@ az_add_nsec3_proof(struct auth_zone* z, struct regional* region, /* find nsec3 that matches or covers it */ node = az_nsec3_find_cover(z, wc, wclen, algo, iter, salt, saltlen); - if(!az_nsec3_insert(region, msg, node)) + if(!az_nsec3_insert(z, region, msg, node)) return 0; } return 1; @@ -1919,17 +1927,17 @@ az_add_nsec3_proof(struct auth_zone* z, struct regional* region, /** generate answer for positive answer */ static int az_generate_positive_answer(struct auth_zone* z, struct regional* region, - struct dns_msg* msg, struct auth_rrset* rrset) + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; /* see if we want additional rrs */ - if(az_rrset_type(rrset) == LDNS_RR_TYPE_MX) { + if(rrset->type == LDNS_RR_TYPE_MX) { if(!az_add_additionals_from(z, region, msg, rrset, 2)) return 0; - } else if(az_rrset_type(rrset) == LDNS_RR_TYPE_SRV) { + } else if(rrset->type == LDNS_RR_TYPE_SRV) { if(!az_add_additionals_from(z, region, msg, rrset, 6)) return 0; - } else if(az_rrset_type(rrset) == LDNS_RR_TYPE_NS) { + } else if(rrset->type == LDNS_RR_TYPE_NS) { if(!az_add_additionals_from(z, region, msg, rrset, 0)) return 0; } @@ -1938,40 +1946,41 @@ az_generate_positive_answer(struct auth_zone* z, struct regional* region, /** generate answer for type ANY answer */ static int -az_generate_any_answer(struct regional* region, struct dns_msg* msg, - struct auth_data* node) +az_generate_any_answer(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node) { struct auth_rrset* rrset; int added = 0; /* add a couple (at least one) RRs */ if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_SOA)) != NULL) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; added++; } if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_MX)) != NULL) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; added++; } if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_A)) != NULL) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; added++; } if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_AAAA)) != NULL) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; added++; } if(added == 0 && node->rrsets) { - if(!msg_add_rrset_an(region, msg, node->rrsets)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, + node->rrsets)) return 0; } return 1; } /** generate answer for cname answer */ static int -az_generate_cname_answer(struct regional* region, struct dns_msg* msg, - struct auth_rrset* rrset) +az_generate_cname_answer(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) { - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0; return 1; } @@ -1984,7 +1993,7 @@ az_generate_notype_answer(struct auth_zone* z, struct regional* region, if(!az_add_negative_soa(z, region, msg)) return 0; /* DNSSEC denial NSEC */ if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_NSEC))!=NULL) { - if(!msg_add_rrset_ns(region, msg, rrset)) return 0; + if(!msg_add_rrset_ns(z, region, msg, node, rrset)) return 0; } else if(node) { /* DNSSEC denial NSEC3 */ if(!az_add_nsec3_proof(z, region, msg, node->name, @@ -2002,16 +2011,18 @@ az_generate_referral_answer(struct auth_zone* z, struct regional* region, { struct auth_rrset* ds, *nsec; /* turn off AA flag, referral is nonAA because it leaves the zone */ + log_assert(ce); msg->rep->flags &= ~BIT_AA; - if(!msg_add_rrset_ns(region, msg, rrset)) return 0; + if(!msg_add_rrset_ns(z, region, msg, ce, rrset)) return 0; /* add DS or deny it */ if((ds=az_domain_rrset(ce, LDNS_RR_TYPE_DS))!=NULL) { - if(!msg_add_rrset_ns(region, msg, ds)) return 0; + if(!msg_add_rrset_ns(z, region, msg, ce, ds)) return 0; } else { /* deny the DS */ if((nsec=az_domain_rrset(ce, LDNS_RR_TYPE_NSEC))!=NULL) { - if(!msg_add_rrset_ns(region, msg, nsec)) return 0; - } else if(ce) { + if(!msg_add_rrset_ns(z, region, msg, ce, + nsec)) return 0; + } else { if(!az_add_nsec3_proof(z, region, msg, ce->name, ce->namelen, msg->qinfo.qname, msg->qinfo.qname_len, 0, 0)) @@ -2025,14 +2036,16 @@ az_generate_referral_answer(struct auth_zone* z, struct regional* region, /** generate answer for DNAME answer */ static int -az_generate_dname_answer(struct query_info* qinfo, struct regional* region, - struct dns_msg* msg, struct auth_rrset* rrset) +az_generate_dname_answer(struct auth_zone* z, struct query_info* qinfo, + struct regional* region, struct dns_msg* msg, struct auth_data* ce, + struct auth_rrset* rrset) { struct ub_packed_rrset_key* cname; + log_assert(ce); /* add the DNAME */ - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, ce, rrset)) return 0; /* synthesize a CNAME */ - if(!create_synth_cname(qinfo, region, rrset->rrset, &cname)) { + if(!create_synth_cname(qinfo, region, ce, rrset, z->dclass, &cname)) { /* out of memory */ return 0; } @@ -2066,13 +2079,15 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo, } if((rrset=az_domain_rrset(wildcard, qinfo->qtype)) != NULL) { /* wildcard has type, add it */ - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, wildcard, + rrset)) return 0; } else if((rrset=az_domain_rrset(wildcard, LDNS_RR_TYPE_CNAME))!=NULL) { /* wildcard has cname instead, do that */ - if(!msg_add_rrset_an(region, msg, rrset)) return 0; + if(!msg_add_rrset_an(z, region, msg, wildcard, + rrset)) return 0; } else if(qinfo->qtype == LDNS_RR_TYPE_ANY && wildcard->rrsets) { /* add ANY rrsets from wildcard node */ - if(!az_generate_any_answer(region, msg, wildcard)) + if(!az_generate_any_answer(z, region, msg, wildcard)) return 0; } else { /* wildcard has nodata, notype answer */ @@ -2082,8 +2097,8 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo, } /* ce and node for dnssec denial of wildcard original name */ - if((nsec=az_find_nsec_cover(z, node)) != NULL) { - if(!msg_add_rrset_ns(region, msg, nsec)) return 0; + if((nsec=az_find_nsec_cover(z, &node)) != NULL) { + if(!msg_add_rrset_ns(z, region, msg, node, nsec)) return 0; } else if(ce) { if(!az_add_nsec3_proof(z, region, msg, ce->name, ce->namelen, msg->qinfo.qname, @@ -2106,8 +2121,8 @@ az_generate_nxdomain_answer(struct auth_zone* z, struct regional* region, struct auth_rrset* nsec; msg->rep->flags |= LDNS_RCODE_NXDOMAIN; if(!az_add_negative_soa(z, region, msg)) return 0; - if((nsec=az_find_nsec_cover(z, node)) != NULL) { - if(!msg_add_rrset_ns(region, msg, nsec)) return 0; + if((nsec=az_find_nsec_cover(z, &node)) != NULL) { + if(!msg_add_rrset_ns(z, region, msg, node, nsec)) return 0; if(ce && !az_nsec_wildcard_denial(z, region, msg, ce->name, ce->namelen)) return 0; } else if(ce) { @@ -2127,15 +2142,15 @@ az_generate_answer_with_node(struct auth_zone* z, struct query_info* qinfo, struct auth_rrset* rrset; /* positive answer, rrset we are looking for exists */ if((rrset=az_domain_rrset(node, qinfo->qtype)) != NULL) { - return az_generate_positive_answer(z, region, msg, rrset); + return az_generate_positive_answer(z, region, msg, node, rrset); } /* CNAME? */ if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_CNAME)) != NULL) { - return az_generate_cname_answer(region, msg, rrset); + return az_generate_cname_answer(z, region, msg, node, rrset); } /* type ANY ? */ if(qinfo->qtype == LDNS_RR_TYPE_ANY) { - return az_generate_any_answer(region, msg, node); + return az_generate_any_answer(z, region, msg, node); } /* NOERROR/NODATA (no such type at domain name) */ return az_generate_notype_answer(z, region, msg, node); @@ -2152,11 +2167,12 @@ az_generate_answer_nonexistnode(struct auth_zone* z, struct query_info* qinfo, /* we do not have an exact matching name (that exists) */ /* see if we have a NS or DNAME in the ce */ - if(ce && rrset && az_rrset_type(rrset) == LDNS_RR_TYPE_NS) { + if(ce && rrset && rrset->type == LDNS_RR_TYPE_NS) { return az_generate_referral_answer(z, region, msg, ce, rrset); } - if(ce && rrset && az_rrset_type(rrset) == LDNS_RR_TYPE_DNAME) { - return az_generate_dname_answer(qinfo, region, msg, rrset); + if(ce && rrset && rrset->type == LDNS_RR_TYPE_DNAME) { + return az_generate_dname_answer(z, qinfo, region, msg, ce, + rrset); } /* if there is an empty nonterminal, wildcard and nxdomain don't * happen, it is a notype answer */ @@ -2209,8 +2225,8 @@ auth_zone_generate_answer(struct auth_zone* z, struct query_info* qinfo, sldns_wire2str_dname_buf(ce->name, ce->namelen, cename, sizeof(cename)); else snprintf(cename, sizeof(cename), "NULL"); - if(rrset) sldns_wire2str_type_buf(az_rrset_type(rrset), - rrstr, sizeof(rrstr)); + if(rrset) sldns_wire2str_type_buf(rrset->type, rrstr, + sizeof(rrstr)); else snprintf(rrstr, sizeof(rrstr), "NULL"); log_info("auth_zone %s query %s %s, domain %s %s %s, " "ce %s, rrset %s", zname, qname, tpstr, nname, diff --git a/services/authzone.h b/services/authzone.h index e5b14e35b..5b4623b65 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -75,7 +75,7 @@ struct auth_zone { size_t namelen; /** number of labels in zone name */ int namelabs; - /** the class of this zone. + /** the class of this zone, in host byteorder. * uses 'dclass' to not conflict with c++ keyword class. */ uint16_t dclass; @@ -121,8 +121,10 @@ struct auth_data { struct auth_rrset { /** next in list */ struct auth_rrset* next; + /** RR type in host byteorder */ + uint16_t type; /** RRset data item */ - struct ub_packed_rrset_key* rrset; + struct packed_rrset_data* data; }; /**