On Sat, May 12, 2018 at 4:37 PM, Kevin Darbyshire-Bryant <l...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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 <si...@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 <l...@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+dnsm...@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 <l...@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 <si...@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 <l...@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@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/lede-dev _______________________________________________ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev