* [PATCH] dnsmasq 2.75: latest upstream patches ;-)
@ 2015-12-18 14:11 Matthias Fischer
2015-12-18 15:30 ` Michael Tremer
0 siblings, 1 reply; 3+ messages in thread
From: Matthias Fischer @ 2015-12-18 14:11 UTC (permalink / raw)
To: development
[-- Attachment #1: Type: text/plain, Size: 31843 bytes --]
The neverending story continues...
Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
---
lfs/dnsmasq | 4 +
...1-Tweaks_to_EDNS0_handling_in_DNS_replies.patch | 133 +++++++
..._code_Check_zone_status_is_NSEC_proof_bad.patch | 409 +++++++++++++++++++++
...023-Fix_brace_botch_in_dnssec_validate_ds.patch | 98 +++++
...ning_which_DNSSEC_sig_algos_are_supported.patch | 145 ++++++++
5 files changed, 789 insertions(+)
create mode 100644 src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
create mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
create mode 100644 src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
create mode 100644 src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
diff --git a/lfs/dnsmasq b/lfs/dnsmasq
index eeb7e03..c8fd7db 100644
--- a/lfs/dnsmasq
+++ b/lfs/dnsmasq
@@ -93,6 +93,10 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/018-Move_code_which_caches_DS_records_to_a_more_logical_place.patch
cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
cd $(DIR_APP) && sed -i src/config.h \
diff --git a/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch b/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
new file mode 100644
index 0000000..c3c74cc
--- /dev/null
+++ b/src/patches/dnsmasq/021-Tweaks_to_EDNS0_handling_in_DNS_replies.patch
@@ -0,0 +1,133 @@
+From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Thu, 17 Dec 2015 10:44:58 +0000
+Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies.
+
+---
+ src/dnssec.c | 20 +++++++++-----------
+ src/rfc1035.c | 57 +++++++++++++++++++++++++++++++++------------------------
+ 2 files changed, 42 insertions(+), 35 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index dc563e0..012b2a6 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ /* Empty DS without NSECS */
+ if (qtype == T_DS)
+ return STAT_BOGUS;
+- else
++
++ rc = zone_status(name, qclass, keyname, now);
++ if (rc != STAT_SECURE)
+ {
+- rc = zone_status(name, qclass, keyname, now);
+- if (rc != STAT_SECURE)
+- {
+- if (class)
+- *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
+- return rc;
+- }
+-
+- return STAT_BOGUS; /* signed zone, no NSECs */
+- }
++ if (class)
++ *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
++ return rc;
++ }
++
++ return STAT_BOGUS; /* signed zone, no NSECs */
+ }
+
+ if (nsec_type == T_NSEC)
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index def8fa0..188d05f 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
+ struct mx_srv_record *rec;
+ size_t len;
+-
++
++ if (ntohs(header->ancount) != 0 ||
++ ntohs(header->nscount) != 0 ||
++ ntohs(header->qdcount) == 0 ||
++ OPCODE(header) != QUERY )
++ return 0;
++
+ /* Don't return AD set if checking disabled. */
+ if (header->hb4 & HB4_CD)
+ sec_data = 0;
+@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ *ad_reqd = header->hb4 & HB4_AD;
+ *do_bit = 0;
+
+- /* If there is an RFC2671 pseudoheader then it will be overwritten by
++ /* If there is an additional data section then it will be overwritten by
+ partial replies, so we have to do a dry run to see if we can answer
+- the query. We check to see if the do bit is set, if so we always
+- forward rather than answering from the cache, which doesn't include
+- security information, unless we're in DNSSEC validation mode. */
++ the query. */
+
+- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
+- {
+- unsigned short flags;
+-
+- have_pseudoheader = 1;
++ if (ntohs(header->arcount) != 0)
++ {
++ dryrun = 1;
+
+- pheader += 4; /* udp size, ext_rcode */
+- GETSHORT(flags, pheader);
+-
+- if ((sec_reqd = flags & 0x8000))
+- {
+- *do_bit = 1;/* do bit */
+- *ad_reqd = 1;
++ /* If there's an additional section, there might be an EDNS(0) pseudoheader */
++ if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
++ {
++ unsigned short flags;
++
++ have_pseudoheader = 1;
++
++ pheader += 4; /* udp size, ext_rcode */
++ GETSHORT(flags, pheader);
++
++ if ((sec_reqd = flags & 0x8000))
++ {
++ *do_bit = 1;/* do bit */
++ *ad_reqd = 1;
++ }
+ }
+-
+- dryrun = 1;
+ }
+
+- if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
+- return 0;
+-
+ for (rec = daemon->mxnames; rec; rec = rec->next)
+ rec->offset = 0;
+
+@@ -1730,8 +1735,12 @@ 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)))
+ {
+- /* Don't use cache when DNSSEC data required. */
+- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
++ /* Don't use cache when DNSSEC data required, unless we know that
++ the zone is unsigned, which implies that we're doing
++ validation. */
++ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
++ !sec_reqd ||
++ (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+ {
+ do
+ {
+--
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
new file mode 100644
index 0000000..60503e9
--- /dev/null
+++ b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
@@ -0,0 +1,409 @@
+From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Thu, 17 Dec 2015 11:57:26 +0000
+Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone status is NSEC
+ proof bad.
+
+---
+ src/dnssec.c | 207 +++++++++++++++++++++++++---------------------------------
+ 1 file changed, 90 insertions(+), 117 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 012b2a6..ddae497 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const char *b)
+ }
+ }
+
+-/* Find all the NSEC or NSEC3 records in a reply.
+- return an array of pointers to them. */
+-static int find_nsec_records(struct dns_header *header, size_t plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
+-{
+- static unsigned char **nsecset = NULL;
+- static int nsecset_sz = 0;
+-
+- int type_found = 0;
+- unsigned char *p = skip_questions(header, plen);
+- int type, class, rdlen, i, nsecs_found;
+-
+- /* Move to NS section */
+- if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
+- return 0;
+-
+- for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
+- {
+- unsigned char *pstart = p;
+-
+- if (!(p = skip_name(p, header, plen, 10)))
+- return 0;
+-
+- GETSHORT(type, p);
+- GETSHORT(class, p);
+- p += 4; /* TTL */
+- GETSHORT(rdlen, p);
+-
+- if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
+- {
+- /* No mixed NSECing 'round here, thankyouverymuch */
+- if (type_found == T_NSEC && type == T_NSEC3)
+- return 0;
+- if (type_found == T_NSEC3 && type == T_NSEC)
+- return 0;
+-
+- type_found = type;
+-
+- if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
+- return 0;
+-
+- nsecset[nsecs_found++] = pstart;
+- }
+-
+- if (!ADD_RDLEN(header, p, plen, rdlen))
+- return 0;
+- }
+-
+- *nsecsetp = nsecset;
+- *nsecsetl = nsecs_found;
+-
+- return type_found;
+-}
+-
+ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
+ char *workspace1, char *workspace2, char *name, int type, int *nons)
+ {
+@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ {
+ p = nsecs[i];
+ if (!extract_name(header, plen, &p, workspace1, 1, 10))
+- return STAT_BOGUS;
++ return 0;
+ p += 8; /* class, type, TTL */
+ GETSHORT(rdlen, p);
+ psave = p;
+ if (!extract_name(header, plen, &p, workspace2, 1, 10))
+- return STAT_BOGUS;
++ return 0;
+
+ rc = hostname_cmp(workspace1, name);
+
+@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ {
+ /* 4035 para 5.4. Last sentence */
+ if (type == T_NSEC || type == T_RRSIG)
+- return STAT_SECURE;
++ return 1;
+
+ /* NSEC with the same name as the RR we're testing, check
+ that the type in question doesn't appear in the type map */
+@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ /* A CNAME answer would also be valid, so if there's a CNAME is should
+ have been returned. */
+ if ((p[2] & (0x80 >> T_CNAME)) != 0)
+- return STAT_BOGUS;
++ return 0;
+
+ /* If the SOA bit is set for a DS record, then we have the
+ DS from the wrong side of the delegation. */
+ if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
+- return STAT_BOGUS;
++ return 0;
+ }
+
+ while (rdlen >= 2)
+ {
+ if (!CHECK_LEN(header, p, plen, rdlen))
+- return STAT_BOGUS;
++ return 0;
+
+ if (p[0] == type >> 8)
+ {
+ /* Does the NSEC say our type exists? */
+ if (offset < p[1] && (p[offset+2] & mask) != 0)
+- return STAT_BOGUS;
++ return 0;
+
+ break; /* finshed checking */
+ }
+@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ p += p[1];
+ }
+
+- return STAT_SECURE;
++ return 1;
+ }
+ else if (rc == -1)
+ {
+ /* Normal case, name falls between NSEC name and next domain name,
+ wrap around case, name falls between NSEC name (rc == -1) and end */
+ if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
+- return STAT_SECURE;
++ return 1;
+ }
+ else
+ {
+ /* wrap around case, name falls between start and next domain name */
+ if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
+- return STAT_SECURE;
++ return 1;
+ }
+ }
+
+- return STAT_BOGUS;
++ return 0;
+ }
+
+ /* return digest length, or zero on error */
+@@ -1701,7 +1648,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+ for (i = 0; i < nsec_count; i++)
+ {
+ if (!(p = skip_name(nsecs[i], header, plen, 15)))
+- return STAT_BOGUS; /* bad packet */
++ return 0; /* bad packet */
+
+ p += 10; /* type, class, TTL, rdlen */
+ algo = *p++;
+@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+
+ /* No usable NSEC3s */
+ if (i == nsec_count)
+- return STAT_BOGUS;
++ return 0;
+
+ p++; /* flags */
+ GETSHORT (iterations, p);
+ salt_len = *p++;
+ salt = p;
+ if (!CHECK_LEN(header, salt, plen, salt_len))
+- return STAT_BOGUS; /* bad packet */
++ return 0; /* bad packet */
+
+ /* Now prune so we only have NSEC3 records with same iterations, salt and algo */
+ for (i = 0; i < nsec_count; i++)
+@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+ nsecs[i] = NULL; /* Speculative, will be restored if OK. */
+
+ if (!(p = skip_name(nsec3p, header, plen, 15)))
+- return STAT_BOGUS; /* bad packet */
++ return 0; /* bad packet */
+
+ p += 10; /* type, class, TTL, rdlen */
+
+@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+ continue;
+
+ if (!CHECK_LEN(header, p, plen, salt_len))
+- return STAT_BOGUS; /* bad packet */
++ return 0; /* bad packet */
+
+ if (memcmp(p, salt, salt_len) != 0)
+ continue;
+@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+
+ /* Algo is checked as 1 above */
+ if (!(hash = hash_find("sha1")))
+- return STAT_BOGUS;
++ return 0;
+
+ if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
+- return STAT_BOGUS;
++ return 0;
+
+ if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
+- return STAT_SECURE;
++ return 1;
+
+ /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
+ or an answer inferred from a wildcard record. */
+@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+ break;
+
+ if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
+- return STAT_BOGUS;
++ return 0;
+
+ 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;
++ return 0;
+
+ if (digest_len == base32_len &&
+ memcmp(digest, workspace2, digest_len) == 0)
+@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+ while ((closest_encloser = strchr(closest_encloser, '.')));
+
+ if (!closest_encloser)
+- return STAT_BOGUS;
++ return 0;
+
+ /* 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;
++ return 0;
+
+ if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
+- return STAT_BOGUS;
++ return 0;
+
+ /* Finally, check that there's no seat of wildcard synthesis */
+ if (!wildname)
+ {
+ if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
+- return STAT_BOGUS;
++ return 0;
+
+ wildcard--;
+ *wildcard = '*';
+
+ if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
+- return STAT_BOGUS;
++ return 0;
+
+ if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
+- return STAT_BOGUS;
++ return 0;
+ }
+
+- return STAT_SECURE;
++ return 1;
++}
++
++static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
++{
++ static unsigned char **nsecset = NULL;
++ static int nsecset_sz = 0;
++
++ int type_found = 0;
++ unsigned char *p = skip_questions(header, plen);
++ int type, class, rdlen, i, nsecs_found;
++
++ /* Move to NS section */
++ if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
++ return 0;
++
++ for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
++ {
++ unsigned char *pstart = p;
++
++ if (!(p = skip_name(p, header, plen, 10)))
++ return 0;
++
++ GETSHORT(type, p);
++ GETSHORT(class, p);
++ p += 4; /* TTL */
++ GETSHORT(rdlen, p);
++
++ if (class == qclass && (type == T_NSEC || type == T_NSEC3))
++ {
++ /* No mixed NSECing 'round here, thankyouverymuch */
++ if (type_found != 0 && type_found != type)
++ return 0;
++
++ type_found = type;
++
++ if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
++ return 0;
++
++ nsecset[nsecs_found++] = pstart;
++ }
++
++ if (!ADD_RDLEN(header, p, plen, rdlen))
++ return 0;
++ }
++
++ if (type_found == T_NSEC)
++ return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
++ else
++ return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
+ }
+
+ /* Check signing status of name.
+@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ static unsigned char **targets = NULL;
+ static int target_sz = 0;
+
+- unsigned char *ans_start, *p1, *p2, **nsecs;
++ unsigned char *ans_start, *p1, *p2;
+ int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
+- int i, j, rc, nsec_count;
+- int nsec_type;
++ int i, j, rc;
+
+ if (neganswer)
+ *neganswer = 0;
+@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ targets[j] = NULL;
+ }
+
+- if (rc == STAT_SECURE_WILDCARD)
+- {
+- /* An attacker replay a wildcard answer with a different
+- answer and overlay a genuine RR. To prove this
+- hasn't happened, the answer must prove that
+- the gennuine record doesn't exist. Check that here. */
+- if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
+- return STAT_BOGUS; /* No NSECs or bad packet */
+-
+- /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
+- below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
+- we'll return BOGUS then. */
+-
+- if (nsec_type == T_NSEC)
+- rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
+- else
+- rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename,
+- keyname, name, type1, wildname, NULL);
+-
+- if (rc == STAT_BOGUS)
+- return rc;
+- }
++ /* An attacker replay a wildcard answer with a different
++ answer and overlay a genuine RR. To prove this
++ hasn't happened, the answer must prove that
++ the gennuine record doesn't exist. Check that here.
++ Note that we may not yet have validated the NSEC/NSEC3 RRsets.
++ That's not a problem since if the RRsets later fail
++ we'll return BOGUS then. */
++ if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
++ return STAT_BOGUS;
+ }
+ }
+ }
+@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+
+ /* For anything other than a DS record, this situation is OK if either
+ the answer is in an unsigned zone, or there's a NSEC records. */
+- if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
++ if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
+ {
+ /* Empty DS without NSECS */
+ if (qtype == T_DS)
+ return STAT_BOGUS;
+
+- rc = zone_status(name, qclass, keyname, now);
+- if (rc != STAT_SECURE)
++ if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
+ {
+ if (class)
+ *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
+@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+
+ return STAT_BOGUS; /* signed zone, no NSECs */
+ }
+-
+- if (nsec_type == T_NSEC)
+- rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
+- else
+- rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
+-
+- if (rc != STAT_SECURE)
+- return rc;
+ }
+
+ return STAT_SECURE;
+--
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
new file mode 100644
index 0000000..eda6fbd
--- /dev/null
+++ b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
@@ -0,0 +1,98 @@
+From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Thu, 17 Dec 2015 16:58:04 +0000
+Subject: [PATCH] Fix brace botch in dnssec_validate_ds()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf8
+Content-Transfer-Encoding: 8bit
+
+Thanks to MichaÅ KÄpieÅ for spotting this.
+---
+ src/dnssec.c | 34 +++++++++++++++++-----------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index ddae497..1f8c954 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+ /* The DNS packet is expected to contain the answer to a DNSKEY query.
+ Put all DNSKEYs in the answer which are valid into the cache.
+ return codes:
+- STAT_OK Done, key(s) in cache.
+- STAT_BOGUS No DNSKEYs found, which can be validated with DS,
+- or self-sign for DNSKEY RRset is not valid, bad packet.
+- STAT_NEED_DS DS records to validate a key not found, name in keyname
+- STAT_NEED_DNSKEY DNSKEY records to validate a key not found, name in keyname
++ STAT_OK Done, key(s) in cache.
++ STAT_BOGUS No DNSKEYs found, which can be validated with DS,
++ or self-sign for DNSKEY RRset is not valid, bad packet.
++ STAT_NEED_DS DS records to validate a key not found, name in keyname
++ STAT_NEED_KEY DNSKEY records to validate a key not found, name in keyname
+ */
+ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
+ {
+@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
+ }
+
+ p = psave;
+-
+- if (!ADD_RDLEN(header, p, plen, rdlen))
+- return STAT_BOGUS; /* bad packet */
+ }
+-
+- cache_end_insert();
++ if (!ADD_RDLEN(header, p, plen, rdlen))
++ return STAT_BOGUS; /* bad packet */
+ }
++
++ cache_end_insert();
++
+ }
+ else
+ {
+@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
+
+ /* Check signing status of name.
+ returns:
+- STAT_SECURE zone is signed.
+- STAT_INSECURE zone proved unsigned.
+- STAT_NEED_DS require DS record of name returned in keyname.
+- STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
++ STAT_SECURE zone is signed.
++ STAT_INSECURE zone proved unsigned.
++ STAT_NEED_DS require DS record of name returned in keyname.
++ STAT_NEED_KEY require DNSKEY record of name returned in keyname.
+ name returned unaltered.
+ */
+ static int zone_status(char *name, int class, char *keyname, time_t now)
+@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ if (rc == STAT_SECURE)
+ rc = STAT_BOGUS;
+ if (class)
+- *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
++ *class = class1; /* Class for NEED_DS or NEED_KEY */
+ }
+ else
+ rc = STAT_INSECURE;
+@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ {
+ /* Zone is insecure, don't need to validate RRset */
+ if (class)
+- *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
++ *class = class1; /* Class for NEED_DS or NEED_KEY */
+ return rc;
+ }
+
+@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
+ if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
+ {
+ if (class)
+- *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
++ *class = qclass; /* Class for NEED_DS or NEED_KEY */
+ return rc;
+ }
+
+--
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch b/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
new file mode 100644
index 0000000..abcae5c
--- /dev/null
+++ b/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
@@ -0,0 +1,145 @@
+From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Thu, 17 Dec 2015 17:23:03 +0000
+Subject: [PATCH] Do a better job of determining which DNSSEC sig algos are
+ supported.
+
+---
+ src/dnssec.c | 52 +++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 37 insertions(+), 15 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 1f8c954..82394ee 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo)
+ case 8: return "sha256";
+ case 10: return "sha512";
+ case 12: return "gosthash94";
+-#ifndef NO_NETTLE_ECC
+ case 13: return "sha256";
+ case 14: return "sha384";
+-#endif
++
+ default: return NULL;
+ }
+ }
+@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char
+ }
+
+ static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+- unsigned char *digest, int algo)
++ unsigned char *digest, size_t digest_len, int algo)
+ {
+ unsigned char *p;
+ size_t exp_len;
+
+ static struct rsa_public_key *key = NULL;
+ static mpz_t sig_mpz;
++
++ (void)digest_len;
+
+ if (key == NULL)
+ {
+@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len,
+ }
+
+ static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+- unsigned char *digest, int algo)
++ unsigned char *digest, size_t digest_len, int algo)
+ {
+ unsigned char *p;
+ unsigned int t;
+@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len,
+ static struct dsa_public_key *key = NULL;
+ static struct dsa_signature *sig_struct;
+
++ (void)digest_len;
++
+ if (key == NULL)
+ {
+ if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
+@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
+ }
+ #endif
+
+-static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
+- unsigned char *digest, size_t digest_len, int algo)
++static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
++ unsigned char *digest, size_t digest_len, int algo)
+ {
+- (void)digest_len;
+-
++
++ /* Enure at runtime that we have support for this digest */
++ if (!hash_find(algo_digest_name(algo)))
++ return NULL;
++
++ /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
+ switch (algo)
+ {
+ case 1: case 5: case 7: case 8: case 10:
+- return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
++ return dnsmasq_rsa_verify;
+
+ case 3: case 6:
+- return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
++ return dnsmasq_dsa_verify;
+
+ #ifndef NO_NETTLE_ECC
+ case 13: case 14:
+- return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
++ return dnsmasq_ecdsa_verify;
+ #endif
+ }
+
+- return 0;
++ return NULL;
++}
++
++static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
++ unsigned char *digest, size_t digest_len, int algo)
++{
++
++ int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
++ unsigned char *digest, size_t digest_len, int algo);
++
++ func = verify_func(algo);
++
++ if (!func)
++ return 0;
++
++ return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
+ }
+
+ /* Convert from presentation format to wire format, in place.
+@@ -732,7 +754,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
+ if (check_date_range(sig_inception, sig_expiration) &&
+ labels <= name_labels &&
+ type_covered == type &&
+- algo_digest_name(algo))
++ verify_func(algo))
+ {
+ if (!expand_workspace(&sigs, &sig_sz, sigidx))
+ return 0;
+@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
+ if (crecp->flags & F_DNSSECOK)
+ return STAT_INSECURE; /* proved no DS here */
+ }
+- else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
++ else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
+ return STAT_INSECURE; /* algo we can't use - insecure */
+ else
+ secure_ds = 1;
+@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
+
+ do
+ {
+- if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
++ if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
+ return STAT_INSECURE;
+ }
+ while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
+--
+1.7.10.4
+
--
2.6.4
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] dnsmasq 2.75: latest upstream patches ;-)
2015-12-18 14:11 [PATCH] dnsmasq 2.75: latest upstream patches ;-) Matthias Fischer
@ 2015-12-18 15:30 ` Michael Tremer
2015-12-18 16:58 ` Matthias Fischer
0 siblings, 1 reply; 3+ messages in thread
From: Michael Tremer @ 2015-12-18 15:30 UTC (permalink / raw)
To: development
[-- Attachment #1: Type: text/plain, Size: 33354 bytes --]
Hi,
I merged them both since we are still having stability issues with
dnsmasq. Some of the cleanup patches look quite promising.
All give that some good testing, please.
-Michael
On Fri, 2015-12-18 at 15:11 +0100, Matthias Fischer wrote:
> The neverending story continues...
>
> Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
> ---
> lfs/dnsmasq | 4 +
> ...1-Tweaks_to_EDNS0_handling_in_DNS_replies.patch | 133 +++++++
> ..._code_Check_zone_status_is_NSEC_proof_bad.patch | 409
> +++++++++++++++++++++
> ...023-Fix_brace_botch_in_dnssec_validate_ds.patch | 98 +++++
> ...ning_which_DNSSEC_sig_algos_are_supported.patch | 145 ++++++++
> 5 files changed, 789 insertions(+)
> create mode 100644 src/patches/dnsmasq/021
> -Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> create mode 100644 src/patches/dnsmasq/022-Tidy_up_DNSSEC_non
> -existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> create mode 100644 src/patches/dnsmasq/023
> -Fix_brace_botch_in_dnssec_validate_ds.patch
> create mode 100644 src/patches/dnsmasq/024
> -Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.
> patch
>
> diff --git a/lfs/dnsmasq b/lfs/dnsmasq
> index eeb7e03..c8fd7db 100644
> --- a/lfs/dnsmasq
> +++ b/lfs/dnsmasq
> @@ -93,6 +93,10 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
> cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/018
> -Move_code_which_caches_DS_records_to_a_more_logical_place.patch
> cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/019-Generalise_RR
> -filtering_code_for_use_with_EDNS0.patch
> cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/020-DNSSEC_validation_tweak.patch
> + cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/021
> -Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> + cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non
> -existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> + cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/023
> -Fix_brace_botch_in_dnssec_validate_ds.patch
> + cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq/024
> -Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.
> patch
> cd $(DIR_APP) && patch -Np1 -i
> $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease
> -file.patch
>
> cd $(DIR_APP) && sed -i src/config.h \
> diff --git a/src/patches/dnsmasq/021
> -Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> b/src/patches/dnsmasq/021
> -Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> new file mode 100644
> index 0000000..c3c74cc
> --- /dev/null
> +++ b/src/patches/dnsmasq/021
> -Tweaks_to_EDNS0_handling_in_DNS_replies.patch
> @@ -0,0 +1,133 @@
> +From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Thu, 17 Dec 2015 10:44:58 +0000
> +Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies.
> +
> +---
> + src/dnssec.c | 20 +++++++++-----------
> + src/rfc1035.c | 57 +++++++++++++++++++++++++++++++++-------------
> -----------
> + 2 files changed, 42 insertions(+), 35 deletions(-)
> +
> +diff --git a/src/dnssec.c b/src/dnssec.c
> +index dc563e0..012b2a6 100644
> +--- a/src/dnssec.c
> ++++ b/src/dnssec.c
> +@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + /* Empty DS without NSECS */
> + if (qtype == T_DS)
> + return STAT_BOGUS;
> +- else
> ++
> ++ rc = zone_status(name, qclass, keyname, now);
> ++ if (rc != STAT_SECURE)
> + {
> +- rc = zone_status(name, qclass, keyname, now);
> +- if (rc != STAT_SECURE)
> +- {
> +- if (class)
> +- *class = qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> +- return rc;
> +- }
> +-
> +- return STAT_BOGUS; /* signed zone, no NSECs */
> +- }
> ++ if (class)
> ++ *class = qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> ++ return rc;
> ++ }
> ++
> ++ return STAT_BOGUS; /* signed zone, no NSECs */
> + }
> +
> + if (nsec_type == T_NSEC)
> +diff --git a/src/rfc1035.c b/src/rfc1035.c
> +index def8fa0..188d05f 100644
> +--- a/src/rfc1035.c
> ++++ b/src/rfc1035.c
> +@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> + int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
> + struct mx_srv_record *rec;
> + size_t len;
> +-
> ++
> ++ if (ntohs(header->ancount) != 0 ||
> ++ ntohs(header->nscount) != 0 ||
> ++ ntohs(header->qdcount) == 0 ||
> ++ OPCODE(header) != QUERY )
> ++ return 0;
> ++
> + /* Don't return AD set if checking disabled. */
> + if (header->hb4 & HB4_CD)
> + sec_data = 0;
> +@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header
> *header, char *limit, size_t qlen,
> + *ad_reqd = header->hb4 & HB4_AD;
> + *do_bit = 0;
> +
> +- /* If there is an RFC2671 pseudoheader then it will be
> overwritten by
> ++ /* If there is an additional data section then it will be
> overwritten by
> + partial replies, so we have to do a dry run to see if we can
> answer
> +- the query. We check to see if the do bit is set, if so we
> always
> +- forward rather than answering from the cache, which doesn't
> include
> +- security information, unless we're in DNSSEC validation mode.
> */
> ++ the query. */
> +
> +- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
> +- {
> +- unsigned short flags;
> +-
> +- have_pseudoheader = 1;
> ++ if (ntohs(header->arcount) != 0)
> ++ {
> ++ dryrun = 1;
> +
> +- pheader += 4; /* udp size, ext_rcode */
> +- GETSHORT(flags, pheader);
> +-
> +- if ((sec_reqd = flags & 0x8000))
> +- {
> +- *do_bit = 1;/* do bit */
> +- *ad_reqd = 1;
> ++ /* If there's an additional section, there might be an
> EDNS(0) pseudoheader */
> ++ if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
> ++ {
> ++ unsigned short flags;
> ++
> ++ have_pseudoheader = 1;
> ++
> ++ pheader += 4; /* udp size, ext_rcode */
> ++ GETSHORT(flags, pheader);
> ++
> ++ if ((sec_reqd = flags & 0x8000))
> ++ {
> ++ *do_bit = 1;/* do bit */
> ++ *ad_reqd = 1;
> ++ }
> + }
> +-
> +- dryrun = 1;
> + }
> +
> +- if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
> +- return 0;
> +-
> + for (rec = daemon->mxnames; rec; rec = rec->next)
> + rec->offset = 0;
> +
> +@@ -1730,8 +1735,12 @@ 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)))
> + {
> +- /* Don't use cache when DNSSEC data required. */
> +- if ((crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
> ++ /* Don't use cache when DNSSEC data required,
> unless we know that
> ++ the zone is unsigned, which implies that we're
> doing
> ++ validation. */
> ++ if ((crecp->flags & (F_HOSTS | F_DHCP |
> F_CONFIG)) ||
> ++ !sec_reqd ||
> ++ (option_bool(OPT_DNSSEC_VALID) && !(crecp
> ->flags & F_DNSSECOK)))
> + {
> + do
> + {
> +--
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non
> -existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non
> -existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> new file mode 100644
> index 0000000..60503e9
> --- /dev/null
> +++ b/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non
> -existence_code_Check_zone_status_is_NSEC_proof_bad.patch
> @@ -0,0 +1,409 @@
> +From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Thu, 17 Dec 2015 11:57:26 +0000
> +Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone
> status is NSEC
> + proof bad.
> +
> +---
> + src/dnssec.c | 207 +++++++++++++++++++++++++----------------------
> -----------
> + 1 file changed, 90 insertions(+), 117 deletions(-)
> +
> +diff --git a/src/dnssec.c b/src/dnssec.c
> +index 012b2a6..ddae497 100644
> +--- a/src/dnssec.c
> ++++ b/src/dnssec.c
> +@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const
> char *b)
> + }
> + }
> +
> +-/* Find all the NSEC or NSEC3 records in a reply.
> +- return an array of pointers to them. */
> +-static int find_nsec_records(struct dns_header *header, size_t
> plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
> +-{
> +- static unsigned char **nsecset = NULL;
> +- static int nsecset_sz = 0;
> +-
> +- int type_found = 0;
> +- unsigned char *p = skip_questions(header, plen);
> +- int type, class, rdlen, i, nsecs_found;
> +-
> +- /* Move to NS section */
> +- if (!p || !(p = skip_section(p, ntohs(header->ancount), header,
> plen)))
> +- return 0;
> +-
> +- for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
> +- {
> +- unsigned char *pstart = p;
> +-
> +- if (!(p = skip_name(p, header, plen, 10)))
> +- return 0;
> +-
> +- GETSHORT(type, p);
> +- GETSHORT(class, p);
> +- p += 4; /* TTL */
> +- GETSHORT(rdlen, p);
> +-
> +- if (class == class_reqd && (type == T_NSEC || type ==
> T_NSEC3))
> +- {
> +- /* No mixed NSECing 'round here, thankyouverymuch */
> +- if (type_found == T_NSEC && type == T_NSEC3)
> +- return 0;
> +- if (type_found == T_NSEC3 && type == T_NSEC)
> +- return 0;
> +-
> +- type_found = type;
> +-
> +- if (!expand_workspace(&nsecset, &nsecset_sz,
> nsecs_found))
> +- return 0;
> +-
> +- nsecset[nsecs_found++] = pstart;
> +- }
> +-
> +- if (!ADD_RDLEN(header, p, plen, rdlen))
> +- return 0;
> +- }
> +-
> +- *nsecsetp = nsecset;
> +- *nsecsetl = nsecs_found;
> +-
> +- return type_found;
> +-}
> +-
> + static int prove_non_existence_nsec(struct dns_header *header,
> size_t plen, unsigned char **nsecs, int nsec_count,
> + char *workspace1, char
> *workspace2, char *name, int type, int *nons)
> + {
> +@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> + {
> + p = nsecs[i];
> + if (!extract_name(header, plen, &p, workspace1, 1, 10))
> +- return STAT_BOGUS;
> ++ return 0;
> + p += 8; /* class, type, TTL */
> + GETSHORT(rdlen, p);
> + psave = p;
> + if (!extract_name(header, plen, &p, workspace2, 1, 10))
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + rc = hostname_cmp(workspace1, name);
> +
> +@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> + {
> + /* 4035 para 5.4. Last sentence */
> + if (type == T_NSEC || type == T_RRSIG)
> +- return STAT_SECURE;
> ++ return 1;
> +
> + /* NSEC with the same name as the RR we're testing, check
> + that the type in question doesn't appear in the type
> map */
> +@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> + /* A CNAME answer would also be valid, so if there's
> a CNAME is should
> + have been returned. */
> + if ((p[2] & (0x80 >> T_CNAME)) != 0)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + /* If the SOA bit is set for a DS record, then we
> have the
> + DS from the wrong side of the delegation. */
> + if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
> +- return STAT_BOGUS;
> ++ return 0;
> + }
> +
> + while (rdlen >= 2)
> + {
> + if (!CHECK_LEN(header, p, plen, rdlen))
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + if (p[0] == type >> 8)
> + {
> + /* Does the NSEC say our type exists? */
> + if (offset < p[1] && (p[offset+2] & mask) != 0)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + break; /* finshed checking */
> + }
> +@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct
> dns_header *header, size_t plen, unsi
> + p += p[1];
> + }
> +
> +- return STAT_SECURE;
> ++ return 1;
> + }
> + else if (rc == -1)
> + {
> + /* Normal case, name falls between NSEC name and next
> domain name,
> + wrap around case, name falls between NSEC name (rc ==
> -1) and end */
> + if (hostname_cmp(workspace2, name) >= 0 ||
> hostname_cmp(workspace1, workspace2) >= 0)
> +- return STAT_SECURE;
> ++ return 1;
> + }
> + else
> + {
> + /* wrap around case, name falls between start and next
> domain name */
> + if (hostname_cmp(workspace1, workspace2) >= 0 &&
> hostname_cmp(workspace2, name) >=0 )
> +- return STAT_SECURE;
> ++ return 1;
> + }
> + }
> +
> +- return STAT_BOGUS;
> ++ return 0;
> + }
> +
> + /* return digest length, or zero on error */
> +@@ -1701,7 +1648,7 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> + for (i = 0; i < nsec_count; i++)
> + {
> + if (!(p = skip_name(nsecs[i], header, plen, 15)))
> +- return STAT_BOGUS; /* bad packet */
> ++ return 0; /* bad packet */
> +
> + p += 10; /* type, class, TTL, rdlen */
> + algo = *p++;
> +@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> +
> + /* No usable NSEC3s */
> + if (i == nsec_count)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + p++; /* flags */
> + GETSHORT (iterations, p);
> + salt_len = *p++;
> + salt = p;
> + if (!CHECK_LEN(header, salt, plen, salt_len))
> +- return STAT_BOGUS; /* bad packet */
> ++ return 0; /* bad packet */
> +
> + /* Now prune so we only have NSEC3 records with same iterations,
> salt and algo */
> + for (i = 0; i < nsec_count; i++)
> +@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> + nsecs[i] = NULL; /* Speculative, will be restored if OK. */
> +
> + if (!(p = skip_name(nsec3p, header, plen, 15)))
> +- return STAT_BOGUS; /* bad packet */
> ++ return 0; /* bad packet */
> +
> + p += 10; /* type, class, TTL, rdlen */
> +
> +@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> + continue;
> +
> + if (!CHECK_LEN(header, p, plen, salt_len))
> +- return STAT_BOGUS; /* bad packet */
> ++ return 0; /* bad packet */
> +
> + if (memcmp(p, salt, salt_len) != 0)
> + continue;
> +@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> +
> + /* Algo is checked as 1 above */
> + if (!(hash = hash_find("sha1")))
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + if ((digest_len = hash_name(name, &digest, hash, salt, salt_len,
> iterations)) == 0)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + if (check_nsec3_coverage(header, plen, digest_len, digest, type,
> workspace1, workspace2, nsecs, nsec_count, nons))
> +- return STAT_SECURE;
> ++ return 1;
> +
> + /* Can't find an NSEC3 which covers the name directly, we need
> the "closest encloser NSEC3"
> + or an answer inferred from a wildcard record. */
> +@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> + break;
> +
> + if ((digest_len = hash_name(closest_encloser, &digest, hash,
> salt, salt_len, iterations)) == 0)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + 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;
> ++ return 0;
> +
> + if (digest_len == base32_len &&
> + memcmp(digest, workspace2, digest_len) == 0)
> +@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct
> dns_header *header, size_t plen, uns
> + while ((closest_encloser = strchr(closest_encloser, '.')));
> +
> + if (!closest_encloser)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + /* 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;
> ++ return 0;
> +
> + if (!check_nsec3_coverage(header, plen, digest_len, digest, type,
> workspace1, workspace2, nsecs, nsec_count, NULL))
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + /* Finally, check that there's no seat of wildcard synthesis */
> + if (!wildname)
> + {
> + if (!(wildcard = strchr(next_closest, '.')) || wildcard ==
> next_closest)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + wildcard--;
> + *wildcard = '*';
> +
> + if ((digest_len = hash_name(wildcard, &digest, hash, salt,
> salt_len, iterations)) == 0)
> +- return STAT_BOGUS;
> ++ return 0;
> +
> + if (!check_nsec3_coverage(header, plen, digest_len, digest,
> type, workspace1, workspace2, nsecs, nsec_count, NULL))
> +- return STAT_BOGUS;
> ++ return 0;
> + }
> +
> +- return STAT_SECURE;
> ++ return 1;
> ++}
> ++
> ++static int prove_non_existence(struct dns_header *header, size_t
> plen, char *keyname, char *name, int qtype, int qclass, char
> *wildname, int *nons)
> ++{
> ++ static unsigned char **nsecset = NULL;
> ++ static int nsecset_sz = 0;
> ++
> ++ int type_found = 0;
> ++ unsigned char *p = skip_questions(header, plen);
> ++ int type, class, rdlen, i, nsecs_found;
> ++
> ++ /* Move to NS section */
> ++ if (!p || !(p = skip_section(p, ntohs(header->ancount), header,
> plen)))
> ++ return 0;
> ++
> ++ for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
> ++ {
> ++ unsigned char *pstart = p;
> ++
> ++ if (!(p = skip_name(p, header, plen, 10)))
> ++ return 0;
> ++
> ++ GETSHORT(type, p);
> ++ GETSHORT(class, p);
> ++ p += 4; /* TTL */
> ++ GETSHORT(rdlen, p);
> ++
> ++ if (class == qclass && (type == T_NSEC || type == T_NSEC3))
> ++ {
> ++ /* No mixed NSECing 'round here, thankyouverymuch */
> ++ if (type_found != 0 && type_found != type)
> ++ return 0;
> ++
> ++ type_found = type;
> ++
> ++ if (!expand_workspace(&nsecset, &nsecset_sz,
> nsecs_found))
> ++ return 0;
> ++
> ++ nsecset[nsecs_found++] = pstart;
> ++ }
> ++
> ++ if (!ADD_RDLEN(header, p, plen, rdlen))
> ++ return 0;
> ++ }
> ++
> ++ if (type_found == T_NSEC)
> ++ return prove_non_existence_nsec(header, plen, nsecset,
> nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
> ++ else
> ++ return prove_non_existence_nsec3(header, plen, nsecset,
> nsecs_found, daemon->workspacename, keyname, name, qtype, wildname,
> nons);
> + }
> +
> + /* Check signing status of name.
> +@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + static unsigned char **targets = NULL;
> + static int target_sz = 0;
> +
> +- unsigned char *ans_start, *p1, *p2, **nsecs;
> ++ unsigned char *ans_start, *p1, *p2;
> + int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype,
> targetidx;
> +- int i, j, rc, nsec_count;
> +- int nsec_type;
> ++ int i, j, rc;
> +
> + if (neganswer)
> + *neganswer = 0;
> +@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + targets[j] = NULL;
> + }
> +
> +- if (rc == STAT_SECURE_WILDCARD)
> +- {
> +- /* An attacker replay a wildcard answer with
> a different
> +- answer and overlay a genuine RR. To prove
> this
> +- hasn't happened, the answer must prove
> that
> +- the gennuine record doesn't exist. Check
> that here. */
> +- if (!(nsec_type = find_nsec_records(header,
> plen, &nsecs, &nsec_count, class1)))
> +- return STAT_BOGUS; /* No NSECs or bad
> packet */
> +-
> +- /* Note that we may not yet have validated
> the NSEC/NSEC3 RRsets. Since the check
> +- below returns either SECURE or BOGUS,
> that's not a problem. If the RRsets later fail
> +- we'll return BOGUS then. */
> +-
> +- if (nsec_type == T_NSEC)
> +- rc = prove_non_existence_nsec(header, plen,
> nsecs, nsec_count, daemon->workspacename, keyname, name, type1,
> NULL);
> +- else
> +- rc = prove_non_existence_nsec3(header,
> plen, nsecs, nsec_count, daemon->workspacename,
> +- keyname,
> name, type1, wildname, NULL);
> +-
> +- if (rc == STAT_BOGUS)
> +- return rc;
> +- }
> ++ /* An attacker replay a wildcard answer with a
> different
> ++ answer and overlay a genuine RR. To prove
> this
> ++ hasn't happened, the answer must prove that
> ++ the gennuine record doesn't exist. Check that
> here.
> ++ Note that we may not yet have validated the
> NSEC/NSEC3 RRsets.
> ++ That's not a problem since if the RRsets
> later fail
> ++ we'll return BOGUS then. */
> ++ if (rc == STAT_SECURE_WILDCARD &&
> !prove_non_existence(header, plen, keyname, name, type1, class1,
> wildname, NULL))
> ++ return STAT_BOGUS;
> + }
> + }
> + }
> +@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> +
> + /* For anything other than a DS record, this situation is
> OK if either
> + the answer is in an unsigned zone, or there's a NSEC
> records. */
> +- if (!(nsec_type = find_nsec_records(header, plen, &nsecs,
> &nsec_count, qclass)))
> ++ if (!prove_non_existence(header, plen, keyname, name,
> qtype, qclass, NULL, nons))
> + {
> + /* Empty DS without NSECS */
> + if (qtype == T_DS)
> + return STAT_BOGUS;
> +
> +- rc = zone_status(name, qclass, keyname, now);
> +- if (rc != STAT_SECURE)
> ++ if ((rc = zone_status(name, qclass, keyname, now)) !=
> STAT_SECURE)
> + {
> + if (class)
> + *class = qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> +@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> +
> + return STAT_BOGUS; /* signed zone, no NSECs */
> + }
> +-
> +- if (nsec_type == T_NSEC)
> +- rc = prove_non_existence_nsec(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, nons);
> +- else
> +- rc = prove_non_existence_nsec3(header, plen, nsecs,
> nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
> +-
> +- if (rc != STAT_SECURE)
> +- return rc;
> + }
> +
> + return STAT_SECURE;
> +--
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/023
> -Fix_brace_botch_in_dnssec_validate_ds.patch
> b/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
> new file mode 100644
> index 0000000..eda6fbd
> --- /dev/null
> +++ b/src/patches/dnsmasq/023
> -Fix_brace_botch_in_dnssec_validate_ds.patch
> @@ -0,0 +1,98 @@
> +From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Thu, 17 Dec 2015 16:58:04 +0000
> +Subject: [PATCH] Fix brace botch in dnssec_validate_ds()
> +MIME-Version: 1.0
> +Content-Type: text/plain; charset=utf8
> +Content-Transfer-Encoding: 8bit
> +
> +Thanks to Michał Kępień for spotting this.
> +---
> + src/dnssec.c | 34 +++++++++++++++++-----------------
> + 1 file changed, 17 insertions(+), 17 deletions(-)
> +
> +diff --git a/src/dnssec.c b/src/dnssec.c
> +index ddae497..1f8c954 100644
> +--- a/src/dnssec.c
> ++++ b/src/dnssec.c
> +@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct
> dns_header *header, size_t plen, in
> + /* The DNS packet is expected to contain the answer to a DNSKEY
> query.
> + Put all DNSKEYs in the answer which are valid into the cache.
> + return codes:
> +- STAT_OK Done, key(s) in cache.
> +- STAT_BOGUS No DNSKEYs found, which can be
> validated with DS,
> +- or self-sign for DNSKEY RRset is not
> valid, bad packet.
> +- STAT_NEED_DS DS records to validate a key not found,
> name in keyname
> +- STAT_NEED_DNSKEY DNSKEY records to validate a key not
> found, name in keyname
> ++ STAT_OK Done, key(s) in cache.
> ++ STAT_BOGUS No DNSKEYs found, which can be validated
> with DS,
> ++ or self-sign for DNSKEY RRset is not valid,
> bad packet.
> ++ STAT_NEED_DS DS records to validate a key not found,
> name in keyname
> ++ STAT_NEED_KEY DNSKEY records to validate a key not found,
> name in keyname
> + */
> + int dnssec_validate_by_ds(time_t now, struct dns_header *header,
> size_t plen, char *name, char *keyname, int class)
> + {
> +@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct
> dns_header *header, size_t plen, char
> + }
> +
> + p = psave;
> +-
> +- if (!ADD_RDLEN(header, p, plen, rdlen))
> +- return STAT_BOGUS; /* bad packet */
> + }
> +-
> +- cache_end_insert();
> ++ if (!ADD_RDLEN(header, p, plen, rdlen))
> ++ return STAT_BOGUS; /* bad packet */
> + }
> ++
> ++ cache_end_insert();
> ++
> + }
> + else
> + {
> +@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct
> dns_header *header, size_t plen, char *key
> +
> + /* Check signing status of name.
> + returns:
> +- STAT_SECURE zone is signed.
> +- STAT_INSECURE zone proved unsigned.
> +- STAT_NEED_DS require DS record of name returned in keyname.
> +- STAT_NEED_DNSKEY require DNSKEY record of name returned in
> keyname.
> ++ STAT_SECURE zone is signed.
> ++ STAT_INSECURE zone proved unsigned.
> ++ STAT_NEED_DS require DS record of name returned in keyname.
> ++ STAT_NEED_KEY require DNSKEY record of name returned in keyname.
> + name returned unaltered.
> + */
> + static int zone_status(char *name, int class, char *keyname, time_t
> now)
> +@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + if (rc == STAT_SECURE)
> + rc = STAT_BOGUS;
> + if (class)
> +- *class = class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> ++ *class = class1; /* Class for NEED_DS or
> NEED_KEY */
> + }
> + else
> + rc = STAT_INSECURE;
> +@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + {
> + /* Zone is insecure, don't need to validate RRset
> */
> + if (class)
> +- *class = class1; /* Class for NEED_DS or
> NEED_DNSKEY */
> ++ *class = class1; /* Class for NEED_DS or
> NEED_KEY */
> + return rc;
> + }
> +
> +@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct
> dns_header *header, size_t plen, ch
> + if ((rc = zone_status(name, qclass, keyname, now)) !=
> STAT_SECURE)
> + {
> + if (class)
> +- *class = qclass; /* Class for NEED_DS or
> NEED_DNSKEY */
> ++ *class = qclass; /* Class for NEED_DS or NEED_KEY
> */
> + return rc;
> + }
> +
> +--
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/024
> -Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.
> patch b/src/patches/dnsmasq/024
> -Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.
> patch
> new file mode 100644
> index 0000000..abcae5c
> --- /dev/null
> +++ b/src/patches/dnsmasq/024
> -Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.
> patch
> @@ -0,0 +1,145 @@
> +From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00
> 2001
> +From: Simon Kelley <simon(a)thekelleys.org.uk>
> +Date: Thu, 17 Dec 2015 17:23:03 +0000
> +Subject: [PATCH] Do a better job of determining which DNSSEC sig
> algos are
> + supported.
> +
> +---
> + src/dnssec.c | 52 +++++++++++++++++++++++++++++++++++++----------
> -----
> + 1 file changed, 37 insertions(+), 15 deletions(-)
> +
> +diff --git a/src/dnssec.c b/src/dnssec.c
> +index 1f8c954..82394ee 100644
> +--- a/src/dnssec.c
> ++++ b/src/dnssec.c
> +@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo)
> + case 8: return "sha256";
> + case 10: return "sha512";
> + case 12: return "gosthash94";
> +-#ifndef NO_NETTLE_ECC
> + case 13: return "sha256";
> + case 14: return "sha384";
> +-#endif
> ++
> + default: return NULL;
> + }
> + }
> +@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash
> *hash, void **ctxp, unsigned char
> + }
> +
> + static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned
> int key_len, unsigned char *sig, size_t sig_len,
> +- unsigned char *digest, int algo)
> ++ unsigned char *digest, size_t
> digest_len, int algo)
> + {
> + unsigned char *p;
> + size_t exp_len;
> +
> + static struct rsa_public_key *key = NULL;
> + static mpz_t sig_mpz;
> ++
> ++ (void)digest_len;
> +
> + if (key == NULL)
> + {
> +@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata
> *key_data, unsigned int key_len,
> + }
> +
> + static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned
> int key_len, unsigned char *sig, size_t sig_len,
> +- unsigned char *digest, int algo)
> ++ unsigned char *digest, size_t
> digest_len, int algo)
> + {
> + unsigned char *p;
> + unsigned int t;
> +@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata
> *key_data, unsigned int key_len,
> + static struct dsa_public_key *key = NULL;
> + static struct dsa_signature *sig_struct;
> +
> ++ (void)digest_len;
> ++
> + if (key == NULL)
> + {
> + if (!(sig_struct = whine_malloc(sizeof(struct
> dsa_signature))) ||
> +@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct
> blockdata *key_data, unsigned int key_len
> + }
> + #endif
> +
> +-static int verify(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> +- unsigned char *digest, size_t digest_len, int
> algo)
> ++static int (*verify_func(int algo))(struct blockdata *key_data,
> unsigned int key_len, unsigned char *sig, size_t sig_len,
> ++ unsigned char *digest, size_t
> digest_len, int algo)
> + {
> +- (void)digest_len;
> +-
> ++
> ++ /* Enure at runtime that we have support for this digest */
> ++ if (!hash_find(algo_digest_name(algo)))
> ++ return NULL;
> ++
> ++ /* This switch defines which sig algorithms we support, can't
> introspect Nettle for that. */
> + switch (algo)
> + {
> + case 1: case 5: case 7: case 8: case 10:
> +- return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len,
> digest, algo);
> ++ return dnsmasq_rsa_verify;
> +
> + case 3: case 6:
> +- return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len,
> digest, algo);
> ++ return dnsmasq_dsa_verify;
> +
> + #ifndef NO_NETTLE_ECC
> + case 13: case 14:
> +- return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len,
> digest, digest_len, algo);
> ++ return dnsmasq_ecdsa_verify;
> + #endif
> + }
> +
> +- return 0;
> ++ return NULL;
> ++}
> ++
> ++static int verify(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> ++ unsigned char *digest, size_t digest_len, int
> algo)
> ++{
> ++
> ++ int (*func)(struct blockdata *key_data, unsigned int key_len,
> unsigned char *sig, size_t sig_len,
> ++ unsigned char *digest, size_t digest_len, int algo);
> ++
> ++ func = verify_func(algo);
> ++
> ++ if (!func)
> ++ return 0;
> ++
> ++ return (*func)(key_data, key_len, sig, sig_len, digest,
> digest_len, algo);
> + }
> +
> + /* Convert from presentation format to wire format, in place.
> +@@ -732,7 +754,7 @@ static int explore_rrset(struct dns_header
> *header, size_t plen, int class, int
> + if (check_date_range(sig_inception, sig_expiration)
> &&
> + labels <= name_labels &&
> + type_covered == type &&
> +- algo_digest_name(algo))
> ++ verify_func(algo))
> + {
> + if (!expand_workspace(&sigs, &sig_sz, sigidx))
> + return 0;
> +@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class,
> char *keyname, time_t now)
> + if (crecp->flags & F_DNSSECOK)
> + return STAT_INSECURE; /* proved no DS here
> */
> + }
> +- else if (!ds_digest_name(crecp->addr.ds.digest)
> || !algo_digest_name(crecp->addr.ds.algo))
> ++ else if (!hash_find(ds_digest_name(crecp
> ->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
> + return STAT_INSECURE; /* algo we can't use -
> insecure */
> + else
> + secure_ds = 1;
> +@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class,
> char *keyname, time_t now)
> +
> + do
> + {
> +- if (crecp->uid == (unsigned int)class &&
> !algo_digest_name(crecp->addr.key.algo))
> ++ if (crecp->uid == (unsigned int)class &&
> !verify_func(crecp->addr.key.algo))
> + return STAT_INSECURE;
> + }
> + while ((crecp = cache_find_by_name(crecp, keyname, now,
> F_DNSKEY)));
> +--
> +1.7.10.4
> +
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] dnsmasq 2.75: latest upstream patches ;-)
2015-12-18 15:30 ` Michael Tremer
@ 2015-12-18 16:58 ` Matthias Fischer
0 siblings, 0 replies; 3+ messages in thread
From: Matthias Fischer @ 2015-12-18 16:58 UTC (permalink / raw)
To: development
[-- Attachment #1: Type: text/plain, Size: 1197 bytes --]
Hi,
On 18.12.2015 16:30, Michael Tremer wrote:
> All give that some good testing, please.
You can bet that I'll do that...! ;-))
Latest compiled version (Dec 18, 14:21) is running since then without any (known) problems:
...
14:35:03 dnsmasq[27964]: exiting on receipt of SIGTERM
14:35:24 dnsmasq[18002]: started, version 2.75 cachesize 2500
14:35:24 dnsmasq[18002]: compile time options: IPv6 GNU-getopt no-DBus no-i18n IDN no-DHCP no-TFTP no-con ntrack ipset auth DNSSEC loop-detect no-inotify
14:35:24 dnsmasq[18002]: DNSSEC validation enabled
14:35:24 dnsmasq[18002]: reading /var/ipfire/red/resolv.conf
14:35:24 dnsmasq[18002]: using nameserver 84.200.69.80#53
14:35:24 dnsmasq[18002]: using nameserver 84.200.70.40#53
14:35:24 dnsmasq[18002]: reading /var/state/dhcp/dhcpd.leases
14:35:24 dnsmasq[18002]: read /etc/hosts - 9 addresses
...
If anyone wants to test, too:
http://people.ipfire.org/~mfischer/dnsmasq_275_2015_12_18 (MD5: ba95b04fca60d99dfe7e2188e24d7fb3)
This is the compiled binary, nothing more is needed.
Copy to '/usr/sbin', stop 'dnsmasq', rename (don't forget backing up the *old* version!), restart
'dnsmasq'.
Best,
Matthias
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2015-12-18 16:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-18 14:11 [PATCH] dnsmasq 2.75: latest upstream patches ;-) Matthias Fischer
2015-12-18 15:30 ` Michael Tremer
2015-12-18 16:58 ` Matthias Fischer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox