Blame SOURCES/dnsmasq-2.79-server-domain-rh1919894.patch

53807b
From 5747d7b3dffdcd45d4410bb380e466818734cb27 Mon Sep 17 00:00:00 2001
53807b
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
53807b
Date: Mon, 19 Apr 2021 13:56:23 +0200
53807b
Subject: [PATCH] Use load-balancing also for --server=/domains/
53807b
53807b
Do not (yet) move servers to server_domain structure. Instead use
53807b
separate server_domains to store just last_server and requests count and
53807b
time.
53807b
53807b
Introduces domain information duplicity, but minimizes required changes
53807b
to daemon->servers usage.
53807b
53807b
Optimize server domain record
53807b
53807b
Set pointer to domain record when struct server is created. When
53807b
searching for domain pointer, use this pointer to make it quick.
53807b
---
53807b
 src/dnsmasq.h |  18 +++++++--
53807b
 src/forward.c |  52 ++++++++++++++++----------
53807b
 src/network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++----
53807b
 src/option.c  |   5 +++
53807b
 4 files changed, 146 insertions(+), 30 deletions(-)
53807b
53807b
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
53807b
index 1e21005..b6dcc50 100644
53807b
--- a/src/dnsmasq.h
53807b
+++ b/src/dnsmasq.h
53807b
@@ -559,6 +559,17 @@ struct randfd_list {
53807b
   struct randfd_list *next;
53807b
 };
53807b
 
53807b
+/* contains domain specific set of servers.
53807b
+ * If domain is NULL, just normal servers. */
53807b
+struct server_domain {
53807b
+  char *domain;
53807b
+  struct server *last_server;
53807b
+  time_t forwardtime;
53807b
+  int forwardcount;
53807b
+  unsigned int flags; /* server.flags alternative */
53807b
+  struct server_domain *next;
53807b
+};
53807b
+
53807b
 struct server {
53807b
   union mysockaddr addr, source_addr;
53807b
   char interface[IF_NAMESIZE+1];
53807b
@@ -571,6 +582,7 @@ struct server {
53807b
 #ifdef HAVE_LOOP
53807b
   u32 uid;
53807b
 #endif
53807b
+  struct server_domain *serv_domain;
53807b
   struct server *next; 
53807b
 };
53807b
 
53807b
@@ -1053,6 +1065,7 @@ extern struct daemon {
53807b
   struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
53807b
   struct bogus_addr *bogus_addr, *ignore_addr;
53807b
   struct server *servers;
53807b
+  struct server_domain *server_domains;
53807b
   struct ipsets *ipsets;
53807b
   int log_fac; /* log facility */
53807b
   char *log_file; /* optional log file */
53807b
@@ -1121,9 +1134,6 @@ extern struct daemon {
53807b
   struct serverfd *sfds;
53807b
   struct irec *interfaces;
53807b
   struct listener *listeners;
53807b
-  struct server *last_server;
53807b
-  time_t forwardtime;
53807b
-  int forwardcount;
53807b
   struct server *srv_save; /* Used for resend on DoD */
53807b
   size_t packet_len;       /*      "        "        */
53807b
   int    fd_save;          /*      "        "        */
53807b
@@ -1394,6 +1404,8 @@ int label_exception(int index, int family, union all_addr *addr);
53807b
 int fix_fd(int fd);
53807b
 int tcp_interface(int fd, int af);
53807b
 int set_ipv6pktinfo(int fd);
53807b
+struct server_domain *server_domain_find_domain(const char *domain);
53807b
+struct server_domain *server_domain_new(struct server *serv);
53807b
 #ifdef HAVE_DHCP6
53807b
 void join_multicast(int dienow);
53807b
 #endif
53807b
diff --git a/src/forward.c b/src/forward.c
53807b
index 9322b6a..b09dc96 100644
53807b
--- a/src/forward.c
53807b
+++ b/src/forward.c
53807b
@@ -107,7 +107,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
53807b
 }
53807b
           
53807b
 static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
53807b
-				   char *qdomain, int *type, char **domain, int *norebind)
53807b
+				   char *qdomain, int *type, char **domain, int *norebind,
53807b
+				   struct server_domain **serv_domain)
53807b
 			      
53807b
 {
53807b
   /* If the query ends in the domain in one of our servers, set
53807b
@@ -120,6 +121,9 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
53807b
   unsigned int flags = 0;
53807b
   static union all_addr zero;
53807b
   
53807b
+  if (serv_domain)
53807b
+    *serv_domain = NULL;
53807b
+
53807b
   for (serv = daemon->servers; serv; serv=serv->next)
53807b
     if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
53807b
       continue;
53807b
@@ -187,6 +191,8 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
53807b
 		  {
53807b
 		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
53807b
 		    *domain = serv->domain;
53807b
+		    if (serv_domain)
53807b
+		      *serv_domain = serv->serv_domain;
53807b
 		    matchlen = domainlen;
53807b
 		    if (serv->flags & SERV_NO_ADDR)
53807b
 		      flags = F_NXDOMAIN;
53807b
@@ -243,6 +249,8 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
53807b
       *type = 0; /* use normal servers for this domain */
53807b
       *domain = NULL;
53807b
     }
53807b
+  if (serv_domain && !*serv_domain)
53807b
+    *serv_domain = server_domain_find_domain(*domain);
53807b
   return  flags;
53807b
 }
53807b
 
53807b
@@ -304,6 +312,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
53807b
   unsigned int flags = 0;
53807b
   unsigned int fwd_flags = 0;
53807b
   struct server *start = NULL;
53807b
+  struct server_domain *sd = NULL;
53807b
   void *hash = hash_questions(header, plen, daemon->namebuff);
53807b
 #ifdef HAVE_DNSSEC
53807b
   int do_dnssec = 0;
53807b
@@ -422,8 +431,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
53807b
       forward->sentto->failed_queries++;
53807b
       if (!option_bool(OPT_ORDER) && old_src)
53807b
 	{
53807b
+	  sd = forward->sentto->serv_domain;
53807b
 	  forward->forwardall = 1;
53807b
-	  daemon->last_server = NULL;
53807b
+	  if (sd)
53807b
+	    sd->last_server = NULL;
53807b
 	}
53807b
       type = forward->sentto->flags & SERV_TYPE;
53807b
 #ifdef HAVE_DNSSEC
53807b
@@ -439,8 +450,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
53807b
       /* new query */
53807b
 
53807b
       if (gotname)
53807b
-	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
53807b
-      
53807b
+	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
53807b
+
53807b
 #ifdef HAVE_DNSSEC
53807b
       do_dnssec = type & SERV_DO_DNSSEC;
53807b
 #endif
53807b
@@ -482,18 +493,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
53807b
 	     always try all the available servers,
53807b
 	     otherwise, use the one last known to work. */
53807b
 	  
53807b
-	  if (type == 0)
53807b
+	  if (sd)
53807b
 	    {
53807b
 	      if (option_bool(OPT_ORDER))
53807b
 		start = daemon->servers;
53807b
-	      else if (!(start = daemon->last_server) ||
53807b
-		       daemon->forwardcount++ > FORWARD_TEST ||
53807b
-		       difftime(now, daemon->forwardtime) > FORWARD_TIME)
53807b
+	      else if (!(start = sd->last_server) ||
53807b
+		       sd->forwardcount++ > FORWARD_TEST ||
53807b
+		       difftime(now, sd->forwardtime) > FORWARD_TIME)
53807b
 		{
53807b
 		  start = daemon->servers;
53807b
 		  forward->forwardall = 1;
53807b
-		  daemon->forwardcount = 0;
53807b
-		  daemon->forwardtime = now;
53807b
+		  sd->forwardcount = 0;
53807b
+		  sd->forwardtime = now;
53807b
 		}
53807b
 	    }
53807b
 	  else
53807b
@@ -844,6 +855,7 @@ void reply_query(int fd, time_t now)
53807b
   size_t nn;
53807b
   struct server *server;
53807b
   void *hash;
53807b
+  struct server_domain *sd;
53807b
 
53807b
   /* packet buffer overwritten */
53807b
   daemon->srv_save = NULL;
53807b
@@ -968,7 +980,8 @@ void reply_query(int fd, time_t now)
53807b
     }   
53807b
    
53807b
   server = forward->sentto;
53807b
-  if ((forward->sentto->flags & SERV_TYPE) == 0)
53807b
+  sd = server->serv_domain;
53807b
+  if (sd)
53807b
     {
53807b
       if (RCODE(header) == REFUSED)
53807b
 	server = NULL;
53807b
@@ -986,7 +999,7 @@ void reply_query(int fd, time_t now)
53807b
 	      }
53807b
 	} 
53807b
       if (!option_bool(OPT_ALL_SERVERS))
53807b
-	daemon->last_server = server;
53807b
+	sd->last_server = server;
53807b
     }
53807b
  
53807b
   /* We tried resending to this server with a smaller maximum size and got an answer.
53807b
@@ -1093,7 +1106,7 @@ void reply_query(int fd, time_t now)
53807b
 		      /* Find server to forward to. This will normally be the 
53807b
 			 same as for the original query, but may be another if
53807b
 			 servers for domains are involved. */		      
53807b
-		      if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
53807b
+		      if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL, &sd) == 0)
53807b
 			{
53807b
 			  struct server *start, *new_server = NULL;
53807b
 			  start = server = forward->sentto;
53807b
@@ -1664,7 +1677,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
53807b
       /* Find server to forward to. This will normally be the 
53807b
 	 same as for the original query, but may be another if
53807b
 	 servers for domains are involved. */		      
53807b
-      if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
53807b
+      if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL, NULL) != 0)
53807b
 	{
53807b
 	  new_status = STAT_ABANDONED;
53807b
 	  break;
53807b
@@ -1944,12 +1957,13 @@ unsigned char *tcp_request(int confd, time_t now,
53807b
 	      union all_addr *addrp = NULL;
53807b
 	      int type = SERV_DO_DNSSEC;
53807b
 	      char *domain = NULL;
53807b
+	      struct server_domain *sd = NULL;
53807b
 	      unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
53807b
 
53807b
 	      size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
53807b
 
53807b
 	      if (gotname)
53807b
-		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
53807b
+		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
53807b
 
53807b
 #ifdef HAVE_DNSSEC
53807b
 	      if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
53807b
@@ -1970,10 +1984,10 @@ unsigned char *tcp_request(int confd, time_t now,
53807b
 
53807b
 	      type &= ~SERV_DO_DNSSEC;
53807b
 	      
53807b
-	      if (type != 0  || option_bool(OPT_ORDER) || !daemon->last_server)
53807b
+	      if (!sd  || option_bool(OPT_ORDER) || !sd->last_server)
53807b
 		last_server = daemon->servers;
53807b
 	      else
53807b
-		last_server = daemon->last_server;
53807b
+		last_server = sd->last_server;
53807b
 	      
53807b
 	      if (!flags && last_server)
53807b
 		{
53807b
@@ -2567,9 +2581,7 @@ void server_gone(struct server *server)
53807b
     if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
53807b
       daemon->randomsocks[i].serv = NULL;
53807b
   
53807b
-  if (daemon->last_server == server)
53807b
-    daemon->last_server = NULL;
53807b
-  
53807b
+  /* last_server cleared by server_domains_cleanup */
53807b
   if (daemon->srv_save == server)
53807b
     daemon->srv_save = NULL;
53807b
 }
53807b
diff --git a/src/network.c b/src/network.c
53807b
index 3600250..1fa81ff 100644
53807b
--- a/src/network.c
53807b
+++ b/src/network.c
53807b
@@ -1537,6 +1537,29 @@ void cleanup_servers(void)
53807b
 #endif
53807b
 }
53807b
 
53807b
+static void server_domains_cleanup(void)
53807b
+{
53807b
+  struct server_domain *sd, *tmp, **up;
53807b
+
53807b
+  /* unlink and free anything still marked. */
53807b
+  for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
53807b
+    {
53807b
+      tmp = sd->next;
53807b
+      if (sd->flags & SERV_MARK)
53807b
+       {
53807b
+         *up = sd->next;
53807b
+         if (sd->domain)
53807b
+	   free(sd->domain);
53807b
+	 free(sd);
53807b
+       }
53807b
+      else {
53807b
+        up = &sd->next;
53807b
+        if (sd->last_server && (sd->last_server->flags & SERV_MARK))
53807b
+	  sd->last_server = NULL;
53807b
+      }
53807b
+    }
53807b
+}
53807b
+
53807b
 void add_update_server(int flags,
53807b
 		       union mysockaddr *addr,
53807b
 		       union mysockaddr *source_addr,
53807b
@@ -1616,10 +1639,72 @@ void add_update_server(int flags,
53807b
     }
53807b
 }
53807b
 
53807b
+static const char *server_get_domain(const struct server *serv)
53807b
+{
53807b
+  const char *domain = serv->domain;
53807b
+
53807b
+  if (serv->flags & SERV_HAS_DOMAIN)
53807b
+		  /* .example.com is valid */
53807b
+    while (*domain == '.')
53807b
+      domain++;
53807b
+
53807b
+  return domain;
53807b
+}
53807b
+
53807b
+struct server_domain *server_domain_find_domain(const char *domain)
53807b
+{
53807b
+  struct server_domain *sd;
53807b
+  for (sd = daemon->server_domains; sd; sd = sd->next)
53807b
+    if ((!domain && sd->domain == domain) || (domain && sd->domain && hostname_isequal(domain, sd->domain)))
53807b
+      return sd;
53807b
+  return NULL;
53807b
+}
53807b
+
53807b
+/**< Test structure has already set domain pointer.
53807b
+ *
53807b
+ * If not, create a new record. */
53807b
+struct server_domain *server_domain_new(struct server *serv)
53807b
+{
53807b
+  struct server_domain *sd;
53807b
+
53807b
+  if ((sd = whine_malloc(sizeof(struct server_domain))))
53807b
+    {
53807b
+      const char *domain = server_get_domain(serv);
53807b
+
53807b
+      /* Ensure all serv->domain values have own record in server_domain.
53807b
+       * Add a new record. */
53807b
+      if (domain)
53807b
+	{
53807b
+	  size_t len = strlen(domain)+1;
53807b
+	  sd->domain = whine_malloc(len);
53807b
+	  if (sd->domain)
53807b
+	    memcpy(sd->domain, domain, len);
53807b
+	}
53807b
+      sd->next = daemon->server_domains;
53807b
+      serv->serv_domain = sd;
53807b
+      daemon->server_domains = sd;
53807b
+    }
53807b
+  return sd;
53807b
+}
53807b
+
53807b
+/**< Test structure has already set domain pointer.
53807b
+ *
53807b
+ * If not, create a new record. */
53807b
+static void server_domain_check(struct server *serv)
53807b
+{
53807b
+  struct server_domain *sd = serv->serv_domain;
53807b
+
53807b
+  if (sd)
53807b
+    sd->flags &= (~SERV_MARK); /* found domain, mark active */
53807b
+  else
53807b
+    server_domain_new(serv);
53807b
+}
53807b
+
53807b
 void check_servers(void)
53807b
 {
53807b
   struct irec *iface;
53807b
   struct server *serv;
53807b
+  struct server_domain *sd;
53807b
   struct serverfd *sfd, *tmp, **up;
53807b
   int port = 0, count;
53807b
   int locals = 0;
53807b
@@ -1632,10 +1717,14 @@ void check_servers(void)
53807b
   for (sfd = daemon->sfds; sfd; sfd = sfd->next)
53807b
     sfd->used = sfd->preallocated;
53807b
 
53807b
+  for (sd = daemon->server_domains; sd; sd = sd->next)
53807b
+    sd->flags |= SERV_MARK;
53807b
+
53807b
   for (count = 0, serv = daemon->servers; serv; serv = serv->next)
53807b
     {
53807b
       if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
53807b
 	{
53807b
+
53807b
 	  /* Init edns_pktsz for newly created server records. */
53807b
 	  if (serv->edns_pktsz == 0)
53807b
 	    serv->edns_pktsz = daemon->edns_pktsz;
53807b
@@ -1651,12 +1740,8 @@ void check_servers(void)
53807b
 	      if (serv->flags & SERV_HAS_DOMAIN)
53807b
 		{
53807b
 		  struct ds_config *ds;
53807b
-		  char *domain = serv->domain;
53807b
-		  
53807b
-		  /* .example.com is valid */
53807b
-		  while (*domain == '.')
53807b
-		    domain++;
53807b
-		  
53807b
+		  const char *domain = server_get_domain(serv);
53807b
+
53807b
 		  for (ds = daemon->ds; ds; ds = ds->next)
53807b
 		    if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
53807b
 		      break;
53807b
@@ -1666,7 +1751,6 @@ void check_servers(void)
53807b
 		}
53807b
 	    }
53807b
 #endif
53807b
-
53807b
 	  port = prettyprint_addr(&serv->addr, daemon->namebuff);
53807b
 	  
53807b
 	  /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
53807b
@@ -1701,6 +1785,8 @@ void check_servers(void)
53807b
 	  
53807b
 	  if (serv->sfd)
53807b
 	    serv->sfd->used = 1;
53807b
+
53807b
+	  server_domain_check(serv);
53807b
 	}
53807b
       
53807b
       if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
53807b
@@ -1763,6 +1849,7 @@ void check_servers(void)
53807b
 	up = &sfd->next;
53807b
     }
53807b
   
53807b
+  server_domains_cleanup();
53807b
   cleanup_servers();
53807b
 }
53807b
 
53807b
diff --git a/src/option.c b/src/option.c
53807b
index 6de5914..e4e3182 100644
53807b
--- a/src/option.c
53807b
+++ b/src/option.c
53807b
@@ -928,6 +928,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
53807b
   p += sprintf(p, "in-addr.arpa");
53807b
   
53807b
   serv->flags = SERV_HAS_DOMAIN;
53807b
+  server_domain_new(serv);
53807b
   serv->next = daemon->servers;
53807b
   daemon->servers = serv;
53807b
 
53807b
@@ -952,6 +953,7 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
53807b
   p += sprintf(p, "ip6.arpa");
53807b
   
53807b
   serv->flags = SERV_HAS_DOMAIN;
53807b
+  server_domain_new(serv);
53807b
   serv->next = daemon->servers;
53807b
   daemon->servers = serv;
53807b
   
53807b
@@ -2292,6 +2294,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
53807b
 				  memset(serv, 0, sizeof(struct server));
53807b
 				  serv->domain = d;
53807b
 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
53807b
+				  server_domain_new(serv);
53807b
 				  serv->next = daemon->servers;
53807b
 				  daemon->servers = serv;
53807b
 				}
53807b
@@ -2335,6 +2338,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
53807b
 				  memset(serv, 0, sizeof(struct server));
53807b
 				  serv->domain = d;
53807b
 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
53807b
+				  server_domain_new(serv);
53807b
 				  serv->next = daemon->servers;
53807b
 				  daemon->servers = serv;
53807b
 				}
53807b
@@ -2587,6 +2591,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
53807b
 		newlist = serv;
53807b
 		serv->domain = domain;
53807b
 		serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
53807b
+		server_domain_new(serv);
53807b
 		arg = end;
53807b
 		if (rebind)
53807b
 		  break;
53807b
-- 
53807b
2.34.1
53807b