Revert "dnsmasq: follow upstream dnsmasq pre-v2.81"
This reverts commit a6a8fe0be5.
buildbot found an error
option.c: In function 'dhcp_context_free':
option.c:1042:15: error: 'struct dhcp_context' has no member named 'template_interface'
       free(ctx->template_interface);
revert for the moment
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
			
			
This commit is contained in:
		| @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk | |||||||
|  |  | ||||||
| PKG_NAME:=dnsmasq | PKG_NAME:=dnsmasq | ||||||
| PKG_VERSION:=2.80 | PKG_VERSION:=2.80 | ||||||
| PKG_RELEASE:=3 | PKG_RELEASE:=2 | ||||||
|  |  | ||||||
| PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz | PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz | ||||||
| PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq | PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq | ||||||
|   | |||||||
| @@ -1,495 +0,0 @@ | |||||||
| From a799ca0c6314ad73a97bc6c89382d2712a9c0b0e Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Thu, 18 Oct 2018 19:35:29 +0100 |  | ||||||
| Subject: [PATCH 01/11] Impove cache behaviour for TCP connections. |  | ||||||
|  |  | ||||||
| For ease of implementaion, dnsmasq has always forked a new process to |  | ||||||
| handle each incoming TCP connection. A side-effect of this is that any |  | ||||||
| DNS queries answered from TCP connections are not cached: when TCP |  | ||||||
| connections were rare, this was not a problem.  With the coming of |  | ||||||
| DNSSEC, it's now the case that some DNSSEC queries have answers which |  | ||||||
| spill to TCP, and if, for instance, this applies to the keys for the |  | ||||||
| root then those never get cached, and performance is very bad.  This |  | ||||||
| fix passes cache entries back from the TCP child process to the main |  | ||||||
| server process, and fixes the problem. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  CHANGELOG       |  14 ++++ |  | ||||||
|  src/blockdata.c |  37 ++++++++- |  | ||||||
|  src/cache.c     | 196 ++++++++++++++++++++++++++++++++++++++++++++++-- |  | ||||||
|  src/dnsmasq.c   |  58 ++++++++++++-- |  | ||||||
|  src/dnsmasq.h   |   5 ++ |  | ||||||
|  5 files changed, 291 insertions(+), 19 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/CHANGELOG |  | ||||||
| +++ b/CHANGELOG |  | ||||||
| @@ -1,3 +1,17 @@ |  | ||||||
| +version 2.81 |  | ||||||
| +	Impove cache behaviour for TCP connections. For ease of |  | ||||||
| +	implementaion, dnsmasq has always forked a new process to handle |  | ||||||
| +	each incoming TCP connection. A side-effect of this is that |  | ||||||
| +	any DNS queries answered from TCP connections are not cached: |  | ||||||
| +	when TCP connections were rare, this was not a problem. |  | ||||||
| +	With the coming of DNSSEC, it's now the case that some |  | ||||||
| +	DNSSEC queries have answers which spill to TCP, and if, |  | ||||||
| +	for instance, this applies to the keys for the root then |  | ||||||
| +	those never get cached, and performance is very bad. |  | ||||||
| +	This fix passes cache entries back from the TCP child process to |  | ||||||
| +	the main server process, and fixes the problem. |  | ||||||
| + |  | ||||||
| + |  | ||||||
|  version 2.80 |  | ||||||
|  	Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method |  | ||||||
|  	for the initial patch and motivation. |  | ||||||
| --- a/src/blockdata.c |  | ||||||
| +++ b/src/blockdata.c |  | ||||||
| @@ -61,7 +61,7 @@ void blockdata_report(void) |  | ||||||
|  	      blockdata_alloced * sizeof(struct blockdata)); |  | ||||||
|  }  |  | ||||||
|   |  | ||||||
| -struct blockdata *blockdata_alloc(char *data, size_t len) |  | ||||||
| +static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len) |  | ||||||
|  { |  | ||||||
|    struct blockdata *block, *ret = NULL; |  | ||||||
|    struct blockdata **prev = &ret; |  | ||||||
| @@ -89,8 +89,17 @@ struct blockdata *blockdata_alloc(char * |  | ||||||
|  	blockdata_hwm = blockdata_count;  |  | ||||||
|         |  | ||||||
|        blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len; |  | ||||||
| -      memcpy(block->key, data, blen); |  | ||||||
| -      data += blen; |  | ||||||
| +      if (data) |  | ||||||
| +	{ |  | ||||||
| +	  memcpy(block->key, data, blen); |  | ||||||
| +	  data += blen; |  | ||||||
| +	} |  | ||||||
| +      else if (!read_write(fd, block->key, blen, 1)) |  | ||||||
| +	{ |  | ||||||
| +	  /* failed read free partial chain */ |  | ||||||
| +	  blockdata_free(ret); |  | ||||||
| +	  return NULL; |  | ||||||
| +	} |  | ||||||
|        len -= blen; |  | ||||||
|        *prev = block; |  | ||||||
|        prev = &block->next; |  | ||||||
| @@ -100,6 +109,10 @@ struct blockdata *blockdata_alloc(char * |  | ||||||
|    return ret; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| +struct blockdata *blockdata_alloc(char *data, size_t len) |  | ||||||
| +{ |  | ||||||
| +  return blockdata_alloc_real(0, data, len); |  | ||||||
| +} |  | ||||||
|   |  | ||||||
|  void blockdata_free(struct blockdata *blocks) |  | ||||||
|  { |  | ||||||
| @@ -148,5 +161,21 @@ void *blockdata_retrieve(struct blockdat |  | ||||||
|   |  | ||||||
|    return data; |  | ||||||
|  } |  | ||||||
| -  |  | ||||||
| + |  | ||||||
| + |  | ||||||
| +void blockdata_write(struct blockdata *block, size_t len, int fd) |  | ||||||
| +{ |  | ||||||
| +  for (; len > 0 && block; block = block->next) |  | ||||||
| +    { |  | ||||||
| +      size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len; |  | ||||||
| +      read_write(fd, block->key, blen, 0); |  | ||||||
| +      len -= blen; |  | ||||||
| +    } |  | ||||||
| +} |  | ||||||
| + |  | ||||||
| +struct blockdata *blockdata_read(int fd, size_t len) |  | ||||||
| +{ |  | ||||||
| +  return blockdata_alloc_real(fd, NULL, len); |  | ||||||
| +} |  | ||||||
| + |  | ||||||
|  #endif |  | ||||||
| --- a/src/cache.c |  | ||||||
| +++ b/src/cache.c |  | ||||||
| @@ -26,6 +26,8 @@ static union bigname *big_free = NULL; |  | ||||||
|  static int bignames_left, hash_size; |  | ||||||
|   |  | ||||||
|  static void make_non_terminals(struct crec *source); |  | ||||||
| +static struct crec *really_insert(char *name, struct all_addr *addr,  |  | ||||||
| +				  time_t now,  unsigned long ttl, unsigned short flags); |  | ||||||
|   |  | ||||||
|  /* type->string mapping: this is also used by the name-hash function as a mixing table. */ |  | ||||||
|  static const struct { |  | ||||||
| @@ -464,16 +466,10 @@ void cache_start_insert(void) |  | ||||||
|    new_chain = NULL; |  | ||||||
|    insert_error = 0; |  | ||||||
|  } |  | ||||||
| -  |  | ||||||
| + |  | ||||||
|  struct crec *cache_insert(char *name, struct all_addr *addr,  |  | ||||||
|  			  time_t now,  unsigned long ttl, unsigned short flags) |  | ||||||
|  { |  | ||||||
| -  struct crec *new, *target_crec = NULL; |  | ||||||
| -  union bigname *big_name = NULL; |  | ||||||
| -  int freed_all = flags & F_REVERSE; |  | ||||||
| -  int free_avail = 0; |  | ||||||
| -  unsigned int target_uid; |  | ||||||
| -   |  | ||||||
|    /* Don't log DNSSEC records here, done elsewhere */ |  | ||||||
|    if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) |  | ||||||
|      { |  | ||||||
| @@ -484,7 +480,20 @@ struct crec *cache_insert(char *name, st |  | ||||||
|        if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl) |  | ||||||
|  	ttl = daemon->min_cache_ttl; |  | ||||||
|      } |  | ||||||
| +   |  | ||||||
| +  return really_insert(name, addr, now, ttl, flags); |  | ||||||
| +} |  | ||||||
|   |  | ||||||
| + |  | ||||||
| +static struct crec *really_insert(char *name, struct all_addr *addr,  |  | ||||||
| +				  time_t now,  unsigned long ttl, unsigned short flags) |  | ||||||
| +{ |  | ||||||
| +  struct crec *new, *target_crec = NULL; |  | ||||||
| +  union bigname *big_name = NULL; |  | ||||||
| +  int freed_all = flags & F_REVERSE; |  | ||||||
| +  int free_avail = 0; |  | ||||||
| +  unsigned int target_uid; |  | ||||||
| +   |  | ||||||
|    /* if previous insertion failed give up now. */ |  | ||||||
|    if (insert_error) |  | ||||||
|      return NULL; |  | ||||||
| @@ -645,12 +654,185 @@ void cache_end_insert(void) |  | ||||||
|  	  cache_hash(new_chain); |  | ||||||
|  	  cache_link(new_chain); |  | ||||||
|  	  daemon->metrics[METRIC_DNS_CACHE_INSERTED]++; |  | ||||||
| + |  | ||||||
| +	  /* If we're a child process, send this cache entry up the pipe to the master. |  | ||||||
| +	     The marshalling process is rather nasty. */ |  | ||||||
| +	  if (daemon->pipe_to_parent != -1) |  | ||||||
| +	    { |  | ||||||
| +	      char *name = cache_get_name(new_chain); |  | ||||||
| +	      ssize_t m = strlen(name); |  | ||||||
| +	      unsigned short flags = new_chain->flags; |  | ||||||
| +#ifdef HAVE_DNSSEC |  | ||||||
| +	      u16 class = new_chain->uid; |  | ||||||
| +#endif |  | ||||||
| +	       |  | ||||||
| +	      read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0); |  | ||||||
| +	      read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0); |  | ||||||
| +	      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0); |  | ||||||
| +	      read_write(daemon->pipe_to_parent, (unsigned  char *)&flags, sizeof(flags), 0); |  | ||||||
| + |  | ||||||
| +	      if (flags & (F_IPV4 | F_IPV6)) |  | ||||||
| +		read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0); |  | ||||||
| +#ifdef HAVE_DNSSEC |  | ||||||
| +	      else if (flags & F_DNSKEY) |  | ||||||
| +		{ |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0); |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.algo, sizeof(new_chain->addr.key.algo), 0); |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keytag, sizeof(new_chain->addr.key.keytag), 0); |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.flags, sizeof(new_chain->addr.key.flags), 0); |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.key.keylen, sizeof(new_chain->addr.key.keylen), 0); |  | ||||||
| +		  blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent); |  | ||||||
| +		} |  | ||||||
| +	      else if (flags & F_DS) |  | ||||||
| +		{ |  | ||||||
| +		  read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0); |  | ||||||
| +		  /* A negative DS entry is possible and has no data, obviously. */ |  | ||||||
| +		  if (!(flags & F_NEG)) |  | ||||||
| +		    { |  | ||||||
| +		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.algo, sizeof(new_chain->addr.ds.algo), 0); |  | ||||||
| +		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keytag, sizeof(new_chain->addr.ds.keytag), 0); |  | ||||||
| +		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.digest, sizeof(new_chain->addr.ds.digest), 0); |  | ||||||
| +		      read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr.ds.keylen, sizeof(new_chain->addr.ds.keylen), 0); |  | ||||||
| +		      blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent); |  | ||||||
| +		    } |  | ||||||
| +		} |  | ||||||
| +#endif |  | ||||||
| +	       |  | ||||||
| +	    } |  | ||||||
|  	} |  | ||||||
| +       |  | ||||||
|        new_chain = tmp; |  | ||||||
|      } |  | ||||||
| + |  | ||||||
| +  /* signal end of cache insert in master process */ |  | ||||||
| +  if (daemon->pipe_to_parent != -1) |  | ||||||
| +    { |  | ||||||
| +      ssize_t m = -1; |  | ||||||
| +      read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0); |  | ||||||
| +    } |  | ||||||
| +       |  | ||||||
|    new_chain = NULL; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| + |  | ||||||
| +/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */ |  | ||||||
| +int cache_recv_insert(time_t now, int fd) |  | ||||||
| +{ |  | ||||||
| +  ssize_t m; |  | ||||||
| +  struct all_addr addr; |  | ||||||
| +  unsigned long ttl; |  | ||||||
| +  time_t ttd; |  | ||||||
| +  unsigned short flags; |  | ||||||
| +  struct crec *crecp = NULL; |  | ||||||
| +   |  | ||||||
| +  cache_start_insert(); |  | ||||||
| +   |  | ||||||
| +  while(1) |  | ||||||
| +    { |  | ||||||
| +  |  | ||||||
| +      if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1)) |  | ||||||
| +	return 0; |  | ||||||
| +       |  | ||||||
| +      if (m == -1) |  | ||||||
| +	{ |  | ||||||
| +	  cache_end_insert(); |  | ||||||
| +	  return 1; |  | ||||||
| +	} |  | ||||||
| + |  | ||||||
| +      if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) || |  | ||||||
| +	  !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) || |  | ||||||
| +	  !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1)) |  | ||||||
| +	return 0; |  | ||||||
| + |  | ||||||
| +      daemon->namebuff[m] = 0; |  | ||||||
| + |  | ||||||
| +      ttl = difftime(ttd, now); |  | ||||||
| +       |  | ||||||
| +      if (flags & (F_IPV4 | F_IPV6)) |  | ||||||
| +	{ |  | ||||||
| +	  if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1)) |  | ||||||
| +	    return 0; |  | ||||||
| +	  crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags); |  | ||||||
| +	} |  | ||||||
| +      else if (flags & F_CNAME) |  | ||||||
| +	{ |  | ||||||
| +	  struct crec *newc = really_insert(daemon->namebuff, NULL, now, ttl, flags); |  | ||||||
| +	  /* This relies on the fact the the target of a CNAME immediately preceeds |  | ||||||
| +	     it because of the order of extraction in extract_addresses, and |  | ||||||
| +	     the order reversal on the new_chain. */ |  | ||||||
| +	  if (newc) |  | ||||||
| +	    { |  | ||||||
| +	      if (!crecp) |  | ||||||
| +		{ |  | ||||||
| +		  newc->addr.cname.target.cache = NULL; |  | ||||||
| +		  /* anything other than zero, to avoid being mistaken for CNAME to interface-name */  |  | ||||||
| +		  newc->addr.cname.uid = 1;  |  | ||||||
| +		} |  | ||||||
| +	      else |  | ||||||
| +		{ |  | ||||||
| +		  next_uid(crecp); |  | ||||||
| +		  newc->addr.cname.target.cache = crecp; |  | ||||||
| +		  newc->addr.cname.uid = crecp->uid; |  | ||||||
| +		} |  | ||||||
| +	    } |  | ||||||
| +	} |  | ||||||
| +#ifdef HAVE_DNSSEC |  | ||||||
| +      else if (flags & (F_DNSKEY | F_DS)) |  | ||||||
| +	{ |  | ||||||
| +	  unsigned short class, keylen, keyflags, keytag; |  | ||||||
| +	  unsigned char algo, digest; |  | ||||||
| +	  struct blockdata *keydata; |  | ||||||
| +	   |  | ||||||
| +	  if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1)) |  | ||||||
| +	    return 0; |  | ||||||
| +	  /* Cache needs to known class for DNSSEC stuff */ |  | ||||||
| +	  addr.addr.dnssec.class = class; |  | ||||||
| + |  | ||||||
| +	  crecp = really_insert(daemon->namebuff, &addr, now, ttl, flags); |  | ||||||
| +	     |  | ||||||
| +	  if (flags & F_DNSKEY) |  | ||||||
| +	    { |  | ||||||
| +	      if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&keyflags, sizeof(keyflags), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) || |  | ||||||
| +		  !(keydata = blockdata_read(fd, keylen))) |  | ||||||
| +		return 0; |  | ||||||
| +	    } |  | ||||||
| +	  else if (!(flags & F_NEG)) |  | ||||||
| +	    { |  | ||||||
| +	      if (!read_write(fd, (unsigned char *)&algo, sizeof(algo), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&keytag, sizeof(keytag), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&digest, sizeof(digest), 1) || |  | ||||||
| +		  !read_write(fd, (unsigned char *)&keylen, sizeof(keylen), 1) || |  | ||||||
| +		  !(keydata = blockdata_read(fd, keylen))) |  | ||||||
| +		return 0; |  | ||||||
| +	    } |  | ||||||
| + |  | ||||||
| +	  if (crecp) |  | ||||||
| +	    { |  | ||||||
| +	       if (flags & F_DNSKEY) |  | ||||||
| +		 { |  | ||||||
| +		   crecp->addr.key.algo = algo; |  | ||||||
| +		   crecp->addr.key.keytag = keytag; |  | ||||||
| +		   crecp->addr.key.flags = flags; |  | ||||||
| +		   crecp->addr.key.keylen = keylen; |  | ||||||
| +		   crecp->addr.key.keydata = keydata; |  | ||||||
| +		 } |  | ||||||
| +	       else if (!(flags & F_NEG)) |  | ||||||
| +		 { |  | ||||||
| +		   crecp->addr.ds.algo = algo; |  | ||||||
| +		   crecp->addr.ds.keytag = keytag; |  | ||||||
| +		   crecp->addr.ds.digest = digest; |  | ||||||
| +		   crecp->addr.ds.keylen = keylen; |  | ||||||
| +		   crecp->addr.ds.keydata = keydata; |  | ||||||
| +		 } |  | ||||||
| +	    } |  | ||||||
| +	} |  | ||||||
| +#endif |  | ||||||
| +    } |  | ||||||
| +} |  | ||||||
| +	 |  | ||||||
|  int cache_find_non_terminal(char *name, time_t now) |  | ||||||
|  { |  | ||||||
|    struct crec *crecp; |  | ||||||
| --- a/src/dnsmasq.c |  | ||||||
| +++ b/src/dnsmasq.c |  | ||||||
| @@ -930,6 +930,10 @@ int main (int argc, char **argv) |  | ||||||
|      check_servers(); |  | ||||||
|     |  | ||||||
|    pid = getpid(); |  | ||||||
| + |  | ||||||
| +  daemon->pipe_to_parent = -1; |  | ||||||
| +  for (i = 0; i < MAX_PROCS; i++) |  | ||||||
| +    daemon->tcp_pipes[i] = -1; |  | ||||||
|     |  | ||||||
|  #ifdef HAVE_INOTIFY |  | ||||||
|    /* Using inotify, have to select a resolv file at startup */ |  | ||||||
| @@ -1611,7 +1615,7 @@ static int set_dns_listeners(time_t now) |  | ||||||
|  	 we don't need to explicitly arrange to wake up here */ |  | ||||||
|        if  (listener->tcpfd != -1) |  | ||||||
|  	for (i = 0; i < MAX_PROCS; i++) |  | ||||||
| -	  if (daemon->tcp_pids[i] == 0) |  | ||||||
| +	  if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) |  | ||||||
|  	    { |  | ||||||
|  	      poll_listen(listener->tcpfd, POLLIN); |  | ||||||
|  	      break; |  | ||||||
| @@ -1624,6 +1628,13 @@ static int set_dns_listeners(time_t now) |  | ||||||
|   |  | ||||||
|      } |  | ||||||
|     |  | ||||||
| +#ifndef NO_FORK |  | ||||||
| +  if (!option_bool(OPT_DEBUG)) |  | ||||||
| +    for (i = 0; i < MAX_PROCS; i++) |  | ||||||
| +      if (daemon->tcp_pipes[i] != -1) |  | ||||||
| +	poll_listen(daemon->tcp_pipes[i], POLLIN); |  | ||||||
| +#endif |  | ||||||
| +   |  | ||||||
|    return wait; |  | ||||||
|  } |  | ||||||
|   |  | ||||||
| @@ -1632,7 +1643,10 @@ static void check_dns_listeners(time_t n |  | ||||||
|    struct serverfd *serverfdp; |  | ||||||
|    struct listener *listener; |  | ||||||
|    int i; |  | ||||||
| - |  | ||||||
| +#ifndef NO_FORK |  | ||||||
| +  int pipefd[2]; |  | ||||||
| +#endif |  | ||||||
| +   |  | ||||||
|    for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) |  | ||||||
|      if (poll_check(serverfdp->fd, POLLIN)) |  | ||||||
|        reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now); |  | ||||||
| @@ -1642,7 +1656,26 @@ static void check_dns_listeners(time_t n |  | ||||||
|        if (daemon->randomsocks[i].refcount != 0 &&  |  | ||||||
|  	  poll_check(daemon->randomsocks[i].fd, POLLIN)) |  | ||||||
|  	reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now); |  | ||||||
| -   |  | ||||||
| + |  | ||||||
| +#ifndef NO_FORK |  | ||||||
| +  /* Races. The child process can die before we read all of the data from the |  | ||||||
| +     pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the  |  | ||||||
| +     process, and tcp_pipes to -1 and close the FD when we read the last |  | ||||||
| +     of the data - indicated by cache_recv_insert returning zero. |  | ||||||
| +     The order of these events is indeterminate, and both are needed |  | ||||||
| +     to free the process slot. Once the child process has gone, poll() |  | ||||||
| +     returns POLLHUP, not POLLIN, so have to check for both here. */ |  | ||||||
| +  if (!option_bool(OPT_DEBUG)) |  | ||||||
| +    for (i = 0; i < MAX_PROCS; i++) |  | ||||||
| +      if (daemon->tcp_pipes[i] != -1 && |  | ||||||
| +	  poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) && |  | ||||||
| +	  !cache_recv_insert(now, daemon->tcp_pipes[i])) |  | ||||||
| +	{ |  | ||||||
| +	  close(daemon->tcp_pipes[i]); |  | ||||||
| +	  daemon->tcp_pipes[i] = -1;	 |  | ||||||
| +	} |  | ||||||
| +#endif |  | ||||||
| +	 |  | ||||||
|    for (listener = daemon->listeners; listener; listener = listener->next) |  | ||||||
|      { |  | ||||||
|        if (listener->fd != -1 && poll_check(listener->fd, POLLIN)) |  | ||||||
| @@ -1736,15 +1769,20 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	      while (retry_send(close(confd))); |  | ||||||
|  	    } |  | ||||||
|  #ifndef NO_FORK |  | ||||||
| -	  else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0) |  | ||||||
| +	  else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0) |  | ||||||
|  	    { |  | ||||||
| -	      if (p != -1) |  | ||||||
| +	      close(pipefd[1]); /* parent needs read pipe end. */ |  | ||||||
| +	      if (p == -1) |  | ||||||
| +		close(pipefd[0]); |  | ||||||
| +	      else |  | ||||||
|  		{ |  | ||||||
|  		  int i; |  | ||||||
| + |  | ||||||
|  		  for (i = 0; i < MAX_PROCS; i++) |  | ||||||
| -		    if (daemon->tcp_pids[i] == 0) |  | ||||||
| +		    if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) |  | ||||||
|  		      { |  | ||||||
|  			daemon->tcp_pids[i] = p; |  | ||||||
| +			daemon->tcp_pipes[i] = pipefd[0]; |  | ||||||
|  			break; |  | ||||||
|  		      } |  | ||||||
|  		} |  | ||||||
| @@ -1761,7 +1799,7 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	      int flags; |  | ||||||
|  	      struct in_addr netmask; |  | ||||||
|  	      int auth_dns; |  | ||||||
| - |  | ||||||
| +	    |  | ||||||
|  	      if (iface) |  | ||||||
|  		{ |  | ||||||
|  		  netmask = iface->netmask; |  | ||||||
| @@ -1777,7 +1815,11 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	      /* Arrange for SIGALRM after CHILD_LIFETIME seconds to |  | ||||||
|  		 terminate the process. */ |  | ||||||
|  	      if (!option_bool(OPT_DEBUG)) |  | ||||||
| -		alarm(CHILD_LIFETIME); |  | ||||||
| +		{ |  | ||||||
| +		  alarm(CHILD_LIFETIME); |  | ||||||
| +		  close(pipefd[0]); /* close read end in child. */ |  | ||||||
| +		  daemon->pipe_to_parent = pipefd[1]; |  | ||||||
| +		} |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
|  	      /* start with no upstream connections. */ |  | ||||||
| --- a/src/dnsmasq.h |  | ||||||
| +++ b/src/dnsmasq.h |  | ||||||
| @@ -1091,6 +1091,8 @@ extern struct daemon { |  | ||||||
|    size_t packet_len;       /*      "        "        */ |  | ||||||
|    struct randfd *rfd_save; /*      "        "        */ |  | ||||||
|    pid_t tcp_pids[MAX_PROCS]; |  | ||||||
| +  int tcp_pipes[MAX_PROCS]; |  | ||||||
| +  int pipe_to_parent; |  | ||||||
|    struct randfd randomsocks[RANDOM_SOCKS]; |  | ||||||
|    int v6pktinfo;  |  | ||||||
|    struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */ |  | ||||||
| @@ -1152,6 +1154,7 @@ struct crec *cache_find_by_name(struct c |  | ||||||
|  				char *name, time_t now, unsigned int prot); |  | ||||||
|  void cache_end_insert(void); |  | ||||||
|  void cache_start_insert(void); |  | ||||||
| +int cache_recv_insert(time_t now, int fd); |  | ||||||
|  struct crec *cache_insert(char *name, struct all_addr *addr, |  | ||||||
|  			  time_t now, unsigned long ttl, unsigned short flags); |  | ||||||
|  void cache_reload(void); |  | ||||||
| @@ -1174,6 +1177,8 @@ void blockdata_init(void); |  | ||||||
|  void blockdata_report(void); |  | ||||||
|  struct blockdata *blockdata_alloc(char *data, size_t len); |  | ||||||
|  void *blockdata_retrieve(struct blockdata *block, size_t len, void *data); |  | ||||||
| +struct blockdata *blockdata_read(int fd, size_t len); |  | ||||||
| +void blockdata_write(struct blockdata *block, size_t len, int fd); |  | ||||||
|  void blockdata_free(struct blockdata *blocks); |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| From a220545c4277cba534be5ef4638b5076fc7d2cf4 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Mon, 22 Oct 2018 18:21:48 +0100 |  | ||||||
| Subject: [PATCH 02/11] Ensure that AD bit is reset on answers from |  | ||||||
|  --address=/<domain>/<address>. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/rfc1035.c | 6 +++--- |  | ||||||
|  1 file changed, 3 insertions(+), 3 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/src/rfc1035.c |  | ||||||
| +++ b/src/rfc1035.c |  | ||||||
| @@ -938,9 +938,9 @@ size_t setup_reply(struct dns_header *he |  | ||||||
|      return 0; |  | ||||||
|     |  | ||||||
|    /* clear authoritative and truncated flags, set QR flag */ |  | ||||||
| -  header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR; |  | ||||||
| -  /* set RA flag */ |  | ||||||
| -  header->hb4 |= HB4_RA; |  | ||||||
| +  header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR; |  | ||||||
| +  /* clear AD flag, set RA flag */ |  | ||||||
| +  header->hb4 = (header->hb4 & ~HB4_AD) | HB4_RA; |  | ||||||
|   |  | ||||||
|    header->nscount = htons(0); |  | ||||||
|    header->arcount = htons(0); |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,52 +0,0 @@ | |||||||
| From cf5984367bc6a949e3803a576512c5a7bc48ebab Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Vladislav Grishenko <themiron@mail.ru> |  | ||||||
| Date: Thu, 18 Oct 2018 04:55:21 +0500 |  | ||||||
| Subject: [PATCH 04/11] Don't forward *.bind/*.server queries upstream |  | ||||||
|  |  | ||||||
| Chaos .bind and .server (RFC4892) zones are local, therefore |  | ||||||
| don't forward queries upstream to avoid mixing with supported |  | ||||||
| locally and false replies with NO_ID enabled. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/rfc1035.c | 15 ++++++++++++++- |  | ||||||
|  1 file changed, 14 insertions(+), 1 deletion(-) |  | ||||||
|  |  | ||||||
| --- a/src/rfc1035.c |  | ||||||
| +++ b/src/rfc1035.c |  | ||||||
| @@ -1276,7 +1276,7 @@ size_t answer_request(struct dns_header |  | ||||||
|    int q, ans, anscount = 0, addncount = 0; |  | ||||||
|    int dryrun = 0; |  | ||||||
|    struct crec *crecp; |  | ||||||
| -  int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; |  | ||||||
| +  int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1; |  | ||||||
|    struct mx_srv_record *rec; |  | ||||||
|    size_t len; |  | ||||||
|   |  | ||||||
| @@ -1355,6 +1355,17 @@ size_t answer_request(struct dns_header |  | ||||||
|  	    } |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| +      if (qclass == C_CHAOS) |  | ||||||
| +	{ |  | ||||||
| +	  /* don't forward *.bind and *.server chaos queries */ |  | ||||||
| +	  if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name)) |  | ||||||
| +	    { |  | ||||||
| +	      if (!ans) |  | ||||||
| +		notimp = 1, auth = 0; |  | ||||||
| +	      ans = 1; |  | ||||||
| +	    } |  | ||||||
| +	} |  | ||||||
| + |  | ||||||
|        if (qclass == C_IN) |  | ||||||
|  	{ |  | ||||||
|  	  struct txt_record *t; |  | ||||||
| @@ -1903,6 +1914,8 @@ size_t answer_request(struct dns_header |  | ||||||
|     |  | ||||||
|    if (nxdomain) |  | ||||||
|      SET_RCODE(header, NXDOMAIN); |  | ||||||
| +  else if (notimp) |  | ||||||
| +    SET_RCODE(header, NOTIMP); |  | ||||||
|    else |  | ||||||
|      SET_RCODE(header, NOERROR); /* no error */ |  | ||||||
|    header->ancount = htons(anscount); |  | ||||||
| @@ -1,63 +0,0 @@ | |||||||
| From cbb5b17ad8e03e08ade62376a4f6a2066e55960d Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Tue, 23 Oct 2018 23:45:57 +0100 |  | ||||||
| Subject: [PATCH 05/11] Fix logging in cf5984367bc6a949e3803a576512c5a7bc48ebab |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/rfc1035.c | 27 ++++++++++++++++++--------- |  | ||||||
|  1 file changed, 18 insertions(+), 9 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/src/rfc1035.c |  | ||||||
| +++ b/src/rfc1035.c |  | ||||||
| @@ -1335,7 +1335,6 @@ size_t answer_request(struct dns_header |  | ||||||
|  		    { |  | ||||||
|  		      unsigned long ttl = daemon->local_ttl; |  | ||||||
|  		      int ok = 1; |  | ||||||
| -		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); |  | ||||||
|  #ifndef NO_ID |  | ||||||
|  		      /* Dynamically generate stat record */ |  | ||||||
|  		      if (t->stat != 0) |  | ||||||
| @@ -1345,11 +1344,14 @@ size_t answer_request(struct dns_header |  | ||||||
|  			    ok = 0; |  | ||||||
|  			} |  | ||||||
|  #endif |  | ||||||
| -		      if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,  |  | ||||||
| -						    ttl, NULL, |  | ||||||
| -						    T_TXT, t->class, "t", t->len, t->txt)) |  | ||||||
| -			anscount++; |  | ||||||
| - |  | ||||||
| +		      if (ok) |  | ||||||
| +			{ |  | ||||||
| +			  log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); |  | ||||||
| +			  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,  |  | ||||||
| +						  ttl, NULL, |  | ||||||
| +						  T_TXT, t->class, "t", t->len, t->txt)) |  | ||||||
| +			    anscount++; |  | ||||||
| +			} |  | ||||||
|  		    } |  | ||||||
|  		} |  | ||||||
|  	    } |  | ||||||
| @@ -1357,12 +1359,19 @@ size_t answer_request(struct dns_header |  | ||||||
|   |  | ||||||
|        if (qclass == C_CHAOS) |  | ||||||
|  	{ |  | ||||||
| -	  /* don't forward *.bind and *.server chaos queries */ |  | ||||||
| +	  /* don't forward *.bind and *.server chaos queries - always reply with NOTIMP */ |  | ||||||
|  	  if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name)) |  | ||||||
|  	    { |  | ||||||
|  	      if (!ans) |  | ||||||
| -		notimp = 1, auth = 0; |  | ||||||
| -	      ans = 1; |  | ||||||
| +		{ |  | ||||||
| +		  notimp = 1, auth = 0; |  | ||||||
| +		  if (!dryrun) |  | ||||||
| +		    { |  | ||||||
| +		       addr.addr.rcode.rcode = NOTIMP; |  | ||||||
| +		       log_query(F_CONFIG | F_RCODE, name, &addr, NULL); |  | ||||||
| +		    } |  | ||||||
| +		  ans = 1; |  | ||||||
| +		} |  | ||||||
|  	    } |  | ||||||
|  	} |  | ||||||
|   |  | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| From 6f7812d97bc8f87004c0a5069c6c94c64af78106 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Tue, 23 Oct 2018 23:54:44 +0100 |  | ||||||
| Subject: [PATCH 06/11] Fix spurious AD flags in some DNS replies from local |  | ||||||
|  config. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/rfc1035.c | 42 ++++++++++++++++++++++++------------------ |  | ||||||
|  1 file changed, 24 insertions(+), 18 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/src/rfc1035.c |  | ||||||
| +++ b/src/rfc1035.c |  | ||||||
| @@ -1330,7 +1330,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  	    { |  | ||||||
|  	      if (t->class == qclass && hostname_isequal(name, t->name)) |  | ||||||
|  		{ |  | ||||||
| -		  ans = 1; |  | ||||||
| +		  ans = 1, sec_data = 0; |  | ||||||
|  		  if (!dryrun) |  | ||||||
|  		    { |  | ||||||
|  		      unsigned long ttl = daemon->local_ttl; |  | ||||||
| @@ -1370,7 +1370,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  		       addr.addr.rcode.rcode = NOTIMP; |  | ||||||
|  		       log_query(F_CONFIG | F_RCODE, name, &addr, NULL); |  | ||||||
|  		    } |  | ||||||
| -		  ans = 1; |  | ||||||
| +		  ans = 1, sec_data = 0; |  | ||||||
|  		} |  | ||||||
|  	    } |  | ||||||
|  	} |  | ||||||
| @@ -1725,7 +1725,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  		} |  | ||||||
|  	      else if (is_name_synthetic(flag, name, &addr)) |  | ||||||
|  		{ |  | ||||||
| -		  ans = 1; |  | ||||||
| +		  ans = 1, sec_data = 0; |  | ||||||
|  		  if (!dryrun) |  | ||||||
|  		    { |  | ||||||
|  		      log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL); |  | ||||||
| @@ -1763,25 +1763,27 @@ size_t answer_request(struct dns_header |  | ||||||
|  	      for (rec = daemon->mxnames; rec; rec = rec->next) |  | ||||||
|  		if (!rec->issrv && hostname_isequal(name, rec->name)) |  | ||||||
|  		  { |  | ||||||
| -		  ans = found = 1; |  | ||||||
| -		  if (!dryrun) |  | ||||||
| -		    { |  | ||||||
| -		      int offset; |  | ||||||
| -		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); |  | ||||||
| -		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, |  | ||||||
| -					      &offset, T_MX, C_IN, "sd", rec->weight, rec->target)) |  | ||||||
| -			{ |  | ||||||
| -			  anscount++; |  | ||||||
| -			  if (rec->target) |  | ||||||
| -			    rec->offset = offset; |  | ||||||
| -			} |  | ||||||
| -		    } |  | ||||||
| +		    ans = found = 1; |  | ||||||
| +		    sec_data = 0; |  | ||||||
| +		    if (!dryrun) |  | ||||||
| +		      { |  | ||||||
| +			int offset; |  | ||||||
| +			log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); |  | ||||||
| +			if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, |  | ||||||
| +						&offset, T_MX, C_IN, "sd", rec->weight, rec->target)) |  | ||||||
| +			  { |  | ||||||
| +			    anscount++; |  | ||||||
| +			    if (rec->target) |  | ||||||
| +			      rec->offset = offset; |  | ||||||
| +			  } |  | ||||||
| +		      } |  | ||||||
|  		  } |  | ||||||
|  	       |  | ||||||
|  	      if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&  |  | ||||||
|  		  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR)) |  | ||||||
|  		{  |  | ||||||
|  		  ans = 1; |  | ||||||
| +		  sec_data = 0; |  | ||||||
|  		  if (!dryrun) |  | ||||||
|  		    { |  | ||||||
|  		      log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); |  | ||||||
| @@ -1802,6 +1804,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  		if (rec->issrv && hostname_isequal(name, rec->name)) |  | ||||||
|  		  { |  | ||||||
|  		    found = ans = 1; |  | ||||||
| +		    sec_data = 0; |  | ||||||
|  		    if (!dryrun) |  | ||||||
|  		      { |  | ||||||
|  			int offset; |  | ||||||
| @@ -1838,6 +1841,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  	      if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_')))) |  | ||||||
|  		{ |  | ||||||
|  		  ans = 1; |  | ||||||
| +		  sec_data = 0; |  | ||||||
|  		  if (!dryrun) |  | ||||||
|  		    log_query(F_CONFIG | F_NEG, name, NULL, NULL); |  | ||||||
|  		} |  | ||||||
| @@ -1850,6 +1854,7 @@ size_t answer_request(struct dns_header |  | ||||||
|  		if (hostname_isequal(name, na->name)) |  | ||||||
|  		  { |  | ||||||
|  		    ans = 1; |  | ||||||
| +		    sec_data = 0; |  | ||||||
|  		    if (!dryrun) |  | ||||||
|  		      { |  | ||||||
|  			log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>"); |  | ||||||
| @@ -1862,11 +1867,12 @@ size_t answer_request(struct dns_header |  | ||||||
|  	    } |  | ||||||
|  	   |  | ||||||
|  	  if (qtype == T_MAILB) |  | ||||||
| -	    ans = 1, nxdomain = 1; |  | ||||||
| +	    ans = 1, nxdomain = 1, sec_data = 0; |  | ||||||
|   |  | ||||||
|  	  if (qtype == T_SOA && option_bool(OPT_FILTER)) |  | ||||||
|  	    { |  | ||||||
| -	      ans = 1;  |  | ||||||
| +	      ans = 1; |  | ||||||
| +	      sec_data = 0; |  | ||||||
|  	      if (!dryrun) |  | ||||||
|  		log_query(F_CONFIG | F_NEG, name, &addr, NULL); |  | ||||||
|  	    } |  | ||||||
| @@ -1,71 +0,0 @@ | |||||||
| From 24b87607c1353e94689e8a2190571ab3f3b36f31 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com> |  | ||||||
| Date: Wed, 24 Oct 2018 22:30:18 +0100 |  | ||||||
| Subject: [PATCH 07/11] Do not rely on dead code elimination, use array |  | ||||||
|  instead. Make options bits derived from size and count. Use size of option |  | ||||||
|  bits and last supported bit in computation. No new change would be required |  | ||||||
|  when new options are added. Just change OPT_LAST constant. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/dnsmasq.h | 11 +++++++---- |  | ||||||
|  src/option.c  | 10 ++-------- |  | ||||||
|  2 files changed, 9 insertions(+), 12 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/src/dnsmasq.h |  | ||||||
| +++ b/src/dnsmasq.h |  | ||||||
| @@ -200,9 +200,6 @@ struct event_desc { |  | ||||||
|  #define EC_MISC        5 |  | ||||||
|  #define EC_INIT_OFFSET 10 |  | ||||||
|   |  | ||||||
| -/* Trust the compiler dead-code eliminator.... */ |  | ||||||
| -#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32))) |  | ||||||
| - |  | ||||||
|  #define OPT_BOGUSPRIV      0 |  | ||||||
|  #define OPT_FILTER         1 |  | ||||||
|  #define OPT_LOG            2 |  | ||||||
| @@ -264,6 +261,12 @@ struct event_desc { |  | ||||||
|  #define OPT_UBUS           58 |  | ||||||
|  #define OPT_LAST           59 |  | ||||||
|   |  | ||||||
| +#define OPTION_BITS (sizeof(unsigned int)*8) |  | ||||||
| +#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) |  | ||||||
| +#define option_var(x) (daemon->options[(x) / OPTION_BITS]) |  | ||||||
| +#define option_val(x) ((1u) << ((x) % OPTION_BITS)) |  | ||||||
| +#define option_bool(x) (option_var(x) & option_val(x)) |  | ||||||
| + |  | ||||||
|  /* extra flags for my_syslog, we use a couple of facilities since they are known  |  | ||||||
|     not to occupy the same bits as priorities, no matter how syslog.h is set up. */ |  | ||||||
|  #define MS_TFTP   LOG_USER |  | ||||||
| @@ -978,7 +981,7 @@ extern struct daemon { |  | ||||||
|       config file arguments. All set (including defaults) |  | ||||||
|       in option.c */ |  | ||||||
|   |  | ||||||
| -  unsigned int options, options2; |  | ||||||
| +  unsigned int options[OPTION_SIZE]; |  | ||||||
|    struct resolvc default_resolv, *resolv_files; |  | ||||||
|    time_t last_resolv; |  | ||||||
|    char *servers_file; |  | ||||||
| --- a/src/option.c |  | ||||||
| +++ b/src/option.c |  | ||||||
| @@ -1490,18 +1490,12 @@ static int parse_dhcp_opt(char *errstr, |  | ||||||
|   |  | ||||||
|  void set_option_bool(unsigned int opt) |  | ||||||
|  { |  | ||||||
| -  if (opt < 32) |  | ||||||
| -    daemon->options |= 1u << opt; |  | ||||||
| -  else |  | ||||||
| -    daemon->options2 |= 1u << (opt - 32); |  | ||||||
| +  option_var(opt) |= option_val(opt); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  void reset_option_bool(unsigned int opt) |  | ||||||
|  { |  | ||||||
| -  if (opt < 32) |  | ||||||
| -    daemon->options &= ~(1u << opt); |  | ||||||
| -  else |  | ||||||
| -    daemon->options2 &= ~(1u << (opt - 32)); |  | ||||||
| +  option_var(opt) &= ~(option_val(opt)); |  | ||||||
|  } |  | ||||||
|   |  | ||||||
|  static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) |  | ||||||
| @@ -1,63 +0,0 @@ | |||||||
| From 3a5a84cdd1488bad118eeac72d09a60299bca744 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Wed, 31 Oct 2018 21:30:13 +0000 |  | ||||||
| Subject: [PATCH 08/11] Fix Makefile lines generating UBUS linker config. |  | ||||||
|  |  | ||||||
| If arg2 of pkg-wrapper is "--copy", then arg1 is NOT the name of |  | ||||||
| the package manager (--copy doesn't invoke it) it's a secondary |  | ||||||
| config string that inhibts the copy if found. This patch allows that |  | ||||||
| to be the empty string, for unconditional copy, and modifies the |  | ||||||
| ubus linker config to use it. It worked by coincidence before, because |  | ||||||
| there was no config string called "pkg-config". |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  Makefile        |  2 +- |  | ||||||
|  bld/pkg-wrapper | 14 ++++++++------ |  | ||||||
|  2 files changed, 9 insertions(+), 7 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/Makefile |  | ||||||
| +++ b/Makefile |  | ||||||
| @@ -53,7 +53,7 @@ top?=$(CURDIR) |  | ||||||
|   |  | ||||||
|  dbus_cflags =   `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`  |  | ||||||
|  dbus_libs =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`  |  | ||||||
| -ubus_libs =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS $(PKG_CONFIG) --copy -lubox -lubus` |  | ||||||
| +ubus_libs =     `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus` |  | ||||||
|  idn_cflags =    `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`  |  | ||||||
|  idn_libs =      `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`  |  | ||||||
|  idn2_cflags =   `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2` |  | ||||||
| --- a/bld/pkg-wrapper |  | ||||||
| +++ b/bld/pkg-wrapper |  | ||||||
| @@ -11,23 +11,25 @@ in=`cat` |  | ||||||
|   |  | ||||||
|  if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \ |  | ||||||
|      echo $in | grep $search >/dev/null 2>&1; then |  | ||||||
| -# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP |  | ||||||
| +# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP |  | ||||||
|      if [ $op = "--copy" ]; then |  | ||||||
| -	if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \ |  | ||||||
| -            echo $in | grep $pkg >/dev/null 2>&1; then |  | ||||||
| +	if [ -z "$pkg" ]; then |  | ||||||
| +	    pkg="$*" |  | ||||||
| +	elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \ |  | ||||||
| +		 echo $in | grep $pkg >/dev/null 2>&1; then |  | ||||||
|  	    pkg="" |  | ||||||
|  	else  |  | ||||||
|  	    pkg="$*" |  | ||||||
|  	fi |  | ||||||
|      elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \ |  | ||||||
| -	      echo $in | grep ${search}_STATIC >/dev/null 2>&1; then |  | ||||||
| +	     echo $in | grep ${search}_STATIC >/dev/null 2>&1; then |  | ||||||
|  	pkg=`$pkg  --static $op $*` |  | ||||||
|      else |  | ||||||
|  	pkg=`$pkg $op $*` |  | ||||||
|      fi |  | ||||||
| - |  | ||||||
| +     |  | ||||||
|      if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \ |  | ||||||
| -	echo $in | grep ${search}_STATIC >/dev/null 2>&1; then |  | ||||||
| +	   echo $in | grep ${search}_STATIC >/dev/null 2>&1; then |  | ||||||
|  	if [ $op = "--libs" ] || [ $op = "--copy" ]; then |  | ||||||
|  	    echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic" |  | ||||||
|  	else |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| From 122392e0b352507cabb9e982208d35d2e56902e0 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Wed, 31 Oct 2018 22:24:02 +0000 |  | ||||||
| Subject: [PATCH 09/11] Revert 68f6312d4bae30b78daafcd6f51dc441b8685b1e |  | ||||||
|  |  | ||||||
| The above is intended to increase robustness, but actually does the |  | ||||||
| opposite. The problem is that by ignoring SERVFAIL messages and hoping |  | ||||||
| for a better answer from another of the servers we've forwarded to, |  | ||||||
| we become vulnerable in the case that one or more of the configured |  | ||||||
| servers is down or not responding. |  | ||||||
|  |  | ||||||
| Consider the case that a domain is indeed BOGUS, and we've send the |  | ||||||
| query to n servers. With 68f6312d4bae30b78daafcd6f51dc441b8685b1e |  | ||||||
| we ignore the first n-1 SERVFAIL replies, and only return the |  | ||||||
| final n'th answer to the client. Now, if one of the servers we are |  | ||||||
| forwarding to is down, then we won't get all n replies, and the |  | ||||||
| client will never get an answer! This is a far more likely scenario |  | ||||||
| than a temporary SERVFAIL from only one of a set of notionally identical |  | ||||||
| servers, so, on the ground of robustness, we have to believe |  | ||||||
| any SERVFAIL answers we get, and return them to the client. |  | ||||||
|  |  | ||||||
| The client could be using the same recursive servers we are, |  | ||||||
| so it should, in theory, retry on SERVFAIL anyway. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  src/forward.c | 3 +-- |  | ||||||
|  1 file changed, 1 insertion(+), 2 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/src/forward.c |  | ||||||
| +++ b/src/forward.c |  | ||||||
| @@ -957,8 +957,7 @@ void reply_query(int fd, int family, tim |  | ||||||
|       we get a good reply from another server. Kill it when we've |  | ||||||
|       had replies from all to avoid filling the forwarding table when |  | ||||||
|       everything is broken */ |  | ||||||
| -  if (forward->forwardall == 0 || --forward->forwardall == 1 || |  | ||||||
| -      (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL)) |  | ||||||
| +  if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != REFUSED) |  | ||||||
|      { |  | ||||||
|        int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; |  | ||||||
|         |  | ||||||
| @@ -1,199 +0,0 @@ | |||||||
| From 48d12f14c9c0fc8cf943b52774c3892517dd72d4 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Simon Kelley <simon@thekelleys.org.uk> |  | ||||||
| Date: Fri, 2 Nov 2018 21:55:04 +0000 |  | ||||||
| Subject: [PATCH 10/11] Remove the NO_FORK compile-time option, and support for |  | ||||||
|  uclinux. |  | ||||||
|  |  | ||||||
| In an era where everything has an MMU, this looks like |  | ||||||
| an anachronism, and it adds to (Ok, multiplies!) the |  | ||||||
| combinatorial explosion of compile-time options. |  | ||||||
|  |  | ||||||
| Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> |  | ||||||
| --- |  | ||||||
|  CHANGELOG     |  6 ++++++ |  | ||||||
|  src/config.h  | 21 ++------------------- |  | ||||||
|  src/dnsmasq.c | 14 -------------- |  | ||||||
|  src/option.c  |  4 +--- |  | ||||||
|  4 files changed, 9 insertions(+), 36 deletions(-) |  | ||||||
|  |  | ||||||
| --- a/CHANGELOG |  | ||||||
| +++ b/CHANGELOG |  | ||||||
| @@ -11,6 +11,12 @@ version 2.81 |  | ||||||
|  	This fix passes cache entries back from the TCP child process to |  | ||||||
|  	the main server process, and fixes the problem. |  | ||||||
|   |  | ||||||
| +	Remove the NO_FORK compile-time option, and support for uclinux. |  | ||||||
| +	In an era where everything has an MMU, this looks like |  | ||||||
| +	an anachronism, and it adds to (Ok, multiplies!) the |  | ||||||
| +	combinatorial explosion of compile-time options. Thanks to |  | ||||||
| +	Kevin Darbyshire-Bryant for the patch. |  | ||||||
| + |  | ||||||
|   |  | ||||||
|  version 2.80 |  | ||||||
|  	Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method |  | ||||||
| --- a/src/config.h |  | ||||||
| +++ b/src/config.h |  | ||||||
| @@ -239,27 +239,13 @@ HAVE_SOCKADDR_SA_LEN |  | ||||||
|     defined if struct sockaddr has sa_len field (*BSD)  |  | ||||||
|  */ |  | ||||||
|   |  | ||||||
| -/* Must precede __linux__ since uClinux defines __linux__ too. */ |  | ||||||
| -#if defined(__uClinux__) |  | ||||||
| -#define HAVE_LINUX_NETWORK |  | ||||||
| -#define HAVE_GETOPT_LONG |  | ||||||
| -#undef HAVE_SOCKADDR_SA_LEN |  | ||||||
| -/* Never use fork() on uClinux. Note that this is subtly different from the |  | ||||||
| -   --keep-in-foreground option, since it also  suppresses forking new  |  | ||||||
| -   processes for TCP connections and disables the call-a-script on leasechange |  | ||||||
| -   system. It's intended for use on MMU-less kernels. */ |  | ||||||
| -#define NO_FORK |  | ||||||
| - |  | ||||||
| -#elif defined(__UCLIBC__) |  | ||||||
| +#if defined(__UCLIBC__) |  | ||||||
|  #define HAVE_LINUX_NETWORK |  | ||||||
|  #if defined(__UCLIBC_HAS_GNU_GETOPT__) || \ |  | ||||||
|     ((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21)) |  | ||||||
|  #    define HAVE_GETOPT_LONG |  | ||||||
|  #endif |  | ||||||
|  #undef HAVE_SOCKADDR_SA_LEN |  | ||||||
| -#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__) |  | ||||||
| -#  define NO_FORK |  | ||||||
| -#endif |  | ||||||
|  #if defined(__UCLIBC_HAS_IPV6__) |  | ||||||
|  #  ifndef IPV6_V6ONLY |  | ||||||
|  #    define IPV6_V6ONLY 26 |  | ||||||
| @@ -328,7 +314,7 @@ HAVE_SOCKADDR_SA_LEN |  | ||||||
|  #define HAVE_DHCP |  | ||||||
|  #endif |  | ||||||
|   |  | ||||||
| -#if defined(NO_SCRIPT) || defined(NO_FORK) |  | ||||||
| +#if defined(NO_SCRIPT) |  | ||||||
|  #undef HAVE_SCRIPT |  | ||||||
|  #undef HAVE_LUASCRIPT |  | ||||||
|  #endif |  | ||||||
| @@ -372,9 +358,6 @@ static char *compile_opts = |  | ||||||
|  #ifdef HAVE_BROKEN_RTC |  | ||||||
|  "no-RTC " |  | ||||||
|  #endif |  | ||||||
| -#ifdef NO_FORK |  | ||||||
| -"no-MMU " |  | ||||||
| -#endif |  | ||||||
|  #ifndef HAVE_DBUS |  | ||||||
|  "no-" |  | ||||||
|  #endif |  | ||||||
| --- a/src/dnsmasq.c |  | ||||||
| +++ b/src/dnsmasq.c |  | ||||||
| @@ -485,7 +485,6 @@ int main (int argc, char **argv) |  | ||||||
|        if (chdir("/") != 0) |  | ||||||
|  	die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);  |  | ||||||
|   |  | ||||||
| -#ifndef NO_FORK       |  | ||||||
|        if (!option_bool(OPT_NO_FORK)) |  | ||||||
|  	{ |  | ||||||
|  	  pid_t pid; |  | ||||||
| @@ -525,7 +524,6 @@ int main (int argc, char **argv) |  | ||||||
|  	  if (pid != 0) |  | ||||||
|  	    _exit(0); |  | ||||||
|  	} |  | ||||||
| -#endif |  | ||||||
|               |  | ||||||
|        /* write pidfile _after_ forking ! */ |  | ||||||
|        if (daemon->runfile) |  | ||||||
| @@ -1628,12 +1626,10 @@ static int set_dns_listeners(time_t now) |  | ||||||
|   |  | ||||||
|      } |  | ||||||
|     |  | ||||||
| -#ifndef NO_FORK |  | ||||||
|    if (!option_bool(OPT_DEBUG)) |  | ||||||
|      for (i = 0; i < MAX_PROCS; i++) |  | ||||||
|        if (daemon->tcp_pipes[i] != -1) |  | ||||||
|  	poll_listen(daemon->tcp_pipes[i], POLLIN); |  | ||||||
| -#endif |  | ||||||
|     |  | ||||||
|    return wait; |  | ||||||
|  } |  | ||||||
| @@ -1643,9 +1639,7 @@ static void check_dns_listeners(time_t n |  | ||||||
|    struct serverfd *serverfdp; |  | ||||||
|    struct listener *listener; |  | ||||||
|    int i; |  | ||||||
| -#ifndef NO_FORK |  | ||||||
|    int pipefd[2]; |  | ||||||
| -#endif |  | ||||||
|     |  | ||||||
|    for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) |  | ||||||
|      if (poll_check(serverfdp->fd, POLLIN)) |  | ||||||
| @@ -1657,7 +1651,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	  poll_check(daemon->randomsocks[i].fd, POLLIN)) |  | ||||||
|  	reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now); |  | ||||||
|   |  | ||||||
| -#ifndef NO_FORK |  | ||||||
|    /* Races. The child process can die before we read all of the data from the |  | ||||||
|       pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the  |  | ||||||
|       process, and tcp_pipes to -1 and close the FD when we read the last |  | ||||||
| @@ -1674,7 +1667,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	  close(daemon->tcp_pipes[i]); |  | ||||||
|  	  daemon->tcp_pipes[i] = -1;	 |  | ||||||
|  	} |  | ||||||
| -#endif |  | ||||||
|  	 |  | ||||||
|    for (listener = daemon->listeners; listener; listener = listener->next) |  | ||||||
|      { |  | ||||||
| @@ -1768,7 +1760,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	      shutdown(confd, SHUT_RDWR); |  | ||||||
|  	      while (retry_send(close(confd))); |  | ||||||
|  	    } |  | ||||||
| -#ifndef NO_FORK |  | ||||||
|  	  else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0) |  | ||||||
|  	    { |  | ||||||
|  	      close(pipefd[1]); /* parent needs read pipe end. */ |  | ||||||
| @@ -1791,7 +1782,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  	      /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */ |  | ||||||
|  	      daemon->log_id += TCP_MAX_QUERIES; |  | ||||||
|  	    } |  | ||||||
| -#endif |  | ||||||
|  	  else |  | ||||||
|  	    { |  | ||||||
|  	      unsigned char *buff; |  | ||||||
| @@ -1811,7 +1801,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  		  auth_dns = 0; |  | ||||||
|  		} |  | ||||||
|   |  | ||||||
| -#ifndef NO_FORK |  | ||||||
|  	      /* Arrange for SIGALRM after CHILD_LIFETIME seconds to |  | ||||||
|  		 terminate the process. */ |  | ||||||
|  	      if (!option_bool(OPT_DEBUG)) |  | ||||||
| @@ -1820,7 +1809,6 @@ static void check_dns_listeners(time_t n |  | ||||||
|  		  close(pipefd[0]); /* close read end in child. */ |  | ||||||
|  		  daemon->pipe_to_parent = pipefd[1]; |  | ||||||
|  		} |  | ||||||
| -#endif |  | ||||||
|   |  | ||||||
|  	      /* start with no upstream connections. */ |  | ||||||
|  	      for (s = daemon->servers; s; s = s->next) |  | ||||||
| @@ -1846,13 +1834,11 @@ static void check_dns_listeners(time_t n |  | ||||||
|  		    shutdown(s->tcpfd, SHUT_RDWR); |  | ||||||
|  		    while (retry_send(close(s->tcpfd))); |  | ||||||
|  		  } |  | ||||||
| -#ifndef NO_FORK		    |  | ||||||
|  	      if (!option_bool(OPT_DEBUG)) |  | ||||||
|  		{ |  | ||||||
|  		  flush_log(); |  | ||||||
|  		  _exit(0); |  | ||||||
|  		} |  | ||||||
| -#endif |  | ||||||
|  	    } |  | ||||||
|  	} |  | ||||||
|      } |  | ||||||
| --- a/src/option.c |  | ||||||
| +++ b/src/option.c |  | ||||||
| @@ -1828,9 +1828,7 @@ static int one_opt(int option, char *arg |  | ||||||
|        /* Sorry about the gross pre-processor abuse */ |  | ||||||
|      case '6':             /* --dhcp-script */ |  | ||||||
|      case LOPT_LUASCRIPT:  /* --dhcp-luascript */ |  | ||||||
| -#  if defined(NO_FORK) |  | ||||||
| -      ret_err(_("cannot run scripts under uClinux")); |  | ||||||
| -#  elif !defined(HAVE_SCRIPT) |  | ||||||
| +#  if !defined(HAVE_SCRIPT) |  | ||||||
|        ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts")); |  | ||||||
|  #  else |  | ||||||
|        if (option == LOPT_LUASCRIPT) |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -44,7 +44,7 @@ | |||||||
|        (buffer = safe_malloc(BUFF_SZ)) && |        (buffer = safe_malloc(BUFF_SZ)) && | ||||||
|        (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 && |        (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 && | ||||||
|        (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1)) |        (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1)) | ||||||
| @@ -211,16 +192,9 @@ int add_to_ipset(const char *setname, co | @@ -217,17 +198,10 @@ int add_to_ipset(const char *setname, co | ||||||
|    if (flags & F_IPV6) |    if (flags & F_IPV6) | ||||||
|      { |      { | ||||||
|        af = AF_INET6; |        af = AF_INET6; | ||||||
| @@ -55,6 +55,7 @@ | |||||||
| -	  ret = -1; | -	  ret = -1; | ||||||
| -	} | -	} | ||||||
|      } |      } | ||||||
|  |  #endif | ||||||
|     |     | ||||||
| -  if (ret != -1)  | -  if (ret != -1)  | ||||||
| -    ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove); | -    ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Kevin Darbyshire-Bryant
					Kevin Darbyshire-Bryant