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

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