xref: /openbsd/sbin/dhcpleased/engine.c (revision 771fbea0)
1 /*	$OpenBSD: engine.c,v 1.14 2021/05/01 11:51:59 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
5  * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/syslog.h>
26 #include <sys/uio.h>
27 
28 #include <net/if.h>
29 #include <net/route.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <netinet/if_ether.h>
33 #include <netinet/ip.h>
34 #include <netinet/udp.h>
35 
36 #include <errno.h>
37 #include <event.h>
38 #include <imsg.h>
39 #include <pwd.h>
40 #include <signal.h>
41 #include <stddef.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <vis.h>
48 
49 #include "checksum.h"
50 #include "log.h"
51 #include "dhcpleased.h"
52 #include "engine.h"
53 
54 /*
55  * RFC 2131 4.1 p23 has "SHOULD be 4 seconds", we are a bit more aggressive,
56  * networks are faster these days.
57  */
58 #define	START_EXP_BACKOFF	 1
59 #define	MAX_EXP_BACKOFF_SLOW	64 /* RFC 2131 4.1 p23 */
60 #define	MAX_EXP_BACKOFF_FAST	 2
61 #define	MINIMUM(a, b)		(((a) < (b)) ? (a) : (b))
62 
63 enum if_state {
64 	IF_DOWN,
65 	IF_INIT,
66 	/* IF_SELECTING, */
67 	IF_REQUESTING,
68 	IF_BOUND,
69 	IF_RENEWING,
70 	IF_REBINDING,
71 	/* IF_INIT_REBOOT, */
72 	IF_REBOOTING,
73 };
74 
75 const char* if_state_name[] = {
76 	"Down",
77 	"Init",
78 	/* "Selecting", */
79 	"Requesting",
80 	"Bound",
81 	"Renewing",
82 	"Rebinding",
83 	/* "Init-Reboot", */
84 	"Rebooting",
85 };
86 
87 struct dhcpleased_iface {
88 	LIST_ENTRY(dhcpleased_iface)	 entries;
89 	enum if_state			 state;
90 	struct event			 timer;
91 	struct timeval			 timo;
92 	uint32_t			 if_index;
93 	int				 rdomain;
94 	int				 running;
95 	struct ether_addr		 hw_address;
96 	int				 link_state;
97 	uint32_t			 cur_mtu;
98 	uint32_t			 xid;
99 	struct timespec			 request_time;
100 	struct in_addr			 server_identifier;
101 	struct in_addr			 dhcp_server; /* for unicast */
102 	struct in_addr			 requested_ip;
103 	struct in_addr			 mask;
104 	struct in_addr			 router;
105 	struct in_addr			 nameservers[MAX_RDNS_COUNT];
106 	uint32_t			 lease_time;
107 	uint32_t			 renewal_time;
108 	uint32_t			 rebinding_time;
109 };
110 
111 LIST_HEAD(, dhcpleased_iface) dhcpleased_interfaces;
112 
113 __dead void		 engine_shutdown(void);
114 void			 engine_sig_handler(int sig, short, void *);
115 void			 engine_dispatch_frontend(int, short, void *);
116 void			 engine_dispatch_main(int, short, void *);
117 #ifndef	SMALL
118 void			 send_interface_info(struct dhcpleased_iface *, pid_t);
119 void			 engine_showinfo_ctl(struct imsg *, uint32_t);
120 #endif	/* SMALL */
121 void			 engine_update_iface(struct imsg_ifinfo *);
122 struct dhcpleased_iface	*get_dhcpleased_iface_by_id(uint32_t);
123 void			 remove_dhcpleased_iface(uint32_t);
124 void			 parse_dhcp(struct dhcpleased_iface *,
125 			     struct imsg_dhcp *);
126 void			 state_transition(struct dhcpleased_iface *, enum
127 			     if_state);
128 void			 iface_timeout(int, short, void *);
129 void			 request_dhcp_discover(struct dhcpleased_iface *);
130 void			 request_dhcp_request(struct dhcpleased_iface *);
131 void			 log_lease(struct dhcpleased_iface *, int);
132 void			 log_rdns(struct dhcpleased_iface *, int);
133 void			 send_configure_interface(struct dhcpleased_iface *);
134 void			 send_rdns_proposal(struct dhcpleased_iface *);
135 void			 send_deconfigure_interface(struct dhcpleased_iface *);
136 void			 send_rdns_withdraw(struct dhcpleased_iface *);
137 void			 parse_lease(struct dhcpleased_iface *,
138 			     struct imsg_ifinfo *);
139 int			 engine_imsg_compose_main(int, pid_t, void *, uint16_t);
140 void			 log_dhcp_hdr(struct dhcp_hdr *);
141 const char		*dhcp_message_type2str(uint8_t);
142 
143 static struct imsgev	*iev_frontend;
144 static struct imsgev	*iev_main;
145 int64_t			 proposal_id;
146 
147 void
148 engine_sig_handler(int sig, short event, void *arg)
149 {
150 	/*
151 	 * Normal signal handler rules don't apply because libevent
152 	 * decouples for us.
153 	 */
154 
155 	switch (sig) {
156 	case SIGINT:
157 	case SIGTERM:
158 		engine_shutdown();
159 	default:
160 		fatalx("unexpected signal");
161 	}
162 }
163 
164 void
165 engine(int debug, int verbose)
166 {
167 	struct event		 ev_sigint, ev_sigterm;
168 	struct passwd		*pw;
169 
170 	log_init(debug, LOG_DAEMON);
171 	log_setverbose(verbose);
172 
173 	if ((pw = getpwnam(DHCPLEASED_USER)) == NULL)
174 		fatal("getpwnam");
175 
176 	if (chdir("/") == -1)
177 		fatal("chdir(\"/\")");
178 
179 	if (unveil("/", "") == -1)
180 		fatal("unveil(\"/\", \"\")");
181 	if (unveil(NULL, NULL) == -1)
182 		fatal("unveil(NULL, NULL)");
183 
184 	setproctitle("%s", "engine");
185 	log_procinit("engine");
186 
187 	if (setgroups(1, &pw->pw_gid) ||
188 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
189 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
190 		fatal("can't drop privileges");
191 
192 	if (pledge("stdio recvfd", NULL) == -1)
193 		fatal("pledge");
194 
195 	event_init();
196 
197 	/* Setup signal handler(s). */
198 	signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
199 	signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
200 	signal_add(&ev_sigint, NULL);
201 	signal_add(&ev_sigterm, NULL);
202 	signal(SIGPIPE, SIG_IGN);
203 	signal(SIGHUP, SIG_IGN);
204 
205 	/* Setup pipe and event handler to the main process. */
206 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
207 		fatal(NULL);
208 
209 	imsg_init(&iev_main->ibuf, 3);
210 	iev_main->handler = engine_dispatch_main;
211 
212 	/* Setup event handlers. */
213 	iev_main->events = EV_READ;
214 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
215 	    iev_main->handler, iev_main);
216 	event_add(&iev_main->ev, NULL);
217 
218 	LIST_INIT(&dhcpleased_interfaces);
219 
220 	event_dispatch();
221 
222 	engine_shutdown();
223 }
224 
225 __dead void
226 engine_shutdown(void)
227 {
228 	/* Close pipes. */
229 	msgbuf_clear(&iev_frontend->ibuf.w);
230 	close(iev_frontend->ibuf.fd);
231 	msgbuf_clear(&iev_main->ibuf.w);
232 	close(iev_main->ibuf.fd);
233 
234 	free(iev_frontend);
235 	free(iev_main);
236 
237 	log_info("engine exiting");
238 	exit(0);
239 }
240 
241 int
242 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
243     uint16_t datalen)
244 {
245 	return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
246 	    data, datalen));
247 }
248 
249 int
250 engine_imsg_compose_main(int type, pid_t pid, void *data,
251     uint16_t datalen)
252 {
253 	return (imsg_compose_event(iev_main, type, 0, pid, -1,
254 	    data, datalen));
255 }
256 
257 void
258 engine_dispatch_frontend(int fd, short event, void *bula)
259 {
260 	struct imsgev			*iev = bula;
261 	struct imsgbuf			*ibuf = &iev->ibuf;
262 	struct imsg			 imsg;
263 	struct dhcpleased_iface		*iface;
264 	ssize_t				 n;
265 	int				 shut = 0;
266 #ifndef	SMALL
267 	int				 verbose;
268 #endif	/* SMALL */
269 	uint32_t			 if_index;
270 
271 	if (event & EV_READ) {
272 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
273 			fatal("imsg_read error");
274 		if (n == 0)	/* Connection closed. */
275 			shut = 1;
276 	}
277 	if (event & EV_WRITE) {
278 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
279 			fatal("msgbuf_write");
280 		if (n == 0)	/* Connection closed. */
281 			shut = 1;
282 	}
283 
284 	for (;;) {
285 		if ((n = imsg_get(ibuf, &imsg)) == -1)
286 			fatal("%s: imsg_get error", __func__);
287 		if (n == 0)	/* No more messages. */
288 			break;
289 
290 		switch (imsg.hdr.type) {
291 #ifndef	SMALL
292 		case IMSG_CTL_LOG_VERBOSE:
293 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
294 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
295 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
296 			memcpy(&verbose, imsg.data, sizeof(verbose));
297 			log_setverbose(verbose);
298 			break;
299 		case IMSG_CTL_SHOW_INTERFACE_INFO:
300 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
301 				fatalx("%s: IMSG_CTL_SHOW_INTERFACE_INFO wrong "
302 				    "length: %lu", __func__,
303 				    IMSG_DATA_SIZE(imsg));
304 			memcpy(&if_index, imsg.data, sizeof(if_index));
305 			engine_showinfo_ctl(&imsg, if_index);
306 			break;
307 		case IMSG_CTL_SEND_REQUEST:
308 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
309 				fatalx("%s: IMSG_CTL_SEND_DISCOVER wrong "
310 				    "length: %lu", __func__,
311 				    IMSG_DATA_SIZE(imsg));
312 			memcpy(&if_index, imsg.data, sizeof(if_index));
313 			iface = get_dhcpleased_iface_by_id(if_index);
314 			if (iface != NULL) {
315 				switch (iface->state) {
316 				case IF_DOWN:
317 					break;
318 				case IF_INIT:
319 				case IF_REQUESTING:
320 				case IF_RENEWING:
321 				case IF_REBINDING:
322 				case IF_REBOOTING:
323 					state_transition(iface, iface->state);
324 					break;
325 				case IF_BOUND:
326 					state_transition(iface, IF_RENEWING);
327 					break;
328 				}
329 			}
330 			break;
331 #endif	/* SMALL */
332 		case IMSG_REMOVE_IF:
333 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
334 				fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
335 				    __func__, IMSG_DATA_SIZE(imsg));
336 			memcpy(&if_index, imsg.data, sizeof(if_index));
337 			remove_dhcpleased_iface(if_index);
338 			break;
339 		case IMSG_DHCP: {
340 			struct imsg_dhcp	imsg_dhcp;
341 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_dhcp))
342 				fatalx("%s: IMSG_DHCP wrong length: %lu",
343 				    __func__, IMSG_DATA_SIZE(imsg));
344 			memcpy(&imsg_dhcp, imsg.data, sizeof(imsg_dhcp));
345 			iface = get_dhcpleased_iface_by_id(imsg_dhcp.if_index);
346 			if (iface != NULL)
347 				parse_dhcp(iface, &imsg_dhcp);
348 			break;
349 		}
350 		case IMSG_REPROPOSE_RDNS:
351 			LIST_FOREACH (iface, &dhcpleased_interfaces, entries)
352 				send_rdns_proposal(iface);
353 			break;
354 		default:
355 			log_debug("%s: unexpected imsg %d", __func__,
356 			    imsg.hdr.type);
357 			break;
358 		}
359 		imsg_free(&imsg);
360 	}
361 	if (!shut)
362 		imsg_event_add(iev);
363 	else {
364 		/* This pipe is dead. Remove its event handler. */
365 		event_del(&iev->ev);
366 		event_loopexit(NULL);
367 	}
368 }
369 
370 void
371 engine_dispatch_main(int fd, short event, void *bula)
372 {
373 	struct imsg		 imsg;
374 	struct imsgev		*iev = bula;
375 	struct imsgbuf		*ibuf = &iev->ibuf;
376 	struct imsg_ifinfo	 imsg_ifinfo;
377 	ssize_t			 n;
378 	int			 shut = 0;
379 
380 	if (event & EV_READ) {
381 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
382 			fatal("imsg_read error");
383 		if (n == 0)	/* Connection closed. */
384 			shut = 1;
385 	}
386 	if (event & EV_WRITE) {
387 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
388 			fatal("msgbuf_write");
389 		if (n == 0)	/* Connection closed. */
390 			shut = 1;
391 	}
392 
393 	for (;;) {
394 		if ((n = imsg_get(ibuf, &imsg)) == -1)
395 			fatal("%s: imsg_get error", __func__);
396 		if (n == 0)	/* No more messages. */
397 			break;
398 
399 		switch (imsg.hdr.type) {
400 		case IMSG_SOCKET_IPC:
401 			/*
402 			 * Setup pipe and event handler to the frontend
403 			 * process.
404 			 */
405 			if (iev_frontend)
406 				fatalx("%s: received unexpected imsg fd "
407 				    "to engine", __func__);
408 
409 			if ((fd = imsg.fd) == -1)
410 				fatalx("%s: expected to receive imsg fd to "
411 				   "engine but didn't receive any", __func__);
412 
413 			iev_frontend = malloc(sizeof(struct imsgev));
414 			if (iev_frontend == NULL)
415 				fatal(NULL);
416 
417 			imsg_init(&iev_frontend->ibuf, fd);
418 			iev_frontend->handler = engine_dispatch_frontend;
419 			iev_frontend->events = EV_READ;
420 
421 			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
422 			iev_frontend->events, iev_frontend->handler,
423 			    iev_frontend);
424 			event_add(&iev_frontend->ev, NULL);
425 
426 			if (pledge("stdio", NULL) == -1)
427 				fatal("pledge");
428 
429 			break;
430 		case IMSG_UPDATE_IF:
431 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
432 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
433 				    __func__, IMSG_DATA_SIZE(imsg));
434 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
435 			engine_update_iface(&imsg_ifinfo);
436 			break;
437 		default:
438 			log_debug("%s: unexpected imsg %d", __func__,
439 			    imsg.hdr.type);
440 			break;
441 		}
442 		imsg_free(&imsg);
443 	}
444 	if (!shut)
445 		imsg_event_add(iev);
446 	else {
447 		/* This pipe is dead. Remove its event handler. */
448 		event_del(&iev->ev);
449 		event_loopexit(NULL);
450 	}
451 }
452 
453 #ifndef	SMALL
454 void
455 send_interface_info(struct dhcpleased_iface *iface, pid_t pid)
456 {
457 	struct ctl_engine_info	 cei;
458 
459 	memset(&cei, 0, sizeof(cei));
460 	cei.if_index = iface->if_index;
461 	cei.running = iface->running;
462 	cei.link_state = iface->link_state;
463 	strlcpy(cei.state, if_state_name[iface->state], sizeof(cei.state));
464 	memcpy(&cei.request_time, &iface->request_time,
465 	    sizeof(cei.request_time));
466 	cei.server_identifier.s_addr = iface->server_identifier.s_addr;
467 	cei.dhcp_server.s_addr = iface->dhcp_server.s_addr;
468 	cei.requested_ip.s_addr = iface->requested_ip.s_addr;
469 	cei.mask.s_addr = iface->mask.s_addr;
470 	cei.router.s_addr = iface->router.s_addr;
471 	memcpy(cei.nameservers, iface->nameservers, sizeof(cei.nameservers));
472 	cei.lease_time = iface->lease_time;
473 	cei.renewal_time = iface->renewal_time;
474 	cei.rebinding_time = iface->rebinding_time;
475 	engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
476 	    sizeof(cei));
477 }
478 
479 void
480 engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index)
481 {
482 	struct dhcpleased_iface			*iface;
483 
484 	switch (imsg->hdr.type) {
485 	case IMSG_CTL_SHOW_INTERFACE_INFO:
486 		if (if_index == 0) {
487 			LIST_FOREACH (iface, &dhcpleased_interfaces, entries)
488 				send_interface_info(iface, imsg->hdr.pid);
489 		} else {
490 			if ((iface = get_dhcpleased_iface_by_id(if_index)) !=
491 			    NULL)
492 				send_interface_info(iface, imsg->hdr.pid);
493 		}
494 		engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL,
495 		    0);
496 		break;
497 	default:
498 		log_debug("%s: error handling imsg", __func__);
499 		break;
500 	}
501 }
502 #endif	/* SMALL */
503 
504 void
505 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
506 {
507 	struct dhcpleased_iface	*iface;
508 	int			 need_refresh = 0;
509 
510 	iface = get_dhcpleased_iface_by_id(imsg_ifinfo->if_index);
511 
512 	if (iface == NULL) {
513 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
514 			fatal("calloc");
515 		iface->state = IF_DOWN;
516 		iface->timo.tv_usec = arc4random_uniform(1000000);
517 		evtimer_set(&iface->timer, iface_timeout, iface);
518 		iface->if_index = imsg_ifinfo->if_index;
519 		iface->rdomain = imsg_ifinfo->rdomain;
520 		iface->running = imsg_ifinfo->running;
521 		iface->link_state = imsg_ifinfo->link_state;
522 		iface->requested_ip.s_addr = INADDR_ANY;
523 		memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
524 		    sizeof(struct ether_addr));
525 		LIST_INSERT_HEAD(&dhcpleased_interfaces, iface, entries);
526 		need_refresh = 1;
527 	} else {
528 		if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address,
529 		    sizeof(struct ether_addr)) != 0) {
530 			memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
531 			    sizeof(struct ether_addr));
532 			need_refresh = 1;
533 		}
534 		if (imsg_ifinfo->rdomain != iface->rdomain) {
535 			iface->rdomain = imsg_ifinfo->rdomain;
536 			need_refresh = 1;
537 		}
538 		if (imsg_ifinfo->running != iface->running) {
539 			iface->running = imsg_ifinfo->running;
540 			need_refresh = 1;
541 		}
542 
543 		if (imsg_ifinfo->link_state != iface->link_state) {
544 			iface->link_state = imsg_ifinfo->link_state;
545 			need_refresh = 1;
546 		}
547 	}
548 
549 	if (!need_refresh)
550 		return;
551 
552 	if (iface->running && LINK_STATE_IS_UP(iface->link_state)) {
553 		if (iface->requested_ip.s_addr == INADDR_ANY)
554 			parse_lease(iface, imsg_ifinfo);
555 
556 		if (iface->requested_ip.s_addr == INADDR_ANY)
557 			state_transition(iface, IF_INIT);
558 		else
559 			state_transition(iface, IF_REBOOTING);
560 	} else
561 		state_transition(iface, IF_DOWN);
562 }
563 struct dhcpleased_iface*
564 get_dhcpleased_iface_by_id(uint32_t if_index)
565 {
566 	struct dhcpleased_iface	*iface;
567 	LIST_FOREACH (iface, &dhcpleased_interfaces, entries) {
568 		if (iface->if_index == if_index)
569 			return (iface);
570 	}
571 
572 	return (NULL);
573 }
574 
575 void
576 remove_dhcpleased_iface(uint32_t if_index)
577 {
578 	struct dhcpleased_iface	*iface;
579 
580 	iface = get_dhcpleased_iface_by_id(if_index);
581 
582 	if (iface == NULL)
583 		return;
584 
585 	send_rdns_withdraw(iface);
586 	send_deconfigure_interface(iface);
587 	LIST_REMOVE(iface, entries);
588 	evtimer_del(&iface->timer);
589 	free(iface);
590 }
591 
592 void
593 parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
594 {
595 	static uint8_t		 cookie[] = DHCP_COOKIE;
596 	static struct ether_addr bcast_mac;
597 	struct ether_header	*eh;
598 	struct ether_addr	 ether_src, ether_dst;
599 	struct ip		*ip;
600 	struct udphdr		*udp;
601 	struct dhcp_hdr		*dhcp_hdr;
602 	struct in_addr		 server_identifier, subnet_mask, router;
603 	struct in_addr		 nameservers[MAX_RDNS_COUNT];
604 	size_t			 rem, i;
605 	uint32_t		 sum, usum, lease_time = 0, renewal_time = 0;
606 	uint32_t		 rebinding_time = 0;
607 	uint8_t			*p, dho = DHO_PAD, dho_len;
608 	uint8_t			 dhcp_message_type = 0;
609 	char			 from[sizeof("xx:xx:xx:xx:xx:xx")];
610 	char			 to[sizeof("xx:xx:xx:xx:xx:xx")];
611 	char			 hbuf_src[INET_ADDRSTRLEN];
612 	char			 hbuf_dst[INET_ADDRSTRLEN];
613 	char			 hbuf[INET_ADDRSTRLEN];
614 	char			 vis_buf[4 * 255 + 1];
615 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
616 
617 	if (bcast_mac.ether_addr_octet[0] == 0)
618 		memset(bcast_mac.ether_addr_octet, 0xff, ETHER_ADDR_LEN);
619 
620 	memset(hbuf_src, 0, sizeof(hbuf_src));
621 	memset(hbuf_dst, 0, sizeof(hbuf_dst));
622 
623 	p = dhcp->packet;
624 	rem = dhcp->len;
625 
626 	if (rem < sizeof(*eh)) {
627 		log_warnx("%s: message too short", __func__);
628 		return;
629 	}
630 	eh = (struct ether_header *)p;
631 	memcpy(ether_src.ether_addr_octet, eh->ether_shost,
632 	    sizeof(ether_src.ether_addr_octet));
633 	strlcpy(from, ether_ntoa(&ether_src), sizeof(from));
634 	memcpy(ether_dst.ether_addr_octet, eh->ether_dhost,
635 	    sizeof(ether_dst.ether_addr_octet));
636 	strlcpy(to, ether_ntoa(&ether_dst), sizeof(to));
637 	p += sizeof(*eh);
638 	rem -= sizeof(*eh);
639 
640 	if (memcmp(&ether_dst, &iface->hw_address, sizeof(ether_dst)) != 0 &&
641 	    memcmp(&ether_dst, &bcast_mac, sizeof(ether_dst)) != 0)
642 		return ; /* silently ignore packet not for us */
643 
644 	if (rem < sizeof(*ip))
645 		goto too_short;
646 
647 	if (log_getverbose() > 1)
648 		log_debug("%s, from: %s, to: %s", __func__, from, to);
649 
650 	ip = (struct ip *)p;
651 
652 	if (rem < (size_t)ip->ip_hl << 2)
653 		goto too_short;
654 
655 	if (wrapsum(checksum((uint8_t *)ip, ip->ip_hl << 2, 0)) != 0) {
656 		log_warnx("%s: bad IP checksum", __func__);
657 		return;
658 	}
659 	if (rem < ntohs(ip->ip_len))
660 		goto too_short;
661 
662 	p += ip->ip_hl << 2;
663 	rem -= ip->ip_hl << 2;
664 
665 	if (inet_ntop(AF_INET, &ip->ip_src, hbuf_src, sizeof(hbuf_src)) == NULL)
666 		hbuf_src[0] = '\0';
667 	if (inet_ntop(AF_INET, &ip->ip_dst, hbuf_dst, sizeof(hbuf_dst)) == NULL)
668 		hbuf_dst[0] = '\0';
669 
670 	if (rem < sizeof(*udp))
671 		goto too_short;
672 
673 	udp = (struct udphdr *)p;
674 	if (rem < ntohs(udp->uh_ulen))
675 		goto too_short;
676 
677 	if (rem > ntohs(udp->uh_ulen)) {
678 		if (log_getverbose() > 1) {
679 			log_debug("%s: accepting packet with %lu bytes of data"
680 			    " after udp payload", __func__, rem -
681 			    ntohs(udp->uh_ulen));
682 		}
683 		rem = ntohs(udp->uh_ulen);
684 	}
685 
686 	p += sizeof(*udp);
687 	rem -= sizeof(*udp);
688 
689 	usum = udp->uh_sum;
690 	udp->uh_sum = 0;
691 
692 	sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp), checksum(p, rem,
693 	    checksum((uint8_t *)&ip->ip_src, 2 * sizeof(ip->ip_src),
694 	    IPPROTO_UDP + ntohs(udp->uh_ulen)))));
695 
696 	if (usum != 0 && usum != sum) {
697 		log_warnx("%s: bad UDP checksum", __func__);
698 		return;
699 	}
700 
701 	if (log_getverbose() > 1) {
702 		log_debug("%s: %s:%d -> %s:%d", __func__, hbuf_src,
703 		    ntohs(udp->uh_sport), hbuf_dst, ntohs(udp->uh_dport));
704 	}
705 
706 	if (ntohs(udp->uh_sport) != SERVER_PORT ||
707 	    ntohs(udp->uh_dport) != CLIENT_PORT) {
708 		log_warnx("%s: invalid ports used %s:%d -> %s:%d", __func__,
709 		    hbuf_src, ntohs(udp->uh_sport),
710 		    hbuf_dst, ntohs(udp->uh_dport));
711 		return;
712 	}
713 	if (rem < sizeof(*dhcp_hdr))
714 		goto too_short;
715 
716 	dhcp_hdr = (struct dhcp_hdr *)p;
717 	p += sizeof(*dhcp_hdr);
718 	rem -= sizeof(*dhcp_hdr);
719 
720 	dhcp_hdr->sname[DHCP_SNAME_LEN -1 ] = '\0'; /* ensure it's a string */
721 	dhcp_hdr->file[DHCP_FILE_LEN -1 ] = '\0'; /* ensure it's a string */
722 
723 	if (log_getverbose() > 1)
724 		log_dhcp_hdr(dhcp_hdr);
725 
726 	if (dhcp_hdr->op != DHCP_BOOTREPLY) {
727 		log_warnx("%s: ignorning non-reply packet", __func__);
728 		return;
729 	}
730 
731 	if (dhcp_hdr->xid != iface->xid)
732 		return; /* silently ignore wrong xid */
733 
734 	if (rem < sizeof(cookie))
735 		goto too_short;
736 
737 	if (memcmp(p, cookie, sizeof(cookie)) != 0) {
738 		log_warnx("%s: no dhcp cookie in packet from %s", __func__,
739 		    from);
740 		return;
741 	}
742 	p += sizeof(cookie);
743 	rem -= sizeof(cookie);
744 
745 	memset(&server_identifier, 0, sizeof(server_identifier));
746 	memset(&subnet_mask, 0, sizeof(subnet_mask));
747 	memset(&router, 0, sizeof(router));
748 	memset(&nameservers, 0, sizeof(nameservers));
749 
750 	while (rem > 0 && dho != DHO_END) {
751 		dho = *p;
752 		p += 1;
753 		rem -= 1;
754 		/* only DHO_END and DHO_PAD are 1 byte long without length */
755 		if (dho == DHO_PAD || dho == DHO_END)
756 			dho_len = 0;
757 		else {
758 			if (rem == 0)
759 				goto too_short; /* missing option length */
760 			dho_len = *p;
761 			p += 1;
762 			rem -= 1;
763 			if (rem < dho_len)
764 				goto too_short;
765 		}
766 
767 		switch (dho) {
768 		case DHO_PAD:
769 			if (log_getverbose() > 1)
770 				log_debug("DHO_PAD");
771 			break;
772 		case DHO_END:
773 			if (log_getverbose() > 1)
774 				log_debug("DHO_END");
775 			break;
776 		case DHO_DHCP_MESSAGE_TYPE:
777 			if (dho_len != 1)
778 				goto wrong_length;
779 			dhcp_message_type = *p;
780 			if (log_getverbose() > 1) {
781 				log_debug("DHO_DHCP_MESSAGE_TYPE: %s",
782 				    dhcp_message_type2str(dhcp_message_type));
783 			}
784 			p += dho_len;
785 			rem -= dho_len;
786 			break;
787 		case DHO_DHCP_SERVER_IDENTIFIER:
788 			if (dho_len != sizeof(server_identifier))
789 				goto wrong_length;
790 			memcpy(&server_identifier, p,
791 			    sizeof(server_identifier));
792 			if (log_getverbose() > 1) {
793 				log_debug("DHO_DHCP_SERVER_IDENTIFIER: %s",
794 				    inet_ntop(AF_INET, &server_identifier,
795 				    hbuf, sizeof(hbuf)));
796 			}
797 			p += dho_len;
798 			rem -= dho_len;
799 			break;
800 		case DHO_DHCP_LEASE_TIME:
801 			if (dho_len != sizeof(lease_time))
802 				goto wrong_length;
803 			memcpy(&lease_time, p, sizeof(lease_time));
804 			lease_time = ntohl(lease_time);
805 			if (log_getverbose() > 1) {
806 				log_debug("DHO_DHCP_LEASE_TIME %us",
807 				    lease_time);
808 			}
809 			p += dho_len;
810 			rem -= dho_len;
811 			break;
812 		case DHO_SUBNET_MASK:
813 			if (dho_len != sizeof(subnet_mask))
814 				goto wrong_length;
815 			memcpy(&subnet_mask, p, sizeof(subnet_mask));
816 			if (log_getverbose() > 1) {
817 				log_debug("DHO_SUBNET_MASK: %s",
818 				    inet_ntop(AF_INET, &subnet_mask, hbuf,
819 				    sizeof(hbuf)));
820 			}
821 			p += dho_len;
822 			rem -= dho_len;
823 			break;
824 		case DHO_ROUTERS:
825 			if (dho_len < sizeof(router))
826 				goto wrong_length;
827 			if (dho_len % sizeof(router) != 0)
828 				goto wrong_length;
829 			/* we only use one router */
830 			memcpy(&router, p, sizeof(router));
831 			if (log_getverbose() > 1) {
832 				log_debug("DHO_ROUTER: %s (1/%lu)",
833 				    inet_ntop(AF_INET, &router, hbuf,
834 				    sizeof(hbuf)), dho_len / sizeof(router));
835 			}
836 			p += dho_len;
837 			rem -= dho_len;
838 			break;
839 		case DHO_DOMAIN_NAME_SERVERS:
840 			if (dho_len < sizeof(nameservers[0]))
841 				goto wrong_length;
842 			if (dho_len % sizeof(nameservers[0]) != 0)
843 				goto wrong_length;
844 			/* we limit ourself to 8 nameservers for proposals */
845 			memcpy(&nameservers, p, MINIMUM(sizeof(nameservers),
846 			    dho_len));
847 			if (log_getverbose() > 1) {
848 				for (i = 0; i < MINIMUM(sizeof(nameservers),
849 				    dho_len / sizeof(nameservers[0])); i++) {
850 					log_debug("DHO_DOMAIN_NAME_SERVERS: %s "
851 					    "(%lu/%lu)", inet_ntop(AF_INET,
852 					    &nameservers[i], hbuf,
853 					    sizeof(hbuf)), i + 1,
854 					    dho_len / sizeof(nameservers[0]));
855 				}
856 			}
857 			p += dho_len;
858 			rem -= dho_len;
859 			break;
860 		case DHO_DOMAIN_NAME:
861 			if ( dho_len < 1)
862 				goto wrong_length;
863 			if (log_getverbose() > 1) {
864 				strvisx(vis_buf, p, dho_len, VIS_SAFE);
865 				log_debug("DHO_DOMAIN_NAME: %s", vis_buf);
866 			}
867 			p += dho_len;
868 			rem -= dho_len;
869 			break;
870 		case DHO_DHCP_RENEWAL_TIME:
871 			if (dho_len != sizeof(renewal_time))
872 				goto wrong_length;
873 			memcpy(&renewal_time, p, sizeof(renewal_time));
874 			renewal_time = ntohl(renewal_time);
875 			if (log_getverbose() > 1) {
876 				log_debug("DHO_DHCP_RENEWAL_TIME %us",
877 				    renewal_time);
878 			}
879 			p += dho_len;
880 			rem -= dho_len;
881 			break;
882 		case DHO_DHCP_REBINDING_TIME:
883 			if (dho_len != sizeof(rebinding_time))
884 				goto wrong_length;
885 			memcpy(&rebinding_time, p, sizeof(rebinding_time));
886 			rebinding_time = ntohl(rebinding_time);
887 			if (log_getverbose() > 1) {
888 				log_debug("DHO_DHCP_REBINDING_TIME %us",
889 				    rebinding_time);
890 			}
891 			p += dho_len;
892 			rem -= dho_len;
893 			break;
894 		case DHO_DHCP_CLIENT_IDENTIFIER:
895 			/* the server is supposed to echo this back to us */
896 			if (dho_len != 1 + sizeof(iface->hw_address))
897 				goto wrong_length;
898 			if (*p != HTYPE_ETHER) {
899 				log_warn("DHO_DHCP_CLIENT_IDENTIFIER: wrong "
900 				    "type");
901 				return;
902 			}
903 			if (memcmp(p + 1, &iface->hw_address,
904 			    sizeof(iface->hw_address)) != 0) {
905 				log_warn("wrong DHO_DHCP_CLIENT_IDENTIFIER");
906 				return;
907 			}
908 			p += dho_len;
909 			rem -= dho_len;
910 			break;
911 		default:
912 			if (log_getverbose() > 1)
913 				log_debug("DHO_%u, len: %u", dho, dho_len);
914 			p += dho_len;
915 			rem -= dho_len;
916 		}
917 
918 	}
919 	while (rem != 0) {
920 		if (*p != DHO_PAD)
921 			break;
922 		p++;
923 		rem--;
924 	}
925 	if (rem != 0)
926 		log_warnx("%s: %lu bytes garbage data from %s", __func__, rem,
927 		    from);
928 
929 	if_name = if_indextoname(iface->if_index, ifnamebuf);
930 	log_debug("%s on %s from %s/%s to %s/%s",
931 	    dhcp_message_type2str(dhcp_message_type), if_name == NULL ? "?" :
932 	    if_name, from, hbuf_src, to, hbuf_dst);
933 
934 	switch (dhcp_message_type) {
935 	case DHCPOFFER:
936 		if (iface->state != IF_INIT) {
937 			log_debug("ignoring unexpected DHCPOFFER");
938 			return;
939 		}
940 		if (server_identifier.s_addr == INADDR_ANY &&
941 		    dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
942 			log_warnx("%s: did not receive server identifier or "
943 			    "offered IP address", __func__);
944 			return;
945 		}
946 		iface->server_identifier.s_addr = server_identifier.s_addr;
947 		iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr;
948 		state_transition(iface, IF_REQUESTING);
949 		break;
950 	case DHCPACK:
951 		switch (iface->state) {
952 		case IF_REQUESTING:
953 		case IF_RENEWING:
954 		case IF_REBINDING:
955 		case IF_REBOOTING:
956 			break;
957 		default:
958 			log_debug("ignoring unexpected DHCPACK");
959 			return;
960 		}
961 		if (server_identifier.s_addr == INADDR_ANY &&
962 		    dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
963 			log_warnx("%s: did not receive server identifier or "
964 			    "offered IP address", __func__);
965 			return;
966 		}
967 		if (lease_time == 0) {
968 			log_warnx("%s no lease time from %s", __func__, from);
969 			return;
970 		}
971 		if (subnet_mask.s_addr == INADDR_ANY) {
972 			log_warnx("%s: no subnetmask received from %s",
973 			    __func__, from);
974 			return;
975 		}
976 
977 		/* RFC 2131 4.4.5 */
978 		/* Ignore invalid T1/T2 options */
979 		if (renewal_time >= rebinding_time) {
980 			log_warnx("%s: renewal_time(%u) >= rebinding_time(%u) "
981 			    "from %s: using defaults",
982 			    __func__, renewal_time, rebinding_time, from);
983 			renewal_time = rebinding_time = 0;
984 		} else if (rebinding_time >= lease_time) {
985 			log_warnx("%s: rebinding_time(%u) >= lease_time(%u) "
986 			    "from %s: using defaults",
987 			    __func__, rebinding_time, lease_time, from);
988 			renewal_time = rebinding_time = 0;
989 		}
990 
991 		if (renewal_time == 0)
992 			renewal_time = lease_time / 2;
993 		if (rebinding_time == 0)
994 			rebinding_time = lease_time - (lease_time / 8);
995 
996 		clock_gettime(CLOCK_MONOTONIC, &iface->request_time);
997 		iface->server_identifier.s_addr = server_identifier.s_addr;
998 		iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr;
999 		iface->mask.s_addr = subnet_mask.s_addr;
1000 		iface->router.s_addr = router.s_addr;
1001 		iface->lease_time = lease_time;
1002 		iface->renewal_time = renewal_time;
1003 		iface->rebinding_time = rebinding_time;
1004 		memcpy(iface->nameservers, nameservers,
1005 		    sizeof(iface->nameservers));
1006 		state_transition(iface, IF_BOUND);
1007 		break;
1008 	case DHCPNAK:
1009 		switch (iface->state) {
1010 		case IF_REQUESTING:
1011 		case IF_RENEWING:
1012 		case IF_REBINDING:
1013 		case IF_REBOOTING:
1014 			break;
1015 		default:
1016 			log_debug("ignoring unexpected DHCPNAK");
1017 			return;
1018 		}
1019 
1020 		state_transition(iface, IF_INIT);
1021 		break;
1022 	default:
1023 		log_warnx("%s: unimplemented message type %d", __func__,
1024 		    dhcp_message_type);
1025 		break;
1026 	}
1027 	return;
1028  too_short:
1029 	log_warnx("%s: message from %s too short", __func__, from);
1030 	return;
1031  wrong_length:
1032 	log_warnx("%s: received option %d with wrong length: %d", __func__,
1033 	    dho, dho_len);
1034 	return;
1035 }
1036 
1037 /* XXX check valid transitions */
1038 void
1039 state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
1040 {
1041 	enum if_state	 old_state = iface->state;
1042 	struct timespec	 now, res;
1043 	char		 ifnamebuf[IF_NAMESIZE], *if_name;
1044 
1045 	iface->state = new_state;
1046 	switch (new_state) {
1047 	case IF_DOWN:
1048 		if (iface->requested_ip.s_addr == INADDR_ANY) {
1049 			/* nothing to do until iface comes up */
1050 			iface->timo.tv_sec = -1;
1051 			break;
1052 		}
1053 		if (old_state == IF_DOWN) {
1054 			/* nameservers already withdrawn when if went down */
1055 			send_deconfigure_interface(iface);
1056 			/* nothing more to do until iface comes back */
1057 			iface->timo.tv_sec = -1;
1058 		} else {
1059 			send_rdns_withdraw(iface);
1060 			clock_gettime(CLOCK_MONOTONIC, &now);
1061 			timespecsub(&now, &iface->request_time, &res);
1062 			iface->timo.tv_sec = iface->lease_time - res.tv_sec;
1063 			if (iface->timo.tv_sec < 0)
1064 				iface->timo.tv_sec = 0; /* deconfigure now */
1065 		}
1066 		break;
1067 	case IF_INIT:
1068 		switch (old_state) {
1069 		case IF_INIT:
1070 			if (iface->timo.tv_sec < MAX_EXP_BACKOFF_SLOW)
1071 				iface->timo.tv_sec *= 2;
1072 			break;
1073 		case IF_REQUESTING:
1074 		case IF_RENEWING:
1075 		case IF_REBINDING:
1076 		case IF_REBOOTING:
1077 			/* lease expired, got DHCPNAK or timeout: delete IP */
1078 			send_rdns_withdraw(iface);
1079 			send_deconfigure_interface(iface);
1080 			/* fall through */
1081 		case IF_DOWN:
1082 			iface->timo.tv_sec = START_EXP_BACKOFF;
1083 			break;
1084 		case IF_BOUND:
1085 			fatal("invalid transition Bound -> Init");
1086 			break;
1087 		}
1088 		request_dhcp_discover(iface);
1089 		break;
1090 	case IF_REBOOTING:
1091 		if (old_state == IF_REBOOTING)
1092 			iface->timo.tv_sec *= 2;
1093 		else {
1094 			/* make sure we send broadcast */
1095 			iface->dhcp_server.s_addr = INADDR_ANY;
1096 			iface->timo.tv_sec = START_EXP_BACKOFF;
1097 		}
1098 		request_dhcp_request(iface);
1099 		break;
1100 	case IF_REQUESTING:
1101 		if (old_state == IF_REQUESTING)
1102 			iface->timo.tv_sec *= 2;
1103 		else
1104 			iface->timo.tv_sec = START_EXP_BACKOFF;
1105 		request_dhcp_request(iface);
1106 		break;
1107 	case IF_BOUND:
1108 		iface->timo.tv_sec = iface->renewal_time;
1109 		if (old_state == IF_REQUESTING || old_state == IF_REBOOTING) {
1110 			send_configure_interface(iface);
1111 			send_rdns_proposal(iface);
1112 		}
1113 		break;
1114 	case IF_RENEWING:
1115 		if (old_state == IF_BOUND) {
1116 			iface->dhcp_server.s_addr =
1117 			    iface->server_identifier.s_addr;
1118 			iface->server_identifier.s_addr = INADDR_ANY;
1119 
1120 			iface->timo.tv_sec = (iface->rebinding_time -
1121 			    iface->renewal_time) / 2; /* RFC 2131 4.4.5 */
1122 		} else
1123 			iface->timo.tv_sec /= 2;
1124 
1125 		if (iface->timo.tv_sec < 60)
1126 			iface->timo.tv_sec = 60;
1127 		request_dhcp_request(iface);
1128 		break;
1129 	case IF_REBINDING:
1130 		if (old_state == IF_RENEWING) {
1131 			iface->dhcp_server.s_addr = INADDR_ANY;
1132 			iface->timo.tv_sec = (iface->lease_time -
1133 			    iface->renewal_time) / 2; /* RFC 2131 4.4.5 */
1134 		} else
1135 			iface->timo.tv_sec /= 2;
1136 		request_dhcp_request(iface);
1137 		break;
1138 	}
1139 
1140 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1141 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1142 	    "?" : if_name, if_state_name[old_state], if_state_name[new_state],
1143 	    iface->timo.tv_sec);
1144 
1145 	if (iface->timo.tv_sec == -1) {
1146 		if (evtimer_pending(&iface->timer, NULL))
1147 			evtimer_del(&iface->timer);
1148 	} else
1149 		evtimer_add(&iface->timer, &iface->timo);
1150 }
1151 
1152 void
1153 iface_timeout(int fd, short events, void *arg)
1154 {
1155 	struct dhcpleased_iface	*iface = (struct dhcpleased_iface *)arg;
1156 	struct timespec		 now, res;
1157 
1158 	log_debug("%s[%d]: %s", __func__, iface->if_index,
1159 	    if_state_name[iface->state]);
1160 
1161 	switch (iface->state) {
1162 	case IF_DOWN:
1163 		state_transition(iface, IF_DOWN);
1164 		break;
1165 	case IF_INIT:
1166 		state_transition(iface, IF_INIT);
1167 		break;
1168 	case IF_REBOOTING:
1169 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST)
1170 			state_transition(iface, IF_INIT);
1171 		else
1172 			state_transition(iface, IF_REBOOTING);
1173 		break;
1174 	case IF_REQUESTING:
1175 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST)
1176 			state_transition(iface, IF_INIT);
1177 		else
1178 			state_transition(iface, IF_REQUESTING);
1179 		break;
1180 	case IF_BOUND:
1181 		state_transition(iface, IF_RENEWING);
1182 		break;
1183 	case IF_RENEWING:
1184 		clock_gettime(CLOCK_MONOTONIC, &now);
1185 		timespecsub(&now, &iface->request_time, &res);
1186 		log_debug("%s: res.tv_sec: %lld, rebinding_time: %u", __func__,
1187 		    res.tv_sec, iface->rebinding_time);
1188 		if (res.tv_sec > iface->rebinding_time)
1189 			state_transition(iface, IF_REBINDING);
1190 		else
1191 			state_transition(iface, IF_RENEWING);
1192 		break;
1193 	case IF_REBINDING:
1194 		clock_gettime(CLOCK_MONOTONIC, &now);
1195 		timespecsub(&now, &iface->request_time, &res);
1196 		log_debug("%s: res.tv_sec: %lld, lease_time: %u", __func__,
1197 		    res.tv_sec, iface->lease_time);
1198 		if (res.tv_sec > iface->lease_time)
1199 			state_transition(iface, IF_INIT);
1200 		else
1201 			state_transition(iface, IF_REBINDING);
1202 		break;
1203 	}
1204 }
1205 
1206 void
1207 request_dhcp_discover(struct dhcpleased_iface *iface)
1208 {
1209 	struct imsg_req_discover	 imsg_req_discover;
1210 
1211 	imsg_req_discover.if_index = iface->if_index;
1212 	imsg_req_discover.xid = iface->xid = arc4random();
1213 	engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, &imsg_req_discover,
1214 	    sizeof(imsg_req_discover));
1215 }
1216 
1217 void
1218 request_dhcp_request(struct dhcpleased_iface *iface)
1219 {
1220 	struct imsg_req_request	 imsg_req_request;
1221 
1222 	iface->xid = arc4random();
1223 	imsg_req_request.if_index = iface->if_index;
1224 	imsg_req_request.xid = iface->xid;
1225 	imsg_req_request.server_identifier.s_addr =
1226 	    iface->server_identifier.s_addr;
1227 	imsg_req_request.requested_ip.s_addr = iface->requested_ip.s_addr;
1228 	imsg_req_request.dhcp_server.s_addr =  iface->dhcp_server.s_addr;
1229 	engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg_req_request,
1230 	    sizeof(imsg_req_request));
1231 }
1232 
1233 void
1234 log_lease(struct dhcpleased_iface *iface, int deconfigure)
1235 {
1236 	char	 hbuf_lease[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1237 	char	 ifnamebuf[IF_NAMESIZE], *if_name;
1238 
1239 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1240 	inet_ntop(AF_INET, &iface->requested_ip, hbuf_lease,
1241 	    sizeof(hbuf_lease));
1242 	inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1243 	    sizeof(hbuf_server));
1244 
1245 
1246 	if (deconfigure)
1247 		log_info("deleting %s from %s (lease from %s)", hbuf_lease,
1248 		    if_name == NULL ? "?" : if_name, hbuf_server);
1249 	else
1250 		log_info("adding %s to %s (lease from %s)", hbuf_lease,
1251 		    if_name == NULL ? "?" : if_name, hbuf_server);
1252 }
1253 
1254 void
1255 send_configure_interface(struct dhcpleased_iface *iface)
1256 {
1257 	struct imsg_configure_interface	 imsg;
1258 
1259 	log_lease(iface, 0);
1260 
1261 	imsg.if_index = iface->if_index;
1262 	imsg.rdomain = iface->rdomain;
1263 	imsg.addr.s_addr = iface->requested_ip.s_addr;
1264 	imsg.mask.s_addr = iface->mask.s_addr;
1265 	imsg.router.s_addr = iface->router.s_addr;
1266 	engine_imsg_compose_main(IMSG_CONFIGURE_INTERFACE, 0, &imsg,
1267 	    sizeof(imsg));
1268 }
1269 
1270 void
1271 send_deconfigure_interface(struct dhcpleased_iface *iface)
1272 {
1273 	struct imsg_configure_interface	 imsg;
1274 
1275 	if (iface->requested_ip.s_addr == INADDR_ANY)
1276 		return;
1277 
1278 	log_lease(iface, 1);
1279 
1280 	imsg.if_index = iface->if_index;
1281 	imsg.rdomain = iface->rdomain;
1282 	imsg.addr.s_addr = iface->requested_ip.s_addr;
1283 	imsg.mask.s_addr = iface->mask.s_addr;
1284 	imsg.router.s_addr = iface->router.s_addr;
1285 	engine_imsg_compose_main(IMSG_DECONFIGURE_INTERFACE, 0, &imsg,
1286 	    sizeof(imsg));
1287 
1288 	iface->server_identifier.s_addr = INADDR_ANY;
1289 	iface->dhcp_server.s_addr = INADDR_ANY;
1290 	iface->requested_ip.s_addr = INADDR_ANY;
1291 	iface->mask.s_addr = INADDR_ANY;
1292 	iface->router.s_addr = INADDR_ANY;
1293 }
1294 
1295 void
1296 log_rdns(struct dhcpleased_iface *iface, int withdraw)
1297 {
1298 	int	 i;
1299 	char	 hbuf_rdns[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1300 	char	 ifnamebuf[IF_NAMESIZE], *if_name, *rdns_buf = NULL, *tmp_buf;
1301 
1302 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1303 
1304 	inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1305 	    sizeof(hbuf_server));
1306 
1307 	for (i = 0; i < MAX_RDNS_COUNT && iface->nameservers[i].s_addr !=
1308 		 INADDR_ANY; i++) {
1309 		inet_ntop(AF_INET, &iface->nameservers[i], hbuf_rdns,
1310 		    sizeof(hbuf_rdns));
1311 		tmp_buf = rdns_buf;
1312 		if (asprintf(&rdns_buf, "%s %s", tmp_buf ? tmp_buf : "",
1313 		    hbuf_rdns) < 0) {
1314 			rdns_buf = NULL;
1315 			break;
1316 		}
1317 		free(tmp_buf);
1318 	}
1319 
1320 	if (rdns_buf != NULL) {
1321 		if (withdraw) {
1322 			log_info("deleting nameservers%s (lease from %s on %s)",
1323 			    rdns_buf, hbuf_server, if_name == NULL ? "?" :
1324 			    if_name);
1325 		} else {
1326 			log_info("adding nameservers%s (lease from %s on %s)",
1327 			    rdns_buf, hbuf_server, if_name == NULL ? "?" :
1328 			    if_name);
1329 		}
1330 		free(rdns_buf);
1331 	}
1332 }
1333 
1334 void
1335 send_rdns_proposal(struct dhcpleased_iface *iface)
1336 {
1337 	struct imsg_propose_rdns	 imsg;
1338 
1339 	log_rdns(iface, 0);
1340 
1341 	memset(&imsg, 0, sizeof(imsg));
1342 
1343 	imsg.if_index = iface->if_index;
1344 	imsg.rdomain = iface->rdomain;
1345 	for (imsg.rdns_count = 0; imsg.rdns_count < MAX_RDNS_COUNT &&
1346 		 iface->nameservers[imsg.rdns_count].s_addr != INADDR_ANY;
1347 	     imsg.rdns_count++)
1348 		;
1349 	memcpy(imsg.rdns, iface->nameservers, sizeof(imsg.rdns));
1350 	engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &imsg, sizeof(imsg));
1351 }
1352 
1353 void
1354 send_rdns_withdraw(struct dhcpleased_iface *iface)
1355 {
1356 	struct imsg_propose_rdns	 imsg;
1357 
1358 	log_rdns(iface, 1);
1359 
1360 	memset(&imsg, 0, sizeof(imsg));
1361 
1362 	imsg.if_index = iface->if_index;
1363 	imsg.rdomain = iface->rdomain;
1364 	engine_imsg_compose_main(IMSG_WITHDRAW_RDNS, 0, &imsg, sizeof(imsg));
1365 	memset(iface->nameservers, 0, sizeof(iface->nameservers));
1366 }
1367 
1368 void
1369 parse_lease(struct dhcpleased_iface *iface, struct imsg_ifinfo *imsg_ifinfo)
1370 {
1371 	char	*p, *p1;
1372 
1373 	/* make sure this is a string */
1374 	imsg_ifinfo->lease[sizeof(imsg_ifinfo->lease) - 1] = '\0';
1375 
1376 	iface->requested_ip.s_addr = INADDR_ANY;
1377 
1378 	if ((p = strstr(imsg_ifinfo->lease, LEASE_PREFIX)) == NULL)
1379 		return;
1380 
1381 	p += sizeof(LEASE_PREFIX) - 1;
1382 	if ((p1 = strchr(p, '\n')) == NULL)
1383 		return;
1384 	*p1 = '\0';
1385 
1386 	if (inet_pton(AF_INET, p, &iface->requested_ip) != 1)
1387 		iface->requested_ip.s_addr = INADDR_ANY;
1388 }
1389 
1390 void
1391 log_dhcp_hdr(struct dhcp_hdr *dhcp_hdr)
1392 {
1393 	char	 hbuf[INET_ADDRSTRLEN];
1394 
1395 	log_debug("dhcp_hdr op: %s (%d)", dhcp_hdr->op == DHCP_BOOTREQUEST ?
1396 	    "Boot Request" : dhcp_hdr->op == DHCP_BOOTREPLY ? "Boot Reply" :
1397 	    "Unknown", dhcp_hdr->op);
1398 	log_debug("dhcp_hdr htype: %s (%d)", dhcp_hdr->htype == 1 ? "Ethernet":
1399 	    "Unknown", dhcp_hdr->htype);
1400 	log_debug("dhcp_hdr hlen: %d", dhcp_hdr->hlen);
1401 	log_debug("dhcp_hdr hops: %d", dhcp_hdr->hops);
1402 	log_debug("dhcp_hdr xid: 0x%x", dhcp_hdr->xid);
1403 	log_debug("dhcp_hdr secs: %u", dhcp_hdr->secs);
1404 	log_debug("dhcp_hdr flags: 0x%x", dhcp_hdr->flags);
1405 	log_debug("dhcp_hdr ciaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->ciaddr,
1406 	    hbuf, sizeof(hbuf)));
1407 	log_debug("dhcp_hdr yiaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->yiaddr,
1408 	    hbuf, sizeof(hbuf)));
1409 	log_debug("dhcp_hdr siaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->siaddr,
1410 	    hbuf, sizeof(hbuf)));
1411 	log_debug("dhcp_hdr giaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->giaddr,
1412 	    hbuf, sizeof(hbuf)));
1413 	log_debug("dhcp_hdr chaddr: %02x:%02x:%02x:%02x:%02x:%02x "
1414 	    "(%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x)",
1415 	    dhcp_hdr->chaddr[0], dhcp_hdr->chaddr[1], dhcp_hdr->chaddr[2],
1416 	    dhcp_hdr->chaddr[3], dhcp_hdr->chaddr[4], dhcp_hdr->chaddr[5],
1417 	    dhcp_hdr->chaddr[6], dhcp_hdr->chaddr[7], dhcp_hdr->chaddr[8],
1418 	    dhcp_hdr->chaddr[9], dhcp_hdr->chaddr[10], dhcp_hdr->chaddr[11],
1419 	    dhcp_hdr->chaddr[12], dhcp_hdr->chaddr[13], dhcp_hdr->chaddr[14],
1420 	    dhcp_hdr->chaddr[15]);
1421 	/* ignore sname and file, if we ever print it use strvis(3) */
1422 }
1423 
1424 const char *
1425 dhcp_message_type2str(uint8_t dhcp_message_type)
1426 {
1427 	switch (dhcp_message_type) {
1428 	case DHCPDISCOVER:
1429 		return "DHCPDISCOVER";
1430 	case DHCPOFFER:
1431 		return "DHCPOFFER";
1432 	case DHCPREQUEST:
1433 		return "DHCPREQUEST";
1434 	case DHCPDECLINE:
1435 		return "DHCPDECLINE";
1436 	case DHCPACK:
1437 		return "DHCPACK";
1438 	case DHCPNAK:
1439 		return "DHCPNAK";
1440 	case DHCPRELEASE:
1441 		return "DHCPRELEASE";
1442 	case DHCPINFORM:
1443 		return "DHCPINFORM";
1444 	default:
1445 		return "Unknown";
1446 	}
1447 }
1448