]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
working on negative DS
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 7 Oct 2008 15:22:32 +0000 (15:22 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 7 Oct 2008 15:22:32 +0000 (15:22 +0000)
git-svn-id: file:///svn/unbound/trunk@1288 be551aaa-1e26-0410-a405-d3ace91eadb9

testdata/val_unsecds_negcache.rpl [new file with mode: 0644]
util/module.h
validator/val_neg.c
validator/val_neg.h
validator/validator.c

diff --git a/testdata/val_unsecds_negcache.rpl b/testdata/val_unsecds_negcache.rpl
new file mode 100644 (file)
index 0000000..3f474cd
--- /dev/null
@@ -0,0 +1,191 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with insecure delegation and DS negative cache
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.sub.example.com. IN A
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.sub.example.com. IN A
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com. 3600    IN      RRSIG   DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response for delegation to sub.example.com.
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.sub.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+sub.example.com. IN    NS ns.sub.example.com.
+sub.example.com. IN    NSEC www.example.com. NS RRSIG NSEC
+sub.example.com.        3600    IN      RRSIG   NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFDCaiDM6G+glwNW276HWdH+McmjgAhRSwF5OfimNQCqkWgnYotLOwUghKQ== ;{id = 2854}
+SECTION ADDITIONAL
+ns.sub.example.com. IN A 1.2.3.6
+ENTRY_END
+
+; query for missing DS record.
+; get it from the negative cache instead!
+;ENTRY_BEGIN
+;MATCH opcode qtype qname
+;ADJUST copy_id
+;REPLY QR NOERROR
+;SECTION QUESTION
+;sub.example.com. IN DS
+;SECTION ANSWER
+;SECTION AUTHORITY
+;example.com.  IN      SOA ns.example.com. h.example.com. 2007090504 1800 1800 2419200 7200
+;example.com.    3600    IN      RRSIG   SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFC5uwIHSehZtetK2CMNXttSFUB0XAhROFDAgy/FaxR8zFXJzyPdpQG93Sw== ;{id = 2854}
+;sub.example.com. IN   NSEC www.example.com. NS RRSIG NSEC
+;sub.example.com.        3600    IN      RRSIG   NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFDCaiDM6G+glwNW276HWdH+McmjgAhRSwF5OfimNQCqkWgnYotLOwUghKQ== ;{id = 2854}
+;SECTION ADDITIONAL
+;ns.sub.example.com. IN A 1.2.3.6
+;ENTRY_END
+
+
+RANGE_END
+
+; ns.sub.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.6
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+sub.example.com. IN NS
+SECTION ANSWER
+sub.example.com. IN    NS ns.sub.example.com.
+SECTION ADDITIONAL
+ns.sub.example.com. IN A 1.2.3.6
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.sub.example.com. IN A
+SECTION ANSWER
+www.sub.example.com. IN A      11.11.11.11
+SECTION AUTHORITY
+SECTION ADDITIONAL
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.sub.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.sub.example.com. IN A
+SECTION ANSWER
+www.sub.example.com.   3600    IN      A       11.11.11.11
+SECTION AUTHORITY
+SECTION ADDITIONAL
+ENTRY_END
+
+SCENARIO_END
index 831212b1f70ba850b22a85ad7c16d07dbd051377..68308835bcdd28a37a101f829f4969a2d4a747eb 100644 (file)
@@ -56,6 +56,8 @@ struct module_qstate;
 struct ub_randstate;
 struct mesh_area;
 struct mesh_state;
+struct val_anchors;
+struct val_neg_cache;
 
 /** Maximum number of modules in operation */
 #define MAX_MODULE 5
@@ -203,6 +205,9 @@ struct module_env {
         * and are not primed and ready for validation, but on the bright
         * side, they are read only memory, thus no locks and fast. */
        struct val_anchors* anchors;
+       /** negative cache, configured by the validator. if not NULL,
+        * contains NSEC record lookup trees. */
+       struct val_neg_cache* neg_cache;
        /** module specific data. indexed by module id. */
        void* modinfo[MAX_MODULE];
 };
index 3184ef5a5bfd51c8c450a668e7c1676b667aced9..06adfa7fea2cb8de5ff71353997154c842b1affd 100644 (file)
@@ -44,6 +44,7 @@
 #include "config.h"
 #include "validator/val_neg.h"
 #include "validator/val_nsec.h"
+#include "validator/val_utils.h"
 #include "util/data/dname.h"
 #include "util/data/msgreply.h"
 #include "util/log.h"
@@ -272,19 +273,21 @@ static void neg_make_space(struct val_neg_cache* neg, size_t need)
 /**
  * Find the given zone, from the SOA owner name and class
  * @param neg: negative cache
- * @param soa: what to look for.
+ * @param nm: what to look for.
+ * @param len: length of nm
+ * @param dclass: class to look for.
  * @return zone or NULL if not found.
  */
 static struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg, 
-       struct ub_packed_rrset_key* soa)
+       uint8_t* nm, size_t len, uint16_t dclass)
 {
        struct val_neg_zone lookfor;
        struct val_neg_zone* result;
        lookfor.node.key = &lookfor;
-       lookfor.name = soa->rk.dname;
-       lookfor.len = soa->rk.dname_len;
+       lookfor.name = nm;
+       lookfor.len = len;
        lookfor.labs = dname_count_labels(lookfor.name);
-       lookfor.dclass = ntohs(soa->rk.rrset_class);
+       lookfor.dclass = dclass;
 
        result = (struct val_neg_zone*)
                rbtree_search(&neg->tree, lookfor.node.key);
@@ -318,13 +321,12 @@ static size_t calc_data_need(struct reply_info* rep)
 
 /**
  * Calculate space needed for zone and all its parents
- * @param soa: with name.
+ * @param d: name of zone
+ * @param len: length of name
  * @return size.
  */
-static size_t calc_zone_need(struct ub_packed_rrset_key* soa)
+static size_t calc_zone_need(uint8_t* d, size_t len)
 {
-       uint8_t* d = soa->rk.dname;
-       size_t len = soa->rk.dname_len;
        size_t res = sizeof(struct val_neg_zone) + len;
        while(!dname_is_root(d)) {
                log_assert(len > 1); /* not root label */
@@ -419,7 +421,7 @@ static struct val_neg_data* neg_closest_data_parent(
  * @param nm: name for zone (copied)
  * @param nm_len: length of name
  * @param labs: labels in name.
- * @param dclass: class of zone.
+ * @param dclass: class of zone, host order.
  * @return new zone or NULL on failure
  */
 static struct val_neg_zone* neg_setup_zone_node(
@@ -494,19 +496,18 @@ static struct val_neg_zone* neg_zone_chain(
 /**
  * Create a new zone.
  * @param neg: negative cache
- * @param soa: what to look for.
+ * @param nm: what to look for.
+ * @param nm_len: length of name.
+ * @param dclass: class of zone, host order.
  * @return zone or NULL if out of memory.
  */
 static struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
-       struct ub_packed_rrset_key* soa)
+       uint8_t* nm, size_t nm_len, uint16_t dclass)
 {
        struct val_neg_zone* zone;
        struct val_neg_zone* parent;
        struct val_neg_zone* p, *np;
-       uint8_t* nm = soa->rk.dname;
-       size_t nm_len = soa->rk.dname_len;
        int labs = dname_count_labels(nm);
-       uint16_t dclass = ntohs(soa->rk.rrset_class);
 
        /* find closest enclosing parent zone that (still) exists */
        parent = neg_closest_zone_parent(neg, nm, nm_len, labs, dclass);
@@ -809,14 +810,17 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep)
                soa->rk.dname, LDNS_RR_TYPE_SOA, ntohs(soa->rk.rrset_class));
        
        /* ask for enough space to store all of it */
-       need = calc_data_need(rep) + calc_zone_need(soa);
+       need = calc_data_need(rep) + 
+               calc_zone_need(soa->rk.dname, soa->rk.dname_len);
        lock_basic_lock(&neg->lock);
        neg_make_space(neg, need);
 
        /* find or create the zone entry */
-       zone = neg_find_zone(neg, soa);
+       zone = neg_find_zone(neg, soa->rk.dname, soa->rk.dname_len,
+               ntohs(soa->rk.rrset_class));
        if(!zone) {
-               if(!(zone = neg_create_zone(neg, soa))) {
+               if(!(zone = neg_create_zone(neg, soa->rk.dname, 
+                       soa->rk.dname_len, ntohs(soa->rk.rrset_class)))) {
                        lock_basic_unlock(&neg->lock);
                        log_err("out of memory adding negative zone");
                        return;
@@ -958,3 +962,92 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
        verbose(VERB_ALGO, "negcache DLV denial proven");
        return 1;
 }
+
+/** see if the reply has signed NSEC records and return the signer */
+static uint8_t* reply_nsec_signer(struct reply_info* rep, size_t* signer_len,
+       uint16_t* dclass)
+{
+       size_t i;
+       struct packed_rrset_data* d;
+       uint8_t* s;
+       for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
+               if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC) {
+                       d = (struct packed_rrset_data*)rep->rrsets[i]->
+                               entry.data;
+                       /* return first signer name of first NSEC */
+                       if(d->rrsig_count != 0) {
+                               val_find_rrset_signer(rep->rrsets[i],
+                                       &s, signer_len);
+                               if(s && *signer_len) {
+                                       *dclass = ntohs(rep->rrsets[i]->
+                                               rk.rrset_class);
+                                       return s;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
+       uint8_t* zone_name)
+{
+       size_t i, need;
+       uint8_t* signer;
+       size_t signer_len;
+       uint16_t dclass;
+       struct val_neg_zone* zone;
+       /* no SOA in this message, find RRSIG over NSEC's signer name.
+        * note the NSEC records are maybe not validated yet */
+       signer = reply_nsec_signer(rep, &signer_len, &dclass);
+       if(!signer) 
+               return;
+       if(!dname_subdomain_c(signer, zone_name)) {
+               /* the signer is not in the bailiwick, throw it out */
+               return;
+       }
+
+       log_nametypeclass(VERB_ALGO, "negcache insert referral ",
+               signer, LDNS_RR_TYPE_NS, dclass);
+       
+       /* ask for enough space to store all of it */
+       need = calc_data_need(rep) + calc_zone_need(signer, signer_len);
+       lock_basic_lock(&neg->lock);
+       neg_make_space(neg, need);
+
+       /* find or create the zone entry */
+       zone = neg_find_zone(neg, signer, signer_len, dclass);
+       if(!zone) {
+               if(!(zone = neg_create_zone(neg, signer, signer_len, 
+                       dclass))) {
+                       lock_basic_unlock(&neg->lock);
+                       log_err("out of memory adding negative zone");
+                       return;
+               }
+       }
+
+       /* insert the NSECs */
+       for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
+               if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
+                       continue;
+               if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, 
+                       zone->name)) continue;
+               /* insert NSEC into this zone's tree */
+               neg_insert_data(neg, zone, rep->rrsets[i]);
+       }
+       lock_basic_unlock(&neg->lock);
+}
+
+struct dns_msg* 
+val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, 
+       struct regional* region, struct rrset_cache* rrset_cache)
+{
+       struct dns_msg* msg;
+       /* only for DS queries */
+       if(qinfo->qtype != LDNS_RR_TYPE_DS)
+               return NULL;
+
+       /* see if info from neg cache is available */
+
+       return msg;
+}
index 2bbf1118a4f675c24017180286d388dfe63f7baf..ff79c31cff931cb5f261727a30678a5164243061 100644 (file)
@@ -50,6 +50,9 @@ struct val_neg_data;
 struct config_file;
 struct reply_info;
 struct rrset_cache;
+struct regional;
+struct query_info;
+struct dns_msg;
 
 /**
  * The negative cache.  It is shared between the threads, so locked. 
@@ -187,6 +190,16 @@ int val_neg_zone_compare(const void* a, const void* b);
  */
 void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
 
+/**
+ * Insert NSECs from this referral into the negative cache for reference.
+ * @param neg: negative cache
+ * @param rep: referral reply with NS, NSECs.
+ * @param zone: bailiwick for the referral.
+ * Errors are ignored, means that storage is omitted.
+ */
+void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
+       uint8_t* zone);
+
 /**
  * Perform a DLV style lookup
  * During the lookup, we could find out that data has expired. In that
@@ -207,4 +220,19 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
 int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
        uint16_t qclass, struct rrset_cache* rrset_cache, uint32_t now);
 
+/**
+ * For the given query, try to get a reply out of the negative cache.
+ * The reply still needs to be validated.
+ * @param neg: negative cache.
+ * @param qinfo: query
+ * @param region: where to allocate reply.
+ * @param rrset_cache: rrset cache.
+ * @return a reply message if something was found. 
+ *     This reply may still need validation.
+ *     NULL if nothing found (or out of memory).
+ */
+struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg, 
+       struct query_info* qinfo, struct regional* region, 
+       struct rrset_cache* rrset_cache);
+
 #endif /* VALIDATOR_VAL_NEG_H */
index 1873b89361277c0a81a2a0c1e95f217ddb291195..bcc8a5b7edd357c1e22ee0510b69369e5891efaf 100644 (file)
@@ -127,6 +127,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
                log_err("out of memory");
                return 0;
        }
+       env->neg_cache = val_env->neg_cache;
        val_env->date_override = cfg->val_date_override;
        c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
        if(c < 1 || (c&1)) {