Revert "dnsmasq: follow upstream dnsmasq pre-v2.81"
[openwrt/staging/hauke.git] / package / network / services / dnsmasq / patches / 0001-Impove-cache-behaviour-for-TCP-connections.patch
diff --git a/package/network/services/dnsmasq/patches/0001-Impove-cache-behaviour-for-TCP-connections.patch b/package/network/services/dnsmasq/patches/0001-Impove-cache-behaviour-for-TCP-connections.patch
deleted file mode 100644 (file)
index 453c292..0000000
+++ /dev/null
@@ -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