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