diff --git a/SOURCES/dnsmasq-2.76-forward-sfd.patch b/SOURCES/dnsmasq-2.76-forward-sfd.patch new file mode 100644 index 0000000..f8b693b --- /dev/null +++ b/SOURCES/dnsmasq-2.76-forward-sfd.patch @@ -0,0 +1,53 @@ +From b58aa4f06463947e0f899609ab03264e333c67a1 Mon Sep 17 00:00:00 2001 +From: Petr Mensik +Date: Wed, 21 Apr 2021 12:39:17 +0200 +Subject: [PATCH] Accept responses also from non-last bound interface + +Partial backport of upstream commit +74d4fcd756a85bc1823232ea74334f7ccfb9d5d2, smaller part of CVE-2021-3448 +fix. +--- + src/forward.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index a0b1f1d..ec2de6f 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -2228,6 +2228,8 @@ struct frec *get_new_frec(time_t now, int *wait, int force) + static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash) + { + struct frec *f; ++ struct server *s; ++ int type; + + for(f = daemon->frec_list; f; f = f->next) + if (f->sentto && f->new_id == id && +@@ -2240,9 +2242,21 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has + if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd) + return f; + +- /* sent to upstream from bound socket. */ +- if (f->sentto->sfd && f->sentto->sfd->fd == fd) +- return f; ++ /* Sent to upstream from socket associated with a server. ++ Note we have to iterate over all the possible servers, since they may ++ have different bound sockets. */ ++ type = f->sentto->flags & SERV_TYPE; ++ s = f->sentto; ++ do { ++ if ((type == (s->flags & SERV_TYPE)) && ++ (type != SERV_HAS_DOMAIN || ++ (s->domain && hostname_isequal(f->sentto->domain, s->domain))) && ++ !(s->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) && ++ s->sfd && s->sfd->fd == fd) ++ return f; ++ ++ s = s->next ? s->next : daemon->servers; ++ } while (s != f->sentto); + } + + return NULL; +-- +2.26.3 + diff --git a/SOURCES/dnsmasq-2.84-forward-mixed-af.patch b/SOURCES/dnsmasq-2.84-forward-mixed-af.patch new file mode 100644 index 0000000..62a27fa --- /dev/null +++ b/SOURCES/dnsmasq-2.84-forward-mixed-af.patch @@ -0,0 +1,79 @@ +From 7c80b06983505a0cb52d5e112777c9acbe2cb300 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Fri, 22 Jan 2021 16:49:12 +0000 +Subject: [PATCH] Move fd into frec_src, fixes + 15b60ddf935a531269bb8c68198de012a4967156 + +If identical queries from IPv4 and IPv6 sources are combined by the +new code added in 15b60ddf935a531269bb8c68198de012a4967156 then replies +can end up being sent via the wrong family of socket. The ->fd +should be per query, not per-question. + +In bind-interfaces mode, this could also result in replies being sent +via the wrong socket even when IPv4/IPV6 issues are not in play. + +(cherry picked from commit 04490bf622ac84891aad6f2dd2edf83725decdee) + +Fix for 12af2b171de0d678d98583e2190789e544440e02 + +(cherry picked from commit 3f535da79e7a42104543ef5c7b5fa2bed819a78b) +--- + src/dnsmasq.h | 3 ++- + src/forward.c | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/dnsmasq.h b/src/dnsmasq.h +index 9f5b48b..77f59b9 100644 +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -607,6 +607,7 @@ struct frec { + union mysockaddr source; + struct all_addr dest; + unsigned int iface, log_id; ++ int fd; + unsigned short orig_id; + struct frec_src *next; + } frec_src; +@@ -616,7 +617,7 @@ struct frec { + struct randfd *rfd6; + #endif + unsigned short new_id; +- int fd, forwardall, flags; ++ int forwardall, flags; + time_t time; + unsigned char *hash[HASH_SIZE]; + #ifdef HAVE_DNSSEC +diff --git a/src/forward.c b/src/forward.c +index a0b1f1d..637f220 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -366,6 +366,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + new->dest = *dst_addr; + new->log_id = daemon->log_id; + new->iface = dst_iface; ++ new->fd = udpfd; + } + + return 1; +@@ -390,8 +391,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + forward->frec_src.dest = *dst_addr; + forward->frec_src.iface = dst_iface; + forward->frec_src.next = NULL; ++ forward->frec_src.fd = udpfd; + forward->new_id = get_id(); +- forward->fd = udpfd; + memcpy(forward->hash, hash, HASH_SIZE); + forward->forwardall = 0; + forward->flags = fwd_flags; +@@ -1169,7 +1170,7 @@ void reply_query(int fd, int family, time_t now) + { + header->id = htons(src->orig_id); + +- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, ++ send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, + &src->source, &src->dest, src->iface); + + if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src) +-- +2.26.2 + diff --git a/SOURCES/dnsmasq-2.84-forward-retries.patch b/SOURCES/dnsmasq-2.84-forward-retries.patch new file mode 100644 index 0000000..a08dc03 --- /dev/null +++ b/SOURCES/dnsmasq-2.84-forward-retries.patch @@ -0,0 +1,177 @@ +From 3ae073ab82183075a93e71ed889e0ee4fdb780e6 Mon Sep 17 00:00:00 2001 +From: Simon Kelley +Date: Wed, 17 Feb 2021 23:56:32 +0000 +Subject: [PATCH] Fix problem with DNS retries in 2.83/2.84. + +The new logic in 2.83/2.84 which merges distinct requests for the +same domain causes problems with clients which do retries as distinct +requests (differing IDs and/or source ports.) The retries just get +piggy-backed on the first, failed, request. + +The logic is now changed so that distinct requests for repeated +queries still get merged into a single ID/source port, but they now +always trigger a re-try upstream. + +Thanks to Nicholas Mu for his analysis. + +(cherry picked from commit 141a26f979b4bc959d8e866a295e24f8cf456920) + +Simplify preceding fix. + +Remove distinction between retry with same QID/SP and +retry for same query with different QID/SP. If the +QID/SP are the same as an existing one, simply retry, +if a new QID/SP is seen, add to the list to be replied to. + +(cherry picked from commit 305cb79c5754d5554729b18a2c06fe7ce699687a) +--- + src/forward.c | 105 ++++++++++++++++++++++---------------------------- + 1 file changed, 45 insertions(+), 60 deletions(-) + +diff --git a/src/forward.c b/src/forward.c +index 637f220..1e9c509 100644 +--- a/src/forward.c ++++ b/src/forward.c +@@ -17,9 +17,6 @@ + #include "dnsmasq.h" + + static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash); +-static struct frec *lookup_frec_by_sender(unsigned short id, +- union mysockaddr *addr, +- void *hash); + static struct frec *lookup_frec_by_query(void *hash, unsigned int flags); + + static unsigned short get_id(void); +@@ -260,8 +257,48 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + fwd_flags |= FREC_DO_QUESTION; + #endif + +- /* may be no servers available. */ +- if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))) ++ /* Check for retry on existing query */ ++ if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags))) ++ { ++ struct frec_src *src; ++ ++ for (src = &forward->frec_src; src; src = src->next) ++ if (src->orig_id == ntohs(header->id) && ++ sockaddr_isequal(&src->source, udpaddr)) ++ break; ++ ++ /* Existing query, but from new source, just add this ++ client to the list that will get the reply.*/ ++ if (!src) ++ { ++ /* Note whine_malloc() zeros memory. */ ++ if (!daemon->free_frec_src && ++ daemon->frec_src_count < daemon->ftabsize && ++ (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src)))) ++ { ++ daemon->frec_src_count++; ++ daemon->free_frec_src->next = NULL; ++ } ++ ++ /* If we've been spammed with many duplicates, just drop the query. */ ++ if (!daemon->free_frec_src) ++ return 0; ++ ++ src = daemon->free_frec_src; ++ daemon->free_frec_src = src->next; ++ src->next = forward->frec_src.next; ++ forward->frec_src.next = src; ++ src->orig_id = ntohs(header->id); ++ src->source = *udpaddr; ++ src->dest = *dst_addr; ++ src->log_id = daemon->log_id; ++ src->iface = dst_iface; ++ src->fd = udpfd; ++ } ++ } ++ ++ /* retry existing query */ ++ if (forward) + { + /* If we didn't get an answer advertising a maximal packet in EDNS, + fall back to 1280, which should work everywhere on IPv6. +@@ -336,42 +373,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + } + else + { +- /* Query from new source, but the same query may be in progress +- from another source. If so, just add this client to the +- list that will get the reply. +- +- Note that is the EDNS client subnet option is in use, we can't do this, +- as the clients (and therefore query EDNS options) will be different +- for each query. The EDNS subnet code has checks to avoid +- attacks in this case. */ +- if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags))) +- { +- if (!daemon->free_frec_src && +- daemon->frec_src_count < daemon->ftabsize && +- (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src)))) +- { +- daemon->frec_src_count++; +- daemon->free_frec_src->next = NULL; +- } +- +- /* If we've been spammed with many duplicates, just drop the query. */ +- if (daemon->free_frec_src) +- { +- struct frec_src *new = daemon->free_frec_src; +- daemon->free_frec_src = new->next; +- new->next = forward->frec_src.next; +- forward->frec_src.next = new; +- new->orig_id = ntohs(header->id); +- new->source = *udpaddr; +- new->dest = *dst_addr; +- new->log_id = daemon->log_id; +- new->iface = dst_iface; +- new->fd = udpfd; +- } +- +- return 1; +- } +- ++ /* new query */ ++ + if (gotname) + flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); + +@@ -380,6 +383,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, + #endif + type &= ~SERV_DO_DNSSEC; + ++ /* may be no servers available. */ + if (daemon->servers && !flags) + forward = get_new_frec(now, NULL, 0); + /* table full - flags == 0, return REFUSED */ +@@ -2249,25 +2253,6 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has + return NULL; + } + +-static struct frec *lookup_frec_by_sender(unsigned short id, +- union mysockaddr *addr, +- void *hash) +-{ +- struct frec *f; +- struct frec_src *src; +- +- for (f = daemon->frec_list; f; f = f->next) +- if (f->sentto && +- !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) && +- memcmp(hash, f->hash, HASH_SIZE) == 0) +- for (src = &f->frec_src; src; src = src->next) +- if (src->orig_id == id && +- sockaddr_isequal(&src->source, addr)) +- return f; +- +- return NULL; +-} +- + static struct frec *lookup_frec_by_query(void *hash, unsigned int flags) + { + struct frec *f; +-- +2.26.2 + diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec index e0d3f4e..027f57d 100644 --- a/SPECS/dnsmasq.spec +++ b/SPECS/dnsmasq.spec @@ -13,7 +13,7 @@ Name: dnsmasq Version: 2.76 -Release: 17%{?extraversion}%{?dist}.1 +Release: 17%{?extraversion}%{?dist}.3 Summary: A lightweight DHCP/caching DNS server Group: System Environment/Daemons @@ -87,6 +87,13 @@ Patch38: dnsmasq-2.76-nettlehash.patch Patch39: dnsmasq-2.77-netlink-loop.patch Patch40: dnsmasq-2.81-netlink-table.patch Patch41: dnsmasq-2.84-bind-dynamic-netlink.patch +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=305cb79c5754d5554729b18a2c06fe7ce699687a +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=141a26f979b4bc959d8e866a295e24f8cf456920 +Patch42: dnsmasq-2.84-forward-mixed-af.patch +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=3f535da79e7a42104543ef5c7b5fa2bed819a78b +# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=04490bf622ac84891aad6f2dd2edf83725decdee +Patch43: dnsmasq-2.84-forward-retries.patch +Patch44: dnsmasq-2.76-forward-sfd.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -164,6 +171,9 @@ query/remove a DHCP server's leases. %patch39 -p1 -b .rh1887649-seq %patch40 -p1 -b .rh1887649-table %patch41 -p1 -b .rh1887649 +%patch42 -p1 -b .rh1923913 +%patch43 -p1 -b .rh1923913 +%patch44 -p1 -b .rh1923913-sfd # use /var/lib/dnsmasq instead of /var/lib/misc for file in dnsmasq.conf.example man/dnsmasq.8 man/es/dnsmasq.8 src/config.h; do @@ -253,6 +263,12 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/dhcp_* %changelog +* Fri Mar 05 2021 Petr Menšík - 2.76-17.3 +- Accept replies from bound sockets again (#1923913) + +* Mon Mar 01 2021 Petr Menšík - 2.76-17.2 +- Correct two regressions introduced by CVE fixes (#1923913) + * Thu Feb 11 2021 Petr Menšík - 2.76-17.1 - Fix occasional failures in netlink on many interfaces (#1887649)