summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2017-04-04 15:15:49 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2017-04-04 15:15:49 +0000
commitfaf58e0a0d1387d3cdf857e547de5b78647774c2 (patch)
treed38783942eb1626bfb43eaa28a31e0e05d915d31 /sbin
parente8baad58717642ddcb50b01a70593e7cd630a622 (diff)
Send a RTM_PROPOSAL to clear out other dhclient instances on startup.
Replaces forcing interface link state down and up to generate RTM_IFINFO messages.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/dhclient/dhclient.c81
-rw-r--r--sbin/dhclient/dhcpd.h3
-rw-r--r--sbin/dhclient/dispatch.c22
3 files changed, 89 insertions, 17 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 89bf3b5b5f9..13f346750c8 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhclient.c,v 1.406 2017/04/04 13:01:20 krw Exp $ */
+/* $OpenBSD: dhclient.c,v 1.407 2017/04/04 15:15:48 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -169,6 +169,7 @@ struct client_lease *packet_to_lease(struct interface_info *, struct in_addr,
struct option_data *);
void go_daemon(void);
int rdaemon(int);
+void take_charge(struct interface_info *);
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
@@ -261,6 +262,22 @@ routehandler(struct interface_info *ifi)
goto done;
switch (rtm->rtm_type) {
+ case RTM_PROPOSAL:
+ if (rtm->rtm_index != ifi->index ||
+ rtm->rtm_priority != RTP_PROPOSAL_DHCLIENT)
+ goto done;
+ if ((rtm->rtm_flags & RTF_PROTO3) != 0) {
+ if (rtm->rtm_seq == client->xid) {
+ client->flags |= IN_CHARGE;
+ goto done;
+ } else if ((client->flags & IN_CHARGE) != 0) {
+ rslt = asprintf(&errmsg, "yielding "
+ "responsibility for %s",
+ ifi->name);
+ goto die;
+ }
+ }
+ break;
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)rtm;
if (ifam->ifam_index != ifi->index)
@@ -641,8 +658,9 @@ main(int argc, char *argv[])
if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
fatal("socket(PF_ROUTE, SOCK_RAW)");
- rtfilter = ROUTE_FILTER(RTM_NEWADDR) | ROUTE_FILTER(RTM_DELADDR) |
- ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_IFANNOUNCE);
+ rtfilter = ROUTE_FILTER(RTM_PROPOSAL) | ROUTE_FILTER(RTM_NEWADDR) |
+ ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_IFINFO) |
+ ROUTE_FILTER(RTM_IFANNOUNCE);
if (setsockopt(routefd, PF_ROUTE, ROUTE_MSGFILTER,
&rtfilter, sizeof(rtfilter)) == -1)
@@ -651,6 +669,8 @@ main(int argc, char *argv[])
sizeof(ifi->rdomain)) == -1)
fatal("setsockopt(ROUTE_TABLEFILTER)");
+ take_charge(ifi);
+
/* Register the interface. */
if_register_receive(ifi);
if_register_send(ifi);
@@ -2958,3 +2978,58 @@ compare_lease(struct client_lease *active, struct client_lease *new)
return (0);
}
+
+void
+take_charge(struct interface_info *ifi)
+{
+ struct pollfd fds[1];
+ struct rt_msghdr rtm;
+ time_t start_time, cur_time;
+ int retries;
+
+ if (time(&start_time) == -1)
+ fatal("time");
+
+ /*
+ * Send RTM_PROPOSAL with RTF_PROTO3 set.
+ *
+ * When it comes back, we're in charge and other dhclients are
+ * dead processes walking.
+ */
+ memset(&rtm, 0, sizeof(rtm));
+
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = RTM_PROPOSAL;
+ rtm.rtm_msglen = sizeof(rtm);
+ rtm.rtm_tableid = ifi->rdomain;
+ rtm.rtm_index = ifi->index;
+ rtm.rtm_seq = ifi->client->xid = arc4random();
+ rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
+ rtm.rtm_addrs = 0;
+ rtm.rtm_flags = RTF_UP | RTF_PROTO3;
+
+ retries = 0;
+ while ((ifi->client->flags & IN_CHARGE) == 0) {
+ if (write(routefd, &rtm, sizeof(rtm)) == -1)
+ fatal("tried to take charge");
+ time(&cur_time);
+ if ((cur_time - start_time) > 3) {
+ if (++retries <= 3) {
+ if (time(&start_time) == -1)
+ fatal("time");
+ } else {
+ fatalx("failed to take charge of %s",
+ ifi->name);
+ }
+ }
+ fds[0].fd = routefd;
+ fds[0].events = POLLIN;
+ if (poll(fds, 1, 3) == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ fatal("routefd poll");
+ }
+ if ((fds[0].revents & (POLLIN | POLLHUP)))
+ routehandler(ifi);
+ }
+}
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index f599a6df629..1aae45d1a2f 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.163 2017/04/04 13:01:20 krw Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.164 2017/04/04 15:15:48 krw Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -131,6 +131,7 @@ struct client_state {
struct in_addr destination;
int flags;
#define IS_RESPONSIBLE 0x1
+#define IN_CHARGE 0x2
u_int32_t xid;
u_int16_t secs;
time_t first_sending;
diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c
index dfab902c6f1..2165c0f19f2 100644
--- a/sbin/dhclient/dispatch.c
+++ b/sbin/dhclient/dispatch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dispatch.c,v 1.117 2017/03/08 15:46:36 krw Exp $ */
+/* $OpenBSD: dispatch.c,v 1.118 2017/04/04 15:15:48 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -233,21 +233,17 @@ interface_link_forceup(char *ifname)
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
- log_warn("interface_link_forceup: SIOCGIFFLAGS failed");
+ log_warn("SIOCGIFFLAGS");
return;
}
- /* Force it down and up so others notice link state change. */
- ifr.ifr_flags &= ~IFF_UP;
- if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
- log_warn("interface_link_forceup: SIOCSIFFLAGS DOWN failed");
- return;
- }
-
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
- log_warn("interface_link_forceup: SIOCSIFFLAGS UP failed");
- return;
+ /* Force it up if it isn't already. */
+ if ((ifr.ifr_flags & IFF_UP) == 0) {
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&ifr) == -1) {
+ log_warn("SIOCSIFFLAGS");
+ return;
+ }
}
}