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