From b56472d49b2e50d6c8f84023b80c3ee43114bfe1 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 2 Jan 2015 11:49:07 +0100 Subject: [PATCH] dnsmasq: Import some patches from upstream These may fix the stability issues described in #10607 --- config/rootfiles/core/87/filelists/dnsmasq | 1 + lfs/dnsmasq | 6 + .../dnsmasq-2.73-bad-packet-protection.patch | 25 ++ ...-when-attempting-to-verify-large-RRs.patch | 85 ++++ ...blems-validating-NSEC3-and-wildcards.patch | 365 ++++++++++++++++++ ...dnsmasq-2.73-initialise-return-value.patch | 32 ++ ...A-AAAA-records-shadowed-in-etc-hosts.patch | 99 +++++ ...oor-on-edns0-packet-size-with-DNSSEC.patch | 28 ++ 8 files changed, 641 insertions(+) create mode 120000 config/rootfiles/core/87/filelists/dnsmasq create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch create mode 100644 src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch diff --git a/config/rootfiles/core/87/filelists/dnsmasq b/config/rootfiles/core/87/filelists/dnsmasq new file mode 120000 index 0000000000..d469c74631 --- /dev/null +++ b/config/rootfiles/core/87/filelists/dnsmasq @@ -0,0 +1 @@ +../../../common/dnsmasq \ No newline at end of file diff --git a/lfs/dnsmasq b/lfs/dnsmasq index 60dabf4a53..8493657ed6 100644 --- a/lfs/dnsmasq +++ b/lfs/dnsmasq @@ -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 index 0000000000..bdbe1683c9 --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-bad-packet-protection.patch @@ -0,0 +1,25 @@ +From 0b1008d367d44e77352134a4c5178f896f0db3e7 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 index 0000000000..82c68ed9ee --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-fix-crash-in-DNSSEC-code-when-attempting-to-verify-large-RRs.patch @@ -0,0 +1,85 @@ +From 094b5c3d904bae9aeb3206d9f3b8348926b84975 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 index 0000000000..25bbbb76ba --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-fix-problems-validating-NSEC3-and-wildcards.patch @@ -0,0 +1,365 @@ +From fbc5205702c7f6f431d9f1043c553d7fb62ddfdb Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 index 0000000000..e961734361 --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-initialise-return-value.patch @@ -0,0 +1,32 @@ +From 83d2ed09fc0216b567d7fb2197e4ff3eae150b0d Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 index 0000000000..e2b6f37931 --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-make-caching-work-for-CNAMEs-pointing-to-A-AAAA-records-shadowed-in-etc-hosts.patch @@ -0,0 +1,99 @@ +From cbc652423403e3cef00e00240f6beef713142246 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 ,, + 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 index 0000000000..64a8507ef2 --- /dev/null +++ b/src/patches/dnsmasq/dnsmasq-2.73-remove-floor-on-edns0-packet-size-with-DNSSEC.patch @@ -0,0 +1,28 @@ +From 800c5cc1e7438818fd80f08c2d472df249a6942d Mon Sep 17 00:00:00 2001 +From: Simon Kelley +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 + -- 2.39.2