]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
More DNSSEC caching logic, and avoid repeated validation of DS/DNSKEY
authorSimon Kelley <simon@thekelleys.org.uk>
Sat, 25 Jan 2014 16:40:15 +0000 (16:40 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Sat, 25 Jan 2014 16:40:15 +0000 (16:40 +0000)
src/dnsmasq.c
src/dnssec.c
src/forward.c
src/rfc1035.c

index a264f77b2e1e0f11f5f75cd921343e32f39651d6..a05f639c33ceeca198c43b396fe3f08e3732c44d 100644 (file)
@@ -141,10 +141,18 @@ int main (int argc, char **argv)
     }
 #endif
   
+  if (option_bool(OPT_DNSSEC_VALID))
+    {
 #ifdef HAVE_DNSSEC
-  if (daemon->cachesize <CACHESIZ && option_bool(OPT_DNSSEC_VALID))
-    die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
+      if (!daemon->dnskeys)
+       die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
+      
+      if (daemon->cachesize < CACHESIZ)
+       die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
+#else 
+      die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
 #endif
+    }
 
 #ifndef HAVE_TFTP
   if (option_bool(OPT_TFTP))
index 68b59e9fd6e9eec3ed4d9f2ae4169bb3e927e2c6..4caea9ad449dc48df46f36f837c470234abdd415 100644 (file)
@@ -1099,7 +1099,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
                  struct all_addr a;
                  struct blockdata *key;
                  struct crec *crecp;
-                 
+
                  cache_start_insert();
                  
                  for (p2 = ans_start, j = 0; j < ntohs(header->ancount) + ntohs(header->nscount); j++)
index 31bb7bf788d77e0d9d22cbd79d4b945c2ad4125f..7af6f1fad9b44cfe41c162c168eef8d930ca4fe4 100644 (file)
@@ -855,42 +855,34 @@ void reply_query(int fd, int family, time_t now)
             and validate them with the new data. Failure to find needed data here is an internal error.
             Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
             return it to the original requestor. */
-         if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
+         while (forward->dependent)
            {
-             while (forward->dependent)
+             struct frec *prev = forward->dependent;
+             free_frec(forward);
+             forward = prev;
+             forward->blocking_query = NULL; /* already gone */
+             blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
+             n = forward->stash_len;
+             
+             if (status == STAT_SECURE)
                {
-                 struct frec *prev;
+                 if (forward->flags & FREC_DNSKEY_QUERY)
+                   status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
+                 else if (forward->flags & FREC_DS_QUERY)
+                   status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
+                 else
+                   status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class); 
                  
-                 if (status == STAT_SECURE)
+                 if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
                    {
-                     if (forward->flags & FREC_DNSKEY_QUERY)
-                       status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
-                     else if (forward->flags & FREC_DS_QUERY)
-                       status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
+                     my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
+                     status = STAT_INSECURE;
                    }
-                 
-                 prev = forward->dependent;
-                 free_frec(forward);
-                 forward = prev;
-                 forward->blocking_query = NULL; /* already gone */
-                 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
-                  n = forward->stash_len;
-               }
-             
-             /* All DNSKEY and DS records done and in cache, now finally validate original 
-                answer, provided last DNSKEY is OK. */
-             if (status == STAT_SECURE)
-               status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class);
-             
-             if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
-               {
-                 my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
-                 status = STAT_INSECURE;
                }
            }
          
          if (status == STAT_TRUNCATED)
-            header->hb3 |= HB3_TC;
+           header->hb3 |= HB3_TC;
          else
            log_query(F_KEYTAG | F_SECSTAT, "result", NULL, 
                      status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
index 4c57c8d9d5d8c22d442c9166576890486eecf0f2..ec2c7a912f8433a9516230ee9fcdd35f01642efd 100644 (file)
@@ -1710,32 +1710,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                }
              else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
                {
-#ifdef HAVE_DNSSEC
-                 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && 
-                     (crecp->flags & F_DNSSECOK) &&
-                     !(crecp->flags & F_NEG) && 
-                     sec_reqd &&
-                     option_bool(OPT_DNSSEC_VALID))
+                 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
                    {
-                     int gotsig = 0;
-                     
-                     crecp = NULL;
-                     while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
+                     if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
+                       crecp = NULL;
+#ifdef HAVE_DNSSEC
+                     else if (crecp->flags & F_DNSSECOK)
                        {
-                         if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
+                         int gotsig = 0;
+                         
+                         crecp = NULL;
+                         while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
                            {
-                             char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
-                             gotsig = 1;
-                             
-                             if (!dryrun && 
-                                 add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
-                                                     crecp->ttd - now, &nameoffset,
-                                                     T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
-                               anscount++;
-                           }
-                       } 
-                     /* Need to re-run original cache search */
-                     crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
+                             if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
+                               {
+                                 char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
+                                 gotsig = 1;
+                                 
+                                 if (!dryrun && 
+                                     add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+                                                         crecp->ttd - now, &nameoffset,
+                                                         T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
+                                   anscount++;
+                               }
+                           } 
+                         /* Need to re-run original cache search */
+                         crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
+                       }
                    }
 #endif
 
@@ -1918,42 +1919,45 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
                      crecp = save;
                    }
 
-#ifdef HAVE_DNSSEC
-                 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && 
-                     (crecp->flags & F_DNSSECOK) &&
-                     !(crecp->flags & F_NEG) && 
-                     sec_reqd &&
-                     option_bool(OPT_DNSSEC_VALID))
+                 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
+                    because we've not doing DNSSEC or the cached answer is signed by negative,
+                    don't answer from the cache, forward instead. */
+                 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
                    {
-                     /* We're returning validated data, need to return the RRSIG too. */
-
-                     int sigtype = type;
-                     /* The signature may have expired even though the data is still in cache, 
-                        forward instead of answering from cache if so. */
-                     int gotsig = 0;
-                     
-                     if (crecp->flags & F_CNAME)
-                       sigtype = T_CNAME;
-                     
-                     crecp = NULL;
-                     while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
+                     if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
+                       crecp = NULL;
+#ifdef HAVE_DNSSEC
+                     else if (crecp->flags & F_DNSSECOK)
                        {
-                         if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
+                         /* We're returning validated data, need to return the RRSIG too. */
+                         
+                         int sigtype = type;
+                         /* The signature may have expired even though the data is still in cache, 
+                            forward instead of answering from cache if so. */
+                         int gotsig = 0;
+                         
+                         if (crecp->flags & F_CNAME)
+                           sigtype = T_CNAME;
+                         
+                         crecp = NULL;
+                         while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
                            {
-                             char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
-                             gotsig = 1;
-
-                             if (!dryrun && 
-                                 add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
-                                                     crecp->ttd - now, &nameoffset,
-                                                     T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
-                               anscount++;
+                             if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
+                               {
+                                 char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
+                                 gotsig = 1;
+                                 
+                                 if (!dryrun && 
+                                     add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+                                                         crecp->ttd - now, &nameoffset,
+                                                         T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
+                                   anscount++;
+                               }
                            }
+                         /* Need to re-run original cache search */
+                         crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
                        }
-                     /* Need to re-run original cache search */
-                     crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
-                   }
-                
+                   }            
 #endif
                  if (crecp)
                    do