]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
Handle async notification of address changes using the event system.
authorSimon Kelley <simon@thekelleys.org.uk>
Sat, 7 Jun 2014 12:38:48 +0000 (13:38 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Sat, 7 Jun 2014 12:38:48 +0000 (13:38 +0100)
CHANGELOG
src/bpf.c
src/dhcp6.c
src/dnsmasq.c
src/dnsmasq.h
src/netlink.c
src/network.c

index aba3a67755ad81f1469dd7a6a69989253fb8b19f..4e56a6abcfadb143e2c5ea628f23a5448ac82f3a 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,10 @@ version 2.72
            Add support for "ipsets" in *BSD, using pf. Thanks to 
            Sven Falempim for the patch.
 
+           Fix race condition which could lock up dnsmasq when an 
+           interface goes down and up rapidly. Thanks to Conrad 
+           Kostecki for helping to chase this down.
+           
 
 version 2.71
             Subtle change to error handling to help DNSSEC validation 
index f9c6063d1b4d46f847a4f6d0950578d04843bace..fea84b1dbea302513a9423b4e42ccde3a634dbef 100644 (file)
--- a/src/bpf.c
+++ b/src/bpf.c
@@ -376,7 +376,7 @@ void route_init(void)
     die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
 }
 
-void route_sock(time_t now)
+void route_sock(void)
 {
   struct if_msghdr *msg;
   int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
@@ -401,7 +401,7 @@ void route_sock(time_t now)
    else if (msg->ifm_type == RTM_NEWADDR)
      {
        del_family = 0;
-       newaddress(now);
+       send_newaddr();
      }
    else if (msg->ifm_type == RTM_DELADDR)
      {
@@ -439,7 +439,7 @@ void route_sock(time_t now)
               of += sizeof(long) - (diff & (sizeof(long) - 1));
           }
        
-       newaddress(now);
+       send_newaddr();
      }
 }
 
index 0e470cfba3d0edf5e216c21b7d206e4c60cb9455..bc48fdddd3de6eaca7f63d4f9e00ba0781ed01a5 100644 (file)
@@ -708,20 +708,12 @@ static int construct_worker(struct in6_addr *local, int prefix,
 
 void dhcp_construct_contexts(time_t now)
 { 
-  static int active = 0;
   struct dhcp_context *context, *tmp, **up;
   struct cparam param;
   param.newone = 0;
   param.newname = 0;
   param.now = now;
 
-  /* Various calls that we make may end up calling iface_enumerate(), which can then 
-     call us again, We're NOT re-entrant, so ignore a second invokation. */
-  if (active)
-    return;
-
-  active = 1;
-
   for (context = daemon->dhcp6; context; context = context->next)
     if (context->flags & CONTEXT_CONSTRUCTED)
       context->flags |= CONTEXT_GC;
@@ -779,8 +771,6 @@ void dhcp_construct_contexts(time_t now)
        /* Not doing DHCP, so no lease system, manage alarms for ra only */
        send_alarm(periodic_ra(now), now);
     }
-
-  active = 0;
 }
 
 #endif
index 1c96a0e35d074d4124cff98bcd7ad86fbfbfbd15..5560aa97d7d0592f31349e09dbea58f609fdccb0 100644 (file)
@@ -917,10 +917,10 @@ int main (int argc, char **argv)
 
 #if defined(HAVE_LINUX_NETWORK)
       if (FD_ISSET(daemon->netlinkfd, &rset))
-       netlink_multicast(now);
+       netlink_multicast();
 #elif defined(HAVE_BSD_NETWORK)
       if (FD_ISSET(daemon->routefd, &rset))
-       route_sock(now);
+       route_sock();
 #endif
 
       /* Check for changes to resolv files once per second max. */
@@ -1037,6 +1037,11 @@ void send_alarm(time_t event, time_t now)
     }
 }
 
+void send_newaddr(void)
+{
+  send_event(pipewrite, EVENT_NEWADDR, 0, NULL);
+}
+
 void send_event(int fd, int event, int data, char *msg)
 {
   struct event_desc ev;
@@ -1230,6 +1235,10 @@ static void async_event(int pipe, time_t now)
        if (daemon->log_file != NULL)
          log_reopen(daemon->log_file);
        break;
+
+      case EVENT_NEWADDR:
+       newaddress(now);
+       break;
        
       case EVENT_TERM:
        /* Knock all our children on the head. */
index e11fad402723387b515946131ba5794f07d08f58..de989563c0b2aa2c953f8ea26a50d3962d8f3a28 100644 (file)
@@ -165,6 +165,7 @@ struct event_desc {
 #define EVENT_LUA_ERR   19
 #define EVENT_TFTP_ERR  20
 #define EVENT_INIT      21
+#define EVENT_NEWADDR   22
 
 /* Exit codes. */
 #define EC_GOOD        0
@@ -1288,6 +1289,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
 int make_icmp_sock(void);
 int icmp_ping(struct in_addr addr);
 #endif
+void send_newaddr(void);
 void send_alarm(time_t event, time_t now);
 void send_event(int fd, int event, int data, char *msg);
 void clear_cache_and_reload(time_t now);
@@ -1296,7 +1298,7 @@ void poll_resolv(int force, int do_reload, time_t now);
 /* netlink.c */
 #ifdef HAVE_LINUX_NETWORK
 void netlink_init(void);
-void netlink_multicast(time_t now);
+void netlink_multicast(void);
 #endif
 
 /* bpf.c */
@@ -1305,7 +1307,7 @@ void init_bpf(void);
 void send_via_bpf(struct dhcp_packet *mess, size_t len,
                  struct in_addr iface_addr, struct ifreq *ifr);
 void route_init(void);
-void route_sock(time_t now);
+void route_sock(void);
 #endif
 
 /* bpf.c or netlink.c */
index 3c1e4654bc2db347dc769fe3800e215b871e590f..022c3636fe3ca96b2ed732661c2f4e34d9f734ca 100644 (file)
@@ -38,7 +38,7 @@
 static struct iovec iov;
 static u32 netlink_pid;
 
-static int nl_async(struct nlmsghdr *h);
+static void nl_async(struct nlmsghdr *h);
 
 void netlink_init(void)
 {
@@ -142,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
   struct nlmsghdr *h;
   ssize_t len;
   static unsigned int seq = 0;
-  int callback_ok = 1, newaddr = 0;
+  int callback_ok = 1;
 
   struct {
     struct nlmsghdr nlh;
@@ -191,21 +191,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
        if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
          {
            /* May be multicast arriving async */
-           if (nl_async(h))
-             {
-               newaddr = 1; 
-               enumerate_interfaces(1); /* reset */
-             }
+           nl_async(h);
          }
        else if (h->nlmsg_type == NLMSG_DONE)
-         {
-           /* handle async new interface address arrivals, these have to be done
-              after we complete as we're not re-entrant */
-           if (newaddr) 
-             newaddress(dnsmasq_time());
-               
-           return callback_ok;
-         }
+         return callback_ok;
        else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
          {
            struct ifaddrmsg *ifa = NLMSG_DATA(h);  
@@ -330,11 +319,11 @@ int iface_enumerate(int family, void *parm, int (*callback)())
     }
 }
 
-void netlink_multicast(time_t now)
+void netlink_multicast(void)
 {
   ssize_t len;
   struct nlmsghdr *h;
-  int flags, newaddr = 0;
+  int flags;
   
   /* don't risk blocking reading netlink messages here. */
   if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
@@ -343,24 +332,19 @@ void netlink_multicast(time_t now)
   
   if ((len = netlink_recv()) != -1)
     for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
-      if (nl_async(h))
-       newaddr = 1;
+      nl_async(h);
   
   /* restore non-blocking status */
   fcntl(daemon->netlinkfd, F_SETFL, flags);
-  
-  if (newaddr) 
-    newaddress(now);
 }
 
-static int nl_async(struct nlmsghdr *h)
+static void nl_async(struct nlmsghdr *h)
 {
   if (h->nlmsg_type == NLMSG_ERROR)
     {
       struct nlmsgerr *err = NLMSG_DATA(h);
       if (err->error != 0)
        my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
-      return 0;
     }
   else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) 
     {
@@ -385,18 +369,15 @@ static int nl_async(struct nlmsghdr *h)
              else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
                fd = daemon->rfd_save->fd;
              else
-               return 0;
+               return;
              
              while(sendto(fd, daemon->packet, daemon->packet_len, 0,
                           &daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); 
            }
        }
-      return 0;
     }
   else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) 
-    return 1; /* clever bind mode - rescan */
-  
-  return 0;
+    send_newaddr();
 }
 #endif
 
index 3db7c43b35c94e0858920add9b32aca76b77e9ca..ff9cabb97a1c145f580fed9e729f2122b1986612 100644 (file)
@@ -551,7 +551,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
 int enumerate_interfaces(int reset)
 {
   static struct addrlist *spare = NULL;
-  static int done = 0, active = 0;
+  static int done = 0;
   struct iface_param param;
   int errsave, ret = 1;
   struct addrlist *addr, *tmp;
@@ -570,14 +570,11 @@ int enumerate_interfaces(int reset)
       return 1;
     }
 
-  if (done || active)
+  if (done)
     return 1;
 
   done = 1;
 
-  /* protect against recusive calls from iface_enumerate(); */
-  active = 1;
-
   if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
     return 0;
  
@@ -677,10 +674,8 @@ int enumerate_interfaces(int reset)
     }
   
   errno = errsave;
-  
   spare = param.spare;
-  active = 0;
-  
+    
   return ret;
 }