xref: /openbsd-src/sbin/dhcpleased/engine.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: engine.c,v 1.38 2022/05/05 14:44:59 tb 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			 siaddr;
105 	char				 file[4 * DHCP_FILE_LEN + 1];
106 	char				 hostname[4 * 255 + 1];
107 	char				 domainname[4 * 255 + 1];
108 	struct dhcp_route		 prev_routes[MAX_DHCP_ROUTES];
109 	int				 prev_routes_len;
110 	struct dhcp_route		 routes[MAX_DHCP_ROUTES];
111 	int				 routes_len;
112 	struct in_addr			 nameservers[MAX_RDNS_COUNT];
113 	uint32_t			 lease_time;
114 	uint32_t			 renewal_time;
115 	uint32_t			 rebinding_time;
116 };
117 
118 LIST_HEAD(, dhcpleased_iface) dhcpleased_interfaces;
119 
120 __dead void		 engine_shutdown(void);
121 void			 engine_sig_handler(int sig, short, void *);
122 void			 engine_dispatch_frontend(int, short, void *);
123 void			 engine_dispatch_main(int, short, void *);
124 #ifndef	SMALL
125 void			 send_interface_info(struct dhcpleased_iface *, pid_t);
126 void			 engine_showinfo_ctl(struct imsg *, uint32_t);
127 #endif	/* SMALL */
128 void			 engine_update_iface(struct imsg_ifinfo *);
129 struct dhcpleased_iface	*get_dhcpleased_iface_by_id(uint32_t);
130 void			 remove_dhcpleased_iface(uint32_t);
131 void			 parse_dhcp(struct dhcpleased_iface *,
132 			     struct imsg_dhcp *);
133 void			 state_transition(struct dhcpleased_iface *, enum
134 			     if_state);
135 void			 iface_timeout(int, short, void *);
136 void			 request_dhcp_discover(struct dhcpleased_iface *);
137 void			 request_dhcp_request(struct dhcpleased_iface *);
138 void			 log_lease(struct dhcpleased_iface *, int);
139 void			 log_rdns(struct dhcpleased_iface *, int);
140 void			 send_configure_interface(struct dhcpleased_iface *);
141 void			 send_rdns_proposal(struct dhcpleased_iface *);
142 void			 send_deconfigure_interface(struct dhcpleased_iface *);
143 void			 send_rdns_withdraw(struct dhcpleased_iface *);
144 void			 send_routes_withdraw(struct dhcpleased_iface *);
145 void			 parse_lease(struct dhcpleased_iface *,
146 			     struct imsg_ifinfo *);
147 int			 engine_imsg_compose_main(int, pid_t, void *, uint16_t);
148 void			 log_dhcp_hdr(struct dhcp_hdr *);
149 const char		*dhcp_message_type2str(uint8_t);
150 
151 #ifndef SMALL
152 struct dhcpleased_conf	*engine_conf;
153 #endif /* SMALL */
154 
155 static struct imsgev	*iev_frontend;
156 static struct imsgev	*iev_main;
157 int64_t			 proposal_id;
158 
159 void
160 engine_sig_handler(int sig, short event, void *arg)
161 {
162 	/*
163 	 * Normal signal handler rules don't apply because libevent
164 	 * decouples for us.
165 	 */
166 
167 	switch (sig) {
168 	case SIGINT:
169 	case SIGTERM:
170 		engine_shutdown();
171 	default:
172 		fatalx("unexpected signal");
173 	}
174 }
175 
176 void
177 engine(int debug, int verbose)
178 {
179 	struct event		 ev_sigint, ev_sigterm;
180 	struct passwd		*pw;
181 
182 #ifndef SMALL
183 	engine_conf = config_new_empty();
184 #endif /* SMALL */
185 
186 	log_init(debug, LOG_DAEMON);
187 	log_setverbose(verbose);
188 
189 	if ((pw = getpwnam(DHCPLEASED_USER)) == NULL)
190 		fatal("getpwnam");
191 
192 	if (chdir("/") == -1)
193 		fatal("chdir(\"/\")");
194 
195 	if (unveil("/", "") == -1)
196 		fatal("unveil /");
197 	if (unveil(NULL, NULL) == -1)
198 		fatal("unveil");
199 
200 	setproctitle("%s", "engine");
201 	log_procinit("engine");
202 
203 	if (setgroups(1, &pw->pw_gid) ||
204 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
205 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
206 		fatal("can't drop privileges");
207 
208 	if (pledge("stdio recvfd", NULL) == -1)
209 		fatal("pledge");
210 
211 	event_init();
212 
213 	/* Setup signal handler(s). */
214 	signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
215 	signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
216 	signal_add(&ev_sigint, NULL);
217 	signal_add(&ev_sigterm, NULL);
218 	signal(SIGPIPE, SIG_IGN);
219 	signal(SIGHUP, SIG_IGN);
220 
221 	/* Setup pipe and event handler to the main process. */
222 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
223 		fatal(NULL);
224 
225 	imsg_init(&iev_main->ibuf, 3);
226 	iev_main->handler = engine_dispatch_main;
227 
228 	/* Setup event handlers. */
229 	iev_main->events = EV_READ;
230 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
231 	    iev_main->handler, iev_main);
232 	event_add(&iev_main->ev, NULL);
233 
234 	LIST_INIT(&dhcpleased_interfaces);
235 
236 	event_dispatch();
237 
238 	engine_shutdown();
239 }
240 
241 __dead void
242 engine_shutdown(void)
243 {
244 	/* Close pipes. */
245 	msgbuf_clear(&iev_frontend->ibuf.w);
246 	close(iev_frontend->ibuf.fd);
247 	msgbuf_clear(&iev_main->ibuf.w);
248 	close(iev_main->ibuf.fd);
249 
250 	free(iev_frontend);
251 	free(iev_main);
252 
253 	log_info("engine exiting");
254 	exit(0);
255 }
256 
257 int
258 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
259     uint16_t datalen)
260 {
261 	return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
262 	    data, datalen));
263 }
264 
265 int
266 engine_imsg_compose_main(int type, pid_t pid, void *data,
267     uint16_t datalen)
268 {
269 	return (imsg_compose_event(iev_main, type, 0, pid, -1,
270 	    data, datalen));
271 }
272 
273 void
274 engine_dispatch_frontend(int fd, short event, void *bula)
275 {
276 	struct imsgev			*iev = bula;
277 	struct imsgbuf			*ibuf = &iev->ibuf;
278 	struct imsg			 imsg;
279 	struct dhcpleased_iface		*iface;
280 	ssize_t				 n;
281 	int				 shut = 0;
282 #ifndef	SMALL
283 	int				 verbose;
284 #endif	/* SMALL */
285 	uint32_t			 if_index;
286 
287 	if (event & EV_READ) {
288 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
289 			fatal("imsg_read error");
290 		if (n == 0)	/* Connection closed. */
291 			shut = 1;
292 	}
293 	if (event & EV_WRITE) {
294 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
295 			fatal("msgbuf_write");
296 		if (n == 0)	/* Connection closed. */
297 			shut = 1;
298 	}
299 
300 	for (;;) {
301 		if ((n = imsg_get(ibuf, &imsg)) == -1)
302 			fatal("%s: imsg_get error", __func__);
303 		if (n == 0)	/* No more messages. */
304 			break;
305 
306 		switch (imsg.hdr.type) {
307 #ifndef	SMALL
308 		case IMSG_CTL_LOG_VERBOSE:
309 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
310 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
311 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
312 			memcpy(&verbose, imsg.data, sizeof(verbose));
313 			log_setverbose(verbose);
314 			break;
315 		case IMSG_CTL_SHOW_INTERFACE_INFO:
316 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
317 				fatalx("%s: IMSG_CTL_SHOW_INTERFACE_INFO wrong "
318 				    "length: %lu", __func__,
319 				    IMSG_DATA_SIZE(imsg));
320 			memcpy(&if_index, imsg.data, sizeof(if_index));
321 			engine_showinfo_ctl(&imsg, if_index);
322 			break;
323 		case IMSG_REQUEST_REBOOT:
324 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
325 				fatalx("%s: IMSG_CTL_SEND_DISCOVER wrong "
326 				    "length: %lu", __func__,
327 				    IMSG_DATA_SIZE(imsg));
328 			memcpy(&if_index, imsg.data, sizeof(if_index));
329 			iface = get_dhcpleased_iface_by_id(if_index);
330 			if (iface != NULL) {
331 				switch (iface->state) {
332 				case IF_DOWN:
333 					break;
334 				case IF_INIT:
335 				case IF_REQUESTING:
336 					state_transition(iface, iface->state);
337 					break;
338 				case IF_RENEWING:
339 				case IF_REBINDING:
340 				case IF_REBOOTING:
341 				case IF_BOUND:
342 					state_transition(iface, IF_REBOOTING);
343 					break;
344 				}
345 			}
346 			break;
347 #endif	/* SMALL */
348 		case IMSG_REMOVE_IF:
349 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
350 				fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
351 				    __func__, IMSG_DATA_SIZE(imsg));
352 			memcpy(&if_index, imsg.data, sizeof(if_index));
353 			remove_dhcpleased_iface(if_index);
354 			break;
355 		case IMSG_DHCP: {
356 			struct imsg_dhcp	imsg_dhcp;
357 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_dhcp))
358 				fatalx("%s: IMSG_DHCP wrong length: %lu",
359 				    __func__, IMSG_DATA_SIZE(imsg));
360 			memcpy(&imsg_dhcp, imsg.data, sizeof(imsg_dhcp));
361 			iface = get_dhcpleased_iface_by_id(imsg_dhcp.if_index);
362 			if (iface != NULL)
363 				parse_dhcp(iface, &imsg_dhcp);
364 			break;
365 		}
366 		case IMSG_REPROPOSE_RDNS:
367 			LIST_FOREACH (iface, &dhcpleased_interfaces, entries)
368 				send_rdns_proposal(iface);
369 			break;
370 		default:
371 			log_debug("%s: unexpected imsg %d", __func__,
372 			    imsg.hdr.type);
373 			break;
374 		}
375 		imsg_free(&imsg);
376 	}
377 	if (!shut)
378 		imsg_event_add(iev);
379 	else {
380 		/* This pipe is dead. Remove its event handler. */
381 		event_del(&iev->ev);
382 		event_loopexit(NULL);
383 	}
384 }
385 
386 void
387 engine_dispatch_main(int fd, short event, void *bula)
388 {
389 #ifndef SMALL
390 	static struct dhcpleased_conf	*nconf;
391 	static struct iface_conf	*iface_conf;
392 #endif /* SMALL */
393 	struct imsg			 imsg;
394 	struct imsgev			*iev = bula;
395 	struct imsgbuf			*ibuf = &iev->ibuf;
396 	struct imsg_ifinfo		 imsg_ifinfo;
397 	ssize_t				 n;
398 	int				 shut = 0;
399 
400 	if (event & EV_READ) {
401 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
402 			fatal("imsg_read error");
403 		if (n == 0)	/* Connection closed. */
404 			shut = 1;
405 	}
406 	if (event & EV_WRITE) {
407 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
408 			fatal("msgbuf_write");
409 		if (n == 0)	/* Connection closed. */
410 			shut = 1;
411 	}
412 
413 	for (;;) {
414 		if ((n = imsg_get(ibuf, &imsg)) == -1)
415 			fatal("%s: imsg_get error", __func__);
416 		if (n == 0)	/* No more messages. */
417 			break;
418 
419 		switch (imsg.hdr.type) {
420 		case IMSG_SOCKET_IPC:
421 			/*
422 			 * Setup pipe and event handler to the frontend
423 			 * process.
424 			 */
425 			if (iev_frontend)
426 				fatalx("%s: received unexpected imsg fd "
427 				    "to engine", __func__);
428 
429 			if ((fd = imsg.fd) == -1)
430 				fatalx("%s: expected to receive imsg fd to "
431 				   "engine but didn't receive any", __func__);
432 
433 			iev_frontend = malloc(sizeof(struct imsgev));
434 			if (iev_frontend == NULL)
435 				fatal(NULL);
436 
437 			imsg_init(&iev_frontend->ibuf, fd);
438 			iev_frontend->handler = engine_dispatch_frontend;
439 			iev_frontend->events = EV_READ;
440 
441 			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
442 			iev_frontend->events, iev_frontend->handler,
443 			    iev_frontend);
444 			event_add(&iev_frontend->ev, NULL);
445 
446 			if (pledge("stdio", NULL) == -1)
447 				fatal("pledge");
448 
449 			break;
450 		case IMSG_UPDATE_IF:
451 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
452 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
453 				    __func__, IMSG_DATA_SIZE(imsg));
454 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
455 			if (imsg_ifinfo.lease[LEASE_SIZE - 1] != '\0')
456 				fatalx("Invalid lease");
457 			engine_update_iface(&imsg_ifinfo);
458 			break;
459 #ifndef SMALL
460 		case IMSG_RECONF_CONF:
461 			if (nconf != NULL)
462 				fatalx("%s: IMSG_RECONF_CONF already in "
463 				    "progress", __func__);
464 			if ((nconf = malloc(sizeof(struct dhcpleased_conf))) ==
465 			    NULL)
466 				fatal(NULL);
467 			SIMPLEQ_INIT(&nconf->iface_list);
468 			break;
469 		case IMSG_RECONF_IFACE:
470 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
471 			    iface_conf))
472 				fatalx("%s: IMSG_RECONF_IFACE wrong length: "
473 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
474 			if ((iface_conf = malloc(sizeof(struct iface_conf)))
475 			    == NULL)
476 				fatal(NULL);
477 			memcpy(iface_conf, imsg.data, sizeof(struct
478 			    iface_conf));
479 			iface_conf->vc_id = NULL;
480 			iface_conf->vc_id_len = 0;
481 			iface_conf->c_id = NULL;
482 			iface_conf->c_id_len = 0;
483 			iface_conf->h_name = NULL;
484 			SIMPLEQ_INSERT_TAIL(&nconf->iface_list,
485 			    iface_conf, entry);
486 			break;
487 		case IMSG_RECONF_VC_ID:
488 			if (iface_conf == NULL)
489 				fatal("IMSG_RECONF_VC_ID without "
490 				    "IMSG_RECONF_IFACE");
491 			if (IMSG_DATA_SIZE(imsg) > 255 + 2)
492 				fatalx("%s: IMSG_RECONF_VC_ID wrong length: "
493 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
494 			if ((iface_conf->vc_id = malloc(IMSG_DATA_SIZE(imsg)))
495 			    == NULL)
496 				fatal(NULL);
497 			memcpy(iface_conf->vc_id, imsg.data,
498 			    IMSG_DATA_SIZE(imsg));
499 			iface_conf->vc_id_len = IMSG_DATA_SIZE(imsg);
500 			break;
501 		case IMSG_RECONF_C_ID:
502 			if (iface_conf == NULL)
503 				fatal("IMSG_RECONF_C_ID without "
504 				    "IMSG_RECONF_IFACE");
505 			if (IMSG_DATA_SIZE(imsg) > 255 + 2)
506 				fatalx("%s: IMSG_RECONF_C_ID wrong length: "
507 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
508 			if ((iface_conf->c_id = malloc(IMSG_DATA_SIZE(imsg)))
509 			    == NULL)
510 				fatal(NULL);
511 			memcpy(iface_conf->c_id, imsg.data,
512 			    IMSG_DATA_SIZE(imsg));
513 			iface_conf->c_id_len = IMSG_DATA_SIZE(imsg);
514 			break;
515 		case IMSG_RECONF_H_NAME:
516 			if (iface_conf == NULL)
517 				fatal("IMSG_RECONF_H_NAME without "
518 				    "IMSG_RECONF_IFACE");
519 			if (((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] !=
520 			    '\0')
521 				fatalx("Invalid hostname");
522 			if (IMSG_DATA_SIZE(imsg) > 256)
523 				fatalx("Invalid hostname");
524 			if ((iface_conf->h_name = strdup(imsg.data)) == NULL)
525 				fatal(NULL);
526 			break;
527 		case IMSG_RECONF_END: {
528 			struct dhcpleased_iface	*iface;
529 			int			*ifaces;
530 			int			 i, if_index;
531 			char			*if_name;
532 			char			 ifnamebuf[IF_NAMESIZE];
533 
534 			if (nconf == NULL)
535 				fatalx("%s: IMSG_RECONF_END without "
536 				    "IMSG_RECONF_CONF", __func__);
537 			ifaces = changed_ifaces(engine_conf, nconf);
538 			merge_config(engine_conf, nconf);
539 			nconf = NULL;
540 			for (i = 0; ifaces[i] != 0; i++) {
541 				if_index = ifaces[i];
542 				if_name = if_indextoname(if_index, ifnamebuf);
543 				iface = get_dhcpleased_iface_by_id(if_index);
544 				if (if_name == NULL || iface == NULL)
545 					continue;
546 				iface_conf = find_iface_conf(
547 				    &engine_conf->iface_list, if_name);
548 				if (iface_conf == NULL)
549 					continue;
550 				if (iface_conf->ignore & IGN_DNS)
551 					send_rdns_withdraw(iface);
552 				if (iface_conf->ignore & IGN_ROUTES)
553 					send_routes_withdraw(iface);
554 			}
555 			free(ifaces);
556 			break;
557 		}
558 #endif /* SMALL */
559 		default:
560 			log_debug("%s: unexpected imsg %d", __func__,
561 			    imsg.hdr.type);
562 			break;
563 		}
564 		imsg_free(&imsg);
565 	}
566 	if (!shut)
567 		imsg_event_add(iev);
568 	else {
569 		/* This pipe is dead. Remove its event handler. */
570 		event_del(&iev->ev);
571 		event_loopexit(NULL);
572 	}
573 }
574 
575 #ifndef	SMALL
576 void
577 send_interface_info(struct dhcpleased_iface *iface, pid_t pid)
578 {
579 	struct ctl_engine_info	 cei;
580 
581 	memset(&cei, 0, sizeof(cei));
582 	cei.if_index = iface->if_index;
583 	cei.running = iface->running;
584 	cei.link_state = iface->link_state;
585 	strlcpy(cei.state, if_state_name[iface->state], sizeof(cei.state));
586 	memcpy(&cei.request_time, &iface->request_time,
587 	    sizeof(cei.request_time));
588 	cei.server_identifier = iface->server_identifier;
589 	cei.dhcp_server = iface->dhcp_server;
590 	cei.requested_ip = iface->requested_ip;
591 	cei.mask = iface->mask;
592 	cei.routes_len = iface->routes_len;
593 	memcpy(cei.routes, iface->routes, sizeof(cei.routes));
594 	memcpy(cei.nameservers, iface->nameservers, sizeof(cei.nameservers));
595 	cei.lease_time = iface->lease_time;
596 	cei.renewal_time = iface->renewal_time;
597 	cei.rebinding_time = iface->rebinding_time;
598 	engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
599 	    sizeof(cei));
600 }
601 
602 void
603 engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index)
604 {
605 	struct dhcpleased_iface			*iface;
606 
607 	switch (imsg->hdr.type) {
608 	case IMSG_CTL_SHOW_INTERFACE_INFO:
609 		if ((iface = get_dhcpleased_iface_by_id(if_index)) != NULL)
610 			send_interface_info(iface, imsg->hdr.pid);
611 		else
612 			engine_imsg_compose_frontend(IMSG_CTL_END,
613 			    imsg->hdr.pid, NULL, 0);
614 		break;
615 	default:
616 		log_debug("%s: error handling imsg", __func__);
617 		break;
618 	}
619 }
620 #endif	/* SMALL */
621 
622 void
623 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
624 {
625 	struct dhcpleased_iface	*iface;
626 	int			 need_refresh = 0;
627 
628 	iface = get_dhcpleased_iface_by_id(imsg_ifinfo->if_index);
629 
630 	if (iface == NULL) {
631 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
632 			fatal("calloc");
633 		iface->state = IF_DOWN;
634 		iface->xid = arc4random();
635 		iface->timo.tv_usec = arc4random_uniform(1000000);
636 		evtimer_set(&iface->timer, iface_timeout, iface);
637 		iface->if_index = imsg_ifinfo->if_index;
638 		iface->rdomain = imsg_ifinfo->rdomain;
639 		iface->running = imsg_ifinfo->running;
640 		iface->link_state = imsg_ifinfo->link_state;
641 		iface->requested_ip.s_addr = INADDR_ANY;
642 		memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
643 		    sizeof(struct ether_addr));
644 		LIST_INSERT_HEAD(&dhcpleased_interfaces, iface, entries);
645 		need_refresh = 1;
646 	} else {
647 		if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address,
648 		    sizeof(struct ether_addr)) != 0) {
649 			memcpy(&iface->hw_address, &imsg_ifinfo->hw_address,
650 			    sizeof(struct ether_addr));
651 			need_refresh = 1;
652 		}
653 		if (imsg_ifinfo->rdomain != iface->rdomain) {
654 			iface->rdomain = imsg_ifinfo->rdomain;
655 			need_refresh = 1;
656 		}
657 		if (imsg_ifinfo->running != iface->running) {
658 			iface->running = imsg_ifinfo->running;
659 			need_refresh = 1;
660 		}
661 
662 		if (imsg_ifinfo->link_state != iface->link_state) {
663 			iface->link_state = imsg_ifinfo->link_state;
664 			need_refresh = 1;
665 		}
666 	}
667 
668 	if (!need_refresh)
669 		return;
670 
671 	if (iface->running && LINK_STATE_IS_UP(iface->link_state)) {
672 		if (iface->requested_ip.s_addr == INADDR_ANY)
673 			parse_lease(iface, imsg_ifinfo);
674 
675 		if (iface->requested_ip.s_addr == INADDR_ANY)
676 			state_transition(iface, IF_INIT);
677 		else
678 			state_transition(iface, IF_REBOOTING);
679 	} else
680 		state_transition(iface, IF_DOWN);
681 }
682 struct dhcpleased_iface*
683 get_dhcpleased_iface_by_id(uint32_t if_index)
684 {
685 	struct dhcpleased_iface	*iface;
686 	LIST_FOREACH (iface, &dhcpleased_interfaces, entries) {
687 		if (iface->if_index == if_index)
688 			return (iface);
689 	}
690 
691 	return (NULL);
692 }
693 
694 void
695 remove_dhcpleased_iface(uint32_t if_index)
696 {
697 	struct dhcpleased_iface	*iface;
698 
699 	iface = get_dhcpleased_iface_by_id(if_index);
700 
701 	if (iface == NULL)
702 		return;
703 
704 	send_rdns_withdraw(iface);
705 	send_deconfigure_interface(iface);
706 	LIST_REMOVE(iface, entries);
707 	evtimer_del(&iface->timer);
708 	free(iface);
709 }
710 
711 void
712 parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
713 {
714 	static uint8_t		 cookie[] = DHCP_COOKIE;
715 	static struct ether_addr bcast_mac;
716 #ifndef SMALL
717 	struct iface_conf	*iface_conf;
718 #endif /* SMALL */
719 	struct ether_header	*eh;
720 	struct ether_addr	 ether_src, ether_dst;
721 	struct ip		*ip;
722 	struct udphdr		*udp;
723 	struct dhcp_hdr		*dhcp_hdr;
724 	struct in_addr		 server_identifier, subnet_mask;
725 	struct in_addr		 nameservers[MAX_RDNS_COUNT];
726 	struct dhcp_route	 routes[MAX_DHCP_ROUTES];
727 	size_t			 rem, i;
728 	uint32_t		 sum, usum, lease_time = 0, renewal_time = 0;
729 	uint32_t		 rebinding_time = 0;
730 	uint8_t			*p, dho = DHO_PAD, dho_len, slen;
731 	uint8_t			 dhcp_message_type = 0;
732 	int			 routes_len = 0, routers = 0, csr = 0;
733 	char			 from[sizeof("xx:xx:xx:xx:xx:xx")];
734 	char			 to[sizeof("xx:xx:xx:xx:xx:xx")];
735 	char			 hbuf_src[INET_ADDRSTRLEN];
736 	char			 hbuf_dst[INET_ADDRSTRLEN];
737 	char			 hbuf[INET_ADDRSTRLEN];
738 	char			 domainname[4 * 255 + 1];
739 	char			 hostname[4 * 255 + 1];
740 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
741 
742 	if (bcast_mac.ether_addr_octet[0] == 0)
743 		memset(bcast_mac.ether_addr_octet, 0xff, ETHER_ADDR_LEN);
744 
745 	if_name = if_indextoname(iface->if_index, ifnamebuf);
746 
747 #ifndef SMALL
748 	iface_conf = find_iface_conf(&engine_conf->iface_list, if_name);
749 #endif /* SMALL*/
750 
751 	memset(hbuf_src, 0, sizeof(hbuf_src));
752 	memset(hbuf_dst, 0, sizeof(hbuf_dst));
753 
754 	p = dhcp->packet;
755 	rem = dhcp->len;
756 
757 	if (rem < sizeof(*eh)) {
758 		log_warnx("%s: message too short", __func__);
759 		return;
760 	}
761 	eh = (struct ether_header *)p;
762 	memcpy(ether_src.ether_addr_octet, eh->ether_shost,
763 	    sizeof(ether_src.ether_addr_octet));
764 	strlcpy(from, ether_ntoa(&ether_src), sizeof(from));
765 	memcpy(ether_dst.ether_addr_octet, eh->ether_dhost,
766 	    sizeof(ether_dst.ether_addr_octet));
767 	strlcpy(to, ether_ntoa(&ether_dst), sizeof(to));
768 	p += sizeof(*eh);
769 	rem -= sizeof(*eh);
770 
771 	if (memcmp(&ether_dst, &iface->hw_address, sizeof(ether_dst)) != 0 &&
772 	    memcmp(&ether_dst, &bcast_mac, sizeof(ether_dst)) != 0)
773 		return ; /* silently ignore packet not for us */
774 
775 	if (rem < sizeof(*ip))
776 		goto too_short;
777 
778 	if (log_getverbose() > 1)
779 		log_debug("%s, from: %s, to: %s", __func__, from, to);
780 
781 	ip = (struct ip *)p;
782 
783 	if (rem < (size_t)ip->ip_hl << 2)
784 		goto too_short;
785 
786 	if (wrapsum(checksum((uint8_t *)ip, ip->ip_hl << 2, 0)) != 0) {
787 		log_warnx("%s: bad IP checksum", __func__);
788 		return;
789 	}
790 	if (rem < ntohs(ip->ip_len))
791 		goto too_short;
792 
793 	p += ip->ip_hl << 2;
794 	rem -= ip->ip_hl << 2;
795 
796 	if (inet_ntop(AF_INET, &ip->ip_src, hbuf_src, sizeof(hbuf_src)) == NULL)
797 		hbuf_src[0] = '\0';
798 	if (inet_ntop(AF_INET, &ip->ip_dst, hbuf_dst, sizeof(hbuf_dst)) == NULL)
799 		hbuf_dst[0] = '\0';
800 
801 #ifndef SMALL
802 	if (iface_conf != NULL) {
803 		for (i = 0; (int)i < iface_conf->ignore_servers_len; i++) {
804 			if (iface_conf->ignore_servers[i].s_addr ==
805 			    ip->ip_src.s_addr) {
806 				log_debug("ignoring server %s", hbuf_src);
807 				return;
808 			}
809 		}
810 	}
811 #endif /* SMALL */
812 
813 	if (rem < sizeof(*udp))
814 		goto too_short;
815 
816 	udp = (struct udphdr *)p;
817 	if (rem < ntohs(udp->uh_ulen))
818 		goto too_short;
819 
820 	if (rem > ntohs(udp->uh_ulen)) {
821 		if (log_getverbose() > 1) {
822 			log_debug("%s: accepting packet with %lu bytes of data"
823 			    " after udp payload", __func__, rem -
824 			    ntohs(udp->uh_ulen));
825 		}
826 		rem = ntohs(udp->uh_ulen);
827 	}
828 
829 	p += sizeof(*udp);
830 	rem -= sizeof(*udp);
831 
832 	usum = udp->uh_sum;
833 	udp->uh_sum = 0;
834 
835 	sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp), checksum(p, rem,
836 	    checksum((uint8_t *)&ip->ip_src, 2 * sizeof(ip->ip_src),
837 	    IPPROTO_UDP + ntohs(udp->uh_ulen)))));
838 
839 	if (usum != 0 && usum != sum) {
840 		log_warnx("%s: bad UDP checksum", __func__);
841 		return;
842 	}
843 
844 	if (log_getverbose() > 1) {
845 		log_debug("%s: %s:%d -> %s:%d", __func__, hbuf_src,
846 		    ntohs(udp->uh_sport), hbuf_dst, ntohs(udp->uh_dport));
847 	}
848 
849 	if (rem < sizeof(*dhcp_hdr))
850 		goto too_short;
851 
852 	dhcp_hdr = (struct dhcp_hdr *)p;
853 	p += sizeof(*dhcp_hdr);
854 	rem -= sizeof(*dhcp_hdr);
855 
856 	dhcp_hdr->sname[DHCP_SNAME_LEN -1 ] = '\0'; /* ensure it's a string */
857 	dhcp_hdr->file[DHCP_FILE_LEN -1 ] = '\0'; /* ensure it's a string */
858 
859 	if (log_getverbose() > 1)
860 		log_dhcp_hdr(dhcp_hdr);
861 
862 	if (dhcp_hdr->op != DHCP_BOOTREPLY) {
863 		log_warnx("%s: ignorning non-reply packet", __func__);
864 		return;
865 	}
866 
867 	if (ntohl(dhcp_hdr->xid) != iface->xid)
868 		return; /* silently ignore wrong xid */
869 
870 	if (rem < sizeof(cookie))
871 		goto too_short;
872 
873 	if (memcmp(p, cookie, sizeof(cookie)) != 0) {
874 		log_warnx("%s: no dhcp cookie in packet from %s", __func__,
875 		    from);
876 		return;
877 	}
878 	p += sizeof(cookie);
879 	rem -= sizeof(cookie);
880 
881 	memset(&server_identifier, 0, sizeof(server_identifier));
882 	memset(&subnet_mask, 0, sizeof(subnet_mask));
883 	memset(&routes, 0, sizeof(routes));
884 	memset(&nameservers, 0, sizeof(nameservers));
885 	memset(hostname, 0, sizeof(hostname));
886 	memset(domainname, 0, sizeof(domainname));
887 
888 	while (rem > 0 && dho != DHO_END) {
889 		dho = *p;
890 		p += 1;
891 		rem -= 1;
892 		/* only DHO_END and DHO_PAD are 1 byte long without length */
893 		if (dho == DHO_PAD || dho == DHO_END)
894 			dho_len = 0;
895 		else {
896 			if (rem == 0)
897 				goto too_short; /* missing option length */
898 			dho_len = *p;
899 			p += 1;
900 			rem -= 1;
901 			if (rem < dho_len)
902 				goto too_short;
903 		}
904 
905 		switch (dho) {
906 		case DHO_PAD:
907 			if (log_getverbose() > 1)
908 				log_debug("DHO_PAD");
909 			break;
910 		case DHO_END:
911 			if (log_getverbose() > 1)
912 				log_debug("DHO_END");
913 			break;
914 		case DHO_DHCP_MESSAGE_TYPE:
915 			if (dho_len != 1)
916 				goto wrong_length;
917 			dhcp_message_type = *p;
918 			if (log_getverbose() > 1) {
919 				log_debug("DHO_DHCP_MESSAGE_TYPE: %s",
920 				    dhcp_message_type2str(dhcp_message_type));
921 			}
922 			p += dho_len;
923 			rem -= dho_len;
924 			break;
925 		case DHO_DHCP_SERVER_IDENTIFIER:
926 			if (dho_len != sizeof(server_identifier))
927 				goto wrong_length;
928 			memcpy(&server_identifier, p,
929 			    sizeof(server_identifier));
930 			if (log_getverbose() > 1) {
931 				log_debug("DHO_DHCP_SERVER_IDENTIFIER: %s",
932 				    inet_ntop(AF_INET, &server_identifier,
933 				    hbuf, sizeof(hbuf)));
934 			}
935 			p += dho_len;
936 			rem -= dho_len;
937 			break;
938 		case DHO_DHCP_LEASE_TIME:
939 			if (dho_len != sizeof(lease_time))
940 				goto wrong_length;
941 			memcpy(&lease_time, p, sizeof(lease_time));
942 			lease_time = ntohl(lease_time);
943 			if (log_getverbose() > 1) {
944 				log_debug("DHO_DHCP_LEASE_TIME %us",
945 				    lease_time);
946 			}
947 			p += dho_len;
948 			rem -= dho_len;
949 			break;
950 		case DHO_SUBNET_MASK:
951 			if (dho_len != sizeof(subnet_mask))
952 				goto wrong_length;
953 			memcpy(&subnet_mask, p, sizeof(subnet_mask));
954 			if (log_getverbose() > 1) {
955 				log_debug("DHO_SUBNET_MASK: %s",
956 				    inet_ntop(AF_INET, &subnet_mask, hbuf,
957 				    sizeof(hbuf)));
958 			}
959 			p += dho_len;
960 			rem -= dho_len;
961 			break;
962 		case DHO_ROUTERS:
963 			if (dho_len < sizeof(routes[routes_len].gw))
964 				goto wrong_length;
965 			if (dho_len % sizeof(routes[routes_len].gw) != 0)
966 				goto wrong_length;
967 
968 			/*
969 			 * Ignore routers option if classless static routes
970 			 * are present (RFC3442).
971 			 */
972 			if (!csr) {
973 				routers = 1;
974 				while (routes_len < MAX_DHCP_ROUTES &&
975 				    dho_len > 0) {
976 					memcpy(&routes[routes_len].gw, p,
977 					    sizeof(routes[routes_len].gw));
978 					if (log_getverbose() > 1) {
979 						log_debug("DHO_ROUTER: %s",
980 						    inet_ntop(AF_INET,
981 						    &routes[routes_len].gw,
982 						    hbuf, sizeof(hbuf)));
983 					}
984 					p += sizeof(routes[routes_len].gw);
985 					rem -= sizeof(routes[routes_len].gw);
986 					dho_len -=
987 					    sizeof(routes[routes_len].gw);
988 					routes_len++;
989 				}
990 			}
991 			if (dho_len != 0) {
992 				/* ignore > MAX_DHCP_ROUTES routes */
993 				p += dho_len;
994 				rem -= dho_len;
995 			}
996 			break;
997 		case DHO_DOMAIN_NAME_SERVERS:
998 			if (dho_len < sizeof(nameservers[0]))
999 				goto wrong_length;
1000 			if (dho_len % sizeof(nameservers[0]) != 0)
1001 				goto wrong_length;
1002 			/* we limit ourself to 8 nameservers for proposals */
1003 			memcpy(&nameservers, p, MINIMUM(sizeof(nameservers),
1004 			    dho_len));
1005 			if (log_getverbose() > 1) {
1006 				for (i = 0; i < MINIMUM(sizeof(nameservers),
1007 				    dho_len / sizeof(nameservers[0])); i++) {
1008 					log_debug("DHO_DOMAIN_NAME_SERVERS: %s "
1009 					    "(%lu/%lu)", inet_ntop(AF_INET,
1010 					    &nameservers[i], hbuf,
1011 					    sizeof(hbuf)), i + 1,
1012 					    dho_len / sizeof(nameservers[0]));
1013 				}
1014 			}
1015 			p += dho_len;
1016 			rem -= dho_len;
1017 			break;
1018 		case DHO_HOST_NAME:
1019 			if (dho_len < 1) {
1020 				/*
1021 				 * Protocol violation: minimum length is 1;
1022 				 * pretend the option is not there
1023 				 */
1024 				break;
1025 			}
1026 			/* MUST delete trailing NUL, per RFC 2132 */
1027 			slen = dho_len;
1028 			while (slen > 0 && p[slen - 1] == '\0')
1029 				slen--;
1030 			/* slen might be 0 here, pretend option is not there. */
1031 			strvisx(hostname, p, slen, VIS_SAFE);
1032 			if (log_getverbose() > 1)
1033 				log_debug("DHO_HOST_NAME: %s", hostname);
1034 			p += dho_len;
1035 			rem -= dho_len;
1036 			break;
1037 		case DHO_DOMAIN_NAME:
1038 			if (dho_len < 1) {
1039 				/*
1040 				 * Protocol violation: minimum length is 1;
1041 				 * pretend the option is not there
1042 				 */
1043 				break;
1044 			}
1045 			/* MUST delete trailing NUL, per RFC 2132 */
1046 			slen = dho_len;
1047 			while (slen > 0 && p[slen - 1] == '\0')
1048 				slen--;
1049 			/* slen might be 0 here, pretend option is not there. */
1050 			strvisx(domainname, p, slen, VIS_SAFE);
1051 			if (log_getverbose() > 1)
1052 				log_debug("DHO_DOMAIN_NAME: %s", domainname);
1053 			p += dho_len;
1054 			rem -= dho_len;
1055 			break;
1056 		case DHO_DHCP_RENEWAL_TIME:
1057 			if (dho_len != sizeof(renewal_time))
1058 				goto wrong_length;
1059 			memcpy(&renewal_time, p, sizeof(renewal_time));
1060 			renewal_time = ntohl(renewal_time);
1061 			if (log_getverbose() > 1) {
1062 				log_debug("DHO_DHCP_RENEWAL_TIME %us",
1063 				    renewal_time);
1064 			}
1065 			p += dho_len;
1066 			rem -= dho_len;
1067 			break;
1068 		case DHO_DHCP_REBINDING_TIME:
1069 			if (dho_len != sizeof(rebinding_time))
1070 				goto wrong_length;
1071 			memcpy(&rebinding_time, p, sizeof(rebinding_time));
1072 			rebinding_time = ntohl(rebinding_time);
1073 			if (log_getverbose() > 1) {
1074 				log_debug("DHO_DHCP_REBINDING_TIME %us",
1075 				    rebinding_time);
1076 			}
1077 			p += dho_len;
1078 			rem -= dho_len;
1079 			break;
1080 		case DHO_DHCP_CLIENT_IDENTIFIER:
1081 			/* the server is supposed to echo this back to us */
1082 #ifndef SMALL
1083 			if (iface_conf != NULL && iface_conf->c_id_len > 0) {
1084 				if (dho_len != iface_conf->c_id[1]) {
1085 					log_warnx("wrong "
1086 					    "DHO_DHCP_CLIENT_IDENTIFIER");
1087 					return;
1088 				}
1089 				if (memcmp(p, &iface_conf->c_id[2], dho_len) !=
1090 				    0) {
1091 					log_warnx("wrong "
1092 					    "DHO_DHCP_CLIENT_IDENTIFIER");
1093 					return;
1094 				}
1095 			} else
1096 #endif /* SMALL */
1097 			{
1098 				if (dho_len != 1 + sizeof(iface->hw_address))
1099 					goto wrong_length;
1100 				if (*p != HTYPE_ETHER) {
1101 					log_warnx("DHO_DHCP_CLIENT_IDENTIFIER: "
1102 					    "wrong type");
1103 					return;
1104 				}
1105 				if (memcmp(p + 1, &iface->hw_address,
1106 				    sizeof(iface->hw_address)) != 0) {
1107 					log_warnx("wrong "
1108 					    "DHO_DHCP_CLIENT_IDENTIFIER");
1109 					return;
1110 				}
1111 			}
1112 			p += dho_len;
1113 			rem -= dho_len;
1114 			break;
1115 		case DHO_CLASSLESS_STATIC_ROUTES: {
1116 			int	prefixlen, compressed_prefixlen;
1117 
1118 			csr = 1;
1119 			if (routers) {
1120 				/*
1121 				 * Ignore routers option if classless static
1122 				 * routes are present (RFC3442).
1123 				 */
1124 				routers = 0;
1125 				routes_len = 0;
1126 			}
1127 			while (routes_len < MAX_DHCP_ROUTES && dho_len > 0) {
1128 				prefixlen = *p;
1129 				p += 1;
1130 				rem -= 1;
1131 				dho_len -= 1;
1132 
1133 				if (prefixlen < 0 || prefixlen > 32) {
1134 					log_warnx("%s: invalid prefixlen: %d",
1135 					    __func__, prefixlen);
1136 					return;
1137 				}
1138 
1139 				if (prefixlen > 0)
1140 					routes[routes_len].mask.s_addr =
1141 					    htonl(0xffffffff << (32 -
1142 						prefixlen));
1143 				else
1144 					routes[routes_len].mask.s_addr =
1145 					    INADDR_ANY;
1146 
1147 				compressed_prefixlen = (prefixlen + 7) / 8;
1148 				if (dho_len < compressed_prefixlen)
1149 					goto wrong_length;
1150 
1151 				memcpy(&routes[routes_len].dst, p,
1152 				    compressed_prefixlen);
1153 				p += compressed_prefixlen;
1154 				rem -= compressed_prefixlen;
1155 				dho_len -= compressed_prefixlen;
1156 
1157 				if (dho_len < sizeof(routes[routes_len].gw))
1158 					goto wrong_length;
1159 
1160 				memcpy(&routes[routes_len].gw, p,
1161 				    sizeof(routes[routes_len].gw));
1162 				p += sizeof(routes[routes_len].gw);
1163 				rem -= sizeof(routes[routes_len].gw);
1164 				dho_len -= sizeof(routes[routes_len].gw);
1165 
1166 				routes_len++;
1167 			}
1168 
1169 			if (dho_len != 0) {
1170 				/* ignore > MAX_DHCP_ROUTES routes */
1171 				p += dho_len;
1172 				rem -= dho_len;
1173 			}
1174 			break;
1175 		}
1176 		default:
1177 			if (log_getverbose() > 1)
1178 				log_debug("DHO_%u, len: %u", dho, dho_len);
1179 			p += dho_len;
1180 			rem -= dho_len;
1181 		}
1182 
1183 	}
1184 	while (rem != 0) {
1185 		if (*p != DHO_PAD)
1186 			break;
1187 		p++;
1188 		rem--;
1189 	}
1190 	if (rem != 0)
1191 		log_debug("%s: %lu bytes garbage data from %s", __func__, rem,
1192 		    from);
1193 
1194 	log_debug("%s on %s from %s/%s to %s/%s",
1195 	    dhcp_message_type2str(dhcp_message_type), if_name == NULL ? "?" :
1196 	    if_name, from, hbuf_src, to, hbuf_dst);
1197 
1198 	switch (dhcp_message_type) {
1199 	case DHCPOFFER:
1200 		if (iface->state != IF_INIT) {
1201 			log_debug("ignoring unexpected DHCPOFFER");
1202 			return;
1203 		}
1204 		if (server_identifier.s_addr == INADDR_ANY &&
1205 		    dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
1206 			log_warnx("%s: did not receive server identifier or "
1207 			    "offered IP address", __func__);
1208 			return;
1209 		}
1210 		iface->server_identifier = server_identifier;
1211 		iface->dhcp_server = server_identifier;
1212 		iface->requested_ip = dhcp_hdr->yiaddr;
1213 		state_transition(iface, IF_REQUESTING);
1214 		break;
1215 	case DHCPACK:
1216 		switch (iface->state) {
1217 		case IF_REQUESTING:
1218 		case IF_RENEWING:
1219 		case IF_REBINDING:
1220 		case IF_REBOOTING:
1221 			break;
1222 		default:
1223 			log_debug("ignoring unexpected DHCPACK");
1224 			return;
1225 		}
1226 		if (server_identifier.s_addr == INADDR_ANY &&
1227 		    dhcp_hdr->yiaddr.s_addr == INADDR_ANY) {
1228 			log_warnx("%s: did not receive server identifier or "
1229 			    "offered IP address", __func__);
1230 			return;
1231 		}
1232 		if (lease_time == 0) {
1233 			log_warnx("%s no lease time from %s", __func__, from);
1234 			return;
1235 		}
1236 		if (subnet_mask.s_addr == INADDR_ANY) {
1237 			log_warnx("%s: no subnetmask received from %s",
1238 			    __func__, from);
1239 			return;
1240 		}
1241 
1242 		/* Defaults if we didn't receive renewal or rebinding time. */
1243 		if (renewal_time == 0)
1244 			renewal_time = lease_time / 2;
1245 		if (rebinding_time == 0)
1246 			rebinding_time = lease_time - (lease_time / 8);
1247 
1248 		/* RFC 2131 4.4.5 */
1249 		/* Ignore invalid T1/T2 options */
1250 		if (renewal_time >= rebinding_time) {
1251 			log_warnx("%s: renewal_time(%u) >= rebinding_time(%u) "
1252 			    "from %s: using defaults",
1253 			    __func__, renewal_time, rebinding_time, from);
1254 			renewal_time = rebinding_time = 0;
1255 		} else if (rebinding_time >= lease_time) {
1256 			log_warnx("%s: rebinding_time(%u) >= lease_time(%u) "
1257 			    "from %s: using defaults",
1258 			    __func__, rebinding_time, lease_time, from);
1259 			renewal_time = rebinding_time = 0;
1260 		}
1261 
1262 		/* Defaults if we received wrong renewal or rebinding time. */
1263 		if (renewal_time == 0)
1264 			renewal_time = lease_time / 2;
1265 		if (rebinding_time == 0)
1266 			rebinding_time = lease_time - (lease_time / 8);
1267 
1268 		clock_gettime(CLOCK_MONOTONIC, &iface->request_time);
1269 		iface->server_identifier = server_identifier;
1270 		iface->dhcp_server = server_identifier;
1271 		iface->requested_ip = dhcp_hdr->yiaddr;
1272 		iface->mask = subnet_mask;
1273 #ifndef SMALL
1274 		if (iface_conf != NULL && iface_conf->ignore & IGN_ROUTES) {
1275 			iface->routes_len = 0;
1276 			memset(iface->routes, 0, sizeof(iface->routes));
1277 		} else
1278 #endif /* SMALL */
1279 		{
1280 			iface->prev_routes_len = iface->routes_len;
1281 			memcpy(iface->prev_routes, iface->routes,
1282 			    sizeof(iface->prev_routes));
1283 			iface->routes_len = routes_len;
1284 			memcpy(iface->routes, routes, sizeof(iface->routes));
1285 		}
1286 		iface->lease_time = lease_time;
1287 		iface->renewal_time = renewal_time;
1288 		iface->rebinding_time = rebinding_time;
1289 
1290 #ifndef SMALL
1291 		if (iface_conf != NULL && iface_conf->ignore & IGN_DNS) {
1292 			memset(iface->nameservers, 0,
1293 			    sizeof(iface->nameservers));
1294 		} else
1295 #endif /* SMALL */
1296 		{
1297 			memcpy(iface->nameservers, nameservers,
1298 			    sizeof(iface->nameservers));
1299 		}
1300 
1301 		iface->siaddr = dhcp_hdr->siaddr;
1302 
1303 		/* we made sure this is a string futher up */
1304 		strnvis(iface->file, dhcp_hdr->file, sizeof(iface->file),
1305 		    VIS_SAFE);
1306 
1307 		strlcpy(iface->domainname, domainname,
1308 		    sizeof(iface->domainname));
1309 		strlcpy(iface->hostname, hostname, sizeof(iface->hostname));
1310 		state_transition(iface, IF_BOUND);
1311 		break;
1312 	case DHCPNAK:
1313 		switch (iface->state) {
1314 		case IF_REQUESTING:
1315 		case IF_RENEWING:
1316 		case IF_REBINDING:
1317 		case IF_REBOOTING:
1318 			break;
1319 		default:
1320 			log_debug("ignoring unexpected DHCPNAK");
1321 			return;
1322 		}
1323 
1324 		state_transition(iface, IF_INIT);
1325 		break;
1326 	default:
1327 		log_warnx("%s: unimplemented message type %d", __func__,
1328 		    dhcp_message_type);
1329 		break;
1330 	}
1331 	return;
1332  too_short:
1333 	log_warnx("%s: message from %s too short", __func__, from);
1334 	return;
1335  wrong_length:
1336 	log_warnx("%s: received option %d with wrong length: %d", __func__,
1337 	    dho, dho_len);
1338 	return;
1339 }
1340 
1341 /* XXX check valid transitions */
1342 void
1343 state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
1344 {
1345 	enum if_state	 old_state = iface->state;
1346 	struct timespec	 now, res;
1347 	char		 ifnamebuf[IF_NAMESIZE], *if_name;
1348 
1349 	iface->state = new_state;
1350 	if (new_state != old_state)
1351 		iface->xid = arc4random();
1352 
1353 	switch (new_state) {
1354 	case IF_DOWN:
1355 		if (iface->requested_ip.s_addr == INADDR_ANY) {
1356 			/* nothing to do until iface comes up */
1357 			iface->timo.tv_sec = -1;
1358 			break;
1359 		}
1360 		if (old_state == IF_DOWN) {
1361 			/* nameservers already withdrawn when if went down */
1362 			send_deconfigure_interface(iface);
1363 			/* nothing more to do until iface comes back */
1364 			iface->timo.tv_sec = -1;
1365 		} else {
1366 			send_rdns_withdraw(iface);
1367 			clock_gettime(CLOCK_MONOTONIC, &now);
1368 			timespecsub(&now, &iface->request_time, &res);
1369 			iface->timo.tv_sec = iface->lease_time - res.tv_sec;
1370 			if (iface->timo.tv_sec < 0)
1371 				iface->timo.tv_sec = 0; /* deconfigure now */
1372 		}
1373 		break;
1374 	case IF_INIT:
1375 		switch (old_state) {
1376 		case IF_INIT:
1377 			if (iface->timo.tv_sec < MAX_EXP_BACKOFF_SLOW)
1378 				iface->timo.tv_sec *= 2;
1379 			break;
1380 		case IF_REQUESTING:
1381 		case IF_RENEWING:
1382 		case IF_REBINDING:
1383 		case IF_REBOOTING:
1384 			/* lease expired, got DHCPNAK or timeout: delete IP */
1385 			send_rdns_withdraw(iface);
1386 			send_deconfigure_interface(iface);
1387 			/* fall through */
1388 		case IF_DOWN:
1389 			iface->timo.tv_sec = START_EXP_BACKOFF;
1390 			break;
1391 		case IF_BOUND:
1392 			fatal("invalid transition Bound -> Init");
1393 			break;
1394 		}
1395 		request_dhcp_discover(iface);
1396 		break;
1397 	case IF_REBOOTING:
1398 		if (old_state == IF_REBOOTING)
1399 			iface->timo.tv_sec *= 2;
1400 		else
1401 			iface->timo.tv_sec = START_EXP_BACKOFF;
1402 		request_dhcp_request(iface);
1403 		break;
1404 	case IF_REQUESTING:
1405 		if (old_state == IF_REQUESTING)
1406 			iface->timo.tv_sec *= 2;
1407 		else
1408 			iface->timo.tv_sec = START_EXP_BACKOFF;
1409 		request_dhcp_request(iface);
1410 		break;
1411 	case IF_BOUND:
1412 		iface->timo.tv_sec = iface->renewal_time;
1413 		if (old_state == IF_REQUESTING || old_state == IF_REBOOTING) {
1414 			send_configure_interface(iface);
1415 			send_rdns_proposal(iface);
1416 		}
1417 		break;
1418 	case IF_RENEWING:
1419 		if (old_state == IF_BOUND) {
1420 			iface->timo.tv_sec = (iface->rebinding_time -
1421 			    iface->renewal_time) / 2; /* RFC 2131 4.4.5 */
1422 		} else
1423 			iface->timo.tv_sec /= 2;
1424 
1425 		if (iface->timo.tv_sec < 60)
1426 			iface->timo.tv_sec = 60;
1427 		request_dhcp_request(iface);
1428 		break;
1429 	case IF_REBINDING:
1430 		if (old_state == IF_RENEWING) {
1431 			iface->timo.tv_sec = (iface->lease_time -
1432 			    iface->rebinding_time) / 2; /* RFC 2131 4.4.5 */
1433 		} else
1434 			iface->timo.tv_sec /= 2;
1435 		request_dhcp_request(iface);
1436 		break;
1437 	}
1438 
1439 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1440 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1441 	    "?" : if_name, if_state_name[old_state], if_state_name[new_state],
1442 	    iface->timo.tv_sec);
1443 
1444 	if (iface->timo.tv_sec == -1) {
1445 		if (evtimer_pending(&iface->timer, NULL))
1446 			evtimer_del(&iface->timer);
1447 	} else
1448 		evtimer_add(&iface->timer, &iface->timo);
1449 }
1450 
1451 void
1452 iface_timeout(int fd, short events, void *arg)
1453 {
1454 	struct dhcpleased_iface	*iface = (struct dhcpleased_iface *)arg;
1455 	struct timespec		 now, res;
1456 
1457 	log_debug("%s[%d]: %s", __func__, iface->if_index,
1458 	    if_state_name[iface->state]);
1459 
1460 	switch (iface->state) {
1461 	case IF_DOWN:
1462 		state_transition(iface, IF_DOWN);
1463 		break;
1464 	case IF_INIT:
1465 		state_transition(iface, IF_INIT);
1466 		break;
1467 	case IF_REBOOTING:
1468 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST)
1469 			state_transition(iface, IF_INIT);
1470 		else
1471 			state_transition(iface, IF_REBOOTING);
1472 		break;
1473 	case IF_REQUESTING:
1474 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_SLOW)
1475 			state_transition(iface, IF_INIT);
1476 		else
1477 			state_transition(iface, IF_REQUESTING);
1478 		break;
1479 	case IF_BOUND:
1480 		state_transition(iface, IF_RENEWING);
1481 		break;
1482 	case IF_RENEWING:
1483 		clock_gettime(CLOCK_MONOTONIC, &now);
1484 		timespecsub(&now, &iface->request_time, &res);
1485 		log_debug("%s: res.tv_sec: %lld, rebinding_time: %u", __func__,
1486 		    res.tv_sec, iface->rebinding_time);
1487 		if (res.tv_sec > iface->rebinding_time)
1488 			state_transition(iface, IF_REBINDING);
1489 		else
1490 			state_transition(iface, IF_RENEWING);
1491 		break;
1492 	case IF_REBINDING:
1493 		clock_gettime(CLOCK_MONOTONIC, &now);
1494 		timespecsub(&now, &iface->request_time, &res);
1495 		log_debug("%s: res.tv_sec: %lld, lease_time: %u", __func__,
1496 		    res.tv_sec, iface->lease_time);
1497 		if (res.tv_sec > iface->lease_time)
1498 			state_transition(iface, IF_INIT);
1499 		else
1500 			state_transition(iface, IF_REBINDING);
1501 		break;
1502 	}
1503 }
1504 
1505 void
1506 request_dhcp_discover(struct dhcpleased_iface *iface)
1507 {
1508 	struct imsg_req_dhcp	 imsg;
1509 
1510 	memset(&imsg, 0, sizeof(imsg));
1511 
1512 	imsg.if_index = iface->if_index;
1513 	imsg.xid = iface->xid;
1514 
1515 	/*
1516 	 * similar to RFC 2131 4.3.6, Table 4 for DHCPDISCOVER
1517 	 * ------------------------------
1518 	 * |              | INIT         |
1519 	 * ------------------------------
1520 	 * |broad/unicast | broadcast    |
1521 	 * |server-ip     | MUST NOT     |
1522 	 * |requested-ip  | MAY          |
1523 	 * |ciaddr        | zero         |
1524 	 * ------------------------------
1525 	 *
1526 	 * Leaving everything at 0 from the memset results in this table with
1527 	 * requested-ip not set.
1528 	*/
1529 
1530 	engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, &imsg, sizeof(imsg));
1531 }
1532 
1533 void
1534 request_dhcp_request(struct dhcpleased_iface *iface)
1535 {
1536 	struct imsg_req_dhcp	 imsg;
1537 
1538 	imsg.if_index = iface->if_index;
1539 	imsg.xid = iface->xid;
1540 
1541 	/*
1542 	 * RFC 2131 4.3.6, Table 4
1543 	 * ---------------------------------------------------------------------
1544 	 * |              |REBOOTING    |REQUESTING   |RENEWING     |REBINDING |
1545 	 * ---------------------------------------------------------------------
1546 	 * |broad/unicast |broadcast    |broadcast    |unicast      |broadcast |
1547 	 * |server-ip     |MUST NOT     |MUST         |MUST NOT     |MUST NOT  |
1548 	 * |requested-ip  |MUST         |MUST         |MUST NOT     |MUST NOT  |
1549 	 * |ciaddr        |zero         |zero         |IP address   |IP address|
1550 	 * ---------------------------------------------------------------------
1551 	*/
1552 	switch (iface->state) {
1553 	case IF_DOWN:
1554 		fatalx("invalid state IF_DOWN in %s", __func__);
1555 		break;
1556 	case IF_INIT:
1557 		fatalx("invalid state IF_INIT in %s", __func__);
1558 		break;
1559 	case IF_BOUND:
1560 		fatalx("invalid state IF_BOUND in %s", __func__);
1561 		break;
1562 	case IF_REBOOTING:
1563 		imsg.dhcp_server.s_addr = INADDR_ANY;		/* broadcast */
1564 		imsg.server_identifier.s_addr = INADDR_ANY;	/* MUST NOT */
1565 		imsg.requested_ip = iface->requested_ip;	/* MUST */
1566 		imsg.ciaddr.s_addr = INADDR_ANY;		/* zero */
1567 		break;
1568 	case IF_REQUESTING:
1569 		imsg.dhcp_server.s_addr = INADDR_ANY;		/* broadcast */
1570 		imsg.server_identifier =
1571 		    iface->server_identifier;			/* MUST */
1572 		imsg.requested_ip = iface->requested_ip;	/* MUST */
1573 		imsg.ciaddr.s_addr = INADDR_ANY;		/* zero */
1574 		break;
1575 	case IF_RENEWING:
1576 		imsg.dhcp_server = iface->dhcp_server;		/* unicast */
1577 		imsg.server_identifier.s_addr = INADDR_ANY;	/* MUST NOT */
1578 		imsg.requested_ip.s_addr = INADDR_ANY;		/* MUST NOT */
1579 		imsg.ciaddr = iface->requested_ip;		/* IP address */
1580 		break;
1581 	case IF_REBINDING:
1582 		imsg.dhcp_server.s_addr = INADDR_ANY;		/* broadcast */
1583 		imsg.server_identifier.s_addr = INADDR_ANY;	/* MUST NOT */
1584 		imsg.requested_ip.s_addr = INADDR_ANY;		/* MUST NOT */
1585 		imsg.ciaddr = iface->requested_ip;		/* IP address */
1586 		break;
1587 	}
1588 
1589 	engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg, sizeof(imsg));
1590 }
1591 
1592 void
1593 log_lease(struct dhcpleased_iface *iface, int deconfigure)
1594 {
1595 	char	 hbuf_lease[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1596 	char	 ifnamebuf[IF_NAMESIZE], *if_name;
1597 
1598 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1599 	inet_ntop(AF_INET, &iface->requested_ip, hbuf_lease,
1600 	    sizeof(hbuf_lease));
1601 	inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1602 	    sizeof(hbuf_server));
1603 
1604 
1605 	if (deconfigure)
1606 		log_info("deleting %s from %s (lease from %s)", hbuf_lease,
1607 		    if_name == NULL ? "?" : if_name, hbuf_server);
1608 	else
1609 		log_info("adding %s to %s (lease from %s)", hbuf_lease,
1610 		    if_name == NULL ? "?" : if_name, hbuf_server);
1611 }
1612 
1613 void
1614 send_configure_interface(struct dhcpleased_iface *iface)
1615 {
1616 	struct imsg_configure_interface	 imsg;
1617 	int				 i, j, found;
1618 
1619 	log_lease(iface, 0);
1620 
1621 	memset(&imsg, 0, sizeof(imsg));
1622 	imsg.if_index = iface->if_index;
1623 	imsg.rdomain = iface->rdomain;
1624 	imsg.addr = iface->requested_ip;
1625 	imsg.mask = iface->mask;
1626 	imsg.siaddr = iface->siaddr;
1627 	strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1628 	strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1629 	strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1630 	for (i = 0; i < iface->prev_routes_len; i++) {
1631 		found = 0;
1632 		for (j = 0; j < iface->routes_len; j++) {
1633 			if (memcmp(&iface->prev_routes[i], &iface->routes[j],
1634 			    sizeof(struct dhcp_route)) == 0) {
1635 				found = 1;
1636 				break;
1637 			}
1638 		}
1639 		if (!found)
1640 			imsg.routes[imsg.routes_len++] = iface->prev_routes[i];
1641 	}
1642 	if (imsg.routes_len > 0)
1643 		engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg,
1644 		    sizeof(imsg));
1645 	imsg.routes_len = iface->routes_len;
1646 	memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1647 	engine_imsg_compose_main(IMSG_CONFIGURE_INTERFACE, 0, &imsg,
1648 	    sizeof(imsg));
1649 }
1650 
1651 void
1652 send_deconfigure_interface(struct dhcpleased_iface *iface)
1653 {
1654 	struct imsg_configure_interface	 imsg;
1655 
1656 	if (iface->requested_ip.s_addr == INADDR_ANY)
1657 		return;
1658 
1659 	log_lease(iface, 1);
1660 
1661 	imsg.if_index = iface->if_index;
1662 	imsg.rdomain = iface->rdomain;
1663 	imsg.addr = iface->requested_ip;
1664 	imsg.mask = iface->mask;
1665 	imsg.siaddr = iface->siaddr;
1666 	strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1667 	strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1668 	strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1669 	imsg.routes_len = iface->routes_len;
1670 	memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1671 	engine_imsg_compose_main(IMSG_DECONFIGURE_INTERFACE, 0, &imsg,
1672 	    sizeof(imsg));
1673 
1674 	iface->server_identifier.s_addr = INADDR_ANY;
1675 	iface->dhcp_server.s_addr = INADDR_ANY;
1676 	iface->requested_ip.s_addr = INADDR_ANY;
1677 	iface->mask.s_addr = INADDR_ANY;
1678 	iface->routes_len = 0;
1679 	memset(iface->routes, 0, sizeof(iface->routes));
1680 }
1681 
1682 void
1683 send_routes_withdraw(struct dhcpleased_iface *iface)
1684 {
1685 	struct imsg_configure_interface	 imsg;
1686 
1687 	if (iface->requested_ip.s_addr == INADDR_ANY || iface->routes_len == 0)
1688 		return;
1689 
1690 	imsg.if_index = iface->if_index;
1691 	imsg.rdomain = iface->rdomain;
1692 	imsg.addr = iface->requested_ip;
1693 	imsg.mask = iface->mask;
1694 	imsg.siaddr = iface->siaddr;
1695 	strlcpy(imsg.file, iface->file, sizeof(imsg.file));
1696 	strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname));
1697 	strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname));
1698 	imsg.routes_len = iface->routes_len;
1699 	memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
1700 	engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg,
1701 	    sizeof(imsg));
1702 }
1703 
1704 void
1705 log_rdns(struct dhcpleased_iface *iface, int withdraw)
1706 {
1707 	int	 i;
1708 	char	 hbuf_rdns[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN];
1709 	char	 ifnamebuf[IF_NAMESIZE], *if_name, *rdns_buf = NULL, *tmp_buf;
1710 
1711 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1712 
1713 	inet_ntop(AF_INET, &iface->server_identifier, hbuf_server,
1714 	    sizeof(hbuf_server));
1715 
1716 	for (i = 0; i < MAX_RDNS_COUNT && iface->nameservers[i].s_addr !=
1717 		 INADDR_ANY; i++) {
1718 		inet_ntop(AF_INET, &iface->nameservers[i], hbuf_rdns,
1719 		    sizeof(hbuf_rdns));
1720 		tmp_buf = rdns_buf;
1721 		if (asprintf(&rdns_buf, "%s %s", tmp_buf ? tmp_buf : "",
1722 		    hbuf_rdns) < 0) {
1723 			rdns_buf = NULL;
1724 			break;
1725 		}
1726 		free(tmp_buf);
1727 	}
1728 
1729 	if (rdns_buf != NULL) {
1730 		if (withdraw) {
1731 			log_info("deleting nameservers%s (lease from %s on %s)",
1732 			    rdns_buf, hbuf_server, if_name == NULL ? "?" :
1733 			    if_name);
1734 		} else {
1735 			log_info("adding nameservers%s (lease from %s on %s)",
1736 			    rdns_buf, hbuf_server, if_name == NULL ? "?" :
1737 			    if_name);
1738 		}
1739 		free(rdns_buf);
1740 	}
1741 }
1742 
1743 void
1744 send_rdns_proposal(struct dhcpleased_iface *iface)
1745 {
1746 	struct imsg_propose_rdns	 imsg;
1747 
1748 	log_rdns(iface, 0);
1749 
1750 	memset(&imsg, 0, sizeof(imsg));
1751 
1752 	imsg.if_index = iface->if_index;
1753 	imsg.rdomain = iface->rdomain;
1754 	for (imsg.rdns_count = 0; imsg.rdns_count < MAX_RDNS_COUNT &&
1755 		 iface->nameservers[imsg.rdns_count].s_addr != INADDR_ANY;
1756 	     imsg.rdns_count++)
1757 		;
1758 	memcpy(imsg.rdns, iface->nameservers, sizeof(imsg.rdns));
1759 	engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &imsg, sizeof(imsg));
1760 }
1761 
1762 void
1763 send_rdns_withdraw(struct dhcpleased_iface *iface)
1764 {
1765 	struct imsg_propose_rdns	 imsg;
1766 
1767 	log_rdns(iface, 1);
1768 
1769 	memset(&imsg, 0, sizeof(imsg));
1770 
1771 	imsg.if_index = iface->if_index;
1772 	imsg.rdomain = iface->rdomain;
1773 	engine_imsg_compose_main(IMSG_WITHDRAW_RDNS, 0, &imsg, sizeof(imsg));
1774 	memset(iface->nameservers, 0, sizeof(iface->nameservers));
1775 }
1776 
1777 void
1778 parse_lease(struct dhcpleased_iface *iface, struct imsg_ifinfo *imsg_ifinfo)
1779 {
1780 	char	*p, *p1;
1781 
1782 	iface->requested_ip.s_addr = INADDR_ANY;
1783 
1784 	if ((p = strstr(imsg_ifinfo->lease, LEASE_IP_PREFIX)) == NULL)
1785 		return;
1786 
1787 	p += sizeof(LEASE_IP_PREFIX) - 1;
1788 	if ((p1 = strchr(p, '\n')) == NULL)
1789 		return;
1790 	*p1 = '\0';
1791 
1792 	if (inet_pton(AF_INET, p, &iface->requested_ip) != 1)
1793 		iface->requested_ip.s_addr = INADDR_ANY;
1794 }
1795 
1796 void
1797 log_dhcp_hdr(struct dhcp_hdr *dhcp_hdr)
1798 {
1799 #ifndef	SMALL
1800 	char	 hbuf[INET_ADDRSTRLEN];
1801 
1802 	log_debug("dhcp_hdr op: %s (%d)", dhcp_hdr->op == DHCP_BOOTREQUEST ?
1803 	    "Boot Request" : dhcp_hdr->op == DHCP_BOOTREPLY ? "Boot Reply" :
1804 	    "Unknown", dhcp_hdr->op);
1805 	log_debug("dhcp_hdr htype: %s (%d)", dhcp_hdr->htype == 1 ? "Ethernet":
1806 	    "Unknown", dhcp_hdr->htype);
1807 	log_debug("dhcp_hdr hlen: %d", dhcp_hdr->hlen);
1808 	log_debug("dhcp_hdr hops: %d", dhcp_hdr->hops);
1809 	log_debug("dhcp_hdr xid: 0x%x", ntohl(dhcp_hdr->xid));
1810 	log_debug("dhcp_hdr secs: %u", dhcp_hdr->secs);
1811 	log_debug("dhcp_hdr flags: 0x%x", dhcp_hdr->flags);
1812 	log_debug("dhcp_hdr ciaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->ciaddr,
1813 	    hbuf, sizeof(hbuf)));
1814 	log_debug("dhcp_hdr yiaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->yiaddr,
1815 	    hbuf, sizeof(hbuf)));
1816 	log_debug("dhcp_hdr siaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->siaddr,
1817 	    hbuf, sizeof(hbuf)));
1818 	log_debug("dhcp_hdr giaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->giaddr,
1819 	    hbuf, sizeof(hbuf)));
1820 	log_debug("dhcp_hdr chaddr: %02x:%02x:%02x:%02x:%02x:%02x "
1821 	    "(%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x)",
1822 	    dhcp_hdr->chaddr[0], dhcp_hdr->chaddr[1], dhcp_hdr->chaddr[2],
1823 	    dhcp_hdr->chaddr[3], dhcp_hdr->chaddr[4], dhcp_hdr->chaddr[5],
1824 	    dhcp_hdr->chaddr[6], dhcp_hdr->chaddr[7], dhcp_hdr->chaddr[8],
1825 	    dhcp_hdr->chaddr[9], dhcp_hdr->chaddr[10], dhcp_hdr->chaddr[11],
1826 	    dhcp_hdr->chaddr[12], dhcp_hdr->chaddr[13], dhcp_hdr->chaddr[14],
1827 	    dhcp_hdr->chaddr[15]);
1828 	/* ignore sname and file, if we ever print it use strvis(3) */
1829 #endif
1830 }
1831 
1832 const char *
1833 dhcp_message_type2str(uint8_t dhcp_message_type)
1834 {
1835 	switch (dhcp_message_type) {
1836 	case DHCPDISCOVER:
1837 		return "DHCPDISCOVER";
1838 	case DHCPOFFER:
1839 		return "DHCPOFFER";
1840 	case DHCPREQUEST:
1841 		return "DHCPREQUEST";
1842 	case DHCPDECLINE:
1843 		return "DHCPDECLINE";
1844 	case DHCPACK:
1845 		return "DHCPACK";
1846 	case DHCPNAK:
1847 		return "DHCPNAK";
1848 	case DHCPRELEASE:
1849 		return "DHCPRELEASE";
1850 	case DHCPINFORM:
1851 		return "DHCPINFORM";
1852 	default:
1853 		return "Unknown";
1854 	}
1855 }
1856