Commit a0358e5d authored by Simon Kelley's avatar Simon Kelley

Handle async notification of address changes using the event system.

parent a03f8d4c
...@@ -4,6 +4,10 @@ version 2.72 ...@@ -4,6 +4,10 @@ version 2.72
Add support for "ipsets" in *BSD, using pf. Thanks to Add support for "ipsets" in *BSD, using pf. Thanks to
Sven Falempim for the patch. 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 version 2.71
Subtle change to error handling to help DNSSEC validation Subtle change to error handling to help DNSSEC validation
......
...@@ -376,7 +376,7 @@ void route_init(void) ...@@ -376,7 +376,7 @@ void route_init(void)
die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET); die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
} }
void route_sock(time_t now) void route_sock(void)
{ {
struct if_msghdr *msg; struct if_msghdr *msg;
int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0); int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
...@@ -401,7 +401,7 @@ void route_sock(time_t now) ...@@ -401,7 +401,7 @@ void route_sock(time_t now)
else if (msg->ifm_type == RTM_NEWADDR) else if (msg->ifm_type == RTM_NEWADDR)
{ {
del_family = 0; del_family = 0;
newaddress(now); send_newaddr();
} }
else if (msg->ifm_type == RTM_DELADDR) else if (msg->ifm_type == RTM_DELADDR)
{ {
...@@ -439,7 +439,7 @@ void route_sock(time_t now) ...@@ -439,7 +439,7 @@ void route_sock(time_t now)
of += sizeof(long) - (diff & (sizeof(long) - 1)); of += sizeof(long) - (diff & (sizeof(long) - 1));
} }
newaddress(now); send_newaddr();
} }
} }
......
...@@ -708,20 +708,12 @@ static int construct_worker(struct in6_addr *local, int prefix, ...@@ -708,20 +708,12 @@ static int construct_worker(struct in6_addr *local, int prefix,
void dhcp_construct_contexts(time_t now) void dhcp_construct_contexts(time_t now)
{ {
static int active = 0;
struct dhcp_context *context, *tmp, **up; struct dhcp_context *context, *tmp, **up;
struct cparam param; struct cparam param;
param.newone = 0; param.newone = 0;
param.newname = 0; param.newname = 0;
param.now = now; 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) for (context = daemon->dhcp6; context; context = context->next)
if (context->flags & CONTEXT_CONSTRUCTED) if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC; context->flags |= CONTEXT_GC;
...@@ -779,8 +771,6 @@ void dhcp_construct_contexts(time_t now) ...@@ -779,8 +771,6 @@ void dhcp_construct_contexts(time_t now)
/* Not doing DHCP, so no lease system, manage alarms for ra only */ /* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now); send_alarm(periodic_ra(now), now);
} }
active = 0;
} }
#endif #endif
......
...@@ -917,10 +917,10 @@ int main (int argc, char **argv) ...@@ -917,10 +917,10 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
if (FD_ISSET(daemon->netlinkfd, &rset)) if (FD_ISSET(daemon->netlinkfd, &rset))
netlink_multicast(now); netlink_multicast();
#elif defined(HAVE_BSD_NETWORK) #elif defined(HAVE_BSD_NETWORK)
if (FD_ISSET(daemon->routefd, &rset)) if (FD_ISSET(daemon->routefd, &rset))
route_sock(now); route_sock();
#endif #endif
/* Check for changes to resolv files once per second max. */ /* Check for changes to resolv files once per second max. */
...@@ -1037,6 +1037,11 @@ void send_alarm(time_t event, time_t now) ...@@ -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) void send_event(int fd, int event, int data, char *msg)
{ {
struct event_desc ev; struct event_desc ev;
...@@ -1230,6 +1235,10 @@ static void async_event(int pipe, time_t now) ...@@ -1230,6 +1235,10 @@ static void async_event(int pipe, time_t now)
if (daemon->log_file != NULL) if (daemon->log_file != NULL)
log_reopen(daemon->log_file); log_reopen(daemon->log_file);
break; break;
case EVENT_NEWADDR:
newaddress(now);
break;
case EVENT_TERM: case EVENT_TERM:
/* Knock all our children on the head. */ /* Knock all our children on the head. */
......
...@@ -165,6 +165,7 @@ struct event_desc { ...@@ -165,6 +165,7 @@ struct event_desc {
#define EVENT_LUA_ERR 19 #define EVENT_LUA_ERR 19
#define EVENT_TFTP_ERR 20 #define EVENT_TFTP_ERR 20
#define EVENT_INIT 21 #define EVENT_INIT 21
#define EVENT_NEWADDR 22
/* Exit codes. */ /* Exit codes. */
#define EC_GOOD 0 #define EC_GOOD 0
...@@ -1288,6 +1289,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, ...@@ -1288,6 +1289,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int make_icmp_sock(void); int make_icmp_sock(void);
int icmp_ping(struct in_addr addr); int icmp_ping(struct in_addr addr);
#endif #endif
void send_newaddr(void);
void send_alarm(time_t event, time_t now); void send_alarm(time_t event, time_t now);
void send_event(int fd, int event, int data, char *msg); void send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now); void clear_cache_and_reload(time_t now);
...@@ -1296,7 +1298,7 @@ void poll_resolv(int force, int do_reload, time_t now); ...@@ -1296,7 +1298,7 @@ void poll_resolv(int force, int do_reload, time_t now);
/* netlink.c */ /* netlink.c */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void netlink_init(void); void netlink_init(void);
void netlink_multicast(time_t now); void netlink_multicast(void);
#endif #endif
/* bpf.c */ /* bpf.c */
...@@ -1305,7 +1307,7 @@ void init_bpf(void); ...@@ -1305,7 +1307,7 @@ void init_bpf(void);
void send_via_bpf(struct dhcp_packet *mess, size_t len, void send_via_bpf(struct dhcp_packet *mess, size_t len,
struct in_addr iface_addr, struct ifreq *ifr); struct in_addr iface_addr, struct ifreq *ifr);
void route_init(void); void route_init(void);
void route_sock(time_t now); void route_sock(void);
#endif #endif
/* bpf.c or netlink.c */ /* bpf.c or netlink.c */
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
static struct iovec iov; static struct iovec iov;
static u32 netlink_pid; static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h); static void nl_async(struct nlmsghdr *h);
void netlink_init(void) void netlink_init(void)
{ {
...@@ -142,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -142,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct nlmsghdr *h; struct nlmsghdr *h;
ssize_t len; ssize_t len;
static unsigned int seq = 0; static unsigned int seq = 0;
int callback_ok = 1, newaddr = 0; int callback_ok = 1;
struct { struct {
struct nlmsghdr nlh; struct nlmsghdr nlh;
...@@ -191,21 +191,10 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -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) if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{ {
/* May be multicast arriving async */ /* May be multicast arriving async */
if (nl_async(h)) nl_async(h);
{
newaddr = 1;
enumerate_interfaces(1); /* reset */
}
} }
else if (h->nlmsg_type == NLMSG_DONE) else if (h->nlmsg_type == NLMSG_DONE)
{ return callback_ok;
/* 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;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL) else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
{ {
struct ifaddrmsg *ifa = NLMSG_DATA(h); struct ifaddrmsg *ifa = NLMSG_DATA(h);
...@@ -330,11 +319,11 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -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; ssize_t len;
struct nlmsghdr *h; struct nlmsghdr *h;
int flags, newaddr = 0; int flags;
/* don't risk blocking reading netlink messages here. */ /* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 || if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
...@@ -343,24 +332,19 @@ void netlink_multicast(time_t now) ...@@ -343,24 +332,19 @@ void netlink_multicast(time_t now)
if ((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)) for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (nl_async(h)) nl_async(h);
newaddr = 1;
/* restore non-blocking status */ /* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags); 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) if (h->nlmsg_type == NLMSG_ERROR)
{ {
struct nlmsgerr *err = NLMSG_DATA(h); struct nlmsgerr *err = NLMSG_DATA(h);
if (err->error != 0) if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
return 0;
} }
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE) else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
{ {
...@@ -385,18 +369,15 @@ static int nl_async(struct nlmsghdr *h) ...@@ -385,18 +369,15 @@ static int nl_async(struct nlmsghdr *h)
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0) else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd; fd = daemon->rfd_save->fd;
else else
return 0; return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0, while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); &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) else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
return 1; /* clever bind mode - rescan */ send_newaddr();
return 0;
} }
#endif #endif
......
...@@ -551,7 +551,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label, ...@@ -551,7 +551,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
int enumerate_interfaces(int reset) int enumerate_interfaces(int reset)
{ {
static struct addrlist *spare = NULL; static struct addrlist *spare = NULL;
static int done = 0, active = 0; static int done = 0;
struct iface_param param; struct iface_param param;
int errsave, ret = 1; int errsave, ret = 1;
struct addrlist *addr, *tmp; struct addrlist *addr, *tmp;
...@@ -570,14 +570,11 @@ int enumerate_interfaces(int reset) ...@@ -570,14 +570,11 @@ int enumerate_interfaces(int reset)
return 1; return 1;
} }
if (done || active) if (done)
return 1; return 1;
done = 1; done = 1;
/* protect against recusive calls from iface_enumerate(); */
active = 1;
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0; return 0;
...@@ -677,10 +674,8 @@ int enumerate_interfaces(int reset) ...@@ -677,10 +674,8 @@ int enumerate_interfaces(int reset)
} }
errno = errsave; errno = errsave;
spare = param.spare; spare = param.spare;
active = 0;
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment