public inbox for development@lists.ipfire.org
 help / color / mirror / Atom feed
From: Matthias Fischer <matthias.fischer@ipfire.org>
To: development@lists.ipfire.org
Subject: [PATCH] dnsmasq 2.75: latest patches from upstream
Date: Thu, 24 Dec 2015 10:17:16 +0100	[thread overview]
Message-ID: <1450948636-31650-1-git-send-email-matthias.fischer@ipfire.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 42229 bytes --]

Same procedure as... :-)

Best to all for xmas and 2016!

Matthias

Signed-off-by: Matthias Fischer <matthias.fischer(a)ipfire.org>
---
 lfs/dnsmasq                                        |   5 +
 ...EDNS0_handling_and_computation_use_of_udp.patch | 643 +++++++++++++++++++++
 ...aks_in_handling_unknown_DNSSEC_algorithms.patch | 262 +++++++++
 ...obscure_off-by-one_in_DNSSEC_hostname_cmp.patch |  27 +
 .../028-Minor_tweak_to_previous_commit.patch       |  39 ++
 .../dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch |  39 ++
 6 files changed, 1015 insertions(+)
 create mode 100644 src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
 create mode 100644 src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
 create mode 100644 src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
 create mode 100644 src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
 create mode 100644 src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch

diff --git a/lfs/dnsmasq b/lfs/dnsmasq
index c8fd7db..8058663 100644
--- a/lfs/dnsmasq
+++ b/lfs/dnsmasq
@@ -97,6 +97,11 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/022-Tidy_up_DNSSEC_non-existence_code_Check_zone_status_is_NSEC_proof_bad.patch
 	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/023-Fix_brace_botch_in_dnssec_validate_ds.patch
 	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/024-Do_a_better_job_of_determining_which_DNSSEC_sig_algos_are_supported.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
+	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
 	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq-Add-support-to-read-ISC-DHCP-lease-file.patch
 
 	cd $(DIR_APP) && sed -i src/config.h \
diff --git a/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch b/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
new file mode 100644
index 0000000..c016e73
--- /dev/null
+++ b/src/patches/dnsmasq/025-Major_tidy_up_of_EDNS0_handling_and_computation_use_of_udp.patch
@@ -0,0 +1,643 @@
+From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Sun, 20 Dec 2015 17:12:16 +0000
+Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use of udp
+ packet size.
+
+---
+ src/auth.c     |    8 ++-
+ src/dnsmasq.h  |    7 ++-
+ src/dnssec.c   |    1 -
+ src/forward.c  |  184 ++++++++++++++++++++++++++++++++++++++++----------------
+ src/netlink.c  |    3 +-
+ src/rfc1035.c  |   81 +++++++------------------
+ src/rrfilter.c |    2 +-
+ 7 files changed, 168 insertions(+), 118 deletions(-)
+
+diff --git a/src/auth.c b/src/auth.c
+index 2b0b7d6..85bd5e7 100644
+--- a/src/auth.c
++++ b/src/auth.c
+@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
+ }
+ 
+ 
+-size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) 
++size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, 
++		   int local_query, int do_bit, int have_pseudoheader) 
+ {
+   char *name = daemon->namebuff;
+   unsigned char *p, *ansp;
+@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
+   header->ancount = htons(anscount);
+   header->nscount = htons(authcount);
+   header->arcount = htons(0);
++
++  /* Advertise our packet size limit in our reply */
++  if (have_pseudoheader)
++    return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
++
+   return ansp - (unsigned char *)header;
+ }
+   
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 39a930c..abb34c5 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
+ 		      int no_cache, int secure, int *doctored);
+ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
+ 		      struct in_addr local_addr, struct in_addr local_netmask, 
+-		      time_t now, int *ad_reqd, int *do_bit);
++		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
+ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
+ 			     struct bogus_addr *addr, time_t now);
+ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
+@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now);
+ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
+ size_t resize_packet(struct dns_header *header, size_t plen, 
+ 		  unsigned char *pheader, size_t hlen);
++size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
++			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
+ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
+ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
+ #ifdef HAVE_DNSSEC
+@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost);
+ /* auth.c */
+ #ifdef HAVE_AUTH
+ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, 
+-		   time_t now, union mysockaddr *peer_addr, int local_query);
++		   time_t now, union mysockaddr *peer_addr, int local_query,
++		   int do_bit, int have_pseudoheader);
+ int in_zone(struct auth_zone *zone, char *name, char **cut);
+ #endif
+ 
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 82394ee..299ca64 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo)
+     case 12: return "gosthash94";
+     case 13: return "sha256";
+     case 14: return "sha384";
+-
+     default: return NULL;
+     }
+ }
+diff --git a/src/forward.c b/src/forward.c
+index 3e801c8..041353c 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+   void *hash = &crc;
+ #endif
+  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
+- unsigned char *pheader;
+ 
+  (void)do_bit;
+ 
+@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 	 there's no point retrying the query, retry the key query instead...... */
+       if (forward->blocking_query)
+ 	{
+-	  int fd;
++	  int fd, is_sign;
++	  unsigned char *pheader;
+ 	  
+ 	  forward->flags &= ~FREC_TEST_PKTSZ;
+ 	  
+@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 	  blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
+ 	  plen = forward->stash_len;
+ 	  
+-	  if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
+-	    PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
++	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
++	    PUTSHORT(SAFE_PKTSZ, pheader);
+ 
+ 	  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");
+@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+       forward->log_id = daemon->log_id;
+       
+       if (option_bool(OPT_ADD_MAC))
+-	plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
+-      
++	{
++	  size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
++	  if (new != plen)
++	    {
++	      plen = new;
++	      forward->flags |= FREC_ADDED_PHEADER;
++	    }
++	}
++
+       if (option_bool(OPT_CLIENT_SUBNET))
+ 	{
+ 	  size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); 
+ 	  if (new != plen)
+ 	    {
+ 	      plen = new;
+-	      forward->flags |= FREC_HAS_SUBNET;
++	      forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
+ 	    }
+ 	}
+ 
+ #ifdef HAVE_DNSSEC
+       if (option_bool(OPT_DNSSEC_VALID))
+ 	{
+-	  size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
++	  size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
+ 	 
++	  if (new != plen)
++	    forward->flags |= FREC_ADDED_PHEADER;
++
++	  plen = new;
++	      
+ 	  /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
+ 	     this allows it to select auth servers when one is returning bad data. */
+ 	  if (option_bool(OPT_DNSSEC_DEBUG))
+ 	    header->hb4 |= HB4_CD;
+ 
+-	  if (new_plen != plen)
+-	    forward->flags |= FREC_ADDED_PHEADER;
+-
+-	  plen = new_plen;
+ 	}
+ #endif
+       
+@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 		    }
+ #endif
+ 		}
+-
+-	      if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
+-		PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
+ 	      
++#ifdef HAVE_DNSSEC
++	      if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
++		{
++		  /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
++		     packet size to 512. But that won't provide space for the RRSIGS in many cases.
++		     The RRSIGS will be stripped out before the answer goes back, so the packet should
++		     shrink again. So, if we added a do-bit, bump the udp packet size to the value
++		     known to be OK for this server. Maybe check returned size after stripping and set
++		     the truncated bit? */		  
++		  unsigned char *pheader;
++		  int is_sign;
++		  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
++		    PUTSHORT(start->edns_pktsz, pheader);
++		}
++#endif
++
+ 	      if (retry_send(sendto(fd, (char *)header, plen, 0,
+ 				    &start->addr.sa,
+ 				    sa_len(&start->addr))))
+@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
+     }
+ #endif
+   
+-  /* If upstream is advertising a larger UDP packet size
+-     than we allow, trim it so that we don't get overlarge
+-     requests for the client. We can't do this for signed packets. */
+-
+   if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
+     {
+-      unsigned short udpsz;
+-      unsigned char *psave = sizep;
+-      
+-      GETSHORT(udpsz, sizep);
+-
+-      if (!is_sign && udpsz > daemon->edns_pktsz)
+-	PUTSHORT(daemon->edns_pktsz, psave);
+-      
+       if (check_subnet && !check_source(header, plen, pheader, query_source))
+ 	{
+ 	  my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
+ 	  return 0;
+ 	}
+       
+-      if (added_pheader)
++      if (!is_sign)
+ 	{
+-	  pheader = 0; 
+-	  header->arcount = htons(0);
++	  if (added_pheader)
++	    {
++	      /* client didn't send EDNS0, we added one, strip it off before returning answer. */
++	      n = rrfilter(header, n, 0);
++	      pheader = NULL;
++	    }
++	  else
++	    {
++	      /* If upstream is advertising a larger UDP packet size
++		 than we allow, trim it so that we don't get overlarge
++		 requests for the client. We can't do this for signed packets. */
++	      unsigned short udpsz;
++	      unsigned char *psave = sizep;
++	      
++	      GETSHORT(udpsz, sizep);
++	      if (udpsz > daemon->edns_pktsz)
++		PUTSHORT(daemon->edns_pktsz, psave);
++	    }
+ 	}
+     }
+   
+@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
+     }
+ 
+   if (option_bool(OPT_DNSSEC_VALID))
+-    header->hb4 &= ~HB4_AD;
+-  
+-  if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
+-    header->hb4 |= HB4_AD;
+-
+-  /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
+-  if (!do_bit)
+-    n = rrfilter(header, n, 1);
++    {
++      header->hb4 &= ~HB4_AD;
++      
++      if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
++	header->hb4 |= HB4_AD;
++      
++      /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
++      if (!do_bit)
++	n = rrfilter(header, n, 1);
++    }
+ #endif
+ 
+   /* do this after extract_addresses. Ensure NODATA reply and remove
+@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now)
+ 	  if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
+ 	    {
+ 	      header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
+-	      header->hb4 &= ~(HB4_RA | HB4_RCODE);
+-	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
++	      header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
++	      if (forward->flags |= FREC_CHECKING_DISABLED)
++		header->hb4 |= HB4_CD;
++	      if (forward->flags |= FREC_AD_QUESTION)
++		header->hb4 |= HB4_AD;
++	      if (forward->flags & FREC_DO_QUESTION)
++		add_do_bit(header, nn,  (char *)pheader + plen);
++	      forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
+ 	      return;
+ 	    }
+ 	}
+@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now)
+ {
+   struct dns_header *header = (struct dns_header *)daemon->packet;
+   union mysockaddr source_addr;
+-  unsigned short type;
++  unsigned char *pheader;
++  unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
+   struct all_addr dst_addr;
+   struct in_addr netmask, dst_addr_4;
+   size_t m;
+   ssize_t n;
+-  int if_index = 0, auth_dns = 0;
++  int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
+ #ifdef HAVE_AUTH
+   int local_auth = 0;
+ #endif
+@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now)
+ #endif
+     }
+   
++  if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
++    { 
++      unsigned short flags;
++      
++      have_pseudoheader = 1;
++      GETSHORT(udp_size, pheader);
++      pheader += 2; /* ext_rcode */
++      GETSHORT(flags, pheader);
++      
++      if (flags & 0x8000)
++	do_bit = 1;/* do bit */ 
++	
++      /* If the client provides an EDNS0 UDP size, use that to limit our reply.
++	 (bounded by the maximum configured). If no EDNS0, then it
++	 defaults to 512 */
++      if (udp_size > daemon->edns_pktsz)
++	udp_size = daemon->edns_pktsz;
++    }
++
+ #ifdef HAVE_AUTH
+   if (auth_dns)
+     {
+-      m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth);
++      m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr, 
++		      local_auth, do_bit, have_pseudoheader);
+       if (m >= 1)
+ 	{
+ 	  send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
+@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now)
+   else
+ #endif
+     {
+-      int ad_reqd, do_bit;
+-      m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, 
+-			 dst_addr_4, netmask, now, &ad_reqd, &do_bit);
++      int ad_reqd = do_bit;
++       /* RFC 6840 5.7 */
++      if (header->hb4 & HB4_AD)
++	ad_reqd = 1;
++
++      m = answer_request(header, ((char *) header) + udp_size, (size_t)n, 
++			 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
+       
+       if (m >= 1)
+ 	{
+@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now,
+ #ifdef HAVE_AUTH
+   int local_auth = 0;
+ #endif
+-  int checking_disabled, ad_question, do_bit, added_pheader = 0;
++  int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
+   int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
+   size_t m;
+   unsigned short qtype;
+@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now,
+   union mysockaddr peer_addr;
+   socklen_t peer_len = sizeof(union mysockaddr);
+   int query_count = 0;
++  unsigned char *pheader;
+ 
+   if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
+     return packet;
+@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now,
+       else
+ 	dst_addr_4.s_addr = 0;
+       
++      do_bit = 0;
++
++      if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
++	{ 
++	  unsigned short flags;
++	  
++	  have_pseudoheader = 1;
++	  pheader += 4; /* udp_size, ext_rcode */
++	  GETSHORT(flags, pheader);
++      
++	  if (flags & 0x8000)
++	    do_bit = 1;/* do bit */ 
++	}
++
+ #ifdef HAVE_AUTH
+       if (auth_dns)
+-	m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
++	m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, 
++			local_auth, do_bit, have_pseudoheader);
+       else
+ #endif
+ 	{
+-	  /* m > 0 if answered from cache */
+-	  m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
+-			     dst_addr_4, netmask, now, &ad_question, &do_bit);
++	   int ad_reqd = do_bit;
++	   /* RFC 6840 5.7 */
++	   if (header->hb4 & HB4_AD)
++	     ad_reqd = 1;
++	   
++	   /* m > 0 if answered from cache */
++	   m = answer_request(header, ((char *) header) + 65536, (size_t)size, 
++			      dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader);
+ 	  
+ 	  /* Do this by steam now we're not in the select() loop */
+ 	  check_log_writer(1); 
+@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now,
+ 			    }
+ 			  
+ #ifdef HAVE_DNSSEC
++			  added_pheader = 0;			  
+ 			  if (option_bool(OPT_DNSSEC_VALID))
+ 			    {
+ 			      size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
+@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now,
+ 
+ 		      m = process_reply(header, now, last_server, (unsigned int)m, 
+ 					option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
+-					ad_question, do_bit, added_pheader, check_subnet, &peer_addr); 
++					ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr); 
+ 		      
+ 		      break;
+ 		    }
+diff --git a/src/netlink.c b/src/netlink.c
+index 753784d..3376d68 100644
+--- a/src/netlink.c
++++ b/src/netlink.c
+@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+ 		rta = RTA_NEXT(rta, len1);
+ 	      }
+ 
+-	    if (inaddr && mac && callback_ok)
++	    if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
++		inaddr && mac && callback_ok)
+ 	      if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
+ 		callback_ok = 0;
+ 	  }
+diff --git a/src/rfc1035.c b/src/rfc1035.c
+index 188d05f..18858a8 100644
+--- a/src/rfc1035.c
++++ b/src/rfc1035.c
+@@ -489,8 +489,8 @@ struct macparm {
+   union mysockaddr *l3;
+ };
+  
+-static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
+-			       int optno, unsigned char *opt, size_t optlen, int set_do)
++size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, 
++			unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
+ { 
+   unsigned char *lenp, *datap, *p;
+   int rdlen, is_sign;
+@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
+ 	return plen;
+       *p++ = 0; /* empty name */
+       PUTSHORT(T_OPT, p);
+-      PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
++      PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
+       PUTSHORT(0, p);    /* extended RCODE and version */
+       PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
+       lenp = p;
+@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
+   if (!match)
+     return 1; /* continue */
+ 
+-  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit,  EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
++  parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
+   
+   return 0; /* done */
+ }	      
+@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
+ {
+   struct macparm parm;
+      
+-/* Must have an existing pseudoheader as the only ar-record, 
+-   or have no ar-records. Must also not be signed */
+-   
+-  if (ntohs(header->arcount) > 1)
+-    return plen;
+-
+   parm.header = header;
+   parm.limit = (unsigned char *)limit;
+   parm.plen = plen;
+@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
+   struct subnet_opt opt;
+   
+   len = calc_subnet_opt(&opt, source);
+-  return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
++  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
+ }
+ 
+ #ifdef HAVE_DNSSEC
+ size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
+ {
+-  return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
++  return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
+ }
+ #endif
+ 
+@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
+ /* return zero if we can't answer from cache, or packet size if we can */
+ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
+ 		      struct in_addr local_addr, struct in_addr local_netmask, 
+-		      time_t now, int *ad_reqd, int *do_bit) 
++		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader) 
+ {
+   char *name = daemon->namebuff;
+-  unsigned char *p, *ansp, *pheader;
++  unsigned char *p, *ansp;
+   unsigned int qtype, qclass;
+   struct all_addr addr;
+   int nameoffset;
+   unsigned short flag;
+   int q, ans, anscount = 0, addncount = 0;
+-  int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
++  int dryrun = 0;
+   struct crec *crecp;
+   int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
+   struct mx_srv_record *rec;
+@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+   if (header->hb4 & HB4_CD)
+     sec_data = 0;
+   
+-  /* RFC 6840 5.7 */
+-  *ad_reqd = header->hb4 & HB4_AD;
+-  *do_bit = 0;
+-
+   /* If there is an  additional data section then it will be overwritten by
+      partial replies, so we have to do a dry run to see if we can answer
+      the query. */
+-
+   if (ntohs(header->arcount) != 0)
+-    {
+-      dryrun = 1;
+-
+-      /* If there's an additional section, there might be an EDNS(0) pseudoheader */
+-      if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
+-	{ 
+-	  unsigned short flags;
+-	  
+-	  have_pseudoheader = 1;
+-	  
+-	  pheader += 4; /* udp size, ext_rcode */
+-	  GETSHORT(flags, pheader);
+-	  
+-	  if ((sec_reqd = flags & 0x8000))
+-	    {
+-	      *do_bit = 1;/* do bit */ 
+-	      *ad_reqd = 1;
+-	    }
+-	}
+-    }
++    dryrun = 1;
+ 
+   for (rec = daemon->mxnames; rec; rec = rec->next)
+     rec->offset = 0;
+@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+       GETSHORT(qtype, p); 
+       GETSHORT(qclass, p);
+ 
+-      /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
+-	 not set. */
+-      if (qtype == T_ANY)
+-	*do_bit = 1;
+-
+       ans = 0; /* have we answered this question */
+       
+       if (qtype == T_TXT || qtype == T_ANY)
+@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ 		     the zone is unsigned, which implies that we're doing
+ 		     validation. */
+ 		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
+-		      !sec_reqd || 
++		      !do_bit || 
+ 		      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+ 		    {
+ 		      do 
+@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ 		    }
+ 
+ 		  /* If the client asked for DNSSEC  don't use cached data. */
+-		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
++		  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
+ 		    do
+ 		      { 
+ 			/* don't answer wildcard queries with data not from /etc/hosts
+@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ 			
+ 			if (crecp->flags & F_NEG)
+ 			  {
+-			    /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
+-			       is cached and the client wants DNSSEC, forward rather than answering from the cache */
+-			    if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
+-			      {
+-				ans = 1;
+-				auth = 0;
+-				if (crecp->flags & F_NXDOMAIN)
+-				  nxdomain = 1;
+-				if (!dryrun)
+-				  log_query(crecp->flags, name, NULL, NULL);
+-			      }
++			    ans = 1;
++			    auth = 0;
++			    if (crecp->flags & F_NXDOMAIN)
++			      nxdomain = 1;
++			    if (!dryrun)
++			      log_query(crecp->flags, name, NULL, NULL);
+ 			  }
+ 			else 
+ 			  {
+@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
+ 
+   len = ansp - (unsigned char *)header;
+   
++  /* Advertise our packet size limit in our reply */
+   if (have_pseudoheader)
+-    len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
++    len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
+   
+-  if (*ad_reqd && sec_data)
++  if (ad_reqd && sec_data)
+     header->hb4 |= HB4_AD;
+   else
+     header->hb4 &= ~HB4_AD;
+diff --git a/src/rrfilter.c b/src/rrfilter.c
+index ae12261..b26b39f 100644
+--- a/src/rrfilter.c
++++ b/src/rrfilter.c
+@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
+   for (p = rrs[0], i = 1; i < rr_found; i += 2)
+     {
+       unsigned char *start = rrs[i];
+-      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
++      unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
+       
+       memmove(p, start, end-start);
+       p += end-start;
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch b/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
new file mode 100644
index 0000000..910921b
--- /dev/null
+++ b/src/patches/dnsmasq/026-More_tweaks_in_handling_unknown_DNSSEC_algorithms.patch
@@ -0,0 +1,262 @@
+From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Sun, 20 Dec 2015 20:44:23 +0000
+Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms.
+
+---
+ src/dnssec.c |  128 +++++++++++++++++++++++++++++-----------------------------
+ 1 file changed, 63 insertions(+), 65 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 299ca64..e09f304 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -70,7 +70,17 @@ static char *algo_digest_name(int algo)
+     default: return NULL;
+     }
+ }
+-      
++  
++/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
++static char *nsec3_digest_name(int digest)
++{
++  switch (digest)
++    {
++    case 1: return "sha1";
++    default: return NULL;
++    }
++}
++ 
+ /* Find pointer to correct hash function in nettle library */
+ static const struct nettle_hash *hash_find(char *name)
+ {
+@@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
+   static int rrset_sz = 0, sig_sz = 0; 
+   unsigned char *p;
+   int rrsetidx, sigidx, j, rdlen, res;
+-  int name_labels = count_labels(name); /* For 4035 5.3.2 check */
+   int gotkey = 0;
+ 
+   if (!(p = skip_questions(header, plen)))
+@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
+        j != 0; j--) 
+     {
+       unsigned char *pstart, *pdata;
+-      int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
++      int stype, sclass, type_covered;
+ 
+       pstart = p;
+       
+@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
+ 		return 0; /* bad packet */ 
+ 	      
+ 	      GETSHORT(type_covered, p);
+-	      algo = *p++;
+-	      labels = *p++;
+-	      p += 4; /* orig_ttl */
+-	      GETLONG(sig_expiration, p);
+-	      GETLONG(sig_inception, p);
+-	      p += 2; /* key_tag */
++	      p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
+ 	      
+ 	      if (gotkey)
+ 		{
+@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
+ 		    }
+ 		}
+ 		  
+-	      /* Don't count signatures for algos we don't support */
+-	      if (check_date_range(sig_inception, sig_expiration) &&
+-		  labels <= name_labels &&
+-		  type_covered == type && 
+-		  verify_func(algo))
++	      
++	      if (type_covered == type)
+ 		{
+ 		  if (!expand_workspace(&sigs, &sig_sz, sigidx))
+ 		    return 0; 
+@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+ 			  char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
+ {
+   unsigned char *p;
+-  int rdlen, j, name_labels;
++  int rdlen, j, name_labels, sig_expiration, sig_inception;
+   struct crec *crecp = NULL;
+   int algo, labels, orig_ttl, key_tag;
+   u16 *rr_desc = rrfilter_desc(type);
+@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
+       algo = *p++;
+       labels = *p++;
+       GETLONG(orig_ttl, p);
+-      p += 8; /* sig_expiration, sig_inception already checked */
++      GETLONG(sig_expiration, p);
++      GETLONG(sig_inception, p);
+       GETSHORT(key_tag, p);
+       
+       if (!extract_name(header, plen, &p, keyname, 1, 0))
+ 	return STAT_BOGUS;
+ 
+-      if (!(hash = hash_find(algo_digest_name(algo))) ||
++      if (!check_date_range(sig_inception, sig_expiration) ||
++	  labels > name_labels ||
++	  !(hash = hash_find(algo_digest_name(algo))) ||
+ 	  !hash_init(hash, &ctx, &digest))
+ 	continue;
+       
+@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
+ 		      else
+ 			{
+ 			  a.addr.keytag = keytag;
+-			  log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
++			  if (verify_func(algo))
++			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
++			  else
++			    log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
+ 			  
+ 			  recp1->addr.key.keylen = rdlen - 4;
+ 			  recp1->addr.key.keydata = key;
+@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
+ 		  else
+ 		    {
+ 		      a.addr.keytag = keytag;
+-		      log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
++		      if (hash_find(ds_digest_name(digest)) && verify_func(algo))
++			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
++		      else
++			log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
++		      
+ 		      crecp->addr.ds.digest = digest;
+ 		      crecp->addr.ds.keydata = key;
+ 		      crecp->addr.ds.algo = algo;
+@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+     *nons = 1;
+   
+   /* Look though the NSEC3 records to find the first one with 
+-     an algorithm we support (currently only algo == 1).
++     an algorithm we support.
+ 
+      Take the algo, iterations, and salt of that record
+      as the ones we're going to use, and prune any 
+@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+       p += 10; /* type, class, TTL, rdlen */
+       algo = *p++;
+       
+-      if (algo == 1)
++      if ((hash = hash_find(nsec3_digest_name(algo))))
+ 	break; /* known algo */
+     }
+ 
+@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+       nsecs[i] = nsec3p;
+     }
+ 
+-  /* Algo is checked as 1 above */
+-  if (!(hash = hash_find("sha1")))
+-    return 0;
+-
+   if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
+     return 0;
+   
+@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
+   
+   if (type_found == T_NSEC)
+     return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
+-  else
++  else if (type_found == T_NSEC3)
+     return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
++  else
++    return 0;
+ }
+ 
+ /* Check signing status of name.
+@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
+ */
+ static int zone_status(char *name, int class, char *keyname, time_t now)
+ {
+-  int secure_ds, name_start = strlen(name);
++  int name_start = strlen(name);
+   struct crec *crecp;
+   char *p;
+   
+@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
+       
+       if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
+ 	return STAT_NEED_DS;
++      
++       /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
++	  F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
++	  but that's because there's no NS record either, ie this isn't the start
++	  of a zone. We only prove that the DNS tree below a node is unsigned when
++	  we prove that we're at a zone cut AND there's no DS record. */
++      if (crecp->flags & F_NEG)
++	{
++	  if (crecp->flags & F_DNSSECOK)
++	    return STAT_INSECURE; /* proved no DS here */
++	}
+       else
+ 	{
+-	  secure_ds = 0;
+-	  
++	  int gotone = 0;
++
++	  /* If all the DS records have digest and/or sig algos we don't support,
++	     then the zone is insecure. Note that if an algo
++	     appears in the DS, then RRSIGs for that algo MUST
++	     exist for each RRset: 4035 para 2.2  So if we find
++	     a DS here with digest and sig we can do, we're entitled
++	     to assume we can validate the zone and if we can't later,
++	     because an RRSIG is missing we return BOGUS.
++	  */
+ 	  do 
+ 	    {
+-	      if (crecp->uid == (unsigned int)class)
+-		{
+-		  /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
+-		     F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
+-		     but that's because there's no NS record either, ie this isn't the start
+-		     of a zone. We only prove that the DNS tree below a node is unsigned when
+-		     we prove that we're at a zone cut AND there's no DS record.
+-		  */	  
+-		  if (crecp->flags & F_NEG)
+-		    {
+-		      if (crecp->flags & F_DNSSECOK)
+-			return STAT_INSECURE; /* proved no DS here */
+-		    }
+-		  else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
+-		    return STAT_INSECURE; /* algo we can't use - insecure */
+-		  else
+-		    secure_ds = 1;
+-		}
++	      if (crecp->uid == (unsigned int)class &&
++		  hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
++		  verify_func(crecp->addr.ds.algo))
++		gotone = 1;
+ 	    }
+ 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
+-	}
+-
+-      if (secure_ds)
+-	{
+-	  /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
+-	     that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
+-	     one we can use. However the DNSKEY RRset may contain more than one key and
+-	     one of the other keys may use an algorithm we don't support. If that's 
+-	     the case the zone is insecure for us. */
+-	  
+-	  if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
+-	    return STAT_NEED_KEY;
+ 
+-	  do 
+-	    {
+-	      if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
+-		return STAT_INSECURE;
+-	    }
+-	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
++	  if (!gotone)
++	    return STAT_INSECURE;
+ 	}
+ 
+       if (name_start == 0)
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch b/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
new file mode 100644
index 0000000..031339e
--- /dev/null
+++ b/src/patches/dnsmasq/027-Nasty_rare_and_obscure_off-by-one_in_DNSSEC_hostname_cmp.patch
@@ -0,0 +1,27 @@
+From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Sun, 20 Dec 2015 20:50:05 +0000
+Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC hostname_cmp().
+
+---
+ src/dnssec.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index e09f304..29848e1 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -1394,8 +1394,8 @@ static int hostname_cmp(const char *a, const char *b)
+       if (sb == b)
+ 	return 1;
+       
+-      ea = sa--;
+-      eb = sb--;
++      ea = --sa;
++      eb = --sb;
+     }
+ }
+ 
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch b/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
new file mode 100644
index 0000000..f3758fc
--- /dev/null
+++ b/src/patches/dnsmasq/028-Minor_tweak_to_previous_commit.patch
@@ -0,0 +1,39 @@
+From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Sun, 20 Dec 2015 21:19:20 +0000
+Subject: [PATCH] Minor tweak to previous commit.
+
+---
+ src/dnssec.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 29848e1..9fa64b6 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -1889,8 +1889,6 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
+ 	}
+       else
+ 	{
+-	  int gotone = 0;
+-
+ 	  /* If all the DS records have digest and/or sig algos we don't support,
+ 	     then the zone is insecure. Note that if an algo
+ 	     appears in the DS, then RRSIGs for that algo MUST
+@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
+ 	      if (crecp->uid == (unsigned int)class &&
+ 		  hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
+ 		  verify_func(crecp->addr.ds.algo))
+-		gotone = 1;
++		break;
+ 	    }
+ 	  while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
+ 
+-	  if (!gotone)
++	  if (!crecp)
+ 	    return STAT_INSECURE;
+ 	}
+ 
+-- 
+1.7.10.4
+
diff --git a/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch b/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
new file mode 100644
index 0000000..33219d2
--- /dev/null
+++ b/src/patches/dnsmasq/029-NSEC3_check_RFC5155_para_8_2.patch
@@ -0,0 +1,39 @@
+From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon(a)thekelleys.org.uk>
+Date: Sun, 20 Dec 2015 21:39:19 +0000
+Subject: [PATCH] NSEC3 check: RFC5155 para 8.2
+
+---
+ src/dnssec.c |    8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index 9fa64b6..486e422 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -1704,7 +1704,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+   for (i = 0; i < nsec_count; i++)
+     {
+       unsigned char *nsec3p = nsecs[i];
+-      int this_iter;
++      int this_iter, flags;
+ 
+       nsecs[i] = NULL; /* Speculative, will be restored if OK. */
+       
+@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+       if (*p++ != algo)
+ 	continue;
+  
+-      p++; /* flags */
++      flags = *p++; /* flags */
+       
++      /* 5155 8.2 */
++      if (flags != 0 && flags != 1)
++	continue;
++
+       GETSHORT(this_iter, p);
+       if (this_iter != iterations)
+ 	continue;
+-- 
+1.7.10.4
+
-- 
2.6.4


             reply	other threads:[~2015-12-24  9:17 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-24  9:17 Matthias Fischer [this message]
2015-12-28 14:40 ` Michael Tremer
2016-01-08 18:19 Matthias Fischer
2016-01-14 17:39 Matthias Fischer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1450948636-31650-1-git-send-email-matthias.fischer@ipfire.org \
    --to=matthias.fischer@ipfire.org \
    --cc=development@lists.ipfire.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox