Hi,
because there is more patches, I created a pull request in my fork on
github [1]. I think it is somehow more handy than attachments here. I
think all of them are already sent. Attaching complete set here again in
one place. Also made Fedora bug #1728701 [2].

We need a fix because we are hitting this issue in OpenStack a lot. I
would like to include fix and would like it to be the same way on
upstream. If there is different way to fix it, please say so.

Any more opinions on patches 4 and 5?

1. https://github.com/InfrastructureServices/dnsmasq/pull/1
2. https://bugzilla.redhat.com/show_bug.cgi?id=1728701

On 7/10/19 1:34 PM, Vladislav Grishenko wrote:
> Hi Petr,
> 
>> Not tested this specific case, but I think it should be handled correctly, 
>> unlike previous code. Because it now compares also interface index, it will 
>> mark existing entry as found only if interface index also match. If it does 
>> not, new entry is created with correct index instead.
> 
> Checked, unfortunately interface index comparison breaks the things.
> If there's 2+ interface with same address on startup, no error is happen, 
> single TCP and multiple UDP (unlike before) sockets are created, on any of 
> such interface shutdown - thins single TCP socket is closed (unlike before), 
> so there are noting listens on TCP:53 after that.
> If there's only one interface on startup - single TCP&UDP sockets are 
> created, on subsequent interface up with the same address - bind error raised 
> and only UDP socket is created additionally (unlike before).

Fixed now.
> 
> At the moment, dnsmasq logic expects single TCP/UDP socket per address even 
> for multiple interfaces.
> For example, comment in iface_allowed() states that:
>       /* check whether the interface IP has been added already
>        * we call this routine multiple times */
> So, I'm afraid, seems proposed changes does not play well with that.
> How do you think, can it be solved too?
> Reproduction this case is quite easy, just need to create dummy interface 
> with same address (different netmask) and up/down it.
> 
>> Ok, I forgot to follow style on 3rd patch. Attached fixed formatting and 
>> removed debug log on interface removal.
> 
> Thanks,  fyi sed -r 's/[ ]{8}/\t/' is missed too.
> 
>> I think that is better to state explicitly return value is not used.
> 
> I think that would be better to rip it off from functional patch, and let it 
> be as separate full patch for all prettyprint_* instances not just for some 
> selected.
> At the other hand, with no __attribute__((warn_unused_result)) it will not 
> generate warning anyway.

I changed only things related to changes I did. We sometime run Coverity
scans on the codebase, and such issues arise there. So I make it the way
no new issues are discovered by my changes.

On the other hand, maybe it should print complete address with port as
well. Precise information does not hurt, even when port would be a bit
repeating. Now it includes also port. These are just debug information
after all, no need for them to be shortest possible.
> 
> Best Regards, Vladislav Grishenko
> 
> -----Original Message-----
> From: Petr Mensik <pemen...@redhat.com> 
> Sent: Wednesday, July 10, 2019 3:01 PM
> To: Vladislav Grishenko <themiron...@gmail.com>; 
> dnsmasq-discuss@lists.thekelleys.org.uk
> Subject: Re: [Dnsmasq-discuss] [PATCH] Issues with TCP queries on recreated 
> interfaces.
> 
> Hi Vladislav
> 
> On 7/9/19 10:00 PM, Vladislav Grishenko wrote:
>> Hi Petr,
>>
>> Regarding 0002-Compare-address-and-interface-index-for-allowed-inte.patch, 
>> does it support case with different valid interfaces with the same address?
>> For example:
>>      eth0 192.168.1.1/24
>>      tun0 192.168.1.1./16 (created/destroyed dynamically)
> 
> Not tested this specific case, but I think it should be handled correctly, 
> unlike previous code. Because it now compares also interface index, it will 
> mark existing entry as found only if interface index also match. If it does 
> not, new entry is created with correct index instead.
> It should work, unlike previous code, it should keep both interface addresses 
> stored separately.
> 
> If tun0 is often destroyed and recreated, number of interfaces records might 
> grow. That is reason for patch #3, which removes dropped interfaces after 
> creating new ones.
>>
>> Regarding appearance, seems newly added code doesn’t fully follow dnsmasq 
>> code style in several places:
>> * indentation (should be ident ==2 spaces, 8 spaces == \t)
>> * brackets on the same code lines
> Ok, I forgot to follow style on 3rd patch. Attached fixed formatting and 
> removed debug log on interface removal.
>> * function args on the next line are not aligned with the first 
>> argument
>> * prettyprint_addr() result is forcibly ignored with (void) unlike 
>> other places
> I think that is better to state explicitly return value is not used.
>>
>> Best Regards, Vladislav Grishenko
>>
>> -----Original Message-----
>> From: Dnsmasq-discuss 
>> <dnsmasq-discuss-boun...@lists.thekelleys.org.uk> On Behalf Of Petr 
>> Mensik
>> Sent: Tuesday, July 9, 2019 5:31 PM
>> To: dnsmasq-discuss@lists.thekelleys.org.uk
>> Subject: [Dnsmasq-discuss] [PATCH] Issues with TCP queries on recreated 
>> interfaces.
>>
>> Hello Simon and others,
>>
>> we have discovered issues with TCP DNS query on dnsmasq, when running in 
>> bind-dynamic or bind-interfaces mode. dnsmasq scans automatically new 
>> interfaces or do that on new query in second case. However, because used 
>> speedup comparing only IP adresses in iface_allowed function, it never gets 
>> updated index of an interface.
>>
>> In case where named interface is destroyed and created again, that drops TCP 
>> queries on that interface. They are checked for incoming interface number. 
>> If such number is not found in interfaces list, query is denied.
>>
>> Luckily, there was a bug in checking, hiding this problem from usual 
>> configuration. If IPv6 address is enabled on the new device, new iface entry 
>> would be created, because scope_id of sockaddr_in6 does not match previous. 
>> That makes even IPv4 queries succeed.
>>
>> Bug on bugzilla [1] is partly private.
>>
>> I propose three changes. First is just helper to log what happens with 
>> listeners on bind-dynamic configuration.
>>
>> Second is the most important. Create new interface every time index changes. 
>> Also test address family of incoming TCP query when checking allowed clients.
>>
>> Third is cleanup of unused interfaces. On some virtual machines hosts, 
>> interfaces may often be created and destroyed. It might have negative effect 
>> on walking trough interfaces list. I think listeners should be garbage 
>> collected also on bind-interfaces configuration. But for now, release memory 
>> for unused interfaces at least for bind-dynamic.
>>
>> 1. https://bugzilla.redhat.com/show_bug.cgi?id=1721668


-- 
Petr Menšík
Software Engineer
Red Hat, http://www.redhat.com/
email: pemen...@redhat.com  PGP: 65C6C973
From 3bb9e937c811e4aca26d5efaa1cb8cf50cfdda43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Mon, 15 Jul 2019 17:16:44 +0200
Subject: [PATCH 5/5] Remove duplicate address family from listener

Since address already contain family, remove separate family from
listener. Use now family from address itself.
---
 src/dnsmasq.h |  2 +-
 src/forward.c | 27 ++++++++++++++-------------
 src/network.c |  1 -
 src/tftp.c    | 29 +++++++++++++++--------------
 4 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f31ec6a..978d02f 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -563,7 +563,7 @@ struct irec {
 };
 
 struct listener {
-  int fd, tcpfd, tftpfd, family, used;
+  int fd, tcpfd, tftpfd, used;
   union mysockaddr addr;
   struct irec *iface; /* only sometimes valid for non-wildcard */
   struct listener *next;
diff --git a/src/forward.c b/src/forward.c
index dd22a45..d8bbe04 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -1271,8 +1271,9 @@ void receive_query(struct listener *listen, time_t now)
 		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
 #endif
   } control_u;
+  int family = listen->addr.sa.sa_family;
    /* Can always get recvd interface for IPv6 */
-  int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
+  int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
 
   /* packet buffer overwritten */
   daemon->srv_save = NULL;
@@ -1284,7 +1285,7 @@ void receive_query(struct listener *listen, time_t now)
     {
       auth_dns = listen->iface->dns_auth;
      
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	{
 	  dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
 	  netmask = listen->iface->netmask;
@@ -1314,9 +1315,9 @@ void receive_query(struct listener *listen, time_t now)
      information disclosure. */
   memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
   
-  source_addr.sa.sa_family = listen->family;
+  source_addr.sa.sa_family = family;
   
-  if (listen->family == AF_INET)
+  if (family == AF_INET)
     {
        /* Source-port == 0 is an error, we can't send back to that. 
 	  http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
@@ -1336,7 +1337,7 @@ void receive_query(struct listener *listen, time_t now)
     {
       struct addrlist *addr;
 
-      if (listen->family == AF_INET6) 
+      if (family == AF_INET6) 
 	{
 	  for (addr = daemon->interface_addrs; addr; addr = addr->next)
 	    if ((addr->flags & ADDRLIST_IPV6) &&
@@ -1374,7 +1375,7 @@ void receive_query(struct listener *listen, time_t now)
 	return;
 
 #if defined(HAVE_LINUX_NETWORK)
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
 	    {
@@ -1387,7 +1388,7 @@ void receive_query(struct listener *listen, time_t now)
 	      if_index = p.p->ipi_ifindex;
 	    }
 #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	{
 	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	    {
@@ -1412,7 +1413,7 @@ void receive_query(struct listener *listen, time_t now)
 	}
 #endif
       
-      if (listen->family == AF_INET6)
+      if (family == AF_INET6)
 	{
 	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
@@ -1433,16 +1434,16 @@ void receive_query(struct listener *listen, time_t now)
       if (!indextoname(listen->fd, if_index, ifr.ifr_name))
 	return;
       
-      if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
+      if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
 	{
 	   if (!option_bool(OPT_CLEVERBIND))
 	     enumerate_interfaces(0); 
-	   if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
-	       !label_exception(if_index, listen->family, &dst_addr))
+	   if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
+	       !label_exception(if_index, family, &dst_addr))
 	     return;
 	}
 
-      if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
+      if (family == AF_INET && option_bool(OPT_LOCALISE))
 	{
 	  struct irec *iface;
 	  
@@ -1487,7 +1488,7 @@ void receive_query(struct listener *listen, time_t now)
 #endif
       char *types = querystr(auth_dns ? "auth" : "query", type);
       
-      if (listen->family == AF_INET) 
+      if (family == AF_INET) 
 	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
 		  (union all_addr *)&source_addr.in.sin_addr, types);
       else
diff --git a/src/network.c b/src/network.c
index fc2af05..c57d06c 100644
--- a/src/network.c
+++ b/src/network.c
@@ -960,7 +960,6 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
     {
       l = safe_malloc(sizeof(struct listener));
       l->next = NULL;
-      l->family = addr->sa.sa_family;
       l->fd = fd;
       l->tcpfd = tcpfd;
       l->tftpfd = tftpfd;
diff --git a/src/tftp.c b/src/tftp.c
index 435b216..13b2bc0 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -60,8 +60,9 @@ void tftp_request(struct listener *listen, time_t now)
   char *prefix = daemon->tftp_prefix;
   struct tftp_prefix *pref;
   union all_addr addra;
+  int family = listen->addr.sa.sa_family;
   /* Can always get recvd interface for IPv6 */
-  int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
+  int check_dest = !option_bool(OPT_NOWILD) || family == AF_INET6;
   union {
     struct cmsghdr align; /* this ensures alignment */
     char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
@@ -118,10 +119,10 @@ void tftp_request(struct listener *listen, time_t now)
       if (msg.msg_controllen < sizeof(struct cmsghdr))
         return;
       
-      addr.sa.sa_family = listen->family;
+      addr.sa.sa_family = family;
       
 #if defined(HAVE_LINUX_NETWORK)
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
 	    {
@@ -135,7 +136,7 @@ void tftp_request(struct listener *listen, time_t now)
 	    }
       
 #elif defined(HAVE_SOLARIS_NETWORK)
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	  {
 	    union {
@@ -151,7 +152,7 @@ void tftp_request(struct listener *listen, time_t now)
 	  }
       
 #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
-      if (listen->family == AF_INET)
+      if (family == AF_INET)
 	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
 	  {
 	    union {
@@ -168,7 +169,7 @@ void tftp_request(struct listener *listen, time_t now)
 	  
 #endif
 
-      if (listen->family == AF_INET6)
+      if (family == AF_INET6)
         {
           for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
             if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
@@ -191,7 +192,7 @@ void tftp_request(struct listener *listen, time_t now)
       
       addra.addr4 = addr.in.sin_addr;
 
-      if (listen->family == AF_INET6)
+      if (family == AF_INET6)
 	addra.addr6 = addr.in6.sin6_addr;
 
       if (daemon->tftp_interfaces)
@@ -207,12 +208,12 @@ void tftp_request(struct listener *listen, time_t now)
       else
 	{
 	  /* Do the same as DHCP */
-	  if (!iface_check(listen->family, &addra, name, NULL))
+	  if (!iface_check(family, &addra, name, NULL))
 	    {
 	      if (!option_bool(OPT_CLEVERBIND))
 		enumerate_interfaces(0); 
-	      if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
-		  !label_exception(if_index, listen->family, &addra))
+	      if (!loopback_exception(listen->tftpfd, family, &addra, name) &&
+		  !label_exception(if_index, family, &addra))
 		return;
 	    }
 	  
@@ -245,7 +246,7 @@ void tftp_request(struct listener *listen, time_t now)
 	  prefix = pref->prefix;  
     }
 
-  if (listen->family == AF_INET)
+  if (family == AF_INET)
     {
       addr.in.sin_port = htons(port);
 #ifdef HAVE_SOCKADDR_SA_LEN
@@ -265,7 +266,7 @@ void tftp_request(struct listener *listen, time_t now)
   if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
     return;
   
-  if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
+  if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
     {
       free(transfer);
       return;
@@ -296,7 +297,7 @@ void tftp_request(struct listener *listen, time_t now)
 	    {
 	      if (++port <= daemon->end_tftp_port)
 		{ 
-		  if (listen->family == AF_INET)
+		  if (family == AF_INET)
 		    addr.in.sin_port = htons(port);
 		  else
 		    addr.in6.sin6_port = htons(port);
@@ -334,7 +335,7 @@ void tftp_request(struct listener *listen, time_t now)
 	      if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
 		{
 		  /* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
-		  int overhead = (listen->family == AF_INET) ? 32 : 52;
+		  int overhead = (family == AF_INET) ? 32 : 52;
 		  transfer->blocksize = atoi(opt);
 		  if (transfer->blocksize < 1)
 		    transfer->blocksize = 1;
-- 
2.20.1

From 9b20139cf802464bafad7123970e5e31f653388d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Mon, 15 Jul 2019 17:13:12 +0200
Subject: [PATCH 4/5] Handle listening on duplicate addresses

Save listening address into listener. Use it to find existing listeners
before creating new one. If it exist, increase just used counter.
Release only listeners not already used.

Duplicates family in listener.
---
 src/dnsmasq.h |   3 +-
 src/network.c | 115 ++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 85 insertions(+), 33 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index ff3204a..f31ec6a 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -563,7 +563,8 @@ struct irec {
 };
 
 struct listener {
-  int fd, tcpfd, tftpfd, family;
+  int fd, tcpfd, tftpfd, family, used;
+  union mysockaddr addr;
   struct irec *iface; /* only sometimes valid for non-wildcard */
   struct listener *next;
 };
diff --git a/src/network.c b/src/network.c
index 44bb757..fc2af05 100644
--- a/src/network.c
+++ b/src/network.c
@@ -557,6 +557,56 @@ static void clean_interfaces()
   }
 }
 
+/** Release listener if no other interface needs it.
+ *
+ * @return 1 if released, 0 if still required
+ */
+static int release_listener(struct listener *l)
+{
+  if (l->used > 1)
+    {
+      struct irec *iface;
+      for (iface = daemon->interfaces; iface; iface = iface->next)
+	if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
+	  {
+	    if (iface->found)
+	      {
+		/* update listener to point to active interface instead */
+		if (!l->iface->found)
+		  l->iface = iface;
+	      }
+	    else
+	      {
+		l->used--;
+		iface->done = 0;
+	      }
+	  }
+
+      /* Someone is still using this listener, skip its deletion */
+      if (l->used > 0)
+	return 0;
+    }
+
+  if (l->iface->done)
+    {
+      (void)prettyprint_addr(&l->iface->addr, daemon->addrbuff);
+      my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
+		l->iface->name, l->iface->index, daemon->addrbuff);
+      /* In case it ever returns */
+      l->iface->done = 0;
+    }
+
+  if (l->fd != -1)
+    close(l->fd);
+  if (l->tcpfd != -1)
+    close(l->tcpfd);
+  if (l->tftpfd != -1)
+    close(l->tftpfd);
+
+  free(l);
+  return 1;
+}
+
 int enumerate_interfaces(int reset)
 {
   static struct addrlist *spare = NULL;
@@ -662,29 +712,10 @@ int enumerate_interfaces(int reset)
 	  
 	  if (!l->iface || l->iface->found)
 	    up = &l->next;
-	  else
+	  else if (release_listener(l))
 	    {
-	      *up = l->next;
-	      if (l->iface->done)
-	        {
-	          iface = l->iface;
-	          (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
-	          my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
-	                    iface->name, iface->index, daemon->addrbuff);
-	        }
-	      
-	      /* In case it ever returns */
-	      l->iface->done = 0;
-	      
-	      if (l->fd != -1)
-		close(l->fd);
-	      if (l->tcpfd != -1)
-		close(l->tcpfd);
-	      if (l->tftpfd != -1)
-		close(l->tftpfd);
-	      
-	      free(l);
-	      freed = 1;
+	      *up = tmp;
+		freed = 1;
 	    }
 	}
 
@@ -932,7 +963,9 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
       l->family = addr->sa.sa_family;
       l->fd = fd;
       l->tcpfd = tcpfd;
-      l->tftpfd = tftpfd;	
+      l->tftpfd = tftpfd;
+      l->addr = *addr;
+      l->used = 1;
       l->iface = NULL;
     }
 
@@ -971,23 +1004,41 @@ void create_wildcard_listeners(void)
   daemon->listeners = l;
 }
 
+static struct listener *find_listener(union mysockaddr *addr)
+{
+  struct listener *l;
+  for (l = daemon->listeners; l; l = l->next)
+    if (sockaddr_isequal(&l->addr, addr))
+      return l;
+  return NULL;
+}
+
 void create_bound_listeners(int dienow)
 {
   struct listener *new;
   struct irec *iface;
   struct iname *if_tmp;
+  struct listener *existing;
 
   for (iface = daemon->interfaces; iface; iface = iface->next)
-    if (!iface->done && !iface->dad && iface->found &&
-	(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
+    if (!iface->done && !iface->dad && iface->found)
       {
-	new->iface = iface;
-	new->next = daemon->listeners;
-	daemon->listeners = new;
-	iface->done = 1;
-	(void)prettyprint_addr(&iface->addr, daemon->addrbuff);
-	my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
-	          iface->name, iface->index, daemon->addrbuff);
+	existing = find_listener(&iface->addr);
+	if (existing)
+	  {
+	    iface->done = 1;
+	    existing->used++; /* increase usage counter */
+	  }
+	else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
+	  {
+	    new->iface = iface;
+	    new->next = daemon->listeners;
+	    daemon->listeners = new;
+	    iface->done = 1;
+	    (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+	    my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
+		      iface->name, iface->index, daemon->addrbuff);
+	  }
       }
 
   /* Check for --listen-address options that haven't been used because there's
-- 
2.20.1

From 46a77df93b9e5b04f84a031aede0954c0641fe10 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemen...@redhat.com>
Date: Tue, 9 Jul 2019 14:05:59 +0200
Subject: [PATCH 3/5] Cleanup interfaces no longer available

Clean addresses and interfaces not found after enumerate. Free unused
records to speed up checking active interfaces and reduce used memory.
---
 src/network.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/network.c b/src/network.c
index f487617..44bb757 100644
--- a/src/network.c
+++ b/src/network.c
@@ -533,7 +533,30 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
 
   return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
 }
-   
+
+/*
+ * Clean old interfaces no longer found.
+ */
+static void clean_interfaces()
+{
+  struct irec *iface;
+  struct irec **up = &daemon->interfaces;
+
+  for (iface = *up; iface; iface = *up)
+  {
+    if (!iface->found && !iface->done)
+      {
+        *up = iface->next;
+        free(iface->name);
+        free(iface);
+      }
+    else
+      {
+        up = &iface->next;
+      }
+  }
+}
+
 int enumerate_interfaces(int reset)
 {
   static struct addrlist *spare = NULL;
@@ -631,6 +654,7 @@ int enumerate_interfaces(int reset)
 	 in OPT_CLEVERBIND mode, that at listener will just disappear after
 	 a call to enumerate_interfaces, this is checked OK on all calls. */
       struct listener *l, *tmp, **up;
+      int freed = 0;
       
       for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
 	{
@@ -660,10 +684,14 @@ int enumerate_interfaces(int reset)
 		close(l->tftpfd);
 	      
 	      free(l);
+	      freed = 1;
 	    }
 	}
+
+      if (freed)
+	clean_interfaces();
     }
-  
+
   errno = errsave;
   spare = param.spare;
     
-- 
2.20.1

From e3a22a2ad93c518507cd1b41fabbf0c1160daef1 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemen...@redhat.com>
Date: Wed, 3 Jul 2019 17:02:16 +0200
Subject: [PATCH 2/5] Compare address and interface index for allowed interface

If interface is recreated with the same address but different index, it
would not change any other parameter.

Test also address family on incoming TCP queries.
---
 src/dnsmasq.c | 3 ++-
 src/network.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 704475f..939e69e 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1792,7 +1792,8 @@ static void check_dns_listeners(time_t now)
 		    addr.addr4 = tcp_addr.in.sin_addr;
 		  
 		  for (iface = daemon->interfaces; iface; iface = iface->next)
-		    if (iface->index == if_index)
+		    if (iface->index == if_index &&
+		        iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
 		      break;
 		  
 		  if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
diff --git a/src/network.c b/src/network.c
index 1fe25f7..f487617 100644
--- a/src/network.c
+++ b/src/network.c
@@ -388,10 +388,11 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
   /* check whether the interface IP has been added already 
      we call this routine multiple times. */
   for (iface = daemon->interfaces; iface; iface = iface->next) 
-    if (sockaddr_isequal(&iface->addr, addr))
+    if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
       {
 	iface->dad = !!(iface_flags & IFACE_TENTATIVE);
 	iface->found = 1; /* for garbage collection */
+	iface->netmask = netmask;
 	return 1;
       }
 
-- 
2.20.1

From 2d7212c79ea76a297c3e9107c5e2e5791c3d3a1d Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemen...@redhat.com>
Date: Thu, 4 Jul 2019 20:28:08 +0200
Subject: [PATCH 1/5] Log listening on new interfaces

Log in debug mode listening on interfaces. They can be dynamically
found, include interface number, since it is checked on TCP connections.
Print also addresses found on them.
---
 src/network.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/network.c b/src/network.c
index c1077b4..1fe25f7 100644
--- a/src/network.c
+++ b/src/network.c
@@ -640,6 +640,13 @@ int enumerate_interfaces(int reset)
 	  else
 	    {
 	      *up = l->next;
+	      if (l->iface->done)
+	        {
+	          iface = l->iface;
+	          (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+	          my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
+	                    iface->name, iface->index, daemon->addrbuff);
+	        }
 	      
 	      /* In case it ever returns */
 	      l->iface->done = 0;
@@ -949,6 +956,9 @@ void create_bound_listeners(int dienow)
 	new->next = daemon->listeners;
 	daemon->listeners = new;
 	iface->done = 1;
+	(void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+	my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
+	          iface->name, iface->index, daemon->addrbuff);
       }
 
   /* Check for --listen-address options that haven't been used because there's
@@ -968,6 +978,8 @@ void create_bound_listeners(int dienow)
       {
 	new->next = daemon->listeners;
 	daemon->listeners = new;
+	(void)prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
+	my_syslog(LOG_DEBUG, _("listening on %s"), daemon->addrbuff);
       }
 }
 
-- 
2.20.1

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss

Reply via email to