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

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