diff --git a/SOURCES/dnsmasq-2.79-mixed-family-failed.patch b/SOURCES/dnsmasq-2.79-mixed-family-failed.patch
new file mode 100644
index 0000000..c241d15
--- /dev/null
+++ b/SOURCES/dnsmasq-2.79-mixed-family-failed.patch
@@ -0,0 +1,79 @@
+From 4348c43be45d20aba87ee5564ecdde10aff7e5e7 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Fri, 22 Jan 2021 16:49:12 +0000
+Subject: [PATCH] Move fd into frec_src, fixes
+ 15b60ddf935a531269bb8c68198de012a4967156
+
+If identical queries from IPv4 and IPv6 sources are combined by the
+new code added in 15b60ddf935a531269bb8c68198de012a4967156 then replies
+can end up being sent via the wrong family of socket. The ->fd
+should be per query, not per-question.
+
+In bind-interfaces mode, this could also result in replies being sent
+via the wrong socket even when IPv4/IPV6 issues are not in play.
+
+(cherry picked from commit 04490bf622ac84891aad6f2dd2edf83725decdee)
+
+Fix for 12af2b171de0d678d98583e2190789e544440e02
+
+(cherry picked from commit 3f535da79e7a42104543ef5c7b5fa2bed819a78b)
+---
+ src/dnsmasq.h | 3 ++-
+ src/forward.c | 5 +++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index f3bbb4e..e7e1693 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -632,6 +632,7 @@ struct frec {
+     union mysockaddr source;
+     struct all_addr dest;
+     unsigned int iface, log_id;
++    int fd;
+     unsigned short orig_id;
+     struct frec_src *next;
+   } frec_src;
+@@ -641,7 +642,7 @@ struct frec {
+   struct randfd *rfd6;
+ #endif
+   unsigned short new_id;
+-  int fd, forwardall, flags;
++  int forwardall, flags;
+   time_t time;
+   unsigned char *hash[HASH_SIZE];
+ #ifdef HAVE_DNSSEC 
+diff --git a/src/forward.c b/src/forward.c
+index 9d249c0..82dd850 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -368,6 +368,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 	      new->dest = *dst_addr;
+ 	      new->log_id = daemon->log_id;
+ 	      new->iface = dst_iface;
++	      new->fd = udpfd;
+ 	    }
+ 	  
+ 	  return 1;
+@@ -392,8 +393,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 	  forward->frec_src.dest = *dst_addr;
+ 	  forward->frec_src.iface = dst_iface;
+ 	  forward->frec_src.next = NULL;
++	  forward->frec_src.fd = udpfd;
+ 	  forward->new_id = get_id();
+-	  forward->fd = udpfd;
+ 	  memcpy(forward->hash, hash, HASH_SIZE);
+ 	  forward->forwardall = 0;
+ 	  forward->flags = fwd_flags;
+@@ -1175,7 +1176,7 @@ void reply_query(int fd, int family, time_t now)
+ 	    {
+ 	      header->id = htons(src->orig_id);
+ 	      
+-	      send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, 
++	      send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, 
+ 			&src->source, &src->dest, src->iface);
+ 
+ 	      if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
+-- 
+2.26.2
+
diff --git a/SOURCES/dnsmasq-2.81-netlink-table.patch b/SOURCES/dnsmasq-2.81-netlink-table.patch
new file mode 100644
index 0000000..05d22cf
--- /dev/null
+++ b/SOURCES/dnsmasq-2.81-netlink-table.patch
@@ -0,0 +1,45 @@
+From 595b2e2e87f152c4ade7e2d66cb78915096f60c2 Mon Sep 17 00:00:00 2001
+From: Donald Sharp <donaldsharp72@gmail.com>
+Date: Mon, 2 Mar 2020 11:23:36 -0500
+Subject: [PATCH] Ignore routes in non-main tables
+
+Route lookup in Linux is bounded by `ip rules` as well
+as the contents of specific routing tables.  With the
+advent of vrf's(l3mdev's) non-default tables are regularly being
+used for routing purposes.
+
+dnsmasq listens to all route changes on the box and responds
+to each one with an event.  This is *expensive* when a full
+BGP routing table is placed into the linux kernel, moreso
+when dnsmasq is responding to events in tables that it will
+never actually need to respond to, since dnsmasq at this
+point in time has no concept of vrf's and would need
+to be programmed to understand them.  Help alleviate this load
+by reducing the set of data that dnsmasq pays attention to
+when we know there are events that are not useful at this
+point in time.
+
+Signed-off-by: Donald Sharp <donaldsharp72@gmail.com>
+(cherry picked from commit b2ed691eb3ca6488a8878f5f3dd950a07b14a9db)
+---
+ src/netlink.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/netlink.c b/src/netlink.c
+index 8cd51af..0a3da3e 100644
+--- a/src/netlink.c
++++ b/src/netlink.c
+@@ -363,7 +363,9 @@ static void nl_async(struct nlmsghdr *h)
+ 	 failing. */ 
+       struct rtmsg *rtm = NLMSG_DATA(h);
+       
+-      if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
++      if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
++	  (rtm->rtm_table == RT_TABLE_MAIN ||
++	   rtm->rtm_table == RT_TABLE_LOCAL))
+ 	queue_event(EVENT_NEWROUTE);
+     }
+   else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) 
+-- 
+2.26.2
+
diff --git a/SOURCES/dnsmasq-2.84-bind-dynamic-netlink.patch b/SOURCES/dnsmasq-2.84-bind-dynamic-netlink.patch
new file mode 100644
index 0000000..f325e6d
--- /dev/null
+++ b/SOURCES/dnsmasq-2.84-bind-dynamic-netlink.patch
@@ -0,0 +1,237 @@
+From 5010c42c47b7b5a3d68d83369d6c17ed0bc11cff Mon Sep 17 00:00:00 2001
+From: Petr Mensik <pemensik@redhat.com>
+Date: Wed, 17 Feb 2021 11:47:28 +0100
+Subject: [PATCH] Correct occasional --bind-dynamic synchronization break
+
+Request only one re-read of addresses and/or routes
+
+Previous implementation re-reads systemd addresses exactly the same
+number of time equal number of notifications received.
+This is not necessary, we need just notification of change, then re-read
+the current state and adapt listeners. Repeated re-reading slows netlink
+processing and highers CPU usage on mass interface changes.
+
+Continue reading multicast events from netlink, even when ENOBUFS
+arrive. Broadcasts are not trusted anyway and refresh would be done in
+iface_enumerate. Save queued events sent again.
+
+Remove sleeping on netlink ENOBUFS
+
+With reduced number of written events netlink should receive ENOBUFS
+rarely. It does not make sense to wait if it is received. It is just a
+signal some packets got missing. Fast reading all pending packets is required,
+seq checking ensures it already. Finishes changes by
+commit 1d07667ac77c55b9de56b1b2c385167e0e0ec27a.
+
+Move restart from iface_enumerate to enumerate_interfaces
+
+When ENOBUFS is received, restart of reading addresses is done. But
+previously found addresses might not have been found this time. In order
+to catch this, restart both IPv4 and IPv6 enumeration with clearing
+found interfaces first. It should deliver up-to-date state also after
+ENOBUFS.
+
+Read all netlink messages before netlink restart
+
+Before writing again into netlink socket, try fetching all pending
+messages. They would be ignored, only might trigger new address
+synchronization. Should ensure new try has better chance to succeed.
+
+Request sending ENOBUFS again
+
+ENOBUFS error handling was improved. Netlink is correctly drained before
+sending a new request again. It seems ENOBUFS supression is no longer
+necessary or wanted. Let kernel tell us when it failed and handle it a
+good way.
+---
+ src/netlink.c | 67 ++++++++++++++++++++++++++++++++++++---------------
+ src/network.c | 11 +++++++--
+ 2 files changed, 57 insertions(+), 21 deletions(-)
+
+diff --git a/src/netlink.c b/src/netlink.c
+index ac1a1c5..f95f3e8 100644
+--- a/src/netlink.c
++++ b/src/netlink.c
+@@ -32,13 +32,21 @@
+ 
+ #ifndef NDA_RTA
+ #  define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 
+-#endif 
++#endif
++
++/* Used to request refresh of addresses or routes just once,
++ * when multiple changes might be announced. */
++enum async_states {
++  STATE_NEWADDR = (1 << 0),
++  STATE_NEWROUTE = (1 << 1),
++};
+ 
+ 
+ static struct iovec iov;
+ static u32 netlink_pid;
+ 
+-static void nl_async(struct nlmsghdr *h);
++static unsigned nl_async(struct nlmsghdr *h, unsigned state);
++static void nl_multicast_state(unsigned state);
+ 
+ void netlink_init(void)
+ {
+@@ -135,7 +143,9 @@ static ssize_t netlink_recv(void)
+   
+ 
+ /* family = AF_UNSPEC finds ARP table entries.
+-   family = AF_LOCAL finds MAC addresses. */
++   family = AF_LOCAL finds MAC addresses.
++   returns 0 on failure, 1 on success, -1 when restart is required
++*/
+ int iface_enumerate(int family, void *parm, int (*callback)())
+ {
+   struct sockaddr_nl addr;
+@@ -143,6 +153,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+   ssize_t len;
+   static unsigned int seq = 0;
+   int callback_ok = 1;
++  unsigned state = 0;
+ 
+   struct {
+     struct nlmsghdr nlh;
+@@ -154,7 +165,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+   addr.nl_groups = 0;
+   addr.nl_pid = 0; /* address to kernel */
+  
+- again: 
+   if (family == AF_UNSPEC)
+     req.nlh.nlmsg_type = RTM_GETNEIGH;
+   else if (family == AF_LOCAL)
+@@ -181,8 +191,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+ 	{
+ 	  if (errno == ENOBUFS)
+ 	    {
+-	      sleep(1);
+-	      goto again;
++	      nl_multicast_state(state);
++	      return -1;
+ 	    }
+ 	  return 0;
+ 	}
+@@ -191,7 +201,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+ 	if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
+ 	  {
+ 	    /* May be multicast arriving async */
+-	    nl_async(h);
++	    state = nl_async(h, state);
+ 	  }
+ 	else if (h->nlmsg_seq != seq)
+ 	  {
+@@ -327,26 +337,36 @@ int iface_enumerate(int family, void *parm, int (*callback)())
+     }
+ }
+ 
+-void netlink_multicast(void)
++static void nl_multicast_state(unsigned state)
+ {
+   ssize_t len;
+   struct nlmsghdr *h;
+   int flags;
+-  
+-  /* don't risk blocking reading netlink messages here. */
++
+   if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
+       fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1) 
+     return;
++
++  do {
++    /* don't risk blocking reading netlink messages here. */
++    while ((len = netlink_recv()) != -1)
+   
+-  if ((len = netlink_recv()) != -1)
+-    for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
+-      nl_async(h);
+-  
++      for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
++	state = nl_async(h, state);
++  } while (errno == ENOBUFS);
++
+   /* restore non-blocking status */
+   fcntl(daemon->netlinkfd, F_SETFL, flags);
+ }
+ 
+-static void nl_async(struct nlmsghdr *h)
++void netlink_multicast(void)
++{
++  unsigned state = 0;
++  nl_multicast_state(state);
++}
++
++
++static unsigned nl_async(struct nlmsghdr *h, unsigned state)
+ {
+   if (h->nlmsg_type == NLMSG_ERROR)
+     {
+@@ -354,7 +374,8 @@ static void nl_async(struct nlmsghdr *h)
+       if (err->error != 0)
+ 	my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
+     }
+-  else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) 
++  else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
++	   (state & STATE_NEWROUTE)==0)
+     {
+       /* We arrange to receive netlink multicast messages whenever the network route is added.
+ 	 If this happens and we still have a DNS packet in the buffer, we re-send it.
+@@ -366,10 +387,18 @@ static void nl_async(struct nlmsghdr *h)
+       if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
+ 	  (rtm->rtm_table == RT_TABLE_MAIN ||
+ 	   rtm->rtm_table == RT_TABLE_LOCAL))
+-	queue_event(EVENT_NEWROUTE);
++	{
++	  queue_event(EVENT_NEWROUTE);
++	  state |= STATE_NEWROUTE;
++	}
++    }
++  else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
++	   (state & STATE_NEWADDR)==0)
++    {
++      queue_event(EVENT_NEWADDR);
++      state |= STATE_NEWADDR;
+     }
+-  else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) 
+-    queue_event(EVENT_NEWADDR);
++  return state;
+ }
+ #endif
+ 
+diff --git a/src/network.c b/src/network.c
+index c6e7d89..47caf38 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -656,7 +656,8 @@ int enumerate_interfaces(int reset)
+ 
+   if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+     return 0;
+- 
++
++again:
+   /* Mark interfaces for garbage collection */
+   for (iface = daemon->interfaces; iface; iface = iface->next) 
+     iface->found = 0;
+@@ -709,10 +710,16 @@ int enumerate_interfaces(int reset)
+   
+ #ifdef HAVE_IPV6
+   ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
++  if (ret < 0)
++    goto again;
+ #endif
+ 
+   if (ret)
+-    ret = iface_enumerate(AF_INET, &param, iface_allowed_v4); 
++    {
++      ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
++      if (ret < 0)
++	goto again;
++    }
+  
+   errsave = errno;
+   close(param.fd);
+-- 
+2.26.2
+
diff --git a/SOURCES/dnsmasq-2.85-CVE-2021-3448.patch b/SOURCES/dnsmasq-2.85-CVE-2021-3448.patch
new file mode 100644
index 0000000..a95c6df
--- /dev/null
+++ b/SOURCES/dnsmasq-2.85-CVE-2021-3448.patch
@@ -0,0 +1,1056 @@
+From d88dc5e696f1b8b95e416890ac831eb0c26250ff Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Mon, 15 Mar 2021 21:59:51 +0000
+Subject: [PATCH] Use random source ports where possible if source
+ addresses/interfaces in use.
+
+CVE-2021-3448 applies.
+
+It's possible to specify the source address or interface to be
+used when contacting upstream nameservers: server=8.8.8.8@1.2.3.4
+or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
+these have, until now, used a single socket, bound to a fixed
+port. This was originally done to allow an error (non-existent
+interface, or non-local address) to be detected at start-up. This
+means that any upstream servers specified in such a way don't use
+random source ports, and are more susceptible to cache-poisoning
+attacks.
+
+We now use random ports where possible, even when the
+source is specified, so server=8.8.8.8@1.2.3.4 or
+server=8.8.8.8@eth0 will use random source
+ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will
+use the explicitly configured port, and should only be done with
+understanding of the security implications.
+Note that this change changes non-existing interface, or non-local
+source address errors from fatal to run-time. The error will be
+logged and communiction with the server not possible.
+---
+ man/dnsmasq.8 |   4 +-
+ src/dnsmasq.c |  31 +++--
+ src/dnsmasq.h |  28 ++--
+ src/forward.c | 373 +++++++++++++++++++++++++++++++-------------------
+ src/loop.c    |  20 +--
+ src/network.c | 100 ++++----------
+ src/option.c  |   3 +-
+ src/tftp.c    |   6 +-
+ src/util.c    |   2 +-
+ 9 files changed, 310 insertions(+), 257 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 45d2273..7f4c62e 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -419,7 +419,7 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
+ or domain parts, to upstream nameservers. If the name is not known
+ from /etc/hosts or DHCP then a "not found" answer is returned.
+ .TP
+-.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
++.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]
+ Specify IP address of upstream servers directly. Setting this flag does
+ not suppress reading of /etc/resolv.conf, use -R to do that. If one or
+ more 
+@@ -481,7 +481,7 @@ source address specified but the port may be specified directly as
+ part of the source address. Forcing queries to an interface is not
+ implemented on all platforms supported by dnsmasq.
+ .TP
+-.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
++.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|@<interface>[#<port>]]
+ This is functionally the same as 
+ .B --server, 
+ but provides some syntactic sugar to make specifying address-to-name queries easier. For example
+diff --git a/src/dnsmasq.c b/src/dnsmasq.c
+index b7f0a29..3a1f65e 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -1538,6 +1538,7 @@ static int set_dns_listeners(time_t now)
+ {
+   struct serverfd *serverfdp;
+   struct listener *listener;
++  struct randfd_list *rfl;
+   int wait = 0, i;
+   
+ #ifdef HAVE_TFTP
+@@ -1557,11 +1558,14 @@ static int set_dns_listeners(time_t now)
+   for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
+     poll_listen(serverfdp->fd, POLLIN);
+     
+-  if (daemon->port != 0 && !daemon->osport)
+-    for (i = 0; i < RANDOM_SOCKS; i++)
+-      if (daemon->randomsocks[i].refcount != 0)
+-	poll_listen(daemon->randomsocks[i].fd, POLLIN);
+-	  
++  for (i = 0; i < RANDOM_SOCKS; i++)
++    if (daemon->randomsocks[i].refcount != 0)
++      poll_listen(daemon->randomsocks[i].fd, POLLIN);
++
++  /* Check overflow random sockets too. */
++  for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
++    poll_listen(rfl->rfd->fd, POLLIN);
++  
+   for (listener = daemon->listeners; listener; listener = listener->next)
+     {
+       /* only listen for queries if we have resources */
+@@ -1592,17 +1596,22 @@ static void check_dns_listeners(time_t now)
+ {
+   struct serverfd *serverfdp;
+   struct listener *listener;
++  struct randfd_list *rfl;
+   int i;
+ 
+   for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
+     if (poll_check(serverfdp->fd, POLLIN))
+-      reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
++      reply_query(serverfdp->fd, now);
+   
+-  if (daemon->port != 0 && !daemon->osport)
+-    for (i = 0; i < RANDOM_SOCKS; i++)
+-      if (daemon->randomsocks[i].refcount != 0 && 
+-	  poll_check(daemon->randomsocks[i].fd, POLLIN))
+-	reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
++  for (i = 0; i < RANDOM_SOCKS; i++)
++    if (daemon->randomsocks[i].refcount != 0 && 
++	poll_check(daemon->randomsocks[i].fd, POLLIN))
++      reply_query(daemon->randomsocks[i].fd, now);
++
++  /* Check overflow random sockets too. */
++  for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
++    if (poll_check(rfl->rfd->fd, POLLIN))
++      reply_query(rfl->rfd->fd, now);
+   
+   for (listener = daemon->listeners; listener; listener = listener->next)
+     {
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index 221f788..4beef35 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -521,13 +521,20 @@ struct serverfd {
+ };
+ 
+ struct randfd {
++  struct server *serv;
+   int fd;
+-  unsigned short refcount, family;
++  unsigned short refcount; /* refcount == 0xffff means overflow record. */
+ };
+-  
++
++struct randfd_list {
++  struct randfd *rfd;
++  struct randfd_list *next;
++};
++
+ struct server {
+   union mysockaddr addr, source_addr;
+   char interface[IF_NAMESIZE+1];
++  unsigned int ifindex; /* corresponding to interface, above */
+   struct serverfd *sfd; 
+   char *domain; /* set if this server only handles a domain. */ 
+   int flags, tcpfd, edns_pktsz;
+@@ -640,10 +647,7 @@ struct frec {
+     struct frec_src *next;
+   } frec_src;
+   struct server *sentto; /* NULL means free */
+-  struct randfd *rfd4;
+-#ifdef HAVE_IPV6
+-  struct randfd *rfd6;
+-#endif
++  struct randfd_list *rfds;
+   unsigned short new_id;
+   int forwardall, flags;
+   time_t time;
+@@ -1062,9 +1066,10 @@ extern struct daemon {
+   int forwardcount;
+   struct server *srv_save; /* Used for resend on DoD */
+   size_t packet_len;       /*      "        "        */
+-  struct randfd *rfd_save; /*      "        "        */
++  int    fd_save;          /*      "        "        */
+   pid_t tcp_pids[MAX_PROCS];
+   struct randfd randomsocks[RANDOM_SOCKS];
++  struct randfd_list *rfl_spare, *rfl_poll;
+   int v6pktinfo; 
+   struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
+   int log_id, log_display_id; /* ids of transactions for logging */
+@@ -1227,7 +1232,7 @@ void safe_strncpy(char *dest, const char *src, size_t size);
+ void safe_pipe(int *fd, int read_noblock);
+ void *whine_malloc(size_t size);
+ int sa_len(union mysockaddr *addr);
+-int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
++int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
+ int hostname_isequal(const char *a, const char *b);
+ time_t dnsmasq_time(void);
+ int netmask_length(struct in_addr mask);
+@@ -1276,7 +1281,7 @@ char *parse_server(char *arg, union mysockaddr *addr,
+ int option_read_dynfile(char *file, int flags);
+ 
+ /* forward.c */
+-void reply_query(int fd, int family, time_t now);
++void reply_query(int fd, time_t now);
+ void receive_query(struct listener *listen, time_t now);
+ unsigned char *tcp_request(int confd, time_t now,
+ 			   union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
+@@ -1286,13 +1291,12 @@ int send_from(int fd, int nowild, char *packet, size_t len,
+ 	       union mysockaddr *to, struct all_addr *source,
+ 	       unsigned int iface);
+ void resend_query(void);
+-struct randfd *allocate_rfd(int family);
+-void free_rfd(struct randfd *rfd);
++int allocate_rfd(struct randfd_list **fdlp, struct server *serv);
++void free_rfds(struct randfd_list **fdlp);
+ 
+ /* network.c */
+ int indextoname(int fd, int index, char *name);
+ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
+-int random_sock(int family);
+ void pre_allocate_sfds(void);
+ int reload_servers(char *fname);
+ void mark_servers(int flag);
+diff --git a/src/forward.c b/src/forward.c
+index 82dd850..11e0310 100644
+--- a/src/forward.c
++++ b/src/forward.c
+@@ -16,7 +16,7 @@
+ 
+ #include "dnsmasq.h"
+ 
+-static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
++static struct frec *lookup_frec(unsigned short id, int fd, void *hash);
+ static struct frec *lookup_frec_by_sender(unsigned short id,
+ 					  union mysockaddr *addr,
+ 					  void *hash);
+@@ -291,29 +291,19 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 	  if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
+ 	    PUTSHORT(SAFE_PKTSZ, pheader);
+ 	  
+-	  if (forward->sentto->addr.sa.sa_family == AF_INET) 
+-	    log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
+-#ifdef HAVE_IPV6
+-	  else
+-	    log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
+-#endif
+-  
+-	  if (forward->sentto->sfd)
+-	    fd = forward->sentto->sfd->fd;
+-	  else
++	  if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
+ 	    {
++	      if (forward->sentto->addr.sa.sa_family == AF_INET) 
++		log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
+ #ifdef HAVE_IPV6
+-	      if (forward->sentto->addr.sa.sa_family == AF_INET6)
+-		fd = forward->rfd6->fd;
+ 	      else
++		log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
+ #endif
+-		fd = forward->rfd4->fd;
++	      while (retry_send(sendto(fd, (char *)header, plen, 0,
++				       &forward->sentto->addr.sa,
++				       sa_len(&forward->sentto->addr))));
+ 	    }
+-	  
+-	  while (retry_send( sendto(fd, (char *)header, plen, 0,
+-				    &forward->sentto->addr.sa,
+-				    sa_len(&forward->sentto->addr))));
+-	  
++
+ 	  return 1;
+ 	}
+ #endif
+@@ -490,50 +480,26 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+       
+       while (1)
+ 	{ 
++	  int fd;
++
+ 	  /* only send to servers dealing with our domain.
+ 	     domain may be NULL, in which case server->domain 
+ 	     must be NULL also. */
+ 	  
+ 	  if (type == (start->flags & SERV_TYPE) &&
+ 	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
+-	      !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
++	      !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
++	      ((fd = allocate_rfd(&forward->rfds, start)) != -1))
+ 	    {
+-	      int fd;
+-
+-	      /* find server socket to use, may need to get random one. */
+-	      if (start->sfd)
+-		fd = start->sfd->fd;
+-	      else 
+-		{
+-#ifdef HAVE_IPV6
+-		  if (start->addr.sa.sa_family == AF_INET6)
+-		    {
+-		      if (!forward->rfd6 &&
+-			  !(forward->rfd6 = allocate_rfd(AF_INET6)))
+-			break;
+-		      daemon->rfd_save = forward->rfd6;
+-		      fd = forward->rfd6->fd;
+-		    }
+-		  else
+-#endif
+-		    {
+-		      if (!forward->rfd4 &&
+-			  !(forward->rfd4 = allocate_rfd(AF_INET)))
+-			break;
+-		      daemon->rfd_save = forward->rfd4;
+-		      fd = forward->rfd4->fd;
+-		    }
+-
+ #ifdef HAVE_CONNTRACK
+-		  /* Copy connection mark of incoming query to outgoing connection. */
+-		  if (option_bool(OPT_CONNTRACK))
+-		    {
+-		      unsigned int mark;
+-		      if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
+-			setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+-		    }
+-#endif
++	      /* Copy connection mark of incoming query to outgoing connection. */
++	      if (option_bool(OPT_CONNTRACK))
++		{
++		  unsigned int mark;
++		  if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
++		    setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
+ 		}
++#endif
+ 	      
+ #ifdef HAVE_DNSSEC
+ 	      if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
+@@ -561,6 +527,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 		  /* Keep info in case we want to re-send this packet */
+ 		  daemon->srv_save = start;
+ 		  daemon->packet_len = plen;
++		  daemon->fd_save = fd;
+ 		  
+ 		  if (!gotname)
+ 		    strcpy(daemon->namebuff, "query");
+@@ -579,7 +546,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
+ 		    break;
+ 		  forward->forwardall++;
+ 		}
+-	    } 
++	    }
+ 	  
+ 	  if (!(start = start->next))
+  	    start = daemon->servers;
+@@ -779,7 +746,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
+ }
+ 
+ /* sets new last_server */
+-void reply_query(int fd, int family, time_t now)
++void reply_query(int fd, time_t now)
+ {
+   /* packet from peer server, extract data for cache, and send to
+      original requester */
+@@ -794,9 +761,8 @@ void reply_query(int fd, int family, time_t now)
+ 
+   /* packet buffer overwritten */
+   daemon->srv_save = NULL;
+-  
++
+   /* Determine the address of the server replying  so that we can mark that as good */
+-  serveraddr.sa.sa_family = family;
+ #ifdef HAVE_IPV6
+   if (serveraddr.sa.sa_family == AF_INET6)
+     serveraddr.in6.sin6_flowinfo = 0;
+@@ -822,7 +788,7 @@ void reply_query(int fd, int family, time_t now)
+ 
+   hash = hash_questions(header, n, daemon->namebuff);
+   
+-  if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
++  if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
+     return;
+   
+   /* log_query gets called indirectly all over the place, so 
+@@ -1027,9 +993,8 @@ void reply_query(int fd, int family, time_t now)
+ 			}
+ 		      
+ 		      new->sentto = server;
+-		      new->rfd4 = NULL;
++		      new->rfds = NULL;
+ #ifdef HAVE_IPV6
+-		      new->rfd6 = NULL;
+ #endif
+ 		      new->frec_src.next = NULL;
+ 		      new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
+@@ -1059,26 +1024,7 @@ void reply_query(int fd, int family, time_t now)
+ 		      /* Don't resend this. */
+ 		      daemon->srv_save = NULL;
+ 		      
+-		      if (server->sfd)
+-			fd = server->sfd->fd;
+-		      else
+-			{
+-			  fd = -1;
+-#ifdef HAVE_IPV6
+-			  if (server->addr.sa.sa_family == AF_INET6)
+-			    {
+-			      if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
+-				fd = new->rfd6->fd;
+-			    }
+-			  else
+-#endif
+-			    {
+-			      if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
+-				fd = new->rfd4->fd;
+-			    }
+-			}
+-		      
+-		      if (fd != -1)
++		      if ((fd = allocate_rfd(&new->rfds, server)) != -1)
+ 			{
+ #ifdef HAVE_CONNTRACK
+ 			  /* Copy connection mark of incoming query to outgoing connection. */
+@@ -1234,7 +1180,7 @@ void receive_query(struct listener *listen, time_t now)
+ 
+   /* packet buffer overwritten */
+   daemon->srv_save = NULL;
+-  
++
+   dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
+   netmask.s_addr = 0;
+   
+@@ -2066,10 +2012,9 @@ static struct frec *allocate_frec(time_t now)
+       f->next = daemon->frec_list;
+       f->time = now;
+       f->sentto = NULL;
+-      f->rfd4 = NULL;
++      f->rfds = NULL;
+       f->flags = 0;
+ #ifdef HAVE_IPV6
+-      f->rfd6 = NULL;
+ #endif
+ #ifdef HAVE_DNSSEC
+       f->dependent = NULL;
+@@ -2082,46 +2027,192 @@ static struct frec *allocate_frec(time_t now)
+   return f;
+ }
+ 
+-struct randfd *allocate_rfd(int family)
++/* return a UDP socket bound to a random port, have to cope with straying into
++   occupied port nos and reserved ones. */
++static int random_sock(struct server *s)
+ {
+-  static int finger = 0;
+-  int i;
++  int fd;
++
++  if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
++    {
++      if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
++	return fd;
+ 
++      if (s->interface[0] == 0)
++	(void)prettyprint_addr(&s->source_addr, daemon->namebuff);
++      else
++	strcpy(daemon->namebuff, s->interface);
++
++      my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
++		daemon->namebuff, strerror(errno));
++      close(fd);
++    }
++  
++  return -1;
++}
++
++/* compare source addresses and interface, serv2 can be null. */
++static int server_isequal(const struct server *serv1,
++			 const struct server *serv2)
++{
++  return (serv2 &&
++    serv2->ifindex == serv1->ifindex &&
++    sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
++    strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
++}
++
++/* fdlp points to chain of randomfds already in use by transaction.
++   If there's already a suitable one, return it, else allocate a 
++   new one and add it to the list. 
++
++   Not leaking any resources in the face of allocation failures
++   is rather convoluted here.
++   
++   Note that rfd->serv may be NULL, when a server goes away.
++*/
++int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
++{
++  static int finger = 0;
++  int i, j = 0;
++  struct randfd_list *rfl;
++  struct randfd *rfd = NULL;
++  int fd = 0;
++  
++  /* If server has a pre-allocated fd, use that. */
++  if (serv->sfd)
++    return serv->sfd->fd;
++  
++  /* existing suitable random port socket linked to this transaction? */
++  for (rfl = *fdlp; rfl; rfl = rfl->next)
++    if (server_isequal(serv, rfl->rfd->serv))
++      return rfl->rfd->fd;
++
++  /* No. need new link. */
++  if ((rfl = daemon->rfl_spare))
++    daemon->rfl_spare = rfl->next;
++  else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
++    return -1;
++   
+   /* limit the number of sockets we have open to avoid starvation of 
+      (eg) TFTP. Once we have a reasonable number, randomness should be OK */
+-
+   for (i = 0; i < RANDOM_SOCKS; i++)
+     if (daemon->randomsocks[i].refcount == 0)
+       {
+-	if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
+-	  break;
+-      
+-	daemon->randomsocks[i].refcount = 1;
+-	daemon->randomsocks[i].family = family;
+-	return &daemon->randomsocks[i];
++	if ((fd = random_sock(serv)) != -1)
++    	  {
++	    rfd = &daemon->randomsocks[i];
++	    rfd->serv = serv;
++	    rfd->fd = fd;
++	    rfd->refcount = 1;
++	  }
++	break;
+       }
+-
++  
+   /* No free ones or cannot get new socket, grab an existing one */
+-  for (i = 0; i < RANDOM_SOCKS; i++)
++  if (!rfd)
++    for (j = 0; j < RANDOM_SOCKS; j++)
++      {
++	i = (j + finger) % RANDOM_SOCKS;
++	if (daemon->randomsocks[i].refcount != 0 &&
++	    server_isequal(serv, daemon->randomsocks[i].serv) &&
++	    daemon->randomsocks[i].refcount != 0xfffe)
++	  {
++	    finger = i + 1;
++	    rfd = &daemon->randomsocks[i];
++	    rfd->refcount++;
++	    break;
++	  }
++      }
++
++  if (j == RANDOM_SOCKS)
+     {
+-      int j = (i+finger) % RANDOM_SOCKS;
+-      if (daemon->randomsocks[j].refcount != 0 &&
+-	  daemon->randomsocks[j].family == family && 
+-	  daemon->randomsocks[j].refcount != 0xffff)
++      struct randfd_list *rfl_poll;
++
++      /* there are no free slots, and non with the same parameters we can piggy-back on. 
++	 We're going to have to allocate a new temporary record, distinguished by
++	 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
++	 and be freed when no longer in use. It will also be held on 
++	 the daemon->rfl_poll list so the poll system can find it. */
++
++      if ((rfl_poll = daemon->rfl_spare))
++	daemon->rfl_spare = rfl_poll->next;
++      else
++	rfl_poll = whine_malloc(sizeof(struct randfd_list));
++      
++      if (!rfl_poll ||
++	  !(rfd = whine_malloc(sizeof(struct randfd))) ||
++	  (fd = random_sock(serv)) == -1)
+ 	{
+-	  finger = j;
+-	  daemon->randomsocks[j].refcount++;
+-	  return &daemon->randomsocks[j];
++	  
++	  /* Don't leak anything we may already have */
++	  rfl->next = daemon->rfl_spare;
++	  daemon->rfl_spare = rfl;
++
++	  if (rfl_poll)
++	    {
++	      rfl_poll->next = daemon->rfl_spare;
++	      daemon->rfl_spare = rfl_poll;
++	    }
++	  
++	  if (rfd)
++	    free(rfd);
++	  
++	  return -1; /* doom */
+ 	}
+-    }
+ 
+-  return NULL; /* doom */
++      /* Note rfd->serv not set here, since it's not reused */
++      rfd->fd = fd;
++      rfd->refcount = 0xffff; /* marker for temp record */
++
++      rfl_poll->rfd = rfd;
++      rfl_poll->next = daemon->rfl_poll;
++      daemon->rfl_poll = rfl_poll;
++    }
++  
++  rfl->rfd = rfd;
++  rfl->next = *fdlp;
++  *fdlp = rfl;
++  
++  return rfl->rfd->fd;
+ }
+ 
+-void free_rfd(struct randfd *rfd)
++void free_rfds(struct randfd_list **fdlp)
+ {
+-  if (rfd && --(rfd->refcount) == 0)
+-    close(rfd->fd);
++  struct randfd_list *tmp, *rfl, *poll, *next, **up;
++  
++  for (rfl = *fdlp; rfl; rfl = tmp)
++    {
++      if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
++	close(rfl->rfd->fd);
++
++      /* temporary overflow record */
++      if (rfl->rfd->refcount == 0xffff)
++	{
++	  free(rfl->rfd);
++	  
++	  /* go through the link of all these by steam to delete.
++	     This list is expected to be almost always empty. */
++	  for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
++	    {
++	      next = poll->next;
++	      
++	      if (poll->rfd == rfl->rfd)
++		{
++		  *up = poll->next;
++		  poll->next = daemon->rfl_spare;
++		  daemon->rfl_spare = poll;
++		}
++	      else
++		up = &poll->next;
++	    }
++	}
++
++      tmp = rfl->next;
++      rfl->next = daemon->rfl_spare;
++      daemon->rfl_spare = rfl;
++    }
++
++  *fdlp = NULL;
+ }
+ 
+ static void free_frec(struct frec *f)
+@@ -2137,14 +2228,11 @@ static void free_frec(struct frec *f)
+     }
+     
+   f->frec_src.next = NULL;    
+-  free_rfd(f->rfd4);
+-  f->rfd4 = NULL;
++  free_rfds(&f->rfds);
+   f->sentto = NULL;
+   f->flags = 0;
+   
+ #ifdef HAVE_IPV6
+-  free_rfd(f->rfd6);
+-  f->rfd6 = NULL;
+ #endif
+ 
+ #ifdef HAVE_DNSSEC
+@@ -2252,26 +2340,39 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
+ }
+ 
+ /* crc is all-ones if not known. */
+-static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
++static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
+ {
+   struct frec *f;
+-
++  struct server *s;
++  int type;
++  struct randfd_list *fdl;
++  
+   for(f = daemon->frec_list; f; f = f->next)
+     if (f->sentto && f->new_id == id && 
+ 	(memcmp(hash, f->hash, HASH_SIZE) == 0))
+       {
+ 	/* sent from random port */
+-	if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
+-	  return f;
+-
+-	if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
+-	  return f;
+-
+-	/* sent to upstream from bound socket. */
+-	if (f->sentto->sfd && f->sentto->sfd->fd == fd)
++	for (fdl = f->rfds; fdl; fdl = fdl->next)
++	  if (fdl->rfd->fd == fd)
+ 	  return f;
++	
++	/* Sent to upstream from socket associated with a server. 
++	   Note we have to iterate over all the possible servers, since they may
++	   have different bound sockets. */
++	type = f->sentto->flags & SERV_TYPE;
++	s = f->sentto;
++	do {
++	  if ((type == (s->flags & SERV_TYPE)) &&
++	      (type != SERV_HAS_DOMAIN ||
++	       (s->domain && hostname_isequal(f->sentto->domain, s->domain))) &&
++	      !(s->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
++	      s->sfd && s->sfd->fd == fd)
++	    return f;
++	  
++	  s = s->next ? s->next : daemon->servers;
++	} while (s != f->sentto);
+       }
+-      
++
+   return NULL;
+ }
+ 
+@@ -2317,31 +2418,27 @@ static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
+ void resend_query()
+ {
+   if (daemon->srv_save)
+-    {
+-      int fd;
+-      
+-      if (daemon->srv_save->sfd)
+-	fd = daemon->srv_save->sfd->fd;
+-      else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
+-	fd = daemon->rfd_save->fd;
+-      else
+-	return;
+-      
+-      while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
+-			      &daemon->srv_save->addr.sa, 
+-			      sa_len(&daemon->srv_save->addr)))); 
+-    }
++    while(retry_send(sendto(daemon->fd_save, daemon->packet, daemon->packet_len, 0,
++			    &daemon->srv_save->addr.sa, 
++			    sa_len(&daemon->srv_save->addr)))); 
+ }
+ 
+ /* A server record is going away, remove references to it */
+ void server_gone(struct server *server)
+ {
+   struct frec *f;
++  int i;
+   
+   for (f = daemon->frec_list; f; f = f->next)
+     if (f->sentto && f->sentto == server)
+       free_frec(f);
+-  
++
++  /* If any random socket refers to this server, NULL the reference.
++     No more references to the socket will be created in the future. */
++  for (i = 0; i < RANDOM_SOCKS; i++)
++    if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
++      daemon->randomsocks[i].serv = NULL;
++
+   if (daemon->last_server == server)
+     daemon->last_server = NULL;
+ 
+diff --git a/src/loop.c b/src/loop.c
+index 0b47a2f..98d0b9e 100644
+--- a/src/loop.c
++++ b/src/loop.c
+@@ -22,6 +22,7 @@ static ssize_t loop_make_probe(u32 uid);
+ void loop_send_probes()
+ {
+    struct server *serv;
++   struct randfd_list *rfds = NULL;
+    
+    if (!option_bool(OPT_LOOP_DETECT))
+      return;
+@@ -34,29 +35,22 @@ void loop_send_probes()
+        {
+ 	 ssize_t len = loop_make_probe(serv->uid);
+ 	 int fd;
+-	 struct randfd *rfd = NULL;
+ 	 
+-	 if (serv->sfd)
+-	   fd = serv->sfd->fd;
+-	 else 
+-	   {
+-	     if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
+-	       continue;
+-	     fd = rfd->fd;
+-	   }
+-
++	 if ((fd = allocate_rfd(&rfds, serv)) == -1)
++	   continue;
++	 
+ 	 while (retry_send(sendto(fd, daemon->packet, len, 0, 
+ 				  &serv->addr.sa, sa_len(&serv->addr))));
+-	 
+-	 free_rfd(rfd);
+        }
++
++   free_rfds(&rfds);
+ }
+   
+ static ssize_t loop_make_probe(u32 uid)
+ {
+   struct dns_header *header = (struct dns_header *)daemon->packet;
+   unsigned char *p = (unsigned char *)(header+1);
+-
++  
+   /* packet buffer overwritten */
+   daemon->srv_save = NULL;
+   
+diff --git a/src/network.c b/src/network.c
+index 47caf38..4eda1fd 100644
+--- a/src/network.c
++++ b/src/network.c
+@@ -639,7 +639,8 @@ int enumerate_interfaces(int reset)
+ #ifdef HAVE_AUTH
+   struct auth_zone *zone;
+ #endif
+-
++  struct server *serv;
++  
+   /* Do this max once per select cycle  - also inhibits netlink socket use
+    in TCP child processes. */
+ 
+@@ -657,6 +658,13 @@ int enumerate_interfaces(int reset)
+   if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
+     return 0;
+ 
++  /* iface indexes can change when interfaces are created/destroyed.
++     We use them in the main forwarding control path, when the path
++     to a server is specified by an interface, so cache them.
++     Update the cache here. */
++  for (serv = daemon->servers; serv; serv = serv->next)
++    serv->ifindex = if_nametoindex(serv->interface);
++
+ again:
+   /* Mark interfaces for garbage collection */
+   for (iface = daemon->interfaces; iface; iface = iface->next) 
+@@ -754,7 +762,7 @@ again:
+ 
+   errno = errsave;
+   spare = param.spare;
+-    
++  
+   return ret;
+ }
+ 
+@@ -893,10 +901,10 @@ int tcp_interface(int fd, int af)
+   /* use mshdr so that the CMSDG_* macros are available */
+   msg.msg_control = daemon->packet;
+   msg.msg_controllen = len = daemon->packet_buff_sz;
+-  
++
+   /* we overwrote the buffer... */
+-  daemon->srv_save = NULL;
+-  
++  daemon->srv_save = NULL; 
++
+   if (af == AF_INET)
+     {
+       if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
+@@ -1228,61 +1236,6 @@ void join_multicast(int dienow)
+ }
+ #endif
+ 
+-/* return a UDP socket bound to a random port, have to cope with straying into
+-   occupied port nos and reserved ones. */
+-int random_sock(int family)
+-{
+-  int fd;
+-
+-  if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
+-    {
+-      union mysockaddr addr;
+-      unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
+-      int tries = ports_avail < 30 ? 3 * ports_avail : 100;
+-
+-      memset(&addr, 0, sizeof(addr));
+-      addr.sa.sa_family = family;
+-
+-      /* don't loop forever if all ports in use. */
+-
+-      if (fix_fd(fd))
+-	while(tries--)
+-	  {
+-	    unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
+-	    
+-	    if (family == AF_INET) 
+-	      {
+-		addr.in.sin_addr.s_addr = INADDR_ANY;
+-		addr.in.sin_port = port;
+-#ifdef HAVE_SOCKADDR_SA_LEN
+-		addr.in.sin_len = sizeof(struct sockaddr_in);
+-#endif
+-	      }
+-#ifdef HAVE_IPV6
+-	    else
+-	      {
+-		addr.in6.sin6_addr = in6addr_any; 
+-		addr.in6.sin6_port = port;
+-#ifdef HAVE_SOCKADDR_SA_LEN
+-		addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+-#endif
+-	      }
+-#endif
+-	    
+-	    if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
+-	      return fd;
+-	    
+-	    if (errno != EADDRINUSE && errno != EACCES)
+-	      break;
+-	  }
+-
+-      close(fd);
+-    }
+-
+-  return -1; 
+-}
+-  
+-
+ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
+ {
+   union mysockaddr addr_copy = *addr;
+@@ -1328,39 +1281,34 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
+   return 1;
+ }
+ 
+-static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
++static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
+ {
+   struct serverfd *sfd;
+-  unsigned int ifindex = 0;
+   int errsave;
+ 
+   /* when using random ports, servers which would otherwise use
+-     the INADDR_ANY/port0 socket have sfd set to NULL */
+-  if (!daemon->osport && intname[0] == 0)
++     the INADDR_ANY/port0 socket have sfd set to NULL, this is 
++     anything without an explictly set source port. */
++  if (!daemon->osport)
+     {
+       errno = 0;
+       
+       if (addr->sa.sa_family == AF_INET &&
+-	  addr->in.sin_addr.s_addr == INADDR_ANY &&
+ 	  addr->in.sin_port == htons(0)) 
+ 	return NULL;
+ 
+ #ifdef HAVE_IPV6
+       if (addr->sa.sa_family == AF_INET6 &&
+-	  memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
+ 	  addr->in6.sin6_port == htons(0)) 
+ 	return NULL;
+ #endif
+     }
+ 
+-  if (intname && strlen(intname) != 0)
+-    ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */
+-      
+   /* may have a suitable one already */
+   for (sfd = daemon->sfds; sfd; sfd = sfd->next )
+-    if (sockaddr_isequal(&sfd->source_addr, addr) &&
+-	strcmp(intname, sfd->interface) == 0 &&
+-	ifindex == sfd->ifindex) 
++    if (ifindex == sfd->ifindex &&
++	sockaddr_isequal(&sfd->source_addr, addr) &&
++	strcmp(intname, sfd->interface) == 0)
+       return sfd;
+   
+   /* need to make a new one. */
+@@ -1408,7 +1356,7 @@ void pre_allocate_sfds(void)
+ #ifdef HAVE_SOCKADDR_SA_LEN
+       addr.in.sin_len = sizeof(struct sockaddr_in);
+ #endif
+-      allocate_sfd(&addr, "");
++      allocate_sfd(&addr, "", 0);
+ #ifdef HAVE_IPV6
+       memset(&addr, 0, sizeof(addr));
+       addr.in6.sin6_family = AF_INET6;
+@@ -1417,13 +1365,13 @@ void pre_allocate_sfds(void)
+ #ifdef HAVE_SOCKADDR_SA_LEN
+       addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+ #endif
+-      allocate_sfd(&addr, "");
++      allocate_sfd(&addr, "", 0);
+ #endif
+     }
+   
+   for (srv = daemon->servers; srv; srv = srv->next)
+     if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
+-	!allocate_sfd(&srv->source_addr, srv->interface) &&
++	!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
+ 	errno != 0 &&
+ 	option_bool(OPT_NOWILD))
+       {
+@@ -1631,7 +1579,7 @@ void check_servers(void)
+ 	  
+ 	  /* Do we need a socket set? */
+ 	  if (!serv->sfd && 
+-	      !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
++	      !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
+ 	      errno != 0)
+ 	    {
+ 	      my_syslog(LOG_WARNING, 
+diff --git a/src/option.c b/src/option.c
+index 79122df..abc5a48 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -795,7 +795,8 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
+     if (interface_opt)
+       {
+ #if defined(SO_BINDTODEVICE)
+-	safe_strncpy(interface, interface_opt, IF_NAMESIZE);
++	safe_strncpy(interface, source, IF_NAMESIZE);
++	source = interface_opt;
+ #else
+ 	return _("interface binding not supported");
+ #endif
+diff --git a/src/tftp.c b/src/tftp.c
+index f2eccbc..ba9833e 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -96,7 +96,7 @@ void tftp_request(struct listener *listen, time_t now)
+ 
+   if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
+     return;
+-
++  
+   /* Can always get recvd interface for IPv6 */
+   if (!check_dest)
+     {
+@@ -566,7 +566,7 @@ void check_tftp_listeners(time_t now)
+ 	{
+ 	  /* we overwrote the buffer... */
+ 	  daemon->srv_save = NULL;
+-	  
++
+ 	  if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
+ 	    {
+ 	      if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block) 
+@@ -609,7 +609,7 @@ void check_tftp_listeners(time_t now)
+ 	  	  
+ 	  /* we overwrote the buffer... */
+ 	  daemon->srv_save = NULL;
+-	 
++
+ 	  if ((len = get_block(daemon->packet, transfer)) == -1)
+ 	    {
+ 	      len = tftp_err_oops(daemon->packet, transfer->file->filename);
+diff --git a/src/util.c b/src/util.c
+index 6287529..d016db6 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -311,7 +311,7 @@ void *whine_malloc(size_t size)
+   return ret;
+ }
+ 
+-int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
++int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
+ {
+   if (s1->sa.sa_family == s2->sa.sa_family)
+     { 
+-- 
+2.26.2
+
diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec
index 37482e0..9d1a962 100644
--- a/SPECS/dnsmasq.spec
+++ b/SPECS/dnsmasq.spec
@@ -13,7 +13,7 @@
 
 Name:           dnsmasq
 Version:        2.79
-Release:        15%{?extraversion:.%{extraversion}}%{?dist}
+Release:        18%{?extraversion:.%{extraversion}}%{?dist}
 Summary:        A lightweight DHCP/caching DNS server
 
 License:        GPLv2 or GPLv3
@@ -57,6 +57,14 @@ Patch23:        dnsmasq-2.79-CVE-2020-25684.patch
 Patch24:        dnsmasq-2.79-CVE-2020-25685.patch
 Patch25:        dnsmasq-2.79-CVE-2020-25686.patch
 Patch26:        dnsmasq-2.79-CVE-2020-25686-2.patch
+# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=3f535da79e7a42104543ef5c7b5fa2bed819a78b
+# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=04490bf622ac84891aad6f2dd2edf83725decdee
+Patch27:        dnsmasq-2.79-mixed-family-failed.patch
+# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=b2ed691eb3ca6488a8878f5f3dd950a07b14a9db
+Patch28:        dnsmasq-2.81-netlink-table.patch
+Patch29:        dnsmasq-2.84-bind-dynamic-netlink.patch
+# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=74d4fcd756a85bc1823232ea74334f7ccfb9d5d2
+Patch30:        dnsmasq-2.85-CVE-2021-3448.patch
 
 # This is workaround to nettle bug #1549190
 # https://bugzilla.redhat.com/show_bug.cgi?id=1549190
@@ -116,6 +124,10 @@ server's leases.
 %patch24 -p1 -b .CVE-2020-25685
 %patch25 -p1 -b .CVE-2020-25686
 %patch26 -p1 -b .CVE-2020-25686-2
+%patch27 -p1 -b .rh1921153
+%patch28 -p1 -b .rh1887649-table
+%patch29 -p1 -b .rh1887649
+%patch30 -p1 -b .CVE-2021-3448
 
 # use /var/lib/dnsmasq instead of /var/lib/misc
 for file in dnsmasq.conf.example man/dnsmasq.8 man/es/dnsmasq.8 src/config.h; do
@@ -215,6 +227,15 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/dnsmasq.conf
 %{_mandir}/man1/dhcp_*
 
 %changelog
+* Thu Mar 18 2021 Petr Menšík <pemensik@redhat.com> - 2.79-18
+- Properly randomize outgoing ports also with bound interface (CVE-2021-3448)
+
+* Fri Feb 12 2021 Petr Menšík <pemensik@redhat.com> - 2.79-17
+- Fix sporadic bind-dynamic failures (#1887649)
+
+* Wed Jan 27 2021 Petr Menšík <pemensik@redhat.com> - 2.79-16
+- Fix network errors on queries both from ipv4 and ipv6 (#1921153)
+
 * Wed Nov 25 2020 Petr Menšík <pemensik@redhat.com> - 2.79-15
 - Fix various issues in dnssec validation (CVE-2020-25681)
 - Accept responses only on correct sockets (CVE-2020-25684)