[LEDE-DEV] [PATCH v2] dnsmasq: bump to 2.80test2

Hans Dedecker dedeckeh at gmail.com
Sat May 12 13:05:39 PDT 2018


On Sat, May 12, 2018 at 4:37 PM, Kevin Darbyshire-Bryant
<ldir at darbyshire-bryant.me.uk> wrote:
> Refresh patches and backport upstream to current HEAD:
>
> 1f1873a Log warning on very large cachesize config, instead of truncating it.
> 0a496f0 Do unsolicited RAs for interfaces which appear after dnsmasq startup.
> e27825b Fix logging in previous.
> 1f60a18 Retry SERVFAIL DNSSEC queries to a different server, if possible.
> a0088e8 Handle query retry on REFUSED or SERVFAIL for DNSSEC-generated queries.
> 34e26e1 Retry query to other servers on receipt of SERVFAIL rcode.
> 6b17335 Add packet-dump debugging facility.
> 07ed585 Add logging for DNS error returns from upstream and local configuration.
> 0669ee7 Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip are set.
> f84e674 Be persistent with broken-upstream-DNSSEC warnings.
>
> Compile & run tested: ar71xx Archer C7 v2
Patch applied to master; thx

Hans
>
> Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> ---
>  package/network/services/dnsmasq/Makefile          |   8 +-
>  ...tent-with-broken-upstream-DNSSEC-warnings.patch |  26 +
>  ...oken-ness-when-no-ping-AND-dhcp-sequentia.patch |  35 ++
>  ...-for-DNS-error-returns-from-upstream-and-.patch | 184 +++++++
>  .../0004-Add-packet-dump-debugging-facility.patch  | 587 +++++++++++++++++++++
>  ...-to-other-servers-on-receipt-of-SERVFAIL-.patch |  22 +
>  ...y-retry-on-REFUSED-or-SERVFAIL-for-DNSSEC.patch |  87 +++
>  ...AIL-DNSSEC-queries-to-a-different-server-.patch | 100 ++++
>  .../patches/0008-Fix-logging-in-previous.patch     |  41 ++
>  ...ted-RAs-for-interfaces-which-appear-after.patch |  44 ++
>  ...-on-very-large-cachesize-config-instead-o.patch |  38 ++
>  .../services/dnsmasq/patches/240-ubus.patch        |   8 +-
>  12 files changed, 1172 insertions(+), 8 deletions(-)
>  create mode 100644 package/network/services/dnsmasq/patches/0001-Be-persistent-with-broken-upstream-DNSSEC-warnings.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0002-Fix-DHCP-broken-ness-when-no-ping-AND-dhcp-sequentia.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0003-Add-logging-for-DNS-error-returns-from-upstream-and-.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0004-Add-packet-dump-debugging-facility.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0005-Retry-query-to-other-servers-on-receipt-of-SERVFAIL-.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0006-Handle-query-retry-on-REFUSED-or-SERVFAIL-for-DNSSEC.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0007-Retry-SERVFAIL-DNSSEC-queries-to-a-different-server-.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0008-Fix-logging-in-previous.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0009-Do-unsolicited-RAs-for-interfaces-which-appear-after.patch
>  create mode 100644 package/network/services/dnsmasq/patches/0010-Log-warning-on-very-large-cachesize-config-instead-o.patch
>
> diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
> index 60ed9ed6fb..7fa61ad04f 100644
> --- a/package/network/services/dnsmasq/Makefile
> +++ b/package/network/services/dnsmasq/Makefile
> @@ -8,12 +8,12 @@
>  include $(TOPDIR)/rules.mk
>
>  PKG_NAME:=dnsmasq
> -PKG_VERSION:=2.79
> -PKG_RELEASE:=4
> +PKG_VERSION:=2.80test2
> +PKG_RELEASE:=1
>
>  PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
> -PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/
> -PKG_HASH:=78ad74f5ca14fd85a8bac93f764cd9d60b27579e90eabd3687ca7b030e67861f
> +PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/test-releases
> +PKG_HASH:=e731666094699afcbad947f89f7f8afbf92e5ddc3c915459d4936159d81116f0
>
>  PKG_LICENSE:=GPL-2.0
>  PKG_LICENSE_FILES:=COPYING
> diff --git a/package/network/services/dnsmasq/patches/0001-Be-persistent-with-broken-upstream-DNSSEC-warnings.patch b/package/network/services/dnsmasq/patches/0001-Be-persistent-with-broken-upstream-DNSSEC-warnings.patch
> new file mode 100644
> index 0000000000..0924a92e33
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0001-Be-persistent-with-broken-upstream-DNSSEC-warnings.patch
> @@ -0,0 +1,26 @@
> +From f84e674d8aa2316fea8d2145a40fcef0441e3856 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 4 May 2018 16:29:57 +0100
> +Subject: [PATCH 01/10] Be persistent with broken-upstream-DNSSEC warnings.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/dnssec.c | 7 +------
> + 1 file changed, 1 insertion(+), 6 deletions(-)
> +
> +--- a/src/dnssec.c
> ++++ b/src/dnssec.c
> +@@ -876,12 +876,7 @@ int dnssec_validate_ds(time_t now, struc
> +
> +   if (rc == STAT_INSECURE)
> +     {
> +-      static int reported = 0;
> +-      if (!reported)
> +-      {
> +-        reported = 1;
> +-        my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
> +-      }
> ++      my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
> +       rc = STAT_BOGUS;
> +     }
> +
> diff --git a/package/network/services/dnsmasq/patches/0002-Fix-DHCP-broken-ness-when-no-ping-AND-dhcp-sequentia.patch b/package/network/services/dnsmasq/patches/0002-Fix-DHCP-broken-ness-when-no-ping-AND-dhcp-sequentia.patch
> new file mode 100644
> index 0000000000..12c405945d
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0002-Fix-DHCP-broken-ness-when-no-ping-AND-dhcp-sequentia.patch
> @@ -0,0 +1,35 @@
> +From 0669ee7a69a004ce34fed41e50aa575f8e04427b Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 4 May 2018 16:46:24 +0100
> +Subject: [PATCH 02/10] Fix DHCP broken-ness when --no-ping AND
> + --dhcp-sequential-ip are set.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + CHANGELOG  | 3 ++-
> + src/dhcp.c | 2 +-
> + 2 files changed, 3 insertions(+), 2 deletions(-)
> +
> +--- a/CHANGELOG
> ++++ b/CHANGELOG
> +@@ -14,7 +14,8 @@ version 2.80
> +         when the upstream namesevers do not support DNSSEC, and in this
> +         case no DNSSEC validation at all is occuring.
> +
> +-
> ++        Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip
> ++      are set. Thanks to Daniel Miess for help with this.
> +
> +
> + version 2.79
> +--- a/src/dhcp.c
> ++++ b/src/dhcp.c
> +@@ -678,7 +678,7 @@ struct ping_result *do_icmp_ping(time_t
> +   if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
> +     {
> +       /* overloaded, or configured not to check, loopback interface, return "not in use" */
> +-      dummy.hash = 0;
> ++      dummy.hash = hash;
> +       return &dummy;
> +     }
> +   else if (icmp_ping(addr))
> diff --git a/package/network/services/dnsmasq/patches/0003-Add-logging-for-DNS-error-returns-from-upstream-and-.patch b/package/network/services/dnsmasq/patches/0003-Add-logging-for-DNS-error-returns-from-upstream-and-.patch
> new file mode 100644
> index 0000000000..150cd91c6a
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0003-Add-logging-for-DNS-error-returns-from-upstream-and-.patch
> @@ -0,0 +1,184 @@
> +From 07ed585c38d8f7c0a18470d2e79cf46ea92ea96a Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 4 May 2018 21:52:22 +0100
> +Subject: [PATCH 03/10] Add logging for DNS error returns from upstream and
> + local configuration.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/cache.c   | 13 +++++++++++++
> + src/dnsmasq.h |  7 ++++++-
> + src/forward.c | 25 +++++++++++++++++++------
> + src/rfc1035.c | 19 ++++++++++++++-----
> + 4 files changed, 52 insertions(+), 12 deletions(-)
> +
> +--- a/src/cache.c
> ++++ b/src/cache.c
> +@@ -1598,6 +1598,19 @@ void log_query(unsigned int flags, char
> +     {
> +       if (flags & F_KEYTAG)
> +       sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
> ++      else if (flags & F_RCODE)
> ++      {
> ++        unsigned int rcode = addr->addr.rcode.rcode;
> ++
> ++         if (rcode == SERVFAIL)
> ++           dest = "SERVFAIL";
> ++         else if (rcode == REFUSED)
> ++           dest = "REFUSED";
> ++         else if (rcode == NOTIMP)
> ++           dest = "not implemented";
> ++         else
> ++           sprintf(daemon->addrbuff, "%u", rcode);
> ++      }
> +       else
> +       {
> + #ifdef HAVE_IPV6
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -268,7 +268,11 @@ struct all_addr {
> +     /* for log_query */
> +     struct {
> +       unsigned short keytag, algo, digest;
> +-    } log;
> ++    } log;
> ++    /* for log_query */
> ++    struct {
> ++      unsigned int rcode;
> ++    } rcode;
> +     /* for cache_insert of DNSKEY, DS */
> +     struct {
> +       unsigned short class, type;
> +@@ -459,6 +463,7 @@ struct crec {
> + #define F_IPSET     (1u<<26)
> + #define F_NOEXTRA   (1u<<27)
> + #define F_SERVFAIL  (1u<<28)
> ++#define F_RCODE     (1u<<29)
> +
> + /* Values of uid in crecs with F_CONFIG bit set. */
> + #define SRC_INTERFACE 0
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -563,6 +563,7 @@ static size_t process_reply(struct dns_h
> +   unsigned char *pheader, *sizep;
> +   char **sets = 0;
> +   int munged = 0, is_sign;
> ++  unsigned int rcode = RCODE(header);
> +   size_t plen;
> +
> +   (void)ad_reqd;
> +@@ -593,6 +594,9 @@ static size_t process_reply(struct dns_h
> +
> +   if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
> +     {
> ++      /* Get extended RCODE. */
> ++      rcode |= sizep[2] << 4;
> ++
> +       if (check_subnet && !check_source(header, plen, pheader, query_source))
> +       {
> +         my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
> +@@ -641,11 +645,20 @@ static size_t process_reply(struct dns_h
> +   if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
> +      header->hb4 &= ~HB4_AD;
> +
> +-  if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
> ++  if (OPCODE(header) != QUERY)
> +     return resize_packet(header, n, pheader, plen);
> ++
> ++  if (rcode != NOERROR && rcode != NXDOMAIN)
> ++    {
> ++      struct all_addr a;
> ++      a.addr.rcode.rcode = rcode;
> ++      log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
> ++
> ++      return resize_packet(header, n, pheader, plen);
> ++    }
> +
> +   /* Complain loudly if the upstream server is non-recursive. */
> +-  if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
> ++  if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
> +       server && !(server->flags & SERV_WARNED_RECURSIVE))
> +     {
> +       prettyprint_addr(&server->addr, daemon->namebuff);
> +@@ -654,7 +667,7 @@ static size_t process_reply(struct dns_h
> +       server->flags |= SERV_WARNED_RECURSIVE;
> +     }
> +
> +-  if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
> ++  if (daemon->bogus_addr && rcode != NXDOMAIN &&
> +       check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
> +     {
> +       munged = 1;
> +@@ -666,7 +679,7 @@ static size_t process_reply(struct dns_h
> +     {
> +       int doctored = 0;
> +
> +-      if (RCODE(header) == NXDOMAIN &&
> ++      if (rcode == NXDOMAIN &&
> +         extract_request(header, n, daemon->namebuff, NULL) &&
> +         check_for_local_domain(daemon->namebuff, now))
> +       {
> +@@ -1090,7 +1103,7 @@ void reply_query(int fd, int family, tim
> +             if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
> +               domain = daemon->namebuff;
> +
> +-            log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
> ++            log_query(F_SECSTAT, domain, NULL, result);
> +           }
> +
> +         if (status == STAT_SECURE)
> +@@ -1948,7 +1961,7 @@ unsigned char *tcp_request(int confd, ti
> +                         if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
> +                           domain = daemon->namebuff;
> +
> +-                        log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
> ++                        log_query(F_SECSTAT, domain, NULL, result);
> +
> +                         if (status == STAT_BOGUS)
> +                           {
> +--- a/src/rfc1035.c
> ++++ b/src/rfc1035.c
> +@@ -926,12 +926,11 @@ unsigned int extract_request(struct dns_
> +   return F_QUERY;
> + }
> +
> +-
> + size_t setup_reply(struct dns_header *header, size_t qlen,
> +               struct all_addr *addrp, unsigned int flags, unsigned long ttl)
> + {
> +   unsigned char *p;
> +-
> ++
> +   if (!(p = skip_questions(header, qlen)))
> +     return 0;
> +
> +@@ -948,7 +947,12 @@ size_t setup_reply(struct dns_header *he
> +   else if (flags == F_NXDOMAIN)
> +     SET_RCODE(header, NXDOMAIN);
> +   else if (flags == F_SERVFAIL)
> +-    SET_RCODE(header, SERVFAIL);
> ++    {
> ++      struct all_addr a;
> ++      a.addr.rcode.rcode = SERVFAIL;
> ++      log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
> ++      SET_RCODE(header, SERVFAIL);
> ++    }
> +   else if (flags == F_IPV4)
> +     { /* we know the address */
> +       SET_RCODE(header, NOERROR);
> +@@ -966,8 +970,13 @@ size_t setup_reply(struct dns_header *he
> +     }
> + #endif
> +   else /* nowhere to forward to */
> +-    SET_RCODE(header, REFUSED);
> +-
> ++    {
> ++      struct all_addr a;
> ++      a.addr.rcode.rcode = REFUSED;
> ++      log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
> ++      SET_RCODE(header, REFUSED);
> ++    }
> ++
> +   return p - (unsigned char *)header;
> + }
> +
> diff --git a/package/network/services/dnsmasq/patches/0004-Add-packet-dump-debugging-facility.patch b/package/network/services/dnsmasq/patches/0004-Add-packet-dump-debugging-facility.patch
> new file mode 100644
> index 0000000000..af4020b50b
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0004-Add-packet-dump-debugging-facility.patch
> @@ -0,0 +1,587 @@
> +From 6b17335209639a56f214d011eaed4ebcde8dd276 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Tue, 8 May 2018 18:32:14 +0100
> +Subject: [PATCH 04/10] Add packet-dump debugging facility.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + CHANGELOG      |   6 ++
> + Makefile       |   2 +-
> + bld/Android.mk |   3 +-
> + man/dnsmasq.8  |   7 ++
> + src/config.h   |  16 ++++-
> + src/dnsmasq.c  |  16 ++++-
> + src/dnsmasq.h  |  29 +++++++-
> + src/dump.c     | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> + src/forward.c  |  37 ++++++++--
> + src/option.c   |  14 ++++
> + 10 files changed, 329 insertions(+), 11 deletions(-)
> + create mode 100644 src/dump.c
> +
> +--- a/CHANGELOG
> ++++ b/CHANGELOG
> +@@ -17,6 +17,12 @@ version 2.80
> +         Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip
> +       are set. Thanks to Daniel Miess for help with this.
> +
> ++      Add a facilty to store DNS packets sent/recieved in a
> ++      pcap-format file for later debugging. The file location
> ++      is given by the --dumpfile option, and a bitmap controlling
> ++      which packets should be dumped is given by the --dumpmask
> ++      option.
> ++
> +
> + version 2.79
> +       Fix parsing of CNAME arguments, which are confused by extra spaces.
> +--- a/Makefile
> ++++ b/Makefile
> +@@ -76,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o
> +        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
> +        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
> +        domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
> +-       poll.o rrfilter.o edns0.o arp.o crypto.o
> ++       poll.o rrfilter.o edns0.o arp.o crypto.o dump.o
> +
> + hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
> +        dns-protocol.h radv-protocol.h ip6addr.h
> +--- a/bld/Android.mk
> ++++ b/bld/Android.mk
> +@@ -10,7 +10,8 @@ LOCAL_SRC_FILES :=  bpf.c cache.c dbus.c
> +                   dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
> +                   radv.c slaac.c auth.c ipset.c domain.c \
> +                   dnssec.c dnssec-openssl.c blockdata.c tables.c \
> +-                  loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
> ++                  loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
> ++                  crypto.c dump.c
> +
> + LOCAL_MODULE := dnsmasq
> +
> +--- a/man/dnsmasq.8
> ++++ b/man/dnsmasq.8
> +@@ -647,6 +647,13 @@ V4 mapped IPv6 addresses, which have a r
> + The address range can be of the form
> + <ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
> + .TP
> ++.B --dumpfile=<path/to/file>
> ++Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end.
> ++.TP
> ++.B --dumpmask=<mask>
> ++Specify which types of packets should be added to the dumpfile. The argument should be the OR of the bitmasks for each type of packet to be dumped: it can be specified in hex by preceding the number with 0x in  the normal way. Each time a packet is written to the dumpfile, dnsmasq logs the packet sequence and the mask
> ++representing its type. The current types are: 0x0001 - DNS queries from clients 0x0002 DNS replies to clients 0x0004 - DNS queries to upstream 0x0008 - DNS replies from upstream 0x0010 - queries send upstream for DNSSEC validation 0x0020 - replies to queries for DNSSEC validation 0x0040 - replies to client queries which fail DNSSEC validation 0x0080 replies to queries for DNSSEC validation which fail validation.
> ++.TP
> + .B --add-mac[=base64|text]
> + Add the MAC address of the requestor to DNS queries which are
> + forwarded upstream. This may be used to DNS filtering by the upstream
> +--- a/src/config.h
> ++++ b/src/config.h
> +@@ -117,6 +117,9 @@ HAVE_AUTH
> + HAVE_DNSSEC
> +    include DNSSEC validator.
> +
> ++HAVE_DUMPFILE
> ++   include code to dump packets to a libpcap-format file for debugging.
> ++
> + HAVE_LOOP
> +    include functionality to probe for and remove DNS forwarding loops.
> +
> +@@ -132,6 +135,7 @@ NO_DHCP6
> + NO_SCRIPT
> + NO_LARGEFILE
> + NO_AUTH
> ++NO_DUMPFILE
> + NO_INOTIFY
> +    these are available to explicitly disable compile time options which would
> +    otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
> +@@ -164,6 +168,7 @@ RESOLVFILE
> + #define HAVE_AUTH
> + #define HAVE_IPSET
> + #define HAVE_LOOP
> ++#define HAVE_DUMPFILE
> +
> + /* Build options which require external libraries.
> +
> +@@ -363,6 +368,10 @@ HAVE_SOCKADDR_SA_LEN
> + #undef HAVE_LOOP
> + #endif
> +
> ++#ifdef NO_DUMPFILE
> ++#undef HAVE_DUMPFILE
> ++#endif
> ++
> + #if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
> + #define HAVE_INOTIFY
> + #endif
> +@@ -451,8 +460,11 @@ static char *compile_opts =
> + #ifndef HAVE_INOTIFY
> + "no-"
> + #endif
> +-"inotify";
> +-
> ++"inotify "
> ++#ifndef HAVE_DUMPFILE
> ++"no-"
> ++#endif
> ++"dumpfile";
> +
> + #endif
> +
> +--- a/src/dnsmasq.c
> ++++ b/src/dnsmasq.c
> +@@ -366,7 +366,16 @@ int main (int argc, char **argv)
> +   else
> +     daemon->inotifyfd = -1;
> + #endif
> +-
> ++
> ++  if (daemon->dump_file)
> ++#ifdef HAVE_DUMPFILE
> ++    dump_init();
> ++  else
> ++    daemon->dumpfd = -1;
> ++#else
> ++  die(_("Packet dumps not available: set HAVE_DUMP in src/config.h"), NULL, EC_BADCONF);
> ++#endif
> ++
> +   if (option_bool(OPT_DBUS))
> + #ifdef HAVE_DBUS
> +     {
> +@@ -1424,6 +1433,11 @@ static void async_event(int pipe, time_t
> +
> +       if (daemon->runfile)
> +         unlink(daemon->runfile);
> ++
> ++#ifdef HAVE_DUMPFILE
> ++      if (daemon->dumpfd != -1)
> ++        close(daemon->dumpfd);
> ++#endif
> +
> +       my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
> +       flush_log();
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -119,6 +119,9 @@ typedef unsigned long long u64;
> + #include <net/if_arp.h>
> + #include <netinet/in_systm.h>
> + #include <netinet/ip.h>
> ++#ifdef HAVE_IPV6
> ++#include <netinet/ip6.h>
> ++#endif
> + #include <netinet/ip_icmp.h>
> + #include <sys/uio.h>
> + #include <syslog.h>
> +@@ -598,6 +601,16 @@ struct hostsfile {
> +   unsigned int index; /* matches to cache entries for logging */
> + };
> +
> ++/* packet-dump flags */
> ++#define DUMP_QUERY     0x0001
> ++#define DUMP_REPLY     0x0002
> ++#define DUMP_UP_QUERY  0x0004
> ++#define DUMP_UP_REPLY  0x0008
> ++#define DUMP_SEC_QUERY 0x0010
> ++#define DUMP_SEC_REPLY 0x0020
> ++#define DUMP_BOGUS     0x0040
> ++#define DUMP_SEC_BOGUS 0x0080
> ++
> +
> + /* DNSSEC status values. */
> + #define STAT_SECURE             1
> +@@ -1020,14 +1033,14 @@ extern struct daemon {
> +   unsigned int duid_enterprise, duid_config_len;
> +   unsigned char *duid_config;
> +   char *dbus_name;
> ++  char *dump_file;
> ++  int dump_mask;
> +   unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
> + #ifdef OPTION6_PREFIX_CLASS
> +   struct prefix_class *prefix_classes;
> + #endif
> + #ifdef HAVE_DNSSEC
> +   struct ds_config *ds;
> +-  int dnssec_no_time_check;
> +-  int back_to_the_future;
> +   char *timestamp_file;
> + #endif
> +
> +@@ -1040,6 +1053,8 @@ extern struct daemon {
> +   char *workspacename; /* ditto */
> +   char *rr_status; /* flags for individual RRs */
> +   int rr_status_sz;
> ++  int dnssec_no_time_check;
> ++  int back_to_the_future;
> + #endif
> +   unsigned int local_answer, queries_forwarded, auth_answer;
> +   struct frec *frec_list;
> +@@ -1094,6 +1109,10 @@ extern struct daemon {
> +   char *addrbuff;
> +   char *addrbuff2; /* only allocated when OPT_EXTRALOG */
> +
> ++#ifdef HAVE_DUMPFILE
> ++  /* file for packet dumps. */
> ++  int dumpfd;
> ++#endif
> + } *daemon;
> +
> + /* cache.c */
> +@@ -1588,3 +1607,9 @@ int check_source(struct dns_header *head
> + /* arp.c */
> + int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
> + int do_arp_script_run(void);
> ++
> ++/* dump.c */
> ++#ifdef HAVE_DUMPFILE
> ++void dump_init(void);
> ++void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
> ++#endif
> +--- /dev/null
> ++++ b/src/dump.c
> +@@ -0,0 +1,210 @@
> ++/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
> ++
> ++   This program is free software; you can redistribute it and/or modify
> ++   it under the terms of the GNU General Public License as published by
> ++   the Free Software Foundation; version 2 dated June, 1991, or
> ++   (at your option) version 3 dated 29 June, 2007.
> ++
> ++   This program is distributed in the hope that it will be useful,
> ++   but WITHOUT ANY WARRANTY; without even the implied warranty of
> ++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ++   GNU General Public License for more details.
> ++
> ++   You should have received a copy of the GNU General Public License
> ++   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> ++*/
> ++
> ++#include "dnsmasq.h"
> ++
> ++#ifdef HAVE_DUMPFILE
> ++
> ++static u32 packet_count;
> ++
> ++/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
> ++struct pcap_hdr_s {
> ++        u32 magic_number;   /* magic number */
> ++        u16 version_major;  /* major version number */
> ++        u16 version_minor;  /* minor version number */
> ++        u32 thiszone;       /* GMT to local correction */
> ++        u32 sigfigs;        /* accuracy of timestamps */
> ++        u32 snaplen;        /* max length of captured packets, in octets */
> ++        u32 network;        /* data link type */
> ++};
> ++
> ++struct pcaprec_hdr_s {
> ++        u32 ts_sec;         /* timestamp seconds */
> ++        u32 ts_usec;        /* timestamp microseconds */
> ++        u32 incl_len;       /* number of octets of packet saved in file */
> ++        u32 orig_len;       /* actual length of packet */
> ++};
> ++
> ++
> ++void dump_init(void)
> ++{
> ++  struct stat buf;
> ++  struct pcap_hdr_s header;
> ++  struct pcaprec_hdr_s pcap_header;
> ++
> ++  packet_count = 0;
> ++
> ++  if (stat(daemon->dump_file, &buf) == -1)
> ++    {
> ++      /* doesn't exist, create and add header */
> ++      header.magic_number = 0xa1b2c3d4;
> ++      header.version_major = 2;
> ++      header.version_minor = 4;
> ++      header.thiszone = 0;
> ++      header.sigfigs = 0;
> ++      header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
> ++      header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
> ++
> ++      if (errno != ENOENT ||
> ++        (daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
> ++        !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
> ++      die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
> ++    }
> ++  else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
> ++         !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1) ||
> ++         header.magic_number != 0xa1b2c3d4)
> ++    die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
> ++  else
> ++    {
> ++      /* count existing records */
> ++      while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
> ++      {
> ++        lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
> ++        packet_count++;
> ++      }
> ++    }
> ++}
> ++
> ++void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
> ++{
> ++  struct ip ip;
> ++#ifdef HAVE_IPV6
> ++  struct ip6_hdr ip6;
> ++  int family;
> ++#endif
> ++  struct udphdr {
> ++    u16 uh_sport;               /* source port */
> ++    u16 uh_dport;               /* destination port */
> ++    u16 uh_ulen;                /* udp length */
> ++    u16 uh_sum;                 /* udp checksum */
> ++  } udp;
> ++  struct pcaprec_hdr_s pcap_header;
> ++  struct timeval time;
> ++  u32 i, sum;
> ++  void *iphdr;
> ++  size_t ipsz;
> ++  int rc;
> ++
> ++  if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask))
> ++    return;
> ++
> ++  /* So wireshark can Id the packet. */
> ++  udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
> ++
> ++#ifdef HAVE_IPV6
> ++  if (src)
> ++    family = src->sa.sa_family;
> ++  else
> ++    family = dst->sa.sa_family;
> ++
> ++  if (family == AF_INET6)
> ++    {
> ++      iphdr = &ip6;
> ++      ipsz = sizeof(ip6);
> ++      memset(&ip6, 0, sizeof(ip6));
> ++
> ++      ip6.ip6_vfc = 6 << 4;
> ++      ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
> ++      ip6.ip6_nxt = IPPROTO_UDP;
> ++      ip6.ip6_hops = 64;
> ++
> ++      if (src)
> ++      {
> ++        memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
> ++        udp.uh_sport = src->in6.sin6_port;
> ++      }
> ++
> ++      if (dst)
> ++      {
> ++        memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
> ++        udp.uh_dport = dst->in6.sin6_port;
> ++      }
> ++
> ++      /* start UDP checksum */
> ++      for (sum = 0, i = 0; i < IN6ADDRSZ; i++)
> ++      sum += ((u16 *)&ip6.ip6_src)[i];
> ++    }
> ++  else
> ++#endif
> ++    {
> ++      iphdr = &ip;
> ++      ipsz = sizeof(ip);
> ++      memset(&ip, 0, sizeof(ip));
> ++
> ++      ip.ip_v = IPVERSION;
> ++      ip.ip_hl = sizeof(struct ip) / 4;
> ++      ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
> ++      ip.ip_ttl = IPDEFTTL;
> ++      ip.ip_p = IPPROTO_UDP;
> ++
> ++      if (src)
> ++      {
> ++        ip.ip_src = src->in.sin_addr;
> ++        udp.uh_sport = src->in.sin_port;
> ++      }
> ++
> ++      if (dst)
> ++      {
> ++        ip.ip_dst = dst->in.sin_addr;
> ++        udp.uh_dport = dst->in.sin_port;
> ++      }
> ++
> ++      ip.ip_sum = 0;
> ++      for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
> ++      sum += ((u16 *)&ip)[i];
> ++      while (sum >> 16)
> ++      sum = (sum & 0xffff) + (sum >> 16);
> ++      ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
> ++
> ++      /* start UDP checksum */
> ++      sum = ip.ip_src.s_addr & 0xffff;
> ++      sum += (ip.ip_src.s_addr >> 16) & 0xffff;
> ++      sum += ip.ip_dst.s_addr & 0xffff;
> ++      sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
> ++    }
> ++
> ++  if (len & 1)
> ++    ((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
> ++
> ++  udp.uh_sum = 0;
> ++  udp.uh_ulen = htons(sizeof(struct udphdr) + len);
> ++  sum += htons(IPPROTO_UDP);
> ++  sum += htons(sizeof(struct udphdr) + len);
> ++  for (i = 0; i < sizeof(struct udphdr)/2; i++)
> ++    sum += ((u16 *)&udp)[i];
> ++  for (i = 0; i < (len + 1) / 2; i++)
> ++    sum += ((u16 *)packet)[i];
> ++  while (sum >> 16)
> ++    sum = (sum & 0xffff) + (sum >> 16);
> ++  udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
> ++
> ++  rc = gettimeofday(&time, NULL);
> ++  pcap_header.ts_sec = time.tv_sec;
> ++  pcap_header.ts_usec = time.tv_usec;
> ++  pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
> ++
> ++  if (rc == -1 ||
> ++      !read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
> ++      !read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
> ++      !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
> ++      !read_write(daemon->dumpfd, (void *)packet, len, 0))
> ++    my_syslog(LOG_ERR, _("failed to write packet dump"));
> ++  else
> ++    my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
> ++
> ++}
> ++
> ++#endif
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -508,6 +508,10 @@ static int forward_query(int udpfd, unio
> +
> +             if (errno == 0)
> +               {
> ++#ifdef HAVE_DUMPFILE
> ++                dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
> ++#endif
> ++
> +                 /* Keep info in case we want to re-send this packet */
> +                 daemon->srv_save = start;
> +                 daemon->packet_len = plen;
> +@@ -769,7 +773,7 @@ void reply_query(int fd, int family, tim
> + #endif
> +
> +   header = (struct dns_header *)daemon->packet;
> +-
> ++
> +   if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
> +     return;
> +
> +@@ -796,6 +800,12 @@ void reply_query(int fd, int family, tim
> +   if (!(forward = lookup_frec(ntohs(header->id), hash)))
> +     return;
> +
> ++#ifdef HAVE_DUMPFILE
> ++  dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
> ++            (void *)header, n, &serveraddr, NULL);
> ++#endif
> ++
> ++
> +   /* log_query gets called indirectly all over the place, so
> +      pass these in global variables - sorry. */
> +   daemon->log_display_id = forward->log_id;
> +@@ -934,6 +944,11 @@ void reply_query(int fd, int family, tim
> +                   status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
> +                                                  !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
> +                                                  NULL, NULL);
> ++#ifdef HAVE_DUMPFILE
> ++                if (status == STAT_BOGUS)
> ++                  dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
> ++                              header, (size_t)n, &serveraddr, NULL);
> ++#endif
> +               }
> +
> +             /* Can't validate, as we're missing key data. Put this
> +@@ -1060,6 +1075,11 @@ void reply_query(int fd, int family, tim
> +                               setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
> +                           }
> + #endif
> ++
> ++#ifdef HAVE_DUMPFILE
> ++                        dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
> ++#endif
> ++
> +                         while (retry_send(sendto(fd, (char *)header, nn, 0,
> +                                                  &server->addr.sa,
> +                                                  sa_len(&server->addr))));
> +@@ -1114,8 +1134,8 @@ void reply_query(int fd, int family, tim
> +             bogusanswer = 1;
> +           }
> +       }
> +-#endif
> +-
> ++#endif
> ++
> +       /* restore CD bit to the value in the query */
> +       if (forward->flags & FREC_CHECKING_DISABLED)
> +       header->hb4 |= HB4_CD;
> +@@ -1141,6 +1161,11 @@ void reply_query(int fd, int family, tim
> +             nn = resize_packet(header, nn, NULL, 0);
> +           }
> + #endif
> ++
> ++#ifdef HAVE_DUMPFILE
> ++        dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
> ++#endif
> ++
> +         send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
> +                   &forward->source, &forward->dest, forward->iface);
> +       }
> +@@ -1394,7 +1419,11 @@ void receive_query(struct listener *list
> +      pass these in global variables - sorry. */
> +   daemon->log_display_id = ++daemon->log_id;
> +   daemon->log_source_addr = &source_addr;
> +-
> ++
> ++#ifdef HAVE_DUMPFILE
> ++  dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
> ++#endif
> ++
> +   if (extract_request(header, (size_t)n, daemon->namebuff, &type))
> +     {
> + #ifdef HAVE_AUTH
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -161,6 +161,8 @@ struct myoption {
> + #define LOPT_TFTP_MTU      349
> + #define LOPT_REPLY_DELAY   350
> + #define LOPT_RAPID_COMMIT  351
> ++#define LOPT_DUMPFILE      352
> ++#define LOPT_DUMPMASK      353
> +
> + #ifdef HAVE_GETOPT_LONG
> + static const struct option opts[] =
> +@@ -327,6 +329,8 @@ static const struct myoption opts[] =
> +     { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
> +     { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
> +     { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
> ++    { "dumpfile", 1, 0, LOPT_DUMPFILE },
> ++    { "dumpmask", 1, 0, LOPT_DUMPMASK },
> +     { NULL, 0, 0, 0 }
> +   };
> +
> +@@ -500,6 +504,8 @@ static struct {
> +   { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
> +   { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
> +   { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
> ++  { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
> ++  { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
> +   { 0, 0, NULL, NULL, NULL }
> + };
> +
> +@@ -1811,6 +1817,14 @@ static int one_opt(int option, char *arg
> +       ret_err(_("bad MX target"));
> +       break;
> +
> ++    case LOPT_DUMPFILE:  /* --dumpfile */
> ++      daemon->dump_file = opt_string_alloc(arg);
> ++      break;
> ++
> ++    case LOPT_DUMPMASK:  /* --dumpmask */
> ++      daemon->dump_mask = strtol(arg, NULL, 0);
> ++      break;
> ++
> + #ifdef HAVE_DHCP
> +     case 'l':  /* --dhcp-leasefile */
> +       daemon->lease_file = opt_string_alloc(arg);
> diff --git a/package/network/services/dnsmasq/patches/0005-Retry-query-to-other-servers-on-receipt-of-SERVFAIL-.patch b/package/network/services/dnsmasq/patches/0005-Retry-query-to-other-servers-on-receipt-of-SERVFAIL-.patch
> new file mode 100644
> index 0000000000..d21f9d4320
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0005-Retry-query-to-other-servers-on-receipt-of-SERVFAIL-.patch
> @@ -0,0 +1,22 @@
> +From 34e26e14c5e0fb2d5f05f67858319c9db2058333 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Thu, 10 May 2018 20:54:57 +0100
> +Subject: [PATCH 05/10] Retry query to other servers on receipt of SERVFAIL
> + rcode.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/forward.c | 2 +-
> + 1 file changed, 1 insertion(+), 1 deletion(-)
> +
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -817,7 +817,7 @@ void reply_query(int fd, int family, tim
> +
> +   /* Note: if we send extra options in the EDNS0 header, we can't recreate
> +      the query from the reply. */
> +-  if (RCODE(header) == REFUSED &&
> ++  if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
> +       forward->forwardall == 0 &&
> +       !(forward->flags & FREC_HAS_EXTRADATA))
> +     /* for broken servers, attempt to send to another one. */
> diff --git a/package/network/services/dnsmasq/patches/0006-Handle-query-retry-on-REFUSED-or-SERVFAIL-for-DNSSEC.patch b/package/network/services/dnsmasq/patches/0006-Handle-query-retry-on-REFUSED-or-SERVFAIL-for-DNSSEC.patch
> new file mode 100644
> index 0000000000..b4681af4ff
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0006-Handle-query-retry-on-REFUSED-or-SERVFAIL-for-DNSSEC.patch
> @@ -0,0 +1,87 @@
> +From a0088e83640d7d1544127dd668660462e9f78e52 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Thu, 10 May 2018 21:43:14 +0100
> +Subject: [PATCH 06/10] Handle query retry on REFUSED or SERVFAIL for
> + DNSSEC-generated queries.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/forward.c | 46 ++++++++++++++++++++++++++++++++++++++++------
> + 1 file changed, 40 insertions(+), 6 deletions(-)
> +
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -298,9 +298,9 @@ static int forward_query(int udpfd, unio
> +               fd = forward->rfd4->fd;
> +           }
> +
> +-        while (retry_send( sendto(fd, (char *)header, plen, 0,
> +-                                  &forward->sentto->addr.sa,
> +-                                  sa_len(&forward->sentto->addr))));
> ++        while (retry_send(sendto(fd, (char *)header, plen, 0,
> ++                                 &forward->sentto->addr.sa,
> ++                                 sa_len(&forward->sentto->addr))));
> +
> +         return 1;
> +       }
> +@@ -804,8 +804,7 @@ void reply_query(int fd, int family, tim
> +   dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
> +             (void *)header, n, &serveraddr, NULL);
> + #endif
> +-
> +-
> ++
> +   /* log_query gets called indirectly all over the place, so
> +      pass these in global variables - sorry. */
> +   daemon->log_display_id = forward->log_id;
> +@@ -826,6 +825,40 @@ void reply_query(int fd, int family, tim
> +       size_t plen;
> +       int is_sign;
> +
> ++      /* For DNSSEC originated queries, just retry the query to the same server. */
> ++      if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
> ++      {
> ++        blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
> ++        plen = forward->stash_len;
> ++
> ++        forward->forwardall = 2; /* only retry once */
> ++
> ++        if (forward->sentto->addr.sa.sa_family == AF_INET)
> ++          log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
> ++#ifdef HAVE_IPV6
> ++        else
> ++          log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
> ++#endif
> ++
> ++        if (forward->sentto->sfd)
> ++          fd = forward->sentto->sfd->fd;
> ++        else
> ++          {
> ++#ifdef HAVE_IPV6
> ++            if (forward->sentto->addr.sa.sa_family == AF_INET6)
> ++              fd = forward->rfd6->fd;
> ++            else
> ++#endif
> ++              fd = forward->rfd4->fd;
> ++          }
> ++
> ++        while (retry_send(sendto(fd, (char *)header, plen, 0,
> ++                                 &forward->sentto->addr.sa,
> ++                                 sa_len(&forward->sentto->addr))));
> ++
> ++        return;
> ++      }
> ++
> +       /* 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
> +@@ -1017,7 +1050,8 @@ void reply_query(int fd, int family, tim
> + #ifdef HAVE_IPV6
> +                     new->rfd6 = NULL;
> + #endif
> +-                    new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
> ++                    new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
> ++                    new->forwardall = 0;
> +
> +                     new->dependent = forward; /* to find query awaiting new one. */
> +                     forward->blocking_query = new; /* for garbage cleaning */
> diff --git a/package/network/services/dnsmasq/patches/0007-Retry-SERVFAIL-DNSSEC-queries-to-a-different-server-.patch b/package/network/services/dnsmasq/patches/0007-Retry-SERVFAIL-DNSSEC-queries-to-a-different-server-.patch
> new file mode 100644
> index 0000000000..5756717340
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0007-Retry-SERVFAIL-DNSSEC-queries-to-a-different-server-.patch
> @@ -0,0 +1,100 @@
> +From 1f60a18ea1c64beb8b6cffa0650a2bfad95ac352 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 11 May 2018 16:44:16 +0100
> +Subject: [PATCH 07/10] Retry SERVFAIL DNSSEC queries to a different server, if
> + possible.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/forward.c | 53 ++++++++++++++++++++++++++++++++++++++++++-----------
> + 1 file changed, 42 insertions(+), 11 deletions(-)
> +
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -825,9 +825,12 @@ void reply_query(int fd, int family, tim
> +       size_t plen;
> +       int is_sign;
> +
> ++#ifdef HAVE_DNSSEC
> +       /* For DNSSEC originated queries, just retry the query to the same server. */
> +       if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
> +       {
> ++        struct server *start;
> ++
> +         blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
> +         plen = forward->stash_len;
> +
> +@@ -839,26 +842,54 @@ void reply_query(int fd, int family, tim
> +         else
> +           log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
> + #endif
> +-
> +-        if (forward->sentto->sfd)
> +-          fd = forward->sentto->sfd->fd;
> ++
> ++        start = forward->sentto;
> ++
> ++        /* for non-domain specific servers, see if we can find another to try. */
> ++        if ((forward->sentto->flags & SERV_TYPE) == 0)
> ++          while (1)
> ++            {
> ++              if (!(start = start->next))
> ++                start = daemon->servers;
> ++              if (start == forward->sentto)
> ++                break;
> ++
> ++              if ((start->flags & SERV_TYPE) == 0 &&
> ++                  (start->flags & SERV_DO_DNSSEC))
> ++                break;
> ++            }
> ++
> ++
> ++        if (start->sfd)
> ++          fd = start->sfd->fd;
> +         else
> +           {
> + #ifdef HAVE_IPV6
> +-            if (forward->sentto->addr.sa.sa_family == AF_INET6)
> +-              fd = forward->rfd6->fd;
> ++            if (start->addr.sa.sa_family == AF_INET6)
> ++              {
> ++                /* may have changed family */
> ++                if (!forward->rfd6)
> ++                  forward->rfd6 = allocate_rfd(AF_INET6);
> ++                fd = forward->rfd6->fd;
> ++              }
> +             else
> + #endif
> +-              fd = forward->rfd4->fd;
> ++              {
> ++                /* may have changed family */
> ++                if (!forward->rfd4)
> ++                  forward->rfd4 = allocate_rfd(AF_INET);
> ++                fd = forward->rfd4->fd;
> ++              }
> +           }
> +-
> ++
> +         while (retry_send(sendto(fd, (char *)header, plen, 0,
> +-                                 &forward->sentto->addr.sa,
> +-                                 sa_len(&forward->sentto->addr))));
> ++                                 &start->addr.sa,
> ++                                 sa_len(&start->addr))));
> +
> +         return;
> +       }
> +-
> ++#endif
> ++
> +       /* 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
> +@@ -1024,7 +1055,7 @@ void reply_query(int fd, int family, tim
> +                         while (1)
> +                           {
> +                             if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
> +-                                (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
> ++                                ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
> +                                 !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
> +                               {
> +                                 new_server = start;
> diff --git a/package/network/services/dnsmasq/patches/0008-Fix-logging-in-previous.patch b/package/network/services/dnsmasq/patches/0008-Fix-logging-in-previous.patch
> new file mode 100644
> index 0000000000..d5735a25d5
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0008-Fix-logging-in-previous.patch
> @@ -0,0 +1,41 @@
> +From e27825b0ef1e79ab05b1752c8c838cb43ad39d79 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 11 May 2018 17:20:47 +0100
> +Subject: [PATCH 08/10] Fix logging in previous.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/forward.c | 15 +++++++--------
> + 1 file changed, 7 insertions(+), 8 deletions(-)
> +
> +--- a/src/forward.c
> ++++ b/src/forward.c
> +@@ -835,14 +835,6 @@ void reply_query(int fd, int family, tim
> +         plen = forward->stash_len;
> +
> +         forward->forwardall = 2; /* only retry once */
> +-
> +-        if (forward->sentto->addr.sa.sa_family == AF_INET)
> +-          log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
> +-#ifdef HAVE_IPV6
> +-        else
> +-          log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
> +-#endif
> +-
> +         start = forward->sentto;
> +
> +         /* for non-domain specific servers, see if we can find another to try. */
> +@@ -886,6 +878,13 @@ void reply_query(int fd, int family, tim
> +                                  &start->addr.sa,
> +                                  sa_len(&start->addr))));
> +
> ++        if (start->addr.sa.sa_family == AF_INET)
> ++          log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&start->addr.in.sin_addr, "dnssec");
> ++#ifdef HAVE_IPV6
> ++        else
> ++          log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&start->addr.in6.sin6_addr, "dnssec");
> ++#endif
> ++
> +         return;
> +       }
> + #endif
> diff --git a/package/network/services/dnsmasq/patches/0009-Do-unsolicited-RAs-for-interfaces-which-appear-after.patch b/package/network/services/dnsmasq/patches/0009-Do-unsolicited-RAs-for-interfaces-which-appear-after.patch
> new file mode 100644
> index 0000000000..0aaec7edf4
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0009-Do-unsolicited-RAs-for-interfaces-which-appear-after.patch
> @@ -0,0 +1,44 @@
> +From 0a496f059c1e9d75c33cce4c1211d58422ba4f62 Mon Sep 17 00:00:00 2001
> +From: Maarten de Vries <maarten+dnsmasq at m.de-vri.es>
> +Date: Fri, 11 May 2018 23:20:58 +0100
> +Subject: [PATCH 09/10] Do unsolicited RAs for interfaces which appear after
> + dnsmasq startup.
> +
> +I noticed that dnsmasq often wasn't sending any unsolicited RAs for me.
> +
> +This turned out to happen when the interface (a bridge interface) wasn't
> +created yet at the time dnsmasq started. When dnsmasq is started after
> +the interface is created, it sends RAs as expected. I assume this also
> +extends to other types of virtual interfaces that are created after
> +dnsmasq starts.
> +
> +Digging into the source, it seems to be caused by a missing call to
> +ra_start_unsolicited for non-template contexts in construct_worker from
> +src/dhcp6.c. The attached patch adds that call, but only if the
> +interface index or address changed to prevent doing fast RAs for no reason.
> +
> +I tested it on my own server and it appears to work as expected. When
> +the interface is created and configured, dnsmasq does fast RAs for a
> +while and then settles into slow RAs.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/dhcp6.c | 7 +++++++
> + 1 file changed, 7 insertions(+)
> +
> +--- a/src/dhcp6.c
> ++++ b/src/dhcp6.c
> +@@ -647,6 +647,13 @@ static int construct_worker(struct in6_a
> +           is_same_net6(local, &template->start6, template->prefix) &&
> +           is_same_net6(local, &template->end6, template->prefix))
> +         {
> ++          /* First time found, do fast RA. */
> ++          if (template->if_index != if_index || !IN6_ARE_ADDR_EQUAL(&template->local6, local))
> ++            {
> ++              ra_start_unsolicited(param->now, template);
> ++              param->newone = 1;
> ++            }
> ++
> +           template->if_index = if_index;
> +           template->local6 = *local;
> +         }
> diff --git a/package/network/services/dnsmasq/patches/0010-Log-warning-on-very-large-cachesize-config-instead-o.patch b/package/network/services/dnsmasq/patches/0010-Log-warning-on-very-large-cachesize-config-instead-o.patch
> new file mode 100644
> index 0000000000..98df4520a2
> --- /dev/null
> +++ b/package/network/services/dnsmasq/patches/0010-Log-warning-on-very-large-cachesize-config-instead-o.patch
> @@ -0,0 +1,38 @@
> +From 1f1873aadd092a0fab505dd278a484d887ba0ec3 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon at thekelleys.org.uk>
> +Date: Fri, 11 May 2018 23:38:23 +0100
> +Subject: [PATCH 10/10] Log warning on very large cachesize config, instead of
> + truncating it.
> +
> +Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
> +---
> + src/dnsmasq.c | 6 +++++-
> + src/option.c  | 2 --
> + 2 files changed, 5 insertions(+), 3 deletions(-)
> +
> +--- a/src/dnsmasq.c
> ++++ b/src/dnsmasq.c
> +@@ -740,7 +740,11 @@ int main (int argc, char **argv)
> +   else
> +     {
> +       if (daemon->cachesize != 0)
> +-      my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
> ++      {
> ++        my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
> ++        if (daemon->cachesize > 10000)
> ++          my_syslog(LOG_WARNING, _("cache size greater than 10000 may cause performance issues, and is unlikely to be useful."));
> ++      }
> +       else
> +       my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
> +
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -2603,8 +2603,6 @@ static int one_opt(int option, char *arg
> +
> +           if (size < 0)
> +             size = 0;
> +-          else if (size > 10000)
> +-            size = 10000;
> +
> +           daemon->cachesize = size;
> +         }
> diff --git a/package/network/services/dnsmasq/patches/240-ubus.patch b/package/network/services/dnsmasq/patches/240-ubus.patch
> index 415c7a5e4c..5e44f5b61a 100644
> --- a/package/network/services/dnsmasq/patches/240-ubus.patch
> +++ b/package/network/services/dnsmasq/patches/240-ubus.patch
> @@ -74,7 +74,7 @@
>   int main (int argc, char **argv)
>   {
>     int bind_fallback = 0;
> -@@ -928,6 +988,7 @@ int main (int argc, char **argv)
> +@@ -944,6 +1004,7 @@ int main (int argc, char **argv)
>         set_dbus_listeners();
>   #endif
>
> @@ -82,7 +82,7 @@
>   #ifdef HAVE_DHCP
>         if (daemon->dhcp || daemon->relay4)
>         {
> -@@ -1058,6 +1119,8 @@ int main (int argc, char **argv)
> +@@ -1074,6 +1135,8 @@ int main (int argc, char **argv)
>         check_dbus_listeners();
>   #endif
>
> @@ -104,7 +104,7 @@
>   mostly_clean :
>  --- a/src/dnsmasq.h
>  +++ b/src/dnsmasq.h
> -@@ -1415,6 +1415,8 @@ void emit_dbus_signal(int action, struct
> +@@ -1440,6 +1440,8 @@ void emit_dbus_signal(int action, struct
>   #  endif
>   #endif
>
> @@ -115,7 +115,7 @@
>   void ipset_init(void);
>  --- a/src/rfc2131.c
>  +++ b/src/rfc2131.c
> -@@ -1621,6 +1621,10 @@ static void log_packet(char *type, void
> +@@ -1636,6 +1636,10 @@ static void log_packet(char *type, void
>               daemon->namebuff,
>               string ? string : "",
>               err ? err : "");
> --
> 2.15.1 (Apple Git-101)
>
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev



More information about the Lede-dev mailing list