mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- authzone cname chain, no rrset duplicates, wildcard doesn't change
rrsets added for cname chain. git-svn-id: file:///svn/unbound/trunk@4189 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
632c1e83f8
commit
aa9365446b
3 changed files with 146 additions and 35 deletions
|
|
@ -1,3 +1,7 @@
|
|||
24 May 2017: Wouter
|
||||
- authzone cname chain, no rrset duplicates, wildcard doesn't change
|
||||
rrsets added for cname chain.
|
||||
|
||||
23 May 2017: Wouter
|
||||
- first services/authzone check in, it compiles and reads and writes
|
||||
zonefiles.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@
|
|||
|
||||
/** bytes to use for NSEC3 hash buffer. 20 for sha1 */
|
||||
#define N3HASHBUFLEN 32
|
||||
/** max number of CNAMEs we are willing to follow (in one answer) */
|
||||
#define MAX_CNAME_CHAIN 8
|
||||
|
||||
/** create new dns_msg */
|
||||
static struct dns_msg*
|
||||
|
|
@ -154,6 +156,22 @@ msg_ttl(struct dns_msg* msg)
|
|||
}
|
||||
}
|
||||
|
||||
/** see if rrset is a duplicate in the answer message */
|
||||
static int
|
||||
msg_rrset_duplicate(struct dns_msg* msg, uint8_t* nm, size_t nmlen,
|
||||
uint16_t type, uint16_t dclass)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
|
||||
if(ntohs(k->rk.type) == type && k->rk.dname_len == nmlen &&
|
||||
ntohs(k->rk.rrset_class) == dclass &&
|
||||
query_dname_compare(k->rk.dname, nm) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** add rrset to answer section (no auth, add rrsets yet) */
|
||||
static int
|
||||
msg_add_rrset_an(struct auth_zone* z, struct regional* region,
|
||||
|
|
@ -163,6 +181,9 @@ msg_add_rrset_an(struct auth_zone* z, struct regional* region,
|
|||
log_assert(msg->rep->ar_numrrsets == 0);
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type,
|
||||
z->dclass))
|
||||
return 1;
|
||||
/* grow array */
|
||||
if(!msg_grow_array(region, msg))
|
||||
return 0;
|
||||
|
|
@ -184,6 +205,9 @@ msg_add_rrset_ns(struct auth_zone* z, struct regional* region,
|
|||
log_assert(msg->rep->ar_numrrsets == 0);
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type,
|
||||
z->dclass))
|
||||
return 1;
|
||||
/* grow array */
|
||||
if(!msg_grow_array(region, msg))
|
||||
return 0;
|
||||
|
|
@ -204,6 +228,9 @@ msg_add_rrset_ar(struct auth_zone* z, struct regional* region,
|
|||
{
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type,
|
||||
z->dclass))
|
||||
return 1;
|
||||
/* grow array */
|
||||
if(!msg_grow_array(region, msg))
|
||||
return 0;
|
||||
|
|
@ -1514,7 +1541,7 @@ synth_cname_buf(uint8_t* qname, size_t qname_len, size_t dname_len,
|
|||
/** create synthetic CNAME rrset for in a DNAME answer in region,
|
||||
* false on alloc failure, cname==NULL when name too long. */
|
||||
static int
|
||||
create_synth_cname(struct query_info* qinfo, struct regional* region,
|
||||
create_synth_cname(uint8_t* qname, size_t qname_len, struct regional* region,
|
||||
struct auth_data* node, struct auth_rrset* dname, uint16_t dclass,
|
||||
struct ub_packed_rrset_key** cname)
|
||||
{
|
||||
|
|
@ -1534,8 +1561,8 @@ create_synth_cname(struct query_info* qinfo, struct regional* region,
|
|||
return 0; /* DNAME RR has malformed rdata */
|
||||
|
||||
/* synthesize a CNAME */
|
||||
newlen = synth_cname_buf(qinfo->qname, qinfo->qname_len,
|
||||
node->namelen, dtarg, dtarglen, buf, sizeof(buf));
|
||||
newlen = synth_cname_buf(qname, qname_len, node->namelen,
|
||||
dtarg, dtarglen, buf, sizeof(buf));
|
||||
if(newlen == 0) {
|
||||
/* YXDOMAIN error */
|
||||
*cname = NULL;
|
||||
|
|
@ -1550,11 +1577,10 @@ create_synth_cname(struct query_info* qinfo, struct regional* region,
|
|||
(*cname)->rk.type = htons(LDNS_RR_TYPE_CNAME);
|
||||
(*cname)->rk.rrset_class = htons(dclass);
|
||||
(*cname)->rk.flags = 0;
|
||||
(*cname)->rk.dname = regional_alloc_init(region, qinfo->qname,
|
||||
qinfo->qname_len);
|
||||
(*cname)->rk.dname = regional_alloc_init(region, qname, qname_len);
|
||||
if(!(*cname)->rk.dname)
|
||||
return 0; /* out of memory */
|
||||
(*cname)->rk.dname_len = qinfo->qname_len;
|
||||
(*cname)->rk.dname_len = qname_len;
|
||||
(*cname)->entry.hash = rrset_key_hash(&(*cname)->rk);
|
||||
d = (struct packed_rrset_data*)regional_alloc_zero(region,
|
||||
sizeof(struct packed_rrset_data) + sizeof(size_t) +
|
||||
|
|
@ -1577,13 +1603,44 @@ create_synth_cname(struct query_info* qinfo, struct regional* region,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** add a synthesized CNAME to the answer section */
|
||||
static int
|
||||
add_synth_cname(struct auth_zone* z, uint8_t* qname, size_t qname_len,
|
||||
struct regional* region, struct dns_msg* msg, struct auth_data* dname,
|
||||
struct auth_rrset* rrset)
|
||||
{
|
||||
struct ub_packed_rrset_key* cname;
|
||||
/* synthesize a CNAME */
|
||||
if(!create_synth_cname(qname, qname_len, region, dname, rrset,
|
||||
z->dclass, &cname)) {
|
||||
/* out of memory */
|
||||
return 0;
|
||||
}
|
||||
if(!cname) {
|
||||
/* cname cannot be create because of YXDOMAIN */
|
||||
msg->rep->flags |= LDNS_RCODE_YXDOMAIN;
|
||||
return 1;
|
||||
}
|
||||
/* add cname to message */
|
||||
if(!msg_grow_array(region, msg))
|
||||
return 0;
|
||||
msg->rep->rrsets[msg->rep->rrset_count] = cname;
|
||||
msg->rep->rrset_count++;
|
||||
msg->rep->an_numrrsets++;
|
||||
msg_ttl(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Change a dname to a different one, for wildcard namechange */
|
||||
static void
|
||||
az_change_dnames(struct dns_msg* msg, uint8_t* oldname, uint8_t* newname,
|
||||
size_t newlen)
|
||||
size_t newlen, int an_only)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
size_t start = 0, end = msg->rep->rrset_count;
|
||||
if(!an_only) start = msg->rep->an_numrrsets;
|
||||
if(an_only) end = msg->rep->an_numrrsets;
|
||||
for(i=start; i<end; i++) {
|
||||
/* allocated in region so we can change the ptrs */
|
||||
if(query_dname_compare(msg->rep->rrsets[i]->rk.dname, oldname)
|
||||
== 0) {
|
||||
|
|
@ -1975,12 +2032,51 @@ az_generate_any_answer(struct auth_zone* z, struct regional* region,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/** follow cname chain and add more data to the answer section */
|
||||
static int
|
||||
follow_cname_chain(struct auth_zone* z, uint16_t qtype,
|
||||
struct regional* region, struct dns_msg* msg,
|
||||
struct packed_rrset_data* d)
|
||||
{
|
||||
int maxchain = 0;
|
||||
/* see if we can add the target of the CNAME into the answer */
|
||||
while(maxchain++ < MAX_CNAME_CHAIN) {
|
||||
struct auth_data* node;
|
||||
struct auth_rrset* rrset;
|
||||
size_t clen;
|
||||
/* d has cname rdata */
|
||||
if(d->count == 0) break; /* no CNAME */
|
||||
if(d->rr_len[0] < 2+1) break; /* too small */
|
||||
if((clen=dname_valid(d->rr_data[0]+2, d->rr_len[0]-2))==0)
|
||||
break; /* malformed */
|
||||
if(!dname_subdomain_c(d->rr_data[0]+2, z->name))
|
||||
break; /* target out of zone */
|
||||
if((node = az_find_name(z, d->rr_data[0]+2, clen))==NULL)
|
||||
break; /* no such target name */
|
||||
if((rrset=az_domain_rrset(node, qtype))!=NULL) {
|
||||
/* done we found the target */
|
||||
if(!msg_add_rrset_an(z, region, msg, node, rrset))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_CNAME))==NULL)
|
||||
break; /* no further CNAME chain, notype */
|
||||
if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0;
|
||||
d = rrset->data;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** generate answer for cname answer */
|
||||
static int
|
||||
az_generate_cname_answer(struct auth_zone* z, struct regional* region,
|
||||
struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset)
|
||||
az_generate_cname_answer(struct auth_zone* z, struct query_info* qinfo,
|
||||
struct regional* region, struct dns_msg* msg,
|
||||
struct auth_data* node, struct auth_rrset* rrset)
|
||||
{
|
||||
if(!msg_add_rrset_an(z, region, msg, node, rrset)) return 0;
|
||||
if(!rrset) return 1;
|
||||
if(!follow_cname_chain(z, qinfo->qtype, region, msg, rrset->data))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2020,8 +2116,8 @@ az_generate_referral_answer(struct auth_zone* z, struct regional* region,
|
|||
} else {
|
||||
/* deny the DS */
|
||||
if((nsec=az_domain_rrset(ce, LDNS_RR_TYPE_NSEC))!=NULL) {
|
||||
if(!msg_add_rrset_ns(z, region, msg, ce,
|
||||
nsec)) return 0;
|
||||
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,
|
||||
|
|
@ -2040,27 +2136,20 @@ 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 */
|
||||
/* add the DNAME and then a CNAME */
|
||||
if(!msg_add_rrset_an(z, region, msg, ce, rrset)) return 0;
|
||||
/* synthesize a CNAME */
|
||||
if(!create_synth_cname(qinfo, region, ce, rrset, z->dclass, &cname)) {
|
||||
/* out of memory */
|
||||
return 0;
|
||||
}
|
||||
if(!cname) {
|
||||
/* cname cannot be create because of YXDOMAIN */
|
||||
msg->rep->flags |= LDNS_RCODE_YXDOMAIN;
|
||||
if(!add_synth_cname(z, qinfo->qname, qinfo->qname_len, region,
|
||||
msg, ce, rrset)) return 0;
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_YXDOMAIN)
|
||||
return 1;
|
||||
}
|
||||
/* add cname to message */
|
||||
if(!msg_grow_array(region, msg))
|
||||
if(msg->rep->rrset_count == 0 ||
|
||||
!msg->rep->rrsets[msg->rep->rrset_count-1])
|
||||
return 0;
|
||||
if(!follow_cname_chain(z, qinfo->qtype, region, msg,
|
||||
(struct packed_rrset_data*)msg->rep->rrsets[
|
||||
msg->rep->rrset_count-1]->entry.data))
|
||||
return 0;
|
||||
msg->rep->rrsets[msg->rep->rrset_count] = cname;
|
||||
msg->rep->rrset_count++;
|
||||
msg->rep->an_numrrsets++;
|
||||
msg_ttl(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2079,16 +2168,25 @@ 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(z, region, msg, wildcard,
|
||||
rrset)) return 0;
|
||||
if(!msg_add_rrset_an(z, region, msg, wildcard, rrset))
|
||||
return 0;
|
||||
az_change_dnames(msg, wildcard->name, msg->qinfo.qname,
|
||||
msg->qinfo.qname_len, 1);
|
||||
} else if((rrset=az_domain_rrset(wildcard, LDNS_RR_TYPE_CNAME))!=NULL) {
|
||||
/* wildcard has cname instead, do that */
|
||||
if(!msg_add_rrset_an(z, region, msg, wildcard,
|
||||
rrset)) return 0;
|
||||
if(!msg_add_rrset_an(z, region, msg, wildcard, rrset))
|
||||
return 0;
|
||||
az_change_dnames(msg, wildcard->name, msg->qinfo.qname,
|
||||
msg->qinfo.qname_len, 1);
|
||||
if(!follow_cname_chain(z, qinfo->qtype, region, msg,
|
||||
rrset->data))
|
||||
return 0;
|
||||
} else if(qinfo->qtype == LDNS_RR_TYPE_ANY && wildcard->rrsets) {
|
||||
/* add ANY rrsets from wildcard node */
|
||||
if(!az_generate_any_answer(z, region, msg, wildcard))
|
||||
return 0;
|
||||
az_change_dnames(msg, wildcard->name, msg->qinfo.qname,
|
||||
msg->qinfo.qname_len, 1);
|
||||
} else {
|
||||
/* wildcard has nodata, notype answer */
|
||||
/* call other notype routine for dnssec notype denials */
|
||||
|
|
@ -2109,7 +2207,7 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo,
|
|||
/* fixup name of wildcard from *.zone to qname, use already allocated
|
||||
* pointer to msg qname */
|
||||
az_change_dnames(msg, wildcard->name, msg->qinfo.qname,
|
||||
msg->qinfo.qname_len);
|
||||
msg->qinfo.qname_len, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2146,7 +2244,8 @@ az_generate_answer_with_node(struct auth_zone* z, struct query_info* qinfo,
|
|||
}
|
||||
/* CNAME? */
|
||||
if((rrset=az_domain_rrset(node, LDNS_RR_TYPE_CNAME)) != NULL) {
|
||||
return az_generate_cname_answer(z, region, msg, node, rrset);
|
||||
return az_generate_cname_answer(z, qinfo, region, msg,
|
||||
node, rrset);
|
||||
}
|
||||
/* type ANY ? */
|
||||
if(qinfo->qtype == LDNS_RR_TYPE_ANY) {
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ static struct q_ans example_com_queries[] = {
|
|||
";flags QR AA rcode NOERROR\n"
|
||||
";answer section\n"
|
||||
"out.example.com. 3600 IN CNAME www.example.com.\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.2\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.3\n"
|
||||
},
|
||||
|
||||
{ "example.com", "out.example.com. CNAME", "",
|
||||
|
|
@ -399,18 +401,24 @@ static struct q_ans example_com_queries[] = {
|
|||
";flags QR AA rcode NOERROR\n"
|
||||
";answer section\n"
|
||||
"*.wild2.example.com. 3600 IN CNAME www.example.com.\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.2\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.3\n"
|
||||
},
|
||||
|
||||
{ "example.com", "abc.wild2.example.com. A", "",
|
||||
";flags QR AA rcode NOERROR\n"
|
||||
";answer section\n"
|
||||
"abc.wild2.example.com. 3600 IN CNAME www.example.com.\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.2\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.3\n"
|
||||
},
|
||||
|
||||
{ "example.com", "foo.abc.wild2.example.com. A", "",
|
||||
";flags QR AA rcode NOERROR\n"
|
||||
";answer section\n"
|
||||
"foo.abc.wild2.example.com. 3600 IN CNAME www.example.com.\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.2\n"
|
||||
"www.example.com. 3600 IN A 10.0.0.3\n"
|
||||
},
|
||||
|
||||
{ "example.com", "abc.wild2.example.com. CNAME", "",
|
||||
|
|
|
|||
Loading…
Reference in a new issue