+++ /dev/null
-From ef3d137a646fa8309e1ff5184e3e145eef40cc4d Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Tue, 5 Dec 2017 22:37:29 +0000
-Subject: [PATCH] Fix infinite retries in strict-order mode.
-
- If all configured dns servers return refused in
- response to a query; dnsmasq will end up in an infinite loop
- retransmitting the dns query resulting into high CPU load.
- Problem is caused by the dns refuse retransmission logic which does
- not check for the end of a dns server list iteration in strict mode.
- Having one configured dns server returning a refused reply easily
- triggers this problem in strict order mode. This was introduced in
- 9396752c115b3ab733fa476b30da73237e12e7ba
-
- Thanks to Hans Dedecker <dedeckeh@gmail.com> for spotting this
- and the initial patch.
----
- src/forward.c | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -797,10 +797,20 @@ void reply_query(int fd, int family, tim
- unsigned char *pheader;
- size_t plen;
- int is_sign;
--
-+
-+ /* In strict order mode, there must be a server later in the chain
-+ left to send to, otherwise without the forwardall mechanism,
-+ code further on will cycle around the list forwever if they
-+ all return REFUSED. Note that server is always non-NULL before
-+ this executes. */
-+ if (option_bool(OPT_ORDER))
-+ for (server = forward->sentto->next; server; server = server->next)
-+ if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
-+ break;
-+
- /* recreate query from reply */
- pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
-- if (!is_sign)
-+ if (!is_sign && server)
- {
- header->ancount = htons(0);
- header->nscount = htons(0);
+++ /dev/null
-From 3c973ad92d317df736d5a8fde67baba6b102d91e Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sun, 14 Jan 2018 21:05:37 +0000
-Subject: [PATCH] Use SIGINT (instead of overloading SIGHUP) to turn on DNSSEC
- time validation.
-
----
- src/dnsmasq.c | 36 +++++++++++++++++++++++++-----------
- src/dnsmasq.h | 1 +
- src/helper.c | 3 ++-
- 5 files changed, 38 insertions(+), 14 deletions(-)
-
---- a/src/dnsmasq.c
-+++ b/src/dnsmasq.c
-@@ -137,7 +137,8 @@ int main (int argc, char **argv)
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGALRM, &sigact, NULL);
- sigaction(SIGCHLD, &sigact, NULL);
--
-+ sigaction(SIGINT, &sigact, NULL);
-+
- /* ignore SIGPIPE */
- sigact.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sigact, NULL);
-@@ -815,7 +816,7 @@ int main (int argc, char **argv)
-
- daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
- if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
-- my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
-+ my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until receipt of SIGINT"));
-
- if (rc == 1)
- my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
-@@ -1142,7 +1143,7 @@ static void sig_handler(int sig)
- {
- /* ignore anything other than TERM during startup
- and in helper proc. (helper ignore TERM too) */
-- if (sig == SIGTERM)
-+ if (sig == SIGTERM || sig == SIGINT)
- exit(EC_MISC);
- }
- else if (pid != getpid())
-@@ -1168,6 +1169,15 @@ static void sig_handler(int sig)
- event = EVENT_DUMP;
- else if (sig == SIGUSR2)
- event = EVENT_REOPEN;
-+ else if (sig == SIGINT)
-+ {
-+ /* Handle SIGINT normally in debug mode, so
-+ ctrl-c continues to operate. */
-+ if (option_bool(OPT_DEBUG))
-+ exit(EC_MISC);
-+ else
-+ event = EVENT_TIME;
-+ }
- else
- return;
-
-@@ -1295,14 +1305,7 @@ static void async_event(int pipe, time_t
- {
- case EVENT_RELOAD:
- daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
--
--#ifdef HAVE_DNSSEC
-- if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
-- {
-- my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
-- daemon->dnssec_no_time_check = 0;
-- }
--#endif
-+
- /* fall through */
-
- case EVENT_INIT:
-@@ -1411,6 +1414,17 @@ static void async_event(int pipe, time_t
- poll_resolv(0, 1, now);
- break;
-
-+ case EVENT_TIME:
-+#ifdef HAVE_DNSSEC
-+ if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
-+ {
-+ my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
-+ daemon->dnssec_no_time_check = 0;
-+ clear_cache_and_reload(now);
-+ }
-+#endif
-+ break;
-+
- case EVENT_TERM:
- /* Knock all our children on the head. */
- for (i = 0; i < MAX_PROCS; i++)
---- a/src/dnsmasq.h
-+++ b/src/dnsmasq.h
-@@ -175,6 +175,7 @@ struct event_desc {
- #define EVENT_NEWROUTE 23
- #define EVENT_TIME_ERR 24
- #define EVENT_SCRIPT_LOG 25
-+#define EVENT_TIME 26
-
- /* Exit codes. */
- #define EC_GOOD 0
---- a/src/helper.c
-+++ b/src/helper.c
-@@ -97,13 +97,14 @@ int create_helper(int event_fd, int err_
- return pipefd[1];
- }
-
-- /* ignore SIGTERM, so that we can clean up when the main process gets hit
-+ /* ignore SIGTERM and SIGINT, so that we can clean up when the main process gets hit
- and SIGALRM so that we can use sleep() */
- sigact.sa_handler = SIG_IGN;
- sigact.sa_flags = 0;
- sigemptyset(&sigact.sa_mask);
- sigaction(SIGTERM, &sigact, NULL);
- sigaction(SIGALRM, &sigact, NULL);
-+ sigaction(SIGINT, &sigact, NULL);
-
- if (!option_bool(OPT_DEBUG) && uid != 0)
- {
+++ /dev/null
-From 4fe6744a220eddd3f1749b40cac3dfc510787de6 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Fri, 19 Jan 2018 12:26:08 +0000
-Subject: [PATCH] DNSSEC fix for wildcard NSEC records. CVE-2017-15107
- applies.
-
-It's OK for NSEC records to be expanded from wildcards,
-but in that case, the proof of non-existence is only valid
-starting at the wildcard name, *.<domain> NOT the name expanded
-from the wildcard. Without this check it's possible for an
-attacker to craft an NSEC which wrongly proves non-existence
-in a domain which includes a wildcard for NSEC.
----
- src/dnssec.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
- 2 files changed, 114 insertions(+), 15 deletions(-)
-
---- a/src/dnssec.c
-+++ b/src/dnssec.c
-@@ -424,15 +424,17 @@ static void from_wire(char *name)
- static int count_labels(char *name)
- {
- int i;
--
-+ char *p;
-+
- if (*name == 0)
- return 0;
-
-- for (i = 0; *name; name++)
-- if (*name == '.')
-+ for (p = name, i = 0; *p; p++)
-+ if (*p == '.')
- i++;
-
-- return i+1;
-+ /* Don't count empty first label. */
-+ return *name == '.' ? i : i+1;
- }
-
- /* Implement RFC1982 wrapped compare for 32-bit numbers */
-@@ -1412,8 +1414,8 @@ static int hostname_cmp(const char *a, c
- }
- }
-
--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)
-+static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
-+ char *workspace1_in, char *workspace2, char *name, int type, int *nons)
- {
- int i, rc, rdlen;
- unsigned char *p, *psave;
-@@ -1426,6 +1428,9 @@ static int prove_non_existence_nsec(stru
- /* Find NSEC record that proves name doesn't exist */
- for (i = 0; i < nsec_count; i++)
- {
-+ char *workspace1 = workspace1_in;
-+ int sig_labels, name_labels;
-+
- p = nsecs[i];
- if (!extract_name(header, plen, &p, workspace1, 1, 10))
- return 0;
-@@ -1434,7 +1439,27 @@ static int prove_non_existence_nsec(stru
- psave = p;
- if (!extract_name(header, plen, &p, workspace2, 1, 10))
- return 0;
--
-+
-+ /* If NSEC comes from wildcard expansion, use original wildcard
-+ as name for computation. */
-+ sig_labels = *labels[i];
-+ name_labels = count_labels(workspace1);
-+
-+ if (sig_labels < name_labels)
-+ {
-+ int k;
-+ for (k = name_labels - sig_labels; k != 0; k--)
-+ {
-+ while (*workspace1 != '.' && *workspace1 != 0)
-+ workspace1++;
-+ if (k != 1 && *workspace1 == '.')
-+ workspace1++;
-+ }
-+
-+ workspace1--;
-+ *workspace1 = '*';
-+ }
-+
- rc = hostname_cmp(workspace1, name);
-
- if (rc == 0)
-@@ -1832,24 +1857,26 @@ static int prove_non_existence_nsec3(str
-
- 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;
-+ static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
-+ static int nsecset_sz = 0, rrsig_labels_sz = 0;
-
- int type_found = 0;
-- unsigned char *p = skip_questions(header, plen);
-+ unsigned char *auth_start, *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;
-+
-+ auth_start = p;
-
- for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
- {
- unsigned char *pstart = p;
-
-- if (!(p = skip_name(p, header, plen, 10)))
-+ if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
- return 0;
--
-+
- GETSHORT(type, p);
- GETSHORT(class, p);
- p += 4; /* TTL */
-@@ -1866,7 +1893,69 @@ static int prove_non_existence(struct dn
- if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
- return 0;
-
-- nsecset[nsecs_found++] = pstart;
-+ if (type == T_NSEC)
-+ {
-+ /* If we're looking for NSECs, find the corresponding SIGs, to
-+ extract the labels value, which we need in case the NSECs
-+ are the result of wildcard expansion.
-+ Note that the NSEC may not have been validated yet
-+ so if there are multiple SIGs, make sure the label value
-+ is the same in all, to avoid be duped by a rogue one.
-+ If there are no SIGs, that's an error */
-+ unsigned char *p1 = auth_start;
-+ int res, j, rdlen1, type1, class1;
-+
-+ if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
-+ return 0;
-+
-+ rrsig_labels[nsecs_found] = NULL;
-+
-+ for (j = ntohs(header->nscount); j != 0; j--)
-+ {
-+ if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
-+ return 0;
-+
-+ GETSHORT(type1, p1);
-+ GETSHORT(class1, p1);
-+ p1 += 4; /* TTL */
-+ GETSHORT(rdlen1, p1);
-+
-+ if (!CHECK_LEN(header, p1, plen, rdlen1))
-+ return 0;
-+
-+ if (res == 1 && class1 == qclass && type1 == T_RRSIG)
-+ {
-+ int type_covered;
-+ unsigned char *psav = p1;
-+
-+ if (rdlen1 < 18)
-+ return 0; /* bad packet */
-+
-+ GETSHORT(type_covered, p1);
-+
-+ if (type_covered == T_NSEC)
-+ {
-+ p1++; /* algo */
-+
-+ /* labels field must be the same in every SIG we find. */
-+ if (!rrsig_labels[nsecs_found])
-+ rrsig_labels[nsecs_found] = p1;
-+ else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
-+ return 0;
-+ }
-+ p1 = psav;
-+ }
-+
-+ if (!ADD_RDLEN(header, p1, plen, rdlen1))
-+ return 0;
-+ }
-+
-+ /* Must have found at least one sig. */
-+ if (!rrsig_labels[nsecs_found])
-+ return 0;
-+ }
-+
-+ nsecset[nsecs_found++] = pstart;
- }
-
- if (!ADD_RDLEN(header, p, plen, rdlen))
-@@ -1874,7 +1963,7 @@ static int prove_non_existence(struct dn
- }
-
- if (type_found == T_NSEC)
-- return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
-+ return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
- else if (type_found == T_NSEC3)
- return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
- else