diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2014-06-07 13:38:48 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2014-06-07 13:38:48 +0100 |
commit | a0358e5ddbc1ef3dec791f11f95f5dbe56087a5e (patch) | |
tree | 9a382e6e8a3095e86cd4dd51b6edc6966876a160 | |
parent | a03f8d4c37c9e52833ce2ad7d9744b3c587efb14 (diff) | |
download | dnsmasq-a0358e5ddbc1ef3dec791f11f95f5dbe56087a5e.tar.gz |
Handle async notification of address changes using the event system.
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | src/bpf.c | 6 | ||||
-rw-r--r-- | src/dhcp6.c | 10 | ||||
-rw-r--r-- | src/dnsmasq.c | 13 | ||||
-rw-r--r-- | src/dnsmasq.h | 6 | ||||
-rw-r--r-- | src/netlink.c | 39 | ||||
-rw-r--r-- | src/network.c | 11 |
7 files changed, 35 insertions, 54 deletions
@@ -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 @@ -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(); } } diff --git a/src/dhcp6.c b/src/dhcp6.c index 0e470cf..bc48fdd 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -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 diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 1c96a0e..5560aa9 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -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. */ diff --git a/src/dnsmasq.h b/src/dnsmasq.h index e11fad4..de98956 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -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 */ diff --git a/src/netlink.c b/src/netlink.c index 3c1e465..022c363 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -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 diff --git a/src/network.c b/src/network.c index 3db7c43..ff9cabb 100644 --- a/src/network.c +++ b/src/network.c @@ -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; } |