d7059b
From 11ab42e63f9089c4c14a391f30175d4c2d071e99 Mon Sep 17 00:00:00 2001
d7059b
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
d7059b
Date: Mon, 15 Jul 2019 17:13:12 +0200
d7059b
Subject: [PATCH 4/5] Handle listening on duplicate addresses
d7059b
d7059b
Save listening address into listener. Use it to find existing listeners
d7059b
before creating new one. If it exist, increase just used counter.
d7059b
Release only listeners not already used.
d7059b
d7059b
Duplicates family in listener.
d7059b
---
d7059b
 src/dnsmasq.h |   3 +-
d7059b
 src/network.c | 115 ++++++++++++++++++++++++++++++++++++--------------
d7059b
 2 files changed, 85 insertions(+), 33 deletions(-)
d7059b
d7059b
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
d7059b
index 89d138a..3b3f6ef 100644
d7059b
--- a/src/dnsmasq.h
d7059b
+++ b/src/dnsmasq.h
d7059b
@@ -526,7 +526,8 @@ struct irec {
d7059b
 };
d7059b
 
d7059b
 struct listener {
d7059b
-  int fd, tcpfd, tftpfd, family;
d7059b
+  int fd, tcpfd, tftpfd, family, used;
d7059b
+  union mysockaddr addr;
d7059b
   struct irec *iface; /* only sometimes valid for non-wildcard */
d7059b
   struct listener *next;
d7059b
 };
d7059b
diff --git a/src/network.c b/src/network.c
d7059b
index d6d4b01..4bbd810 100644
d7059b
--- a/src/network.c
d7059b
+++ b/src/network.c
d7059b
@@ -577,6 +577,56 @@ static void clean_interfaces()
d7059b
   }
d7059b
 }
d7059b
 
d7059b
+/** Release listener if no other interface needs it.
d7059b
+ *
d7059b
+ * @return 1 if released, 0 if still required
d7059b
+ */
d7059b
+static int release_listener(struct listener *l)
d7059b
+{
d7059b
+  if (l->used > 1)
d7059b
+    {
d7059b
+      struct irec *iface;
d7059b
+      for (iface = daemon->interfaces; iface; iface = iface->next)
d7059b
+	if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
d7059b
+	  {
d7059b
+	    if (iface->found)
d7059b
+	      {
d7059b
+		/* update listener to point to active interface instead */
d7059b
+		if (!l->iface->found)
d7059b
+		  l->iface = iface;
d7059b
+	      }
d7059b
+	    else
d7059b
+	      {
d7059b
+		l->used--;
d7059b
+		iface->done = 0;
d7059b
+	      }
d7059b
+	  }
d7059b
+
d7059b
+      /* Someone is still using this listener, skip its deletion */
d7059b
+      if (l->used > 0)
d7059b
+	return 0;
d7059b
+    }
d7059b
+
d7059b
+  if (l->iface->done)
d7059b
+    {
d7059b
+      (void)prettyprint_addr(&l->iface->addr, daemon->addrbuff);
d7059b
+      my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
d7059b
+		l->iface->name, l->iface->index, daemon->addrbuff);
d7059b
+      /* In case it ever returns */
d7059b
+      l->iface->done = 0;
d7059b
+    }
d7059b
+
d7059b
+  if (l->fd != -1)
d7059b
+    close(l->fd);
d7059b
+  if (l->tcpfd != -1)
d7059b
+    close(l->tcpfd);
d7059b
+  if (l->tftpfd != -1)
d7059b
+    close(l->tftpfd);
d7059b
+
d7059b
+  free(l);
d7059b
+  return 1;
d7059b
+}
d7059b
+
d7059b
 int enumerate_interfaces(int reset)
d7059b
 {
d7059b
   static struct addrlist *spare = NULL;
d7059b
@@ -684,29 +734,10 @@ int enumerate_interfaces(int reset)
d7059b
 	  
d7059b
 	  if (!l->iface || l->iface->found)
d7059b
 	    up = &l->next;
d7059b
-	  else
d7059b
+	  else if (release_listener(l))
d7059b
 	    {
d7059b
-	      *up = l->next;
d7059b
-	      if (l->iface->done)
d7059b
-	        {
d7059b
-	          iface = l->iface;
d7059b
-	          (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
d7059b
-	          my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
d7059b
-	                    iface->name, iface->index, daemon->addrbuff);
d7059b
-	        }
d7059b
-	      
d7059b
-	      /* In case it ever returns */
d7059b
-	      l->iface->done = 0;
d7059b
-	      
d7059b
-	      if (l->fd != -1)
d7059b
-		close(l->fd);
d7059b
-	      if (l->tcpfd != -1)
d7059b
-		close(l->tcpfd);
d7059b
-	      if (l->tftpfd != -1)
d7059b
-		close(l->tftpfd);
d7059b
-	      
d7059b
-	      free(l);
d7059b
-	      freed = 1;
d7059b
+	      *up = tmp;
d7059b
+		freed = 1;
d7059b
 	    }
d7059b
 	}
d7059b
 
d7059b
@@ -959,7 +990,9 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
d7059b
       l->family = addr->sa.sa_family;
d7059b
       l->fd = fd;
d7059b
       l->tcpfd = tcpfd;
d7059b
-      l->tftpfd = tftpfd;	
d7059b
+      l->tftpfd = tftpfd;
d7059b
+      l->addr = *addr;
d7059b
+      l->used = 1;
d7059b
       l->iface = NULL;
d7059b
     }
d7059b
 
d7059b
@@ -1000,23 +1033,41 @@ void create_wildcard_listeners(void)
d7059b
   daemon->listeners = l;
d7059b
 }
d7059b
 
d7059b
+static struct listener *find_listener(union mysockaddr *addr)
d7059b
+{
d7059b
+  struct listener *l;
d7059b
+  for (l = daemon->listeners; l; l = l->next)
d7059b
+    if (sockaddr_isequal(&l->addr, addr))
d7059b
+      return l;
d7059b
+  return NULL;
d7059b
+}
d7059b
+
d7059b
 void create_bound_listeners(int dienow)
d7059b
 {
d7059b
   struct listener *new;
d7059b
   struct irec *iface;
d7059b
   struct iname *if_tmp;
d7059b
+  struct listener *existing;
d7059b
 
d7059b
   for (iface = daemon->interfaces; iface; iface = iface->next)
d7059b
-    if (!iface->done && !iface->dad && iface->found &&
d7059b
-	(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
d7059b
+    if (!iface->done && !iface->dad && iface->found)
d7059b
       {
d7059b
-	new->iface = iface;
d7059b
-	new->next = daemon->listeners;
d7059b
-	daemon->listeners = new;
d7059b
-	iface->done = 1;
d7059b
-	(void)prettyprint_addr(&iface->addr, daemon->addrbuff);
d7059b
-	my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
d7059b
-	          iface->name, iface->index, daemon->addrbuff);
d7059b
+	existing = find_listener(&iface->addr);
d7059b
+	if (existing)
d7059b
+	  {
d7059b
+	    iface->done = 1;
d7059b
+	    existing->used++; /* increase usage counter */
d7059b
+	  }
d7059b
+	else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
d7059b
+	  {
d7059b
+	    new->iface = iface;
d7059b
+	    new->next = daemon->listeners;
d7059b
+	    daemon->listeners = new;
d7059b
+	    iface->done = 1;
d7059b
+	    (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
d7059b
+	    my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
d7059b
+		      iface->name, iface->index, daemon->addrbuff);
d7059b
+	  }
d7059b
       }
d7059b
 
d7059b
   /* Check for --listen-address options that haven't been used because there's
d7059b
-- 
d7059b
2.20.1
d7059b