]> git.ipfire.org Git - ipfire-2.x.git/commitdiff
dnsmasq: Import some patches from upstream
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 2 Jan 2015 10:49:07 +0000 (11:49 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 2 Jan 2015 10:49:07 +0000 (11:49 +0100)
These may fix the stability issues described in #10607

config/rootfiles/core/87/filelists/dnsmasq [new symlink]
lfs/dnsmasq
src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch [new file with mode: 0644]
src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch [new file with mode: 0644]
src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch [new file with mode: 0644]
src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch [new file with mode: 0644]
src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch [new file with mode: 0644]
src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch [new file with mode: 0644]

diff --git a/config/rootfiles/core/87/filelists/dnsmasq b/config/rootfiles/core/87/filelists/dnsmasq
new file mode 120000 (symlink)
index 0000000..d469c74
--- /dev/null
@@ -0,0 +1 @@
+../../../common/dnsmasq
\ No newline at end of file
index 60dabf4a53ce7ed16df026302dae3fd0b783afd8..8493657ed6c18698c946b7b1d2038ff4c4ca6ee3 100644 (file)
@@ -72,6 +72,12 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch
        cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-2.72rc2-Add-support-to-read-ISC-DHCP-lease-file.patch
        cd $(DIR_APP) && sed -i src/config.h \
                -e 's|/\* #define HAVE_IDN \*/|#define HAVE_IDN|g' \
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch b/src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch
new file mode 100644 (file)
index 0000000..bdbe168
--- /dev/null
@@ -0,0 +1,25 @@
+From 0b1008d367d44e77352134a4c5178f896f0db3e7 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Sat, 27 Dec 2014 15:33:32 +0000
+Subject: [PATCH] Bad packet protection.
+
+---
+ src/dnssec.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index ed8cf89..026794b 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -805,7 +805,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+               {
+                 while (*name_start != '.' && *name_start != 0)
+                   name_start++;
+-                if (k != 1)
++                if (k != 1 && *name_start == '.')
+                   name_start++;
+               }
+             
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch b/src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch
new file mode 100644 (file)
index 0000000..82c68ed
--- /dev/null
@@ -0,0 +1,85 @@
+From 094b5c3d904bae9aeb3206d9f3b8348926b84975 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Sun, 21 Dec 2014 16:11:52 +0000
+Subject: [PATCH] Fix crash in DNSSEC code when attempting to verify large
+ RRs.
+
+---
+ src/dnssec.c |   27 +++++++++++++++++++--------
+ 1 files changed, 22 insertions(+), 8 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 69bfc29..3208ac7 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -456,16 +456,27 @@ static u16 *get_desc(int type)
+ /* Return bytes of canonicalised rdata, when the return value is zero, the remaining 
+    data, pointed to by *p, should be used raw. */
+-static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, 
++static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
+                    unsigned char **p, u16 **desc)
+ {
+   int d = **desc;
+   
+-  (*desc)++;
+-  
+   /* No more data needs mangling */
+   if (d == (u16)-1)
+-    return 0;
++    {
++      /* If there's more data than we have space for, just return what fits,
++       we'll get called again for more chunks */
++      if (end - *p > bufflen)
++      {
++        memcpy(buff, *p, bufflen);
++        *p += bufflen;
++        return bufflen;
++      }
++      
++      return 0;
++    }
++ 
++  (*desc)++;
+   
+   if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
+     /* domain-name, canonicalise */
+@@ -560,7 +571,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
+             if (left1 != 0)
+               memmove(buff1, buff1 + len1 - left1, left1);
+             
+-            if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
++            if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
+               {
+                 quit = 1;
+                 len1 = end1 - p1;
+@@ -571,7 +582,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
+             if (left2 != 0)
+               memmove(buff2, buff2 + len2 - left2, left2);
+             
+-            if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
++            if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
+               {
+                 quit = 1;
+                 len2 = end2 - p2;
+@@ -808,7 +819,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+         /* canonicalise rdata and calculate length of same, use name buffer as workspace */
+         cp = p;
+         dp = rr_desc;
+-        for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
++        for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
+         len += end - cp;
+         len = htons(len);
+         hash->update(ctx, 2, (unsigned char *)&len); 
+@@ -816,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+         /* Now canonicalise again and digest. */
+         cp = p;
+         dp = rr_desc;
+-        while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
++        while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
+           hash->update(ctx, seg, (unsigned char *)name);
+         if (cp != end)
+           hash->update(ctx, end - cp, cp);
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch b/src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch
new file mode 100644 (file)
index 0000000..25bbbb7
--- /dev/null
@@ -0,0 +1,365 @@
+From fbc5205702c7f6f431d9f1043c553d7fb62ddfdb Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Tue, 23 Dec 2014 15:46:08 +0000
+Subject: [PATCH] Fix problems validating NSEC3 and wildcards.
+
+---
+ src/dnssec.c |  253 +++++++++++++++++++++++++++++-----------------------------
+ 1 file changed, 128 insertions(+), 125 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 3208ac7..9350d3e 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -615,6 +615,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
+    Return code:
+    STAT_SECURE   if it validates.
+    STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
++   (In this case *wildcard_out points to the "body" of the wildcard within name.) 
+    STAT_NO_SIG no RRsigs found.
+    STAT_INSECURE RRset empty.
+    STAT_BOGUS    signature is wrong, bad packet.
+@@ -625,8 +626,8 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
+    name is unchanged on exit. keyname is used as workspace and trashed.
+ */
+-static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, 
+-                        int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
++static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, 
++                        char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
+ {
+   static unsigned char **rrset = NULL, **sigs = NULL;
+   static int rrset_sz = 0, sig_sz = 0;
+@@ -798,8 +799,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+           {
+             int k;
+             for (k = name_labels - labels; k != 0; k--)
+-              while (*name_start != '.' && *name_start != 0)
+-                name_start++;
++              {
++                while (*name_start != '.' && *name_start != 0)
++                  name_start++;
++                if (k != 1)
++                  name_start++;
++              }
++            
++            if (wildcard_out)
++              *wildcard_out = name_start+1;
++
+             name_start--;
+             *name_start = '*';
+           }
+@@ -974,7 +983,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
+             if (recp1->addr.ds.keylen == (int)hash->digest_size &&
+                 (ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
+                 memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
+-                validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
++                validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
+               {
+                 valid = 1;
+                 break;
+@@ -1443,11 +1452,88 @@ static int base32_decode(char *in, unsigned char *out)
+   return p - out;
+ }
++static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
++                              char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count)
++{
++  int i, hash_len, salt_len, base32_len, rdlen;
++  unsigned char *p, *psave;
++
++  for (i = 0; i < nsec_count; i++)
++    if ((p = nsecs[i]))
++      {
++              if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
++          !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
++        return 0;
++      
++      p += 8; /* class, type, TTL */
++      GETSHORT(rdlen, p);
++      psave = p;
++      p += 4; /* algo, flags, iterations */
++      salt_len = *p++; /* salt_len */
++      p += salt_len; /* salt */
++      hash_len = *p++; /* p now points to next hashed name */
++      
++      if (!CHECK_LEN(header, p, plen, hash_len))
++        return 0;
++      
++      if (digest_len == base32_len && hash_len == base32_len)
++        {
++          int rc = memcmp(workspace2, digest, digest_len);
++
++          if (rc == 0)
++            {
++              /* We found an NSEC3 whose hashed name exactly matches the query, so
++                 we just need to check the type map. p points to the RR data for the record. */
++              
++              int offset = (type & 0xff) >> 3;
++              int mask = 0x80 >> (type & 0x07);
++              
++              p += hash_len; /* skip next-domain hash */
++              rdlen -= p - psave;
++
++              if (!CHECK_LEN(header, p, plen, rdlen))
++                return 0;
++              
++              while (rdlen >= 2)
++                {
++                  if (p[0] == type >> 8)
++                    {
++                      /* Does the NSEC3 say our type exists? */
++                      if (offset < p[1] && (p[offset+2] & mask) != 0)
++                        return STAT_BOGUS;
++                      
++                      break; /* finshed checking */
++                    }
++                  
++                  rdlen -= p[1];
++                  p +=  p[1];
++                }
++
++              return 1;
++            }
++          else if (rc <= 0)
++            {
++              /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
++                 wrap around case, name-hash falls between NSEC3 name-hash and end */
++              if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
++                return 1;
++            }
++          else 
++            {
++              /* wrap around case, name falls between start and next domain name */
++              if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
++                return 1;
++            }
++        }
++      }
++  return 0;
++}
++
+ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
+-                                   char *workspace1, char *workspace2, char *name, int type)
++                                   char *workspace1, char *workspace2, char *name, int type, char *wildname)
+ {
+   unsigned char *salt, *p, *digest;
+-  int digest_len, i, iterations, salt_len, hash_len, base32_len, algo = 0;
++  int digest_len, i, iterations, salt_len, base32_len, algo = 0;
+   struct nettle_hash const *hash;
+   char *closest_encloser, *next_closest, *wildcard;
+  
+@@ -1520,7 +1606,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+   if (!(hash = hash_find("sha1")))
+     return STAT_BOGUS;
+-  /* Now, we need the "closest encloser NSEC3" */
++  if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
++    return STAT_BOGUS;
++  
++  if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
++    return STAT_SECURE;
++
++  /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" 
++     or an answer inferred from a wildcard record. */
+   closest_encloser = name;
+   next_closest = NULL;
+@@ -1529,6 +1622,9 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+       if (*closest_encloser == '.')
+       closest_encloser++;
++      if (wildname && hostname_isequal(closest_encloser, wildname))
++      break;
++
+       if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
+       return STAT_BOGUS;
+       
+@@ -1551,127 +1647,33 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+     }
+   while ((closest_encloser = strchr(closest_encloser, '.')));
+   
+-  /* No usable NSEC3s */
+-  if (i == nsec_count)
++  if (!closest_encloser)
+     return STAT_BOGUS;
+   
+-  if (!next_closest)
+-    {
+-      /* We found an NSEC3 whose hashed name exactly matches the query, so
+-       Now we just need to check the type map. p points to the RR data for the record. */
+-      int rdlen;
+-      unsigned char *psave;
+-      int offset = (type & 0xff) >> 3;
+-      int mask = 0x80 >> (type & 0x07);
+-      
+-      p += 8; /* class, type, TTL */
+-      GETSHORT(rdlen, p);
+-      psave = p;
+-      p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
+-      hash_len = *p++;
+-      if (!CHECK_LEN(header, p, plen, hash_len))
+-      return STAT_BOGUS; /* bad packet */
+-      p += hash_len;
+-      rdlen -= p - psave;
+-      
+-      while (rdlen >= 2)
+-      {
+-        if (!CHECK_LEN(header, p, plen, rdlen))
+-          return STAT_BOGUS;
+-        
+-        if (p[0] == type >> 8)
+-          {
+-            /* Does the NSEC3 say our type exists? */
+-            if (offset < p[1] && (p[offset+2] & mask) != 0)
+-              return STAT_BOGUS;
+-            
+-            break; /* finshed checking */
+-          }
+-        
+-        rdlen -= p[1];
+-        p +=  p[1];
+-      }
+-      
+-      return STAT_SECURE;
+-    }
+-
+   /* Look for NSEC3 that proves the non-existence of the next-closest encloser */
+   if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
+     return STAT_BOGUS;
+-  for (i = 0; i < nsec_count; i++)
+-    if ((p = nsecs[i]))
+-      {
+-              if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
+-          !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
+-        return STAT_BOGUS;
+-         
+-      p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
+-      hash_len = *p++; /* p now points to next hashed name */
+- 
+-      if (!CHECK_LEN(header, p, plen, hash_len))
+-        return STAT_BOGUS;
+-      
+-      if (digest_len == base32_len && hash_len == base32_len)
+-        {
+-          if (memcmp(workspace2, digest, digest_len) <= 0)
+-            {
+-              /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
+-                 wrap around case, name-hash falls between NSEC3 name-hash and end */
+-              if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
+-                return STAT_SECURE;
+-            }
+-          else 
+-            {
+-              /* wrap around case, name falls between start and next domain name */
+-              if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
+-                return STAT_SECURE;
+-            }
+-        }
+-      }
+-  
+-  /* Finally, check that there's no seat of wildcard synthesis */
+-  if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
+-    return STAT_BOGUS;
+-  
+-  wildcard--;
+-  *wildcard = '*';
+-  
+-  if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
++  if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
+     return STAT_BOGUS;
+   
+-  for (i = 0; i < nsec_count; i++)
+-    if ((p = nsecs[i]))
+-      {
+-      if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
+-          !(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
+-        return STAT_BOGUS;
+-         
+-      p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
+-      hash_len = *p++; /* p now points to next hashed name */
+- 
+-      if (!CHECK_LEN(header, p, plen, hash_len))
+-        return STAT_BOGUS;
+-      
+-      if (digest_len == base32_len && hash_len == base32_len)
+-        {
+-          if (memcmp(workspace2, digest, digest_len) <= 0)
+-            {
+-              /* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
+-                 wrap around case, name-hash falls between NSEC3 name-hash and end */
+-              if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
+-                return STAT_SECURE;
+-            }
+-          else 
+-            {
+-              /* wrap around case, name falls between start and next domain name */
+-              if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
+-                return STAT_SECURE;
+-            }
+-        }
+-      }
++  /* Finally, check that there's no seat of wildcard synthesis */
++  if (!wildname)
++    {
++      if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
++      return STAT_BOGUS;
++      
++      wildcard--;
++      *wildcard = '*';
++      
++      if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
++      return STAT_BOGUS;
++      
++      if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
++      return STAT_BOGUS;
++    }
+   
+-  return STAT_BOGUS;
++  return STAT_SECURE;
+ }
+     
+ /* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
+@@ -1792,8 +1794,9 @@ 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;
+-            
+-            rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0);
++            char *wildname;
++
++            rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
+             
+             if (rc == STAT_SECURE_WILDCARD)
+               {
+@@ -1807,7 +1810,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+                 if (nsec_type == T_NSEC)
+                   rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
+                 else
+-                  rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
++                  rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, wildname);
+                 if (rc != STAT_SECURE)
+                   return rc;
+@@ -1933,7 +1936,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+   if (nsec_type == T_NSEC)
+     return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
+   else
+-    return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
++    return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL);
+ }
+ /* Chase the CNAME chain in the packet until the first record which _doesn't validate.
+@@ -1980,7 +1983,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
+           return STAT_INSECURE;
+         
+         /* validate CNAME chain, return if insecure or need more data */
+-        rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, 0, 0, 0);
++        rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
+         if (rc != STAT_SECURE)
+           {
+             if (rc == STAT_NO_SIG)
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch b/src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch
new file mode 100644 (file)
index 0000000..e961734
--- /dev/null
@@ -0,0 +1,32 @@
+From 83d2ed09fc0216b567d7fb2197e4ff3eae150b0d Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Tue, 23 Dec 2014 18:42:38 +0000
+Subject: [PATCH] Initialise return value.
+
+---
+ src/dnssec.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 9350d3e..ed8cf89 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -637,10 +637,13 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+   struct crec *crecp = NULL;
+   int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
+   u16 *rr_desc = get_desc(type);
+-
++ 
++  if (wildcard_out)
++    *wildcard_out = NULL;
++  
+   if (!(p = skip_questions(header, plen)))
+     return STAT_BOGUS;
+-
++  
+   name_labels = count_labels(name); /* For 4035 5.3.2 check */
+   /* look for RRSIGs for this RRset and get pointers to each RR in the set. */
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch b/src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch
new file mode 100644 (file)
index 0000000..e2b6f37
--- /dev/null
@@ -0,0 +1,99 @@
+From cbc652423403e3cef00e00240f6beef713142246 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Sun, 21 Dec 2014 21:21:53 +0000
+Subject: [PATCH] Make caching work for CNAMEs pointing to A/AAAA records
+ shadowed in /etc/hosts
+
+If the answer to an upstream query is a CNAME which points to an
+A/AAAA record which also exists in /etc/hosts and friends, then
+caching is suppressed, to avoid inconsistent answers. This is
+now modified to allow caching when the upstream and local A/AAAA
+records have the same value.
+---
+ src/cache.c |   34 +++++++++++++++++++++++++---------
+ 1 file changed, 25 insertions(+), 9 deletions(-)
+
+diff --git a/src/cache.c b/src/cache.c
+index f9e1d31..ff1ca6f 100644
+--- a/src/cache.c
++++ b/src/cache.c
+@@ -322,7 +322,7 @@ static int is_expired(time_t now, struct crec *crecp)
+   return 1;
+ }
+-static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
++static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
+ {
+   /* Scan and remove old entries.
+      If (flags & F_FORWARD) then remove any forward entries for name and any expired
+@@ -331,8 +331,8 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
+      entries in the whole cache.
+      If (flags == 0) remove any expired entries in the whole cache. 
+-     In the flags & F_FORWARD case, the return code is valid, and returns zero if the
+-     name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
++     In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
++     to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
+      We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
+      so that when we hit an entry which isn't reverse and is immortal, we're done. */
+@@ -361,7 +361,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
+                 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
+               {
+                 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
+-                  return 0;
++                  return crecp;
+                 *up = crecp->hash_next;
+                 cache_unlink(crecp);
+                 cache_free(crecp);
+@@ -378,7 +378,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
+                  crecp->addr.sig.type_covered == addr->addr.dnssec.type))
+               {
+                 if (crecp->flags & F_CONFIG)
+-                  return 0;
++                  return crecp;
+                 *up = crecp->hash_next;
+                 cache_unlink(crecp);
+                 cache_free(crecp);
+@@ -423,7 +423,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
+           up = &crecp->hash_next;
+     }
+   
+-  return 1;
++  return NULL;
+ }
+ /* Note: The normal calling sequence is
+@@ -471,10 +471,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
+     return NULL;
+   
+   /* First remove any expired entries and entries for the name/address we
+-     are currently inserting. Fail if we attempt to delete a name from
+-     /etc/hosts or DHCP. */
+-  if (!cache_scan_free(name, addr, now, flags))
++     are currently inserting. */
++  if ((new = cache_scan_free(name, addr, now, flags)))
+     {
++      /* We're trying to insert a record over one from 
++       /etc/hosts or DHCP, or other config. If the 
++       existing record is for an A or AAAA and
++       the record we're trying to insert is the same, 
++       just drop the insert, but don't error the whole process. */
++      if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
++      {
++        if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
++            new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
++          return new;
++#ifdef HAVE_IPV6
++        else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
++                 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
++          return new;
++#endif
++      }
++      
+       insert_error = 1;
+       return NULL;
+     }
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch b/src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch
new file mode 100644 (file)
index 0000000..64a8507
--- /dev/null
@@ -0,0 +1,28 @@
+From 800c5cc1e7438818fd80f08c2d472df249a6942d Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 15 Dec 2014 17:50:15 +0000
+Subject: [PATCH] Remove floor on EDNS0 packet size with DNSSEC.
+
+---
+ src/dnsmasq.c |    5 -----
+ 1 files changed, 5 deletions(-)
+
+diff --git a/src/dnsmasq.c b/src/dnsmasq.c
+index bf2e25a..5c7750d 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -87,11 +87,6 @@ int main (int argc, char **argv)
+  
+   if (daemon->edns_pktsz < PACKETSZ)
+     daemon->edns_pktsz = PACKETSZ;
+-#ifdef HAVE_DNSSEC
+-  /* Enforce min packet big enough for DNSSEC */
+-  if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
+-    daemon->edns_pktsz = EDNS_PKTSZ;
+-#endif
+   daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ? 
+     daemon->edns_pktsz : DNSMASQ_PACKETSZ;
+-- 
+1.7.10.4
+