]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Save wildcard RRset from answer with original owner for use in aggressive
authorRalph Dolmans <ralph@nlnetlabs.nl>
Thu, 22 Feb 2018 15:12:31 +0000 (15:12 +0000)
committerRalph Dolmans <ralph@nlnetlabs.nl>
Thu, 22 Feb 2018 15:12:31 +0000 (15:12 +0000)
   NSEC.

git-svn-id: file:///svn/unbound/trunk@4550 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/cache/dns.c
services/cache/rrset.c
services/cache/rrset.h
validator/val_neg.c
validator/val_neg.h
validator/val_utils.c
validator/val_utils.h
validator/validator.c

index c1d822fc91ab6d847279eee781d3546835abf8fc..35a1958f7c887c927df56f18cc68211d30c5c4e3 100644 (file)
@@ -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
        - Fix #3512: unbound incorrectly reports SERVFAIL for CAA query
          when there is a CNAME loop.
index 71ff5266bae82a5aa54d9cec71dc3968c3df497d..8a0e49f5c93a5c8e9757ea6a6171d465978ba3cd 100644 (file)
@@ -787,10 +787,11 @@ dns_cache_lookup(struct module_env* env,
           (rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen, 
                LDNS_RR_TYPE_CNAME, qclass, 0, now, 0))) {
                uint8_t* wc = NULL;
+               size_t wl;
                /* if the rrset is not a wildcard expansion, with wcname */
                /* because, if we return that CNAME rrset on its own, it is
                 * 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);
                        if(msg) {
                                lock_rw_unlock(&rrset->entry.lock);
index 7e5732b760f21be1c740435adc312bb3e117b7e0..0b41fcd7dc3f3798f0ced82478678b90ae34ef3c 100644 (file)
@@ -47,6 +47,7 @@
 #include "util/data/msgreply.h"
 #include "util/regional.h"
 #include "util/alloc.h"
+#include "util/net_help.h"
 
 void
 rrset_markdel(void* key)
@@ -237,6 +238,37 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
        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* 
 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,
index d5439ef085b7da2e35b08fb70962e2031e968dd6..35a0d732b0481b4d6e5325d4e61ed60c6ca6eeea 100644 (file)
@@ -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, 
        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
  * anything of else.
index 25aaaa61ea3ae29eb826d68b461203421ee96e8d..403405d3b5c554c3fac972610f26634774fb8d50 100644 (file)
@@ -847,34 +847,56 @@ void neg_insert_data(struct val_neg_cache* neg,
        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;
        struct ub_packed_rrset_key* soa;
+       uint8_t* dname = NULL;
+       size_t dname_len;
+       uint16_t rrset_class;
        struct val_neg_zone* zone;
        /* see if secure nsecs inside */
        if(!reply_has_nsec(rep))
                return;
        /* find the zone name in message */
-       soa = reply_find_soa(rep);
-       if(!soa)
-               return;
+       if((soa = reply_find_soa(rep))) {
+               dname = soa->rk.dname;
+               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",
-               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 */
        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);
        neg_make_space(neg, need);
 
        /* find or create the zone entry */
-       zone = neg_find_zone(neg, soa->rk.dname, soa->rk.dname_len,
-               ntohs(soa->rk.rrset_class));
+       zone = neg_find_zone(neg, dname, dname_len,
+               ntohs(rrset_class));
        if(!zone) {
-               if(!(zone = neg_create_zone(neg, soa->rk.dname, 
-                       soa->rk.dname_len, ntohs(soa->rk.rrset_class)))) {
+               if(!(zone = neg_create_zone(neg, dname, 
+                       dname_len, ntohs(rrset_class)))) {
                        lock_basic_unlock(&neg->lock);
                        log_err("out of memory adding negative zone");
                        return;
index 00dad6df1f5c277abadd3a4337d60e69375fdde4..1d8128c41c91038cb751dab3a5283ca7b282b84b 100644 (file)
@@ -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.
  * @param neg: negative cache
  * @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.
  */
-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.
index 42795ec46039067e3aca0f35dadc07458462d15e..2f36fccfd4fe3b16106aa995cc6cac48cd738d41 100644 (file)
@@ -767,7 +767,8 @@ rrsig_get_labcount(struct packed_rrset_data* d, size_t sig)
 }
 
 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->
                entry.data;
@@ -800,6 +801,7 @@ val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc)
        if(labdiff > 0) {
                *wc = wn;
                dname_remove_labels(wc, &wl, labdiff);
+               *wc_len = wl;
                return 1;
        }
        return 1;
index b582472f8fafad8d80af3b0950c89bd4d72bb658..6e9867f6e3c76919cee2546b6b08d101b56cca66 100644 (file)
@@ -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.
  *         unchanged if not.  The wildcard name, without "*." in front, is 
  *         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 
  *     wildcard status; possible spoofing of wildcard response for other
  *     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 
  *     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.
index 81d67cd3626ba393b670ddae8e5fa786d094f5e5..d717c30e7688e55986eca2e81665a13134db6f5b 100644 (file)
@@ -51,6 +51,7 @@
 #include "validator/val_sigcrypt.h"
 #include "validator/autotrust.h"
 #include "services/cache/dns.h"
+#include "services/cache/rrset.h"
 #include "util/data/dname.h"
 #include "util/module.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)
 {
        uint8_t* wc = NULL;
+       size_t wl;
+       int wc_cached = 0;
        int wc_NSEC_ok = 0;
        int nsec3s_seen = 0;
        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 
                 * expansion. If so, an additional check will need to be 
                 * 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 "
                                "inconsistent wildcard sigs:", s->rk.dname,
                                ntohs(s->rk.type), ntohs(s->rk.rrset_class));
                        chase_reply->security = sec_status_bogus;
                        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 
@@ -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
         * for qname denial to see if wildcard is applicable */
        uint8_t* wc = NULL;
+       size_t wl;
        int wc_NSEC_ok = 0;
        int nsec3s_seen = 0;
        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 
                 * expansion. If so, an additional check will need to be 
                 * 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"
                                " has inconsistent wildcard sigs:", 
                                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)
 {
        uint8_t* wc = NULL;
+       size_t wl;
        int wc_NSEC_ok = 0;
        int nsec3s_seen = 0;
        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 
                 * expansion. If so, an additional check will need to be 
                 * 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 "
                                "inconsistent wildcard sigs:", s->rk.dname,
                                ntohs(s->rk.type), ntohs(s->rk.rrset_class));
@@ -2178,7 +2189,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
                                &qstate->qinfo);
                        if(!qstate->no_cache_store) {
                                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;
        }
        /* 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? 
         *   if we have to go up into the DLV for a higher DLV anchor