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
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();
}
}
......
......@@ -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
......
......@@ -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. */
......
......@@ -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 */
......
......@@ -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
......
......@@ -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;
}
......
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