mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- Save wildcard RRset from answer with original owner for use in aggressive
NSEC. git-svn-id: file:///svn/unbound/trunk@4550 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
cd955fa34d
commit
24fc3242fc
9 changed files with 114 additions and 19 deletions
|
|
@ -1,3 +1,7 @@
|
||||||
|
22 February 2018: Ralph
|
||||||
|
- Save wildcard RRset from answer with original owner for use in
|
||||||
|
aggressive NSEC.
|
||||||
|
|
||||||
21 February 2018: Wouter
|
21 February 2018: Wouter
|
||||||
- Fix #3512: unbound incorrectly reports SERVFAIL for CAA query
|
- Fix #3512: unbound incorrectly reports SERVFAIL for CAA query
|
||||||
when there is a CNAME loop.
|
when there is a CNAME loop.
|
||||||
|
|
|
||||||
3
services/cache/dns.c
vendored
3
services/cache/dns.c
vendored
|
|
@ -787,10 +787,11 @@ dns_cache_lookup(struct module_env* env,
|
||||||
(rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen,
|
(rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen,
|
||||||
LDNS_RR_TYPE_CNAME, qclass, 0, now, 0))) {
|
LDNS_RR_TYPE_CNAME, qclass, 0, now, 0))) {
|
||||||
uint8_t* wc = NULL;
|
uint8_t* wc = NULL;
|
||||||
|
size_t wl;
|
||||||
/* if the rrset is not a wildcard expansion, with wcname */
|
/* if the rrset is not a wildcard expansion, with wcname */
|
||||||
/* because, if we return that CNAME rrset on its own, it is
|
/* because, if we return that CNAME rrset on its own, it is
|
||||||
* missing the NSEC or NSEC3 proof */
|
* missing the NSEC or NSEC3 proof */
|
||||||
if(!(val_rrset_wildcard(rrset, &wc) && wc != NULL)) {
|
if(!(val_rrset_wildcard(rrset, &wc, &wl) && wc != NULL)) {
|
||||||
struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
|
struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
|
||||||
if(msg) {
|
if(msg) {
|
||||||
lock_rw_unlock(&rrset->entry.lock);
|
lock_rw_unlock(&rrset->entry.lock);
|
||||||
|
|
|
||||||
32
services/cache/rrset.c
vendored
32
services/cache/rrset.c
vendored
|
|
@ -47,6 +47,7 @@
|
||||||
#include "util/data/msgreply.h"
|
#include "util/data/msgreply.h"
|
||||||
#include "util/regional.h"
|
#include "util/regional.h"
|
||||||
#include "util/alloc.h"
|
#include "util/alloc.h"
|
||||||
|
#include "util/net_help.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
rrset_markdel(void* key)
|
rrset_markdel(void* key)
|
||||||
|
|
@ -237,6 +238,37 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||||
|
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
|
||||||
|
struct alloc_cache* alloc, time_t timenow)
|
||||||
|
{
|
||||||
|
struct rrset_ref ref;
|
||||||
|
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
|
||||||
|
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
|
||||||
|
if(!rrset) {
|
||||||
|
log_err("malloc failure in rrset_cache_update_wildcard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* ce has at least one label less then qname, we can therefore safely
|
||||||
|
* add the wildcard label. */
|
||||||
|
wc_dname[0] = 1;
|
||||||
|
wc_dname[1] = (uint8_t)'*';
|
||||||
|
memmove(wc_dname+2, ce, ce_len);
|
||||||
|
|
||||||
|
rrset->rk.dname_len = ce_len + 2;
|
||||||
|
rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len);
|
||||||
|
if(!rrset->rk.dname) {
|
||||||
|
log_err("memdup failure in rrset_cache_update_wildcard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rrset->entry.hash = rrset_key_hash(&rrset->rk);
|
||||||
|
ref.key = rrset;
|
||||||
|
ref.id = rrset->id;
|
||||||
|
/* ignore ret: if it was in the cache, ref updated */
|
||||||
|
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
|
||||||
|
}
|
||||||
|
|
||||||
struct ub_packed_rrset_key*
|
struct ub_packed_rrset_key*
|
||||||
rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
||||||
uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow,
|
uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow,
|
||||||
|
|
|
||||||
18
services/cache/rrset.h
vendored
18
services/cache/rrset.h
vendored
|
|
@ -133,6 +133,24 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
|
||||||
int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||||
struct alloc_cache* alloc, time_t timenow);
|
struct alloc_cache* alloc, time_t timenow);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update or add an rrset in the rrset cache using a wildcard dname.
|
||||||
|
* Generates wildcard dname by prepending the wildcard label to the closest
|
||||||
|
* encloser. Will lookup if the rrset is in the cache and perform an update if
|
||||||
|
* necessary.
|
||||||
|
*
|
||||||
|
* @param rrset_cache: the rrset cache.
|
||||||
|
* @param rrset: which rrset to cache as wildcard. This rrset is left
|
||||||
|
* untouched.
|
||||||
|
* @param ce: the closest encloser, will be uses to generate the wildcard dname.
|
||||||
|
* @param ce_len: the closest encloser lenght.
|
||||||
|
* @param alloc: how to allocate (and deallocate) the special rrset key.
|
||||||
|
* @param timenow: current time (to see if ttl in cache is expired).
|
||||||
|
*/
|
||||||
|
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||||
|
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
|
||||||
|
struct alloc_cache* alloc, time_t timenow);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup rrset. You obtain read/write lock. You must unlock before lookup
|
* Lookup rrset. You obtain read/write lock. You must unlock before lookup
|
||||||
* anything of else.
|
* anything of else.
|
||||||
|
|
|
||||||
|
|
@ -847,34 +847,56 @@ void neg_insert_data(struct val_neg_cache* neg,
|
||||||
wipeout(neg, zone, el, nsec);
|
wipeout(neg, zone, el, nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep)
|
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep,
|
||||||
|
uint8_t* qname)
|
||||||
{
|
{
|
||||||
size_t i, need;
|
size_t i, need;
|
||||||
struct ub_packed_rrset_key* soa;
|
struct ub_packed_rrset_key* soa;
|
||||||
|
uint8_t* dname = NULL;
|
||||||
|
size_t dname_len;
|
||||||
|
uint16_t rrset_class;
|
||||||
struct val_neg_zone* zone;
|
struct val_neg_zone* zone;
|
||||||
/* see if secure nsecs inside */
|
/* see if secure nsecs inside */
|
||||||
if(!reply_has_nsec(rep))
|
if(!reply_has_nsec(rep))
|
||||||
return;
|
return;
|
||||||
/* find the zone name in message */
|
/* find the zone name in message */
|
||||||
soa = reply_find_soa(rep);
|
if((soa = reply_find_soa(rep))) {
|
||||||
if(!soa)
|
dname = soa->rk.dname;
|
||||||
return;
|
dname_len = soa->rk.dname_len;
|
||||||
|
rrset_class = soa->rk.rrset_class;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* No SOA in positive (wildcard) answer. Use signer from the
|
||||||
|
* validated answer RRsets' signature. */
|
||||||
|
size_t i;
|
||||||
|
for(i=0; i<rep->an_numrrsets; i++) {
|
||||||
|
if(qname && query_dname_compare(qname,
|
||||||
|
rep->rrsets[i]->rk.dname) == 0) {
|
||||||
|
val_find_rrset_signer(rep->rrsets[i],
|
||||||
|
&dname, &dname_len);
|
||||||
|
rrset_class = rep->rrsets[i]->rk.rrset_class;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!dname)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log_nametypeclass(VERB_ALGO, "negcache insert for zone",
|
log_nametypeclass(VERB_ALGO, "negcache insert for zone",
|
||||||
soa->rk.dname, LDNS_RR_TYPE_SOA, ntohs(soa->rk.rrset_class));
|
dname, LDNS_RR_TYPE_SOA, ntohs(rrset_class));
|
||||||
|
|
||||||
/* ask for enough space to store all of it */
|
/* ask for enough space to store all of it */
|
||||||
need = calc_data_need(rep) +
|
need = calc_data_need(rep) +
|
||||||
calc_zone_need(soa->rk.dname, soa->rk.dname_len);
|
calc_zone_need(dname, dname_len);
|
||||||
lock_basic_lock(&neg->lock);
|
lock_basic_lock(&neg->lock);
|
||||||
neg_make_space(neg, need);
|
neg_make_space(neg, need);
|
||||||
|
|
||||||
/* find or create the zone entry */
|
/* find or create the zone entry */
|
||||||
zone = neg_find_zone(neg, soa->rk.dname, soa->rk.dname_len,
|
zone = neg_find_zone(neg, dname, dname_len,
|
||||||
ntohs(soa->rk.rrset_class));
|
ntohs(rrset_class));
|
||||||
if(!zone) {
|
if(!zone) {
|
||||||
if(!(zone = neg_create_zone(neg, soa->rk.dname,
|
if(!(zone = neg_create_zone(neg, dname,
|
||||||
soa->rk.dname_len, ntohs(soa->rk.rrset_class)))) {
|
dname_len, ntohs(rrset_class)))) {
|
||||||
lock_basic_unlock(&neg->lock);
|
lock_basic_unlock(&neg->lock);
|
||||||
log_err("out of memory adding negative zone");
|
log_err("out of memory adding negative zone");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -198,9 +198,12 @@ int val_neg_zone_compare(const void* a, const void* b);
|
||||||
* Insert NSECs from this message into the negative cache for reference.
|
* Insert NSECs from this message into the negative cache for reference.
|
||||||
* @param neg: negative cache
|
* @param neg: negative cache
|
||||||
* @param rep: reply with NSECs.
|
* @param rep: reply with NSECs.
|
||||||
|
* @param qname: used to find correct signer, needed when rep does not contain
|
||||||
|
* a SOA record.
|
||||||
* Errors are ignored, means that storage is omitted.
|
* Errors are ignored, means that storage is omitted.
|
||||||
*/
|
*/
|
||||||
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
|
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep,
|
||||||
|
uint8_t* qname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert NSECs from this referral into the negative cache for reference.
|
* Insert NSECs from this referral into the negative cache for reference.
|
||||||
|
|
|
||||||
|
|
@ -767,7 +767,8 @@ rrsig_get_labcount(struct packed_rrset_data* d, size_t sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc)
|
val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc,
|
||||||
|
size_t* wc_len)
|
||||||
{
|
{
|
||||||
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
||||||
entry.data;
|
entry.data;
|
||||||
|
|
@ -800,6 +801,7 @@ val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc)
|
||||||
if(labdiff > 0) {
|
if(labdiff > 0) {
|
||||||
*wc = wn;
|
*wc = wn;
|
||||||
dname_remove_labels(wc, &wl, labdiff);
|
dname_remove_labels(wc, &wl, labdiff);
|
||||||
|
*wc_len = wl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,7 @@ int val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset);
|
||||||
* @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
|
* @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
|
||||||
* unchanged if not. The wildcard name, without "*." in front, is
|
* unchanged if not. The wildcard name, without "*." in front, is
|
||||||
* returned. This is a pointer into the rrset owner name.
|
* returned. This is a pointer into the rrset owner name.
|
||||||
|
* @param wc_len: the length of the returned wildcard name.
|
||||||
* @return false if the signatures are inconsistent in indicating the
|
* @return false if the signatures are inconsistent in indicating the
|
||||||
* wildcard status; possible spoofing of wildcard response for other
|
* wildcard status; possible spoofing of wildcard response for other
|
||||||
* responses is being tried. We lost the status which rrsig was verified
|
* responses is being tried. We lost the status which rrsig was verified
|
||||||
|
|
@ -279,7 +280,8 @@ int val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset);
|
||||||
* of service; but in that you could also have removed the real
|
* of service; but in that you could also have removed the real
|
||||||
* signature anyway.
|
* signature anyway.
|
||||||
*/
|
*/
|
||||||
int val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc);
|
int val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc,
|
||||||
|
size_t* wc_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chase the cname to the next query name.
|
* Chase the cname to the next query name.
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
#include "validator/val_sigcrypt.h"
|
#include "validator/val_sigcrypt.h"
|
||||||
#include "validator/autotrust.h"
|
#include "validator/autotrust.h"
|
||||||
#include "services/cache/dns.h"
|
#include "services/cache/dns.h"
|
||||||
|
#include "services/cache/rrset.h"
|
||||||
#include "util/data/dname.h"
|
#include "util/data/dname.h"
|
||||||
#include "util/module.h"
|
#include "util/module.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
@ -745,6 +746,8 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
||||||
struct key_entry_key* kkey)
|
struct key_entry_key* kkey)
|
||||||
{
|
{
|
||||||
uint8_t* wc = NULL;
|
uint8_t* wc = NULL;
|
||||||
|
size_t wl;
|
||||||
|
int wc_cached = 0;
|
||||||
int wc_NSEC_ok = 0;
|
int wc_NSEC_ok = 0;
|
||||||
int nsec3s_seen = 0;
|
int nsec3s_seen = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -757,13 +760,19 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
||||||
/* Check to see if the rrset is the result of a wildcard
|
/* Check to see if the rrset is the result of a wildcard
|
||||||
* expansion. If so, an additional check will need to be
|
* expansion. If so, an additional check will need to be
|
||||||
* made in the authority section. */
|
* made in the authority section. */
|
||||||
if(!val_rrset_wildcard(s, &wc)) {
|
if(!val_rrset_wildcard(s, &wc, &wl)) {
|
||||||
log_nametypeclass(VERB_QUERY, "Positive response has "
|
log_nametypeclass(VERB_QUERY, "Positive response has "
|
||||||
"inconsistent wildcard sigs:", s->rk.dname,
|
"inconsistent wildcard sigs:", s->rk.dname,
|
||||||
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
|
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
|
||||||
chase_reply->security = sec_status_bogus;
|
chase_reply->security = sec_status_bogus;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(wc && !wc_cached && env->cfg->aggressive_nsec) {
|
||||||
|
rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl,
|
||||||
|
env->alloc, *env->now);
|
||||||
|
wc_cached = 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate the AUTHORITY section as well - this will generally be
|
/* validate the AUTHORITY section as well - this will generally be
|
||||||
|
|
@ -1081,6 +1090,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
||||||
/* but check if a wildcard response is given, then check NSEC/NSEC3
|
/* but check if a wildcard response is given, then check NSEC/NSEC3
|
||||||
* for qname denial to see if wildcard is applicable */
|
* for qname denial to see if wildcard is applicable */
|
||||||
uint8_t* wc = NULL;
|
uint8_t* wc = NULL;
|
||||||
|
size_t wl;
|
||||||
int wc_NSEC_ok = 0;
|
int wc_NSEC_ok = 0;
|
||||||
int nsec3s_seen = 0;
|
int nsec3s_seen = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -1099,7 +1109,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
||||||
/* Check to see if the rrset is the result of a wildcard
|
/* Check to see if the rrset is the result of a wildcard
|
||||||
* expansion. If so, an additional check will need to be
|
* expansion. If so, an additional check will need to be
|
||||||
* made in the authority section. */
|
* made in the authority section. */
|
||||||
if(!val_rrset_wildcard(s, &wc)) {
|
if(!val_rrset_wildcard(s, &wc, &wl)) {
|
||||||
log_nametypeclass(VERB_QUERY, "Positive ANY response"
|
log_nametypeclass(VERB_QUERY, "Positive ANY response"
|
||||||
" has inconsistent wildcard sigs:",
|
" has inconsistent wildcard sigs:",
|
||||||
s->rk.dname, ntohs(s->rk.type),
|
s->rk.dname, ntohs(s->rk.type),
|
||||||
|
|
@ -1188,6 +1198,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||||
struct key_entry_key* kkey)
|
struct key_entry_key* kkey)
|
||||||
{
|
{
|
||||||
uint8_t* wc = NULL;
|
uint8_t* wc = NULL;
|
||||||
|
size_t wl;
|
||||||
int wc_NSEC_ok = 0;
|
int wc_NSEC_ok = 0;
|
||||||
int nsec3s_seen = 0;
|
int nsec3s_seen = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -1200,7 +1211,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||||
/* Check to see if the rrset is the result of a wildcard
|
/* Check to see if the rrset is the result of a wildcard
|
||||||
* expansion. If so, an additional check will need to be
|
* expansion. If so, an additional check will need to be
|
||||||
* made in the authority section. */
|
* made in the authority section. */
|
||||||
if(!val_rrset_wildcard(s, &wc)) {
|
if(!val_rrset_wildcard(s, &wc, &wl)) {
|
||||||
log_nametypeclass(VERB_QUERY, "Cname response has "
|
log_nametypeclass(VERB_QUERY, "Cname response has "
|
||||||
"inconsistent wildcard sigs:", s->rk.dname,
|
"inconsistent wildcard sigs:", s->rk.dname,
|
||||||
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
|
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
|
||||||
|
|
@ -2178,7 +2189,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
|
||||||
&qstate->qinfo);
|
&qstate->qinfo);
|
||||||
if(!qstate->no_cache_store) {
|
if(!qstate->no_cache_store) {
|
||||||
val_neg_addreply(qstate->env->neg_cache,
|
val_neg_addreply(qstate->env->neg_cache,
|
||||||
vq->orig_msg->rep);
|
vq->orig_msg->rep, qstate->qinfo.qname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3109,7 +3120,7 @@ process_dlv_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* store NSECs into negative cache */
|
/* store NSECs into negative cache */
|
||||||
val_neg_addreply(ve->neg_cache, msg->rep);
|
val_neg_addreply(ve->neg_cache, msg->rep, NULL);
|
||||||
|
|
||||||
/* was the lookup a failure?
|
/* was the lookup a failure?
|
||||||
* if we have to go up into the DLV for a higher DLV anchor
|
* if we have to go up into the DLV for a higher DLV anchor
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue