mbox

dnsmasq 2.76: latest patches (013-014)

Message ID 20160807110939.3286-1-matthias.fischer@ipfire.org
State Accepted
Commit bf8378e4b7593916b83fd5dfb517708bbdb67101
Headers

Message

Matthias Fischer Aug. 7, 2016, 9:09 p.m. UTC
  Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org>
---
 lfs/dnsmasq                                        |   2 +
 ...allow_to_exclude_ip_addresses_from_answer.patch | 184 +++++++++++++++++++++
 ...rial_when_reloading_etc_hosts_and_friends.patch |  41 +++++
 3 files changed, 227 insertions(+)
 create mode 100644 src/patches/dnsmasq/013-auth-zone_allow_to_exclude_ip_addresses_from_answer.patch
 create mode 100644 src/patches/dnsmasq/014-Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
  

Comments

Michael Tremer Aug. 8, 2016, 12:09 a.m. UTC | #1
Hi,

thank you. This has been merged as well.

However, since we still have some trouble with dnsmasq (it is still a little bit
unstable and on only one installation it is always falling back to TCP for
DNSSEC signed zones and I have no idea why), Marcel has started looking at
unbound.

It is unknown when, but if everything is working out well, we are going to
replace dnsmasq with unbound.

So maybe you want to join in working on that and test that a bit. I hope that we
can aim for 105, but it could be a bit later, too. So please do not put too much
effort into maintaining dnsmasq in IPFire any more.

But you have done a great job and I hope you can also put that into unbound :)

Best,
-Michael

On Sun, 2016-08-07 at 13:09 +0200, Matthias Fischer wrote:
> Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org>
> ---
>  lfs/dnsmasq                                        |   2 +
>  ...allow_to_exclude_ip_addresses_from_answer.patch | 184
> +++++++++++++++++++++
>  ...rial_when_reloading_etc_hosts_and_friends.patch |  41 +++++
>  3 files changed, 227 insertions(+)
>  create mode 100644 src/patches/dnsmasq/013-auth-
> zone_allow_to_exclude_ip_addresses_from_answer.patch
>  create mode 100644 src/patches/dnsmasq/014-
> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
> 
> diff --git a/lfs/dnsmasq b/lfs/dnsmasq
> index eb0f0ba..474dacc 100644
> --- a/lfs/dnsmasq
> +++ b/lfs/dnsmasq
> @@ -85,6 +85,8 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/010-
> Zero_packet_buffers_before_building_output_to_reduce_risk_of_information_leaka
> ge.patch
>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/011-
> Dont_reset_packet_length_on_transmission_in_case_of_retransmission.patch
>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/012-
> Compile-time_check_on_buffer_sizes_for_leasefile_parsing_code.patch
> +	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/013-
> auth-zone_allow_to_exclude_ip_addresses_from_answer.patch
> +	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/014-
> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.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/013-auth-
> zone_allow_to_exclude_ip_addresses_from_answer.patch
> b/src/patches/dnsmasq/013-auth-
> zone_allow_to_exclude_ip_addresses_from_answer.patch
> new file mode 100644
> index 0000000..bb5fe5d
> --- /dev/null
> +++ b/src/patches/dnsmasq/013-auth-
> zone_allow_to_exclude_ip_addresses_from_answer.patch
> @@ -0,0 +1,184 @@
> +From 094bfaeb4ff69cae99387bc2ea07ff57632c89f5 Mon Sep 17 00:00:00 2001
> +From: Mathias Kresin <dev@kresin.me>
> +Date: Sun, 24 Jul 2016 14:15:22 +0100
> +Subject: [PATCH] auth-zone: allow to exclude ip addresses from answer.
> +
> +---
> + man/dnsmasq.8 |    6 +++++-
> + src/auth.c    |   61 ++++++++++++++++++++++++++++++++++++-------------------
> --
> + src/dnsmasq.h |    1 +
> + src/option.c  |   21 ++++++++++++++++++--
> + 4 files changed, 64 insertions(+), 25 deletions(-)
> +
> +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
> +index ac8d921..8910947 100644
> +--- a/man/dnsmasq.8
> ++++ b/man/dnsmasq.8
> +@@ -739,7 +739,7 @@ a return code of SERVFAIL. Note that
> + setting this may affect DNS behaviour in bad ways, it is not an
> + extra-logging flag and should not be set in production.
> + .TP
> +-.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix
> length>].....]]
> ++.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix
> length>].....][,exclude:<subnet>[/<prefix length>]].....]
> + Define a DNS zone for which dnsmasq acts as authoritative server. Locally
> defined DNS records which are in the domain
> + will be served. If subnet(s) are given, A and AAAA records must be in one of
> the
> + specified subnets.
> +@@ -756,6 +756,10 @@ appear in the zone, but RFC1918 IPv4 addresses which
> should not.
> + Interface-name and address-literal subnet specifications may be used
> + freely in the same --auth-zone declaration.
> + 
> ++It's possible to exclude certain IP addresses from responses. It can be
> ++used, to make sure that answers contain only global routeable IP
> ++addresses (by excluding loopback, RFC1918 and ULA addresses).
> ++
> + The subnet(s) are also used to define in-addr.arpa and
> + ip6.arpa domains which are served for reverse-DNS queries. If not
> + specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
> +diff --git a/src/auth.c b/src/auth.c
> +index 3c5c37f..f1ca2f5 100644
> +--- a/src/auth.c
> ++++ b/src/auth.c
> +@@ -18,36 +18,53 @@
> + 
> + #ifdef HAVE_AUTH
> + 
> +-static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct
> all_addr *addr_u)
> ++static struct addrlist *find_addrlist(struct addrlist *list, int flag,
> struct all_addr *addr_u)
> + {
> +-  struct addrlist *subnet;
> +-
> +-  for (subnet = zone->subnet; subnet; subnet = subnet->next)
> +-    {
> +-      if (!(subnet->flags & ADDRLIST_IPV6))
> +-	{
> +-	  struct in_addr netmask, addr = addr_u->addr.addr4;
> +-
> +-	  if (!(flag & F_IPV4))
> +-	    continue;
> +-	  
> +-	  netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
> +-	  
> +-	  if  (is_same_net(addr, subnet->addr.addr.addr4, netmask))
> +-	    return subnet;
> +-	}
> ++  do {
> ++    if (!(list->flags & ADDRLIST_IPV6))
> ++      {
> ++	struct in_addr netmask, addr = addr_u->addr.addr4;
> ++	
> ++	if (!(flag & F_IPV4))
> ++	  continue;
> ++	
> ++	netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
> ++	
> ++	if  (is_same_net(addr, list->addr.addr.addr4, netmask))
> ++	  return list;
> ++      }
> + #ifdef HAVE_IPV6
> +-      else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, 
> subnet->prefixlen))
> +-	return subnet;
> ++    else if (is_same_net6(&(addr_u->addr.addr6), &list->addr.addr.addr6,
> list->prefixlen))
> ++      return list;
> + #endif
> +-
> +-    }
> ++    
> ++  } while ((list = list->next));
> ++  
> +   return NULL;
> + }
> + 
> ++static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct
> all_addr *addr_u)
> ++{
> ++  if (!zone->subnet)
> ++    return NULL;
> ++  
> ++  return find_addrlist(zone->subnet, flag, addr_u);
> ++}
> ++
> ++static struct addrlist *find_exclude(struct auth_zone *zone, int flag,
> struct all_addr *addr_u)
> ++{
> ++  if (!zone->exclude)
> ++    return NULL;
> ++  
> ++  return find_addrlist(zone->exclude, flag, addr_u);
> ++}
> ++
> + static int filter_zone(struct auth_zone *zone, int flag, struct all_addr
> *addr_u)
> + {
> +-  /* No zones specified, no filter */
> ++  if (find_exclude(zone, flag, addr_u))
> ++    return 0;
> ++
> ++  /* No subnets specified, no filter */
> +   if (!zone->subnet)
> +     return 1;
> +   
> +diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> +index 2bda5d0..27385a9 100644
> +--- a/src/dnsmasq.h
> ++++ b/src/dnsmasq.h
> +@@ -340,6 +340,7 @@ struct auth_zone {
> +     struct auth_name_list *next;
> +   } *interface_names;
> +   struct addrlist *subnet;
> ++  struct addrlist *exclude;
> +   struct auth_zone *next;
> + };
> + 
> +diff --git a/src/option.c b/src/option.c
> +index d8c57d6..6cedef3 100644
> +--- a/src/option.c
> ++++ b/src/option.c
> +@@ -1906,6 +1906,7 @@ static int one_opt(int option, char *arg, char *errstr,
> char *gen_err, int comma
> + 	new = opt_malloc(sizeof(struct auth_zone));
> + 	new->domain = opt_string_alloc(arg);
> + 	new->subnet = NULL;
> ++	new->exclude = NULL;
> + 	new->interface_names = NULL;
> + 	new->next = daemon->auth_zones;
> + 	daemon->auth_zones = new;
> +@@ -1913,6 +1914,7 @@ static int one_opt(int option, char *arg, char *errstr,
> char *gen_err, int comma
> + 	while ((arg = comma))
> + 	  {
> + 	    int prefixlen = 0;
> ++	    int is_exclude = 0;
> + 	    char *prefix;
> + 	    struct addrlist *subnet =  NULL;
> + 	    struct all_addr addr;
> +@@ -1923,6 +1925,12 @@ static int one_opt(int option, char *arg, char
> *errstr, char *gen_err, int comma
> + 	    if (prefix && !atoi_check(prefix, &prefixlen))
> + 	      ret_err(gen_err);
> + 	    
> ++	    if (strstr(arg, "exclude:") == arg)
> ++	      {
> ++		    is_exclude = 1;
> ++		    arg = arg+8;
> ++	      }
> ++
> + 	    if (inet_pton(AF_INET, arg, &addr.addr.addr4))
> + 	      {
> + 		subnet = opt_malloc(sizeof(struct addrlist));
> +@@ -1960,8 +1968,17 @@ static int one_opt(int option, char *arg, char
> *errstr, char *gen_err, int comma
> + 	    if (subnet)
> + 	      {
> + 		subnet->addr = addr;
> +-		subnet->next = new->subnet;
> +-		new->subnet = subnet;
> ++
> ++		if (is_exclude)
> ++		  {
> ++		    subnet->next = new->exclude;
> ++		    new->exclude = subnet;
> ++		  }
> ++		else
> ++		  {
> ++		    subnet->next = new->subnet;
> ++		    new->subnet = subnet;
> ++		  }
> + 	      }
> + 	  }
> + 	break;
> +-- 
> +1.7.10.4
> +
> diff --git a/src/patches/dnsmasq/014-
> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
> b/src/patches/dnsmasq/014-
> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
> new file mode 100644
> index 0000000..054323b
> --- /dev/null
> +++ b/src/patches/dnsmasq/014-
> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
> @@ -0,0 +1,41 @@
> +From c8328ecde896575b3cb81cf537747df531f90771 Mon Sep 17 00:00:00 2001
> +From: Simon Kelley <simon@thekelleys.org.uk>
> +Date: Fri, 5 Aug 2016 16:54:58 +0100
> +Subject: [PATCH] Bump auth zone serial when reloading /etc/hosts and friends.
> +
> +---
> + CHANGELOG     |    4 ++++
> + src/dnsmasq.c |    2 ++
> + 2 files changed, 6 insertions(+)
> +
> +diff --git a/CHANGELOG b/CHANGELOG
> +index 9f1e404..4f89799 100644
> +--- a/CHANGELOG
> ++++ b/CHANGELOG
> +@@ -20,6 +20,10 @@ version 2.77
> +  	    Fix problem with --dnssec-timestamp whereby receipt
> +             of SIGHUP would erroneously engage timestamp checking.
> + 	    Thanks to Kevin Darbyshire-Bryant for this work.
> ++
> ++	    Bump zone serial on reloading /etc/hosts and friends
> ++	    when providing authoritative DNS. Thanks to Harrald
> ++	    Dunkel for spotting this.
> + 	
> + 
> + version 2.76
> +diff --git a/src/dnsmasq.c b/src/dnsmasq.c
> +index a47273f..3580bea 100644
> +--- a/src/dnsmasq.c
> ++++ b/src/dnsmasq.c
> +@@ -1226,6 +1226,8 @@ static void async_event(int pipe, time_t now)
> +     switch (ev.event)
> +       {
> +       case EVENT_RELOAD:
> ++	daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
> ++
> + #ifdef HAVE_DNSSEC
> + 	if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) &&
> option_bool(OPT_DNSSEC_TIME))
> + 	  {
> +-- 
> +1.7.10.4
> +
  
Matthias Fischer Aug. 8, 2016, 1:49 a.m. UTC | #2
Hi,

On 07.08.2016 16:09, Michael Tremer wrote:
> Hi,
> 
> thank you. This has been merged as well.
> 
> However, since we still have some trouble with dnsmasq (it is still a little bit
> unstable and on only one installation it is always falling back to TCP for
> DNSSEC signed zones and I have no idea why), Marcel has started looking at
> unbound.

I didn't know about that oncoming trouble with 'dnsmasq' but noticed the
development about 'unbound' and had an eye on it... ;-)
Looks interesting. As always I think I'll need some time to get familiar
with it but I'll take it easy.

> It is unknown when, but if everything is working out well, we are going to
> replace dnsmasq with unbound.

> So maybe you want to join in working on that and test that a bit. I hope that we
> can aim for 105, but it could be a bit later, too. So please do not put too much
> effort into maintaining dnsmasq in IPFire any more.

No problem. After I read about 'unbound' I first thought if I should
push the last patches for 'dnsmasq' at all, but finally decided to do
so. It could still take a while until 'unbound' is finished to our
needs. So don't worry. Most of the work is done by the 'Devel'. :-)

> But you have done a great job and I hope you can also put that into unbound :)

Yep. Will do... ;-)

Best,
Matthias

> Best,
> -Michael
> 
> On Sun, 2016-08-07 at 13:09 +0200, Matthias Fischer wrote:
>> Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org>
>> ---
>>  lfs/dnsmasq                                        |   2 +
>>  ...allow_to_exclude_ip_addresses_from_answer.patch | 184
>> +++++++++++++++++++++
>>  ...rial_when_reloading_etc_hosts_and_friends.patch |  41 +++++
>>  3 files changed, 227 insertions(+)
>>  create mode 100644 src/patches/dnsmasq/013-auth-
>> zone_allow_to_exclude_ip_addresses_from_answer.patch
>>  create mode 100644 src/patches/dnsmasq/014-
>> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
>> 
>> diff --git a/lfs/dnsmasq b/lfs/dnsmasq
>> index eb0f0ba..474dacc 100644
>> --- a/lfs/dnsmasq
>> +++ b/lfs/dnsmasq
>> @@ -85,6 +85,8 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
>>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/010-
>> Zero_packet_buffers_before_building_output_to_reduce_risk_of_information_leaka
>> ge.patch
>>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/011-
>> Dont_reset_packet_length_on_transmission_in_case_of_retransmission.patch
>>  	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/012-
>> Compile-time_check_on_buffer_sizes_for_leasefile_parsing_code.patch
>> +	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/013-
>> auth-zone_allow_to_exclude_ip_addresses_from_answer.patch
>> +	cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/dnsmasq/014-
>> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.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/013-auth-
>> zone_allow_to_exclude_ip_addresses_from_answer.patch
>> b/src/patches/dnsmasq/013-auth-
>> zone_allow_to_exclude_ip_addresses_from_answer.patch
>> new file mode 100644
>> index 0000000..bb5fe5d
>> --- /dev/null
>> +++ b/src/patches/dnsmasq/013-auth-
>> zone_allow_to_exclude_ip_addresses_from_answer.patch
>> @@ -0,0 +1,184 @@
>> +From 094bfaeb4ff69cae99387bc2ea07ff57632c89f5 Mon Sep 17 00:00:00 2001
>> +From: Mathias Kresin <dev@kresin.me>
>> +Date: Sun, 24 Jul 2016 14:15:22 +0100
>> +Subject: [PATCH] auth-zone: allow to exclude ip addresses from answer.
>> +
>> +---
>> + man/dnsmasq.8 |    6 +++++-
>> + src/auth.c    |   61 ++++++++++++++++++++++++++++++++++++-------------------
>> --
>> + src/dnsmasq.h |    1 +
>> + src/option.c  |   21 ++++++++++++++++++--
>> + 4 files changed, 64 insertions(+), 25 deletions(-)
>> +
>> +diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
>> +index ac8d921..8910947 100644
>> +--- a/man/dnsmasq.8
>> ++++ b/man/dnsmasq.8
>> +@@ -739,7 +739,7 @@ a return code of SERVFAIL. Note that
>> + setting this may affect DNS behaviour in bad ways, it is not an
>> + extra-logging flag and should not be set in production.
>> + .TP
>> +-.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix
>> length>].....]]
>> ++.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix
>> length>].....][,exclude:<subnet>[/<prefix length>]].....]
>> + Define a DNS zone for which dnsmasq acts as authoritative server. Locally
>> defined DNS records which are in the domain
>> + will be served. If subnet(s) are given, A and AAAA records must be in one of
>> the
>> + specified subnets.
>> +@@ -756,6 +756,10 @@ appear in the zone, but RFC1918 IPv4 addresses which
>> should not.
>> + Interface-name and address-literal subnet specifications may be used
>> + freely in the same --auth-zone declaration.
>> + 
>> ++It's possible to exclude certain IP addresses from responses. It can be
>> ++used, to make sure that answers contain only global routeable IP
>> ++addresses (by excluding loopback, RFC1918 and ULA addresses).
>> ++
>> + The subnet(s) are also used to define in-addr.arpa and
>> + ip6.arpa domains which are served for reverse-DNS queries. If not
>> + specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
>> +diff --git a/src/auth.c b/src/auth.c
>> +index 3c5c37f..f1ca2f5 100644
>> +--- a/src/auth.c
>> ++++ b/src/auth.c
>> +@@ -18,36 +18,53 @@
>> + 
>> + #ifdef HAVE_AUTH
>> + 
>> +-static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct
>> all_addr *addr_u)
>> ++static struct addrlist *find_addrlist(struct addrlist *list, int flag,
>> struct all_addr *addr_u)
>> + {
>> +-  struct addrlist *subnet;
>> +-
>> +-  for (subnet = zone->subnet; subnet; subnet = subnet->next)
>> +-    {
>> +-      if (!(subnet->flags & ADDRLIST_IPV6))
>> +-	{
>> +-	  struct in_addr netmask, addr = addr_u->addr.addr4;
>> +-
>> +-	  if (!(flag & F_IPV4))
>> +-	    continue;
>> +-	  
>> +-	  netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
>> +-	  
>> +-	  if  (is_same_net(addr, subnet->addr.addr.addr4, netmask))
>> +-	    return subnet;
>> +-	}
>> ++  do {
>> ++    if (!(list->flags & ADDRLIST_IPV6))
>> ++      {
>> ++	struct in_addr netmask, addr = addr_u->addr.addr4;
>> ++	
>> ++	if (!(flag & F_IPV4))
>> ++	  continue;
>> ++	
>> ++	netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
>> ++	
>> ++	if  (is_same_net(addr, list->addr.addr.addr4, netmask))
>> ++	  return list;
>> ++      }
>> + #ifdef HAVE_IPV6
>> +-      else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, 
>> subnet->prefixlen))
>> +-	return subnet;
>> ++    else if (is_same_net6(&(addr_u->addr.addr6), &list->addr.addr.addr6,
>> list->prefixlen))
>> ++      return list;
>> + #endif
>> +-
>> +-    }
>> ++    
>> ++  } while ((list = list->next));
>> ++  
>> +   return NULL;
>> + }
>> + 
>> ++static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct
>> all_addr *addr_u)
>> ++{
>> ++  if (!zone->subnet)
>> ++    return NULL;
>> ++  
>> ++  return find_addrlist(zone->subnet, flag, addr_u);
>> ++}
>> ++
>> ++static struct addrlist *find_exclude(struct auth_zone *zone, int flag,
>> struct all_addr *addr_u)
>> ++{
>> ++  if (!zone->exclude)
>> ++    return NULL;
>> ++  
>> ++  return find_addrlist(zone->exclude, flag, addr_u);
>> ++}
>> ++
>> + static int filter_zone(struct auth_zone *zone, int flag, struct all_addr
>> *addr_u)
>> + {
>> +-  /* No zones specified, no filter */
>> ++  if (find_exclude(zone, flag, addr_u))
>> ++    return 0;
>> ++
>> ++  /* No subnets specified, no filter */
>> +   if (!zone->subnet)
>> +     return 1;
>> +   
>> +diff --git a/src/dnsmasq.h b/src/dnsmasq.h
>> +index 2bda5d0..27385a9 100644
>> +--- a/src/dnsmasq.h
>> ++++ b/src/dnsmasq.h
>> +@@ -340,6 +340,7 @@ struct auth_zone {
>> +     struct auth_name_list *next;
>> +   } *interface_names;
>> +   struct addrlist *subnet;
>> ++  struct addrlist *exclude;
>> +   struct auth_zone *next;
>> + };
>> + 
>> +diff --git a/src/option.c b/src/option.c
>> +index d8c57d6..6cedef3 100644
>> +--- a/src/option.c
>> ++++ b/src/option.c
>> +@@ -1906,6 +1906,7 @@ static int one_opt(int option, char *arg, char *errstr,
>> char *gen_err, int comma
>> + 	new = opt_malloc(sizeof(struct auth_zone));
>> + 	new->domain = opt_string_alloc(arg);
>> + 	new->subnet = NULL;
>> ++	new->exclude = NULL;
>> + 	new->interface_names = NULL;
>> + 	new->next = daemon->auth_zones;
>> + 	daemon->auth_zones = new;
>> +@@ -1913,6 +1914,7 @@ static int one_opt(int option, char *arg, char *errstr,
>> char *gen_err, int comma
>> + 	while ((arg = comma))
>> + 	  {
>> + 	    int prefixlen = 0;
>> ++	    int is_exclude = 0;
>> + 	    char *prefix;
>> + 	    struct addrlist *subnet =  NULL;
>> + 	    struct all_addr addr;
>> +@@ -1923,6 +1925,12 @@ static int one_opt(int option, char *arg, char
>> *errstr, char *gen_err, int comma
>> + 	    if (prefix && !atoi_check(prefix, &prefixlen))
>> + 	      ret_err(gen_err);
>> + 	    
>> ++	    if (strstr(arg, "exclude:") == arg)
>> ++	      {
>> ++		    is_exclude = 1;
>> ++		    arg = arg+8;
>> ++	      }
>> ++
>> + 	    if (inet_pton(AF_INET, arg, &addr.addr.addr4))
>> + 	      {
>> + 		subnet = opt_malloc(sizeof(struct addrlist));
>> +@@ -1960,8 +1968,17 @@ static int one_opt(int option, char *arg, char
>> *errstr, char *gen_err, int comma
>> + 	    if (subnet)
>> + 	      {
>> + 		subnet->addr = addr;
>> +-		subnet->next = new->subnet;
>> +-		new->subnet = subnet;
>> ++
>> ++		if (is_exclude)
>> ++		  {
>> ++		    subnet->next = new->exclude;
>> ++		    new->exclude = subnet;
>> ++		  }
>> ++		else
>> ++		  {
>> ++		    subnet->next = new->subnet;
>> ++		    new->subnet = subnet;
>> ++		  }
>> + 	      }
>> + 	  }
>> + 	break;
>> +-- 
>> +1.7.10.4
>> +
>> diff --git a/src/patches/dnsmasq/014-
>> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
>> b/src/patches/dnsmasq/014-
>> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
>> new file mode 100644
>> index 0000000..054323b
>> --- /dev/null
>> +++ b/src/patches/dnsmasq/014-
>> Bump_auth_zone_serial_when_reloading_etc_hosts_and_friends.patch
>> @@ -0,0 +1,41 @@
>> +From c8328ecde896575b3cb81cf537747df531f90771 Mon Sep 17 00:00:00 2001
>> +From: Simon Kelley <simon@thekelleys.org.uk>
>> +Date: Fri, 5 Aug 2016 16:54:58 +0100
>> +Subject: [PATCH] Bump auth zone serial when reloading /etc/hosts and friends.
>> +
>> +---
>> + CHANGELOG     |    4 ++++
>> + src/dnsmasq.c |    2 ++
>> + 2 files changed, 6 insertions(+)
>> +
>> +diff --git a/CHANGELOG b/CHANGELOG
>> +index 9f1e404..4f89799 100644
>> +--- a/CHANGELOG
>> ++++ b/CHANGELOG
>> +@@ -20,6 +20,10 @@ version 2.77
>> +  	    Fix problem with --dnssec-timestamp whereby receipt
>> +             of SIGHUP would erroneously engage timestamp checking.
>> + 	    Thanks to Kevin Darbyshire-Bryant for this work.
>> ++
>> ++	    Bump zone serial on reloading /etc/hosts and friends
>> ++	    when providing authoritative DNS. Thanks to Harrald
>> ++	    Dunkel for spotting this.
>> + 	
>> + 
>> + version 2.76
>> +diff --git a/src/dnsmasq.c b/src/dnsmasq.c
>> +index a47273f..3580bea 100644
>> +--- a/src/dnsmasq.c
>> ++++ b/src/dnsmasq.c
>> +@@ -1226,6 +1226,8 @@ static void async_event(int pipe, time_t now)
>> +     switch (ev.event)
>> +       {
>> +       case EVENT_RELOAD:
>> ++	daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
>> ++
>> + #ifdef HAVE_DNSSEC
>> + 	if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) &&
>> option_bool(OPT_DNSSEC_TIME))
>> + 	  {
>> +-- 
>> +1.7.10.4
>> +
>