dnsmasq: backport infinite dns retries fix

If all configured dns servers return refused in response to a query in
strict mode; dnsmasq will end up in an infinite loop retransmitting the
dns query resulting into high CPU load.
Problem is fixed by checking for the end of a dns server list iteration
in strict mode.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
This commit is contained in:
Hans Dedecker 2017-12-06 14:22:59 +01:00
parent deaf9597c6
commit 347d18177e
3 changed files with 48 additions and 3 deletions

View file

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq PKG_NAME:=dnsmasq
PKG_VERSION:=2.78 PKG_VERSION:=2.78
PKG_RELEASE:=4 PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/ PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/

View file

@ -74,7 +74,7 @@
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
int bind_fallback = 0; int bind_fallback = 0;
@@ -911,6 +969,7 @@ int main (int argc, char **argv) @@ -911,6 +971,7 @@ int main (int argc, char **argv)
set_dbus_listeners(); set_dbus_listeners();
#endif #endif
@ -82,7 +82,7 @@
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->relay4) if (daemon->dhcp || daemon->relay4)
{ {
@@ -1041,6 +1100,8 @@ int main (int argc, char **argv) @@ -1041,6 +1102,8 @@ int main (int argc, char **argv)
check_dbus_listeners(); check_dbus_listeners();
#endif #endif

View file

@ -0,0 +1,45 @@
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);