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

a3005a
From b15c92e5d793c9767591dbf8910bf3466aba92ee Mon Sep 17 00:00:00 2001
a3005a
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
a3005a
Date: Mon, 19 Apr 2021 13:56:23 +0200
a3005a
Subject: [PATCH] Use load-balancing also for --server=/domains/
a3005a
a3005a
Do not (yet) move servers to server_domain structure. Instead use
a3005a
separate server_domains to store just last_server and requests count and
a3005a
time.
a3005a
a3005a
Introduces domain information duplicity, but minimizes required changes
a3005a
to daemon->servers usage.
a3005a
a3005a
Optimize server domain record
a3005a
a3005a
Set pointer to domain record when struct server is created. When
a3005a
searching for domain pointer, use this pointer to make it quick.
a3005a
---
a3005a
 src/dnsmasq.h |  18 +++++++--
a3005a
 src/forward.c |  54 ++++++++++++++++-----------
a3005a
 src/network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++----
a3005a
 src/option.c  |   5 +++
a3005a
 4 files changed, 147 insertions(+), 31 deletions(-)
a3005a
a3005a
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
a3005a
index 4beef35..27ff86a 100644
a3005a
--- a/src/dnsmasq.h
a3005a
+++ b/src/dnsmasq.h
a3005a
@@ -531,6 +531,17 @@ struct randfd_list {
a3005a
   struct randfd_list *next;
a3005a
 };
a3005a
 
a3005a
+/* contains domain specific set of servers.
a3005a
+ * If domain is NULL, just normal servers. */
a3005a
+struct server_domain {
a3005a
+  char *domain;
a3005a
+  struct server *last_server;
a3005a
+  time_t forwardtime;
a3005a
+  int forwardcount;
a3005a
+  unsigned int flags; /* server.flags alternative */
a3005a
+  struct server_domain *next;
a3005a
+};
a3005a
+
a3005a
 struct server {
a3005a
   union mysockaddr addr, source_addr;
a3005a
   char interface[IF_NAMESIZE+1];
a3005a
@@ -543,6 +554,7 @@ struct server {
a3005a
 #ifdef HAVE_LOOP
a3005a
   u32 uid;
a3005a
 #endif
a3005a
+  struct server_domain *serv_domain;
a3005a
   struct server *next; 
a3005a
 };
a3005a
 
a3005a
@@ -995,6 +1007,7 @@ extern struct daemon {
a3005a
   struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
a3005a
   struct bogus_addr *bogus_addr, *ignore_addr;
a3005a
   struct server *servers;
a3005a
+  struct server_domain *server_domains;
a3005a
   struct ipsets *ipsets;
a3005a
   int log_fac; /* log facility */
a3005a
   char *log_file; /* optional log file */
a3005a
@@ -1061,9 +1074,6 @@ extern struct daemon {
a3005a
   struct serverfd *sfds;
a3005a
   struct irec *interfaces;
a3005a
   struct listener *listeners;
a3005a
-  struct server *last_server;
a3005a
-  time_t forwardtime;
a3005a
-  int forwardcount;
a3005a
   struct server *srv_save; /* Used for resend on DoD */
a3005a
   size_t packet_len;       /*      "        "        */
a3005a
   int    fd_save;          /*      "        "        */
a3005a
@@ -1319,6 +1329,8 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
a3005a
 int label_exception(int index, int family, struct all_addr *addr);
a3005a
 int fix_fd(int fd);
a3005a
 int tcp_interface(int fd, int af);
a3005a
+struct server_domain *server_domain_find_domain(const char *domain);
a3005a
+struct server_domain *server_domain_new(struct server *serv);
a3005a
 #ifdef HAVE_IPV6
a3005a
 int set_ipv6pktinfo(int fd);
a3005a
 #endif
a3005a
diff --git a/src/forward.c b/src/forward.c
a3005a
index 11e0310..d8e845a 100644
a3005a
--- a/src/forward.c
a3005a
+++ b/src/forward.c
a3005a
@@ -109,7 +109,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
a3005a
 }
a3005a
           
a3005a
 static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
a3005a
-				   char *qdomain, int *type, char **domain, int *norebind)
a3005a
+				   char *qdomain, int *type, char **domain, int *norebind,
a3005a
+				   struct server_domain **serv_domain)
a3005a
 			      
a3005a
 {
a3005a
   /* If the query ends in the domain in one of our servers, set
a3005a
@@ -121,6 +122,9 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
a3005a
   struct server *serv;
a3005a
   unsigned int flags = 0;
a3005a
   
a3005a
+  if (serv_domain)
a3005a
+    *serv_domain = NULL;
a3005a
+
a3005a
   for (serv = daemon->servers; serv; serv=serv->next)
a3005a
     if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
a3005a
       continue;
a3005a
@@ -181,6 +185,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
a3005a
 		  {
a3005a
 		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
a3005a
 		    *domain = serv->domain;
a3005a
+		    if (serv_domain)
a3005a
+		      *serv_domain = serv->serv_domain;
a3005a
 		    matchlen = domainlen;
a3005a
 		    if (serv->flags & SERV_NO_ADDR)
a3005a
 		      flags = F_NXDOMAIN;
a3005a
@@ -228,6 +234,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
a3005a
       *type = 0; /* use normal servers for this domain */
a3005a
       *domain = NULL;
a3005a
     }
a3005a
+  if (serv_domain && !*serv_domain)
a3005a
+    *serv_domain = server_domain_find_domain(*domain);
a3005a
   return  flags;
a3005a
 }
a3005a
 
a3005a
@@ -242,6 +250,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
a3005a
   unsigned int flags = 0;
a3005a
   unsigned int fwd_flags = 0;
a3005a
   struct server *start = NULL;
a3005a
+  struct server_domain *sd = NULL;
a3005a
   void *hash = hash_questions(header, plen, daemon->namebuff);
a3005a
 #ifdef HAVE_DNSSEC
a3005a
   int do_dnssec = 0;
a3005a
@@ -313,8 +322,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
a3005a
       forward->sentto->failed_queries++;
a3005a
       if (!option_bool(OPT_ORDER))
a3005a
 	{
a3005a
+	  sd = forward->sentto->serv_domain;
a3005a
 	  forward->forwardall = 1;
a3005a
-	  daemon->last_server = NULL;
a3005a
+	  if (sd)
a3005a
+	    sd->last_server = NULL;
a3005a
 	}
a3005a
       type = forward->sentto->flags & SERV_TYPE;
a3005a
 #ifdef HAVE_DNSSEC
a3005a
@@ -363,10 +374,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
a3005a
 	  
a3005a
 	  return 1;
a3005a
 	}
a3005a
-	
a3005a
+
a3005a
       if (gotname)
a3005a
-	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
a3005a
-      
a3005a
+	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
a3005a
+
a3005a
 #ifdef HAVE_DNSSEC
a3005a
       do_dnssec = type & SERV_DO_DNSSEC;
a3005a
 #endif
a3005a
@@ -407,18 +418,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
a3005a
 	     always try all the available servers,
a3005a
 	     otherwise, use the one last known to work. */
a3005a
 	  
a3005a
-	  if (type == 0)
a3005a
+	  if (sd)
a3005a
 	    {
a3005a
 	      if (option_bool(OPT_ORDER))
a3005a
 		start = daemon->servers;
a3005a
-	      else if (!(start = daemon->last_server) ||
a3005a
-		       daemon->forwardcount++ > FORWARD_TEST ||
a3005a
-		       difftime(now, daemon->forwardtime) > FORWARD_TIME)
a3005a
+	      else if (!(start = sd->last_server) ||
a3005a
+		       sd->forwardcount++ > FORWARD_TEST ||
a3005a
+		       difftime(now, sd->forwardtime) > FORWARD_TIME)
a3005a
 		{
a3005a
 		  start = daemon->servers;
a3005a
 		  forward->forwardall = 1;
a3005a
-		  daemon->forwardcount = 0;
a3005a
-		  daemon->forwardtime = now;
a3005a
+		  sd->forwardcount = 0;
a3005a
+		  sd->forwardtime = now;
a3005a
 		}
a3005a
 	    }
a3005a
 	  else
a3005a
@@ -758,6 +769,7 @@ void reply_query(int fd, time_t now)
a3005a
   size_t nn;
a3005a
   struct server *server;
a3005a
   void *hash;
a3005a
+  struct server_domain *sd;
a3005a
 
a3005a
   /* packet buffer overwritten */
a3005a
   daemon->srv_save = NULL;
a3005a
@@ -845,7 +857,8 @@ void reply_query(int fd, time_t now)
a3005a
     }   
a3005a
    
a3005a
   server = forward->sentto;
a3005a
-  if ((forward->sentto->flags & SERV_TYPE) == 0)
a3005a
+  sd = server->serv_domain;
a3005a
+  if (sd)
a3005a
     {
a3005a
       if (RCODE(header) == REFUSED)
a3005a
 	server = NULL;
a3005a
@@ -863,7 +876,7 @@ void reply_query(int fd, time_t now)
a3005a
 	      }
a3005a
 	} 
a3005a
       if (!option_bool(OPT_ALL_SERVERS))
a3005a
-	daemon->last_server = server;
a3005a
+	sd->last_server = server;
a3005a
     }
a3005a
  
a3005a
   /* We tried resending to this server with a smaller maximum size and got an answer.
a3005a
@@ -964,7 +977,7 @@ void reply_query(int fd, time_t now)
a3005a
 		      /* Find server to forward to. This will normally be the 
a3005a
 			 same as for the original query, but may be another if
a3005a
 			 servers for domains are involved. */		      
a3005a
-		      if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
a3005a
+		      if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL, &sd) == 0)
a3005a
 			{
a3005a
 			  struct server *start = server, *new_server = NULL;
a3005a
 			  
a3005a
@@ -1541,7 +1554,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
a3005a
       /* Find server to forward to. This will normally be the 
a3005a
 	 same as for the original query, but may be another if
a3005a
 	 servers for domains are involved. */		      
a3005a
-      if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
a3005a
+      if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL, NULL) != 0)
a3005a
 	{
a3005a
 	  new_status = STAT_ABANDONED;
a3005a
 	  break;
a3005a
@@ -1814,11 +1827,12 @@ unsigned char *tcp_request(int confd, time_t now,
a3005a
 	      int type = SERV_DO_DNSSEC;
a3005a
 	      char *domain = NULL;
a3005a
 	      unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
a3005a
+	      struct server_domain *sd = NULL;
a3005a
 
a3005a
 	      size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
a3005a
 
a3005a
 	      if (gotname)
a3005a
-		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
a3005a
+		flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
a3005a
 
a3005a
 #ifdef HAVE_DNSSEC
a3005a
 	      if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
a3005a
@@ -1839,10 +1853,10 @@ unsigned char *tcp_request(int confd, time_t now,
a3005a
 
a3005a
 	      type &= ~SERV_DO_DNSSEC;
a3005a
 	      
a3005a
-	      if (type != 0  || option_bool(OPT_ORDER) || !daemon->last_server)
a3005a
+	      if (!sd  || option_bool(OPT_ORDER) || !sd->last_server)
a3005a
 		last_server = daemon->servers;
a3005a
 	      else
a3005a
-		last_server = daemon->last_server;
a3005a
+		last_server = sd->last_server;
a3005a
 	      
a3005a
 	      if (!flags && last_server)
a3005a
 		{
a3005a
@@ -2439,9 +2453,7 @@ void server_gone(struct server *server)
a3005a
     if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
a3005a
       daemon->randomsocks[i].serv = NULL;
a3005a
 
a3005a
-  if (daemon->last_server == server)
a3005a
-    daemon->last_server = NULL;
a3005a
-
a3005a
+  /* last_server cleared by server_domain_cleanup */
a3005a
   if (daemon->srv_save == server)
a3005a
     daemon->srv_save = NULL;
a3005a
 }
a3005a
diff --git a/src/network.c b/src/network.c
a3005a
index 4eda1fd..4d140bb 100644
a3005a
--- a/src/network.c
a3005a
+++ b/src/network.c
a3005a
@@ -1428,6 +1428,29 @@ void cleanup_servers(void)
a3005a
 #endif
a3005a
 }
a3005a
 
a3005a
+void server_domains_cleanup(void)
a3005a
+{
a3005a
+  struct server_domain *sd, *tmp, **up;
a3005a
+
a3005a
+  /* unlink and free anything still marked. */
a3005a
+  for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
a3005a
+    {
a3005a
+      tmp = sd->next;
a3005a
+      if (sd->flags & SERV_MARK)
a3005a
+       {
a3005a
+         *up = sd->next;
a3005a
+         if (sd->domain)
a3005a
+	   free(sd->domain);
a3005a
+	 free(sd);
a3005a
+       }
a3005a
+      else {
a3005a
+        up = &sd->next;
a3005a
+        if (sd->last_server && (sd->last_server->flags & SERV_MARK))
a3005a
+	  sd->last_server = NULL;
a3005a
+      }
a3005a
+    }
a3005a
+}
a3005a
+
a3005a
 void add_update_server(int flags,
a3005a
 		       union mysockaddr *addr,
a3005a
 		       union mysockaddr *source_addr,
a3005a
@@ -1507,10 +1530,72 @@ void add_update_server(int flags,
a3005a
     }
a3005a
 }
a3005a
 
a3005a
+static const char *server_get_domain(const struct server *serv)
a3005a
+{
a3005a
+  const char *domain = serv->domain;
a3005a
+
a3005a
+  if (serv->flags & SERV_HAS_DOMAIN)
a3005a
+		  /* .example.com is valid */
a3005a
+    while (*domain == '.')
a3005a
+      domain++;
a3005a
+
a3005a
+  return domain;
a3005a
+}
a3005a
+
a3005a
+struct server_domain *server_domain_find_domain(const char *domain)
a3005a
+{
a3005a
+  struct server_domain *sd;
a3005a
+  for (sd = daemon->server_domains; sd; sd = sd->next)
a3005a
+    if ((!domain && sd->domain == domain) || (domain && sd->domain && hostname_isequal(domain, sd->domain)))
a3005a
+      return sd;
a3005a
+  return NULL;
a3005a
+}
a3005a
+
a3005a
+/**< Test structure has already set domain pointer.
a3005a
+ *
a3005a
+ * If not, create a new record. */
a3005a
+struct server_domain *server_domain_new(struct server *serv)
a3005a
+{
a3005a
+  struct server_domain *sd;
a3005a
+
a3005a
+  if ((sd = whine_malloc(sizeof(struct server_domain))))
a3005a
+    {
a3005a
+      const char *domain = server_get_domain(serv);
a3005a
+
a3005a
+      /* Ensure all serv->domain values have own record in server_domain.
a3005a
+       * Add a new record. */
a3005a
+      if (domain)
a3005a
+	{
a3005a
+	  size_t len = strlen(domain)+1;
a3005a
+	  sd->domain = whine_malloc(len);
a3005a
+	  if (sd->domain)
a3005a
+	    memcpy(sd->domain, domain, len);
a3005a
+	}
a3005a
+      sd->next = daemon->server_domains;
a3005a
+      serv->serv_domain = sd;
a3005a
+      daemon->server_domains = sd;
a3005a
+    }
a3005a
+  return sd;
a3005a
+}
a3005a
+
a3005a
+/**< Test structure has already set domain pointer.
a3005a
+ *
a3005a
+ * If not, create a new record. */
a3005a
+static void server_domain_check(struct server *serv)
a3005a
+{
a3005a
+  struct server_domain *sd = serv->serv_domain;
a3005a
+
a3005a
+  if (sd)
a3005a
+    sd->flags &= (~SERV_MARK); /* found domain, mark active */
a3005a
+  else
a3005a
+    server_domain_new(serv);
a3005a
+}
a3005a
+
a3005a
 void check_servers(void)
a3005a
 {
a3005a
   struct irec *iface;
a3005a
   struct server *serv;
a3005a
+  struct server_domain *sd;
a3005a
   struct serverfd *sfd, *tmp, **up;
a3005a
   int port = 0, count;
a3005a
   int locals = 0;
a3005a
@@ -1522,10 +1607,14 @@ void check_servers(void)
a3005a
   for (sfd = daemon->sfds; sfd; sfd = sfd->next)
a3005a
     sfd->used = 0;
a3005a
 
a3005a
+  for (sd = daemon->server_domains; sd; sd = sd->next)
a3005a
+    sd->flags |= SERV_MARK;
a3005a
+
a3005a
   for (count = 0, serv = daemon->servers; serv; serv = serv->next)
a3005a
     {
a3005a
       if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
a3005a
 	{
a3005a
+
a3005a
 	  /* Init edns_pktsz for newly created server records. */
a3005a
 	  if (serv->edns_pktsz == 0)
a3005a
 	    serv->edns_pktsz = daemon->edns_pktsz;
a3005a
@@ -1541,12 +1630,8 @@ void check_servers(void)
a3005a
 	      if (serv->flags & SERV_HAS_DOMAIN)
a3005a
 		{
a3005a
 		  struct ds_config *ds;
a3005a
-		  char *domain = serv->domain;
a3005a
-		  
a3005a
-		  /* .example.com is valid */
a3005a
-		  while (*domain == '.')
a3005a
-		    domain++;
a3005a
-		  
a3005a
+		  const char *domain = server_get_domain(serv);
a3005a
+
a3005a
 		  for (ds = daemon->ds; ds; ds = ds->next)
a3005a
 		    if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
a3005a
 		      break;
a3005a
@@ -1556,7 +1641,6 @@ void check_servers(void)
a3005a
 		}
a3005a
 	    }
a3005a
 #endif
a3005a
-
a3005a
 	  port = prettyprint_addr(&serv->addr, daemon->namebuff);
a3005a
 	  
a3005a
 	  /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
a3005a
@@ -1591,6 +1675,8 @@ void check_servers(void)
a3005a
 	  
a3005a
 	  if (serv->sfd)
a3005a
 	    serv->sfd->used = 1;
a3005a
+
a3005a
+	  server_domain_check(serv);
a3005a
 	}
a3005a
       
a3005a
       if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
a3005a
@@ -1653,6 +1739,7 @@ void check_servers(void)
a3005a
 	up = &sfd->next;
a3005a
     }
a3005a
   
a3005a
+  server_domains_cleanup();
a3005a
   cleanup_servers();
a3005a
 }
a3005a
 
a3005a
diff --git a/src/option.c b/src/option.c
a3005a
index abc5a48..6fa7bbd 100644
a3005a
--- a/src/option.c
a3005a
+++ b/src/option.c
a3005a
@@ -906,6 +906,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
a3005a
   p += sprintf(p, "in-addr.arpa");
a3005a
   
a3005a
   serv->flags = SERV_HAS_DOMAIN;
a3005a
+  server_domain_new(serv);
a3005a
   serv->next = daemon->servers;
a3005a
   daemon->servers = serv;
a3005a
 
a3005a
@@ -930,6 +931,7 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
a3005a
   p += sprintf(p, "ip6.arpa");
a3005a
   
a3005a
   serv->flags = SERV_HAS_DOMAIN;
a3005a
+  server_domain_new(serv);
a3005a
   serv->next = daemon->servers;
a3005a
   daemon->servers = serv;
a3005a
   
a3005a
@@ -2231,6 +2233,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
a3005a
 				  memset(serv, 0, sizeof(struct server));
a3005a
 				  serv->domain = d;
a3005a
 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
a3005a
+				  server_domain_new(serv);
a3005a
 				  serv->next = daemon->servers;
a3005a
 				  daemon->servers = serv;
a3005a
 				}
a3005a
@@ -2275,6 +2278,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
a3005a
 				  memset(serv, 0, sizeof(struct server));
a3005a
 				  serv->domain = d;
a3005a
 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
a3005a
+				  server_domain_new(serv);
a3005a
 				  serv->next = daemon->servers;
a3005a
 				  daemon->servers = serv;
a3005a
 				}
a3005a
@@ -2525,6 +2529,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
a3005a
 		newlist = serv;
a3005a
 		serv->domain = domain;
a3005a
 		serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
a3005a
+		server_domain_new(serv);
a3005a
 		arg = end;
a3005a
 		if (rebind)
a3005a
 		  break;
a3005a
-- 
a3005a
2.34.1
a3005a