summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2017-09-15 15:22:15 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2017-09-15 15:22:15 +0000
commitd922bdede367b57ca44048f0a1b11411b504a78b (patch)
tree70201802a3881e20fe7f7ffb3cae4b1930756800 /sbin
parent0b807fa8e143b27cdbdba2ad8fe364fc9a67687c (diff)
Use a poll() loop when trying read the default route from
a routing socket. Fixes at least one cause of resolv.conf confusion and possibly hanging/looping dhclient if the RTM_GET gets lost. Fingered by phessler@ when doing many suspend/resumes while switching between wifi and wired interfaces. Testing & ok phessler@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/dhclient/kroute.c72
-rw-r--r--sbin/dhclient/privsep.c11
2 files changed, 53 insertions, 30 deletions
diff --git a/sbin/dhclient/kroute.c b/sbin/dhclient/kroute.c
index 5475eab8fb2..20e5062f6eb 100644
--- a/sbin/dhclient/kroute.c
+++ b/sbin/dhclient/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.147 2017/09/14 00:10:17 krw Exp $ */
+/* $OpenBSD: kroute.c,v 1.148 2017/09/15 15:22:14 krw Exp $ */
/*
* Copyright 2012 Kenneth R Westerback <krw@openbsd.org>
@@ -35,6 +35,7 @@
#include <ifaddrs.h>
#include <imsg.h>
#include <limits.h>
+#include <poll.h>
#include <resolv.h>
#include <signal.h>
#include <stdio.h>
@@ -606,11 +607,14 @@ priv_write_resolv_conf(char *contents)
/*
* default_route_index returns the index of the interface which the
- * default route is on.
+ * default route (a.k.a. 0.0.0.0/0) is on.
*/
int
default_route_index(int rdomain, int routefd)
{
+ struct pollfd fds[1];
+ time_t start_time, cur_time;
+ int nfds;
struct iovec iov[3];
struct sockaddr_in sin;
struct {
@@ -619,50 +623,65 @@ default_route_index(int rdomain, int routefd)
} m_rtmsg;
pid_t pid;
ssize_t len;
- int seq, iovcnt = 0;
-
- /* Build RTM header */
+ int seq;
memset(&m_rtmsg, 0, sizeof(m_rtmsg));
-
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
m_rtmsg.m_rtm.rtm_type = RTM_GET;
- m_rtmsg.m_rtm.rtm_seq = seq = arc4random();
m_rtmsg.m_rtm.rtm_tableid = rdomain;
+ m_rtmsg.m_rtm.rtm_seq = seq = arc4random();
m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
+ m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) +
+ 2 * sizeof(struct sockaddr_in);
- iov[iovcnt].iov_base = &m_rtmsg.m_rtm;
- iov[iovcnt++].iov_len = sizeof(m_rtmsg.m_rtm);
-
- /* Ask for route to 0.0.0.0/0 (a.k.a. the default route). */
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
- iov[iovcnt].iov_base = &sin;
- iov[iovcnt++].iov_len = sizeof(sin);
- iov[iovcnt].iov_base = &sin;
- iov[iovcnt++].iov_len = sizeof(sin);
+ iov[0].iov_base = &m_rtmsg.m_rtm;
+ iov[0].iov_len = sizeof(m_rtmsg.m_rtm);
+ iov[1].iov_base = &sin;
+ iov[1].iov_len = sizeof(sin);
+ iov[2].iov_base = &sin;
+ iov[2].iov_len = sizeof(sin);
- m_rtmsg.m_rtm.rtm_msglen = sizeof(m_rtmsg.m_rtm) + 2 * sizeof(sin);
+ pid = getpid();
+ if (time(&start_time) == -1)
+ fatal("start time");
- if (writev(routefd, iov, iovcnt) == -1) {
- if (errno != ESRCH)
- log_warn("RTM_GET of default route");
- goto done;
+ if (writev(routefd, iov, 3) == -1) {
+ log_warn("RTM_GET of default route");
+ return 0;
}
- pid = getpid();
-
do {
+ if (time(&cur_time) == -1)
+ fatal("current time");
+ fds[0].fd = routefd;
+ fds[0].events = POLLIN;
+ nfds = poll(fds, 1, 3);
+ if (nfds == -1) {
+ if (errno == EINTR)
+ continue;
+ log_warn("default route poll");
+ break;
+ }
+ if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
+ log_warnx("default route revents");
+ break;
+ }
+ if (nfds == 0 || (fds[0].revents & POLLIN) == 0)
+ continue;
+
len = read(routefd, &m_rtmsg, sizeof(m_rtmsg));
if (len == -1) {
log_warn("get default route read");
- goto done;
+ break;
} else if (len == 0) {
log_warnx("no data from default route read");
- goto done;
+ break;
}
+
if (m_rtmsg.m_rtm.rtm_version == RTM_VERSION &&
m_rtmsg.m_rtm.rtm_type == RTM_GET &&
m_rtmsg.m_rtm.rtm_pid == pid &&
@@ -670,13 +689,12 @@ default_route_index(int rdomain, int routefd)
if (m_rtmsg.m_rtm.rtm_errno != 0) {
log_warnx("default route read rtm: %s",
strerror(m_rtmsg.m_rtm.rtm_errno));
- goto done;
+ break;
}
return m_rtmsg.m_rtm.rtm_index;
}
- } while (1);
+ } while ((cur_time - start_time) <= 3);
-done:
return 0;
}
diff --git a/sbin/dhclient/privsep.c b/sbin/dhclient/privsep.c
index 6958f2b54a2..fb0cf93f534 100644
--- a/sbin/dhclient/privsep.c
+++ b/sbin/dhclient/privsep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: privsep.c,v 1.68 2017/09/14 00:10:17 krw Exp $ */
+/* $OpenBSD: privsep.c,v 1.69 2017/09/15 15:22:14 krw Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -47,7 +47,7 @@ dispatch_imsg(char *name, int rdomain, int ioctlfd, int routefd,
struct imsg imsg;
ssize_t n;
size_t sz;
- int index, newidx;
+ int index, newidx, retries;
index = if_nametoindex(name);
if (index == 0) {
@@ -130,7 +130,12 @@ dispatch_imsg(char *name, int rdomain, int ioctlfd, int routefd,
if (imsg.hdr.len != IMSG_HEADER_SIZE)
log_warnx("bad IMSG_WRITE_RESOLV_CONF");
else {
- newidx = default_route_index(rdomain, routefd);
+ retries = 0;
+ do {
+ newidx = default_route_index(rdomain,
+ routefd);
+ retries++;
+ } while (newidx == 0 && retries < 3);
if (newidx == index && newidx != lastidx)
priv_write_resolv_conf(resolv_conf);
lastidx = newidx;