xref: /openbsd/sbin/dhcp6leased/engine.c (revision 0498f896)
1 /*	$OpenBSD: engine.c,v 1.24 2024/07/11 10:48:51 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2017, 2021, 2024 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/ip.h>
34 
35 #include <errno.h>
36 #include <event.h>
37 #include <imsg.h>
38 #include <pwd.h>
39 #include <signal.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <vis.h>
47 
48 #include "log.h"
49 #include "dhcp6leased.h"
50 #include "engine.h"
51 
52 /*
53  * RFC 2131 4.1 p23 has "SHOULD be 4 seconds", we are a bit more aggressive,
54  * networks are faster these days.
55  */
56 #define	START_EXP_BACKOFF	 1
57 #define	MAX_EXP_BACKOFF_SLOW	64 /* RFC 2131 4.1 p23 */
58 #define	MAX_EXP_BACKOFF_FAST	 2
59 #define	MINIMUM(a, b)		(((a) < (b)) ? (a) : (b))
60 
61 enum if_state {
62 	IF_DOWN,
63 	IF_INIT,
64 	/* IF_SELECTING, */
65 	IF_REQUESTING,
66 	IF_BOUND,
67 	IF_RENEWING,
68 	IF_REBINDING,
69 	/* IF_INIT_REBOOT, */
70 	IF_REBOOTING,
71 };
72 
73 const char* if_state_name[] = {
74 	"Down",
75 	"Init",
76 	/* "Selecting", */
77 	"Requesting",
78 	"Bound",
79 	"Renewing",
80 	"Rebinding",
81 	/* "Init-Reboot", */
82 	"Rebooting",
83 	"IPv6 only",
84 };
85 
86 enum reconfigure_action {
87 	CONFIGURE,
88 	DECONFIGURE,
89 };
90 
91 const char* reconfigure_action_name[] = {
92 	"configure",
93 	"deconfigure",
94 };
95 
96 struct dhcp6leased_iface {
97 	LIST_ENTRY(dhcp6leased_iface)	 entries;
98 	enum if_state			 state;
99 	struct event			 timer;
100 	struct timeval			 timo;
101 	uint32_t			 if_index;
102 	int				 rdomain;
103 	int				 running;
104 	int				 link_state;
105 	uint8_t				 xid[XID_SIZE];
106 	int				 serverid_len;
107 	uint8_t				 serverid[SERVERID_SIZE];
108 	struct prefix			 pds[MAX_IA];
109 	struct prefix			 new_pds[MAX_IA];
110 	struct timespec			 request_time;
111 	struct timespec			 elapsed_time_start;
112 	uint32_t			 lease_time;
113 	uint32_t			 t1;
114 	uint32_t			 t2;
115 };
116 
117 LIST_HEAD(, dhcp6leased_iface) dhcp6leased_interfaces;
118 
119 __dead void		 engine_shutdown(void);
120 void			 engine_sig_handler(int sig, short, void *);
121 void			 engine_dispatch_frontend(int, short, void *);
122 void			 engine_dispatch_main(int, short, void *);
123 void			 send_interface_info(struct dhcp6leased_iface *, pid_t);
124 void			 engine_showinfo_ctl(struct imsg *, uint32_t);
125 void			 engine_update_iface(struct imsg_ifinfo *);
126 struct dhcp6leased_iface	*get_dhcp6leased_iface_by_id(uint32_t);
127 void			 remove_dhcp6leased_iface(uint32_t);
128 void			 parse_dhcp(struct dhcp6leased_iface *,
129 			     struct imsg_dhcp *);
130 int			 parse_ia_pd_options(uint8_t *, size_t, struct prefix *);
131 void			 state_transition(struct dhcp6leased_iface *, enum
132 			     if_state);
133 void			 iface_timeout(int, short, void *);
134 void			 request_dhcp_discover(struct dhcp6leased_iface *);
135 void			 request_dhcp_request(struct dhcp6leased_iface *);
136 void			 configure_interfaces(struct dhcp6leased_iface *);
137 void			 deconfigure_interfaces(struct dhcp6leased_iface *);
138 int			 prefixcmp(struct prefix *, struct prefix *, int);
139 void			 send_reconfigure_interface(struct iface_pd_conf *,
140 			     struct prefix *, enum reconfigure_action);
141 int			 engine_imsg_compose_main(int, pid_t, void *, uint16_t);
142 const char		*dhcp_option_type2str(int);
143 const char		*dhcp_duid2str(int, uint8_t *);
144 const char		*dhcp_status2str(int);
145 void			 in6_prefixlen2mask(struct in6_addr *, int len);
146 
147 struct dhcp6leased_conf	*engine_conf;
148 
149 static struct imsgev	*iev_frontend;
150 static struct imsgev	*iev_main;
151 int64_t			 proposal_id;
152 static struct dhcp_duid	 duid;
153 
154 void
engine_sig_handler(int sig,short event,void * arg)155 engine_sig_handler(int sig, short event, void *arg)
156 {
157 	/*
158 	 * Normal signal handler rules don't apply because libevent
159 	 * decouples for us.
160 	 */
161 
162 	switch (sig) {
163 	case SIGINT:
164 	case SIGTERM:
165 		engine_shutdown();
166 	default:
167 		fatalx("unexpected signal");
168 	}
169 }
170 
171 void
engine(int debug,int verbose)172 engine(int debug, int verbose)
173 {
174 	struct event		 ev_sigint, ev_sigterm;
175 	struct passwd		*pw;
176 
177 	engine_conf = config_new_empty();
178 
179 	log_init(debug, LOG_DAEMON);
180 	log_setverbose(verbose);
181 
182 	if ((pw = getpwnam(DHCP6LEASED_USER)) == NULL)
183 		fatal("getpwnam");
184 
185 	if (chdir("/") == -1)
186 		fatal("chdir(\"/\")");
187 
188 	if (unveil("/", "") == -1)
189 		fatal("unveil /");
190 	if (unveil(NULL, NULL) == -1)
191 		fatal("unveil");
192 
193 	setproctitle("%s", "engine");
194 	log_procinit("engine");
195 
196 	if (setgroups(1, &pw->pw_gid) ||
197 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
198 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
199 		fatal("can't drop privileges");
200 
201 	if (pledge("stdio recvfd", NULL) == -1)
202 		fatal("pledge");
203 
204 	event_init();
205 
206 	/* Setup signal handler(s). */
207 	signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
208 	signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
209 	signal_add(&ev_sigint, NULL);
210 	signal_add(&ev_sigterm, NULL);
211 	signal(SIGPIPE, SIG_IGN);
212 	signal(SIGHUP, SIG_IGN);
213 
214 	/* Setup pipe and event handler to the main process. */
215 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
216 		fatal(NULL);
217 
218 	imsg_init(&iev_main->ibuf, 3);
219 	iev_main->handler = engine_dispatch_main;
220 
221 	/* Setup event handlers. */
222 	iev_main->events = EV_READ;
223 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
224 	    iev_main->handler, iev_main);
225 	event_add(&iev_main->ev, NULL);
226 
227 	LIST_INIT(&dhcp6leased_interfaces);
228 
229 	event_dispatch();
230 
231 	engine_shutdown();
232 }
233 
234 __dead void
engine_shutdown(void)235 engine_shutdown(void)
236 {
237 	/* Close pipes. */
238 	msgbuf_clear(&iev_frontend->ibuf.w);
239 	close(iev_frontend->ibuf.fd);
240 	msgbuf_clear(&iev_main->ibuf.w);
241 	close(iev_main->ibuf.fd);
242 
243 	free(iev_frontend);
244 	free(iev_main);
245 
246 	log_info("engine exiting");
247 	exit(0);
248 }
249 
250 int
engine_imsg_compose_frontend(int type,pid_t pid,void * data,uint16_t datalen)251 engine_imsg_compose_frontend(int type, pid_t pid, void *data,
252     uint16_t datalen)
253 {
254 	return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
255 	    data, datalen));
256 }
257 
258 int
engine_imsg_compose_main(int type,pid_t pid,void * data,uint16_t datalen)259 engine_imsg_compose_main(int type, pid_t pid, void *data,
260     uint16_t datalen)
261 {
262 	return (imsg_compose_event(iev_main, type, 0, pid, -1,
263 	    data, datalen));
264 }
265 
266 void
engine_dispatch_frontend(int fd,short event,void * bula)267 engine_dispatch_frontend(int fd, short event, void *bula)
268 {
269 	struct imsgev			*iev = bula;
270 	struct imsgbuf			*ibuf = &iev->ibuf;
271 	struct imsg			 imsg;
272 	struct dhcp6leased_iface		*iface;
273 	ssize_t				 n;
274 	int				 shut = 0;
275 	int				 verbose;
276 	uint32_t			 if_index;
277 
278 	if (event & EV_READ) {
279 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
280 			fatal("imsg_read error");
281 		if (n == 0)	/* Connection closed. */
282 			shut = 1;
283 	}
284 	if (event & EV_WRITE) {
285 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
286 			fatal("msgbuf_write");
287 		if (n == 0)	/* Connection closed. */
288 			shut = 1;
289 	}
290 
291 	for (;;) {
292 		if ((n = imsg_get(ibuf, &imsg)) == -1)
293 			fatal("%s: imsg_get error", __func__);
294 		if (n == 0)	/* No more messages. */
295 			break;
296 
297 		switch (imsg.hdr.type) {
298 		case IMSG_CTL_LOG_VERBOSE:
299 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
300 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
301 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
302 			memcpy(&verbose, imsg.data, sizeof(verbose));
303 			log_setverbose(verbose);
304 			break;
305 		case IMSG_CTL_SHOW_INTERFACE_INFO:
306 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
307 				fatalx("%s: IMSG_CTL_SHOW_INTERFACE_INFO wrong "
308 				    "length: %lu", __func__,
309 				    IMSG_DATA_SIZE(imsg));
310 			memcpy(&if_index, imsg.data, sizeof(if_index));
311 			engine_showinfo_ctl(&imsg, if_index);
312 			break;
313 		case IMSG_REQUEST_REBOOT:
314 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
315 				fatalx("%s: IMSG_CTL_SEND_DISCOVER wrong "
316 				    "length: %lu", __func__,
317 				    IMSG_DATA_SIZE(imsg));
318 			memcpy(&if_index, imsg.data, sizeof(if_index));
319 			iface = get_dhcp6leased_iface_by_id(if_index);
320 			if (iface != NULL) {
321 				switch (iface->state) {
322 				case IF_DOWN:
323 					break;
324 				case IF_INIT:
325 				case IF_REQUESTING:
326 					state_transition(iface, iface->state);
327 					break;
328 				case IF_RENEWING:
329 				case IF_REBINDING:
330 				case IF_REBOOTING:
331 				case IF_BOUND:
332 					state_transition(iface, IF_REBOOTING);
333 					break;
334 				}
335 			}
336 			break;
337 		case IMSG_REMOVE_IF:
338 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
339 				fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
340 				    __func__, IMSG_DATA_SIZE(imsg));
341 			memcpy(&if_index, imsg.data, sizeof(if_index));
342 			remove_dhcp6leased_iface(if_index);
343 			break;
344 		case IMSG_DHCP: {
345 			struct imsg_dhcp	imsg_dhcp;
346 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_dhcp))
347 				fatalx("%s: IMSG_DHCP wrong length: %lu",
348 				    __func__, IMSG_DATA_SIZE(imsg));
349 			memcpy(&imsg_dhcp, imsg.data, sizeof(imsg_dhcp));
350 			iface = get_dhcp6leased_iface_by_id(imsg_dhcp.if_index);
351 			if (iface != NULL)
352 				parse_dhcp(iface, &imsg_dhcp);
353 			break;
354 		}
355 		default:
356 			log_debug("%s: unexpected imsg %d", __func__,
357 			    imsg.hdr.type);
358 			break;
359 		}
360 		imsg_free(&imsg);
361 	}
362 	if (!shut)
363 		imsg_event_add(iev);
364 	else {
365 		/* This pipe is dead. Remove its event handler. */
366 		event_del(&iev->ev);
367 		event_loopexit(NULL);
368 	}
369 }
370 
371 void
engine_dispatch_main(int fd,short event,void * bula)372 engine_dispatch_main(int fd, short event, void *bula)
373 {
374 	static struct dhcp6leased_conf	*nconf;
375 	static struct iface_conf	*iface_conf;
376 	static struct iface_ia_conf	*iface_ia_conf;
377 	struct iface_pd_conf		*iface_pd_conf;
378 	struct imsg			 imsg;
379 	struct imsgev			*iev = bula;
380 	struct imsgbuf			*ibuf = &iev->ibuf;
381 	struct imsg_ifinfo		 imsg_ifinfo;
382 	ssize_t				 n;
383 	int				 shut = 0;
384 
385 	if (event & EV_READ) {
386 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
387 			fatal("imsg_read error");
388 		if (n == 0)	/* Connection closed. */
389 			shut = 1;
390 	}
391 	if (event & EV_WRITE) {
392 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
393 			fatal("msgbuf_write");
394 		if (n == 0)	/* Connection closed. */
395 			shut = 1;
396 	}
397 
398 	for (;;) {
399 		if ((n = imsg_get(ibuf, &imsg)) == -1)
400 			fatal("%s: imsg_get error", __func__);
401 		if (n == 0)	/* No more messages. */
402 			break;
403 
404 		switch (imsg.hdr.type) {
405 		case IMSG_SOCKET_IPC:
406 			/*
407 			 * Setup pipe and event handler to the frontend
408 			 * process.
409 			 */
410 			if (iev_frontend)
411 				fatalx("%s: received unexpected imsg fd "
412 				    "to engine", __func__);
413 
414 			if ((fd = imsg_get_fd(&imsg)) == -1)
415 				fatalx("%s: expected to receive imsg fd to "
416 				   "engine but didn't receive any", __func__);
417 
418 			iev_frontend = malloc(sizeof(struct imsgev));
419 			if (iev_frontend == NULL)
420 				fatal(NULL);
421 
422 			imsg_init(&iev_frontend->ibuf, fd);
423 			iev_frontend->handler = engine_dispatch_frontend;
424 			iev_frontend->events = EV_READ;
425 
426 			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
427 			iev_frontend->events, iev_frontend->handler,
428 			    iev_frontend);
429 			event_add(&iev_frontend->ev, NULL);
430 
431 			if (pledge("stdio", NULL) == -1)
432 				fatal("pledge");
433 
434 			break;
435 		case IMSG_UUID:
436 			if (IMSG_DATA_SIZE(imsg) != sizeof(duid.uuid))
437 				fatalx("%s: IMSG_UUID wrong length: "
438 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
439 			duid.type = htons(DUID_UUID_TYPE);
440 			memcpy(duid.uuid, imsg.data, sizeof(duid.uuid));
441 			break;
442 		case IMSG_UPDATE_IF:
443 			if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo))
444 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
445 				    __func__, IMSG_DATA_SIZE(imsg));
446 			memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo));
447 			engine_update_iface(&imsg_ifinfo);
448 			break;
449 		case IMSG_RECONF_CONF:
450 			if (nconf != NULL)
451 				fatalx("%s: IMSG_RECONF_CONF already in "
452 				    "progress", __func__);
453 			if (IMSG_DATA_SIZE(imsg) !=
454 			    sizeof(struct dhcp6leased_conf))
455 				fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
456 				    __func__, IMSG_DATA_SIZE(imsg));
457 			if ((nconf = malloc(sizeof(struct dhcp6leased_conf))) ==
458 			    NULL)
459 				fatal(NULL);
460 			memcpy(nconf, imsg.data,
461 			    sizeof(struct dhcp6leased_conf));
462 			SIMPLEQ_INIT(&nconf->iface_list);
463 			break;
464 		case IMSG_RECONF_IFACE:
465 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
466 			    iface_conf))
467 				fatalx("%s: IMSG_RECONF_IFACE wrong length: "
468 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
469 			if ((iface_conf = malloc(sizeof(struct iface_conf)))
470 			    == NULL)
471 				fatal(NULL);
472 			memcpy(iface_conf, imsg.data, sizeof(struct
473 			    iface_conf));
474 			SIMPLEQ_INIT(&iface_conf->iface_ia_list);
475 			SIMPLEQ_INSERT_TAIL(&nconf->iface_list,
476 			    iface_conf, entry);
477 			iface_conf->ia_count = 0;
478 			break;
479 		case IMSG_RECONF_IFACE_IA:
480 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
481 			    iface_ia_conf))
482 				fatalx("%s: IMSG_RECONF_IFACE_IA wrong "
483 				    "length: %lu", __func__,
484 				    IMSG_DATA_SIZE(imsg));
485 			if ((iface_ia_conf =
486 			    malloc(sizeof(struct iface_ia_conf))) == NULL)
487 				fatal(NULL);
488 			memcpy(iface_ia_conf, imsg.data, sizeof(struct
489 			    iface_ia_conf));
490 			SIMPLEQ_INIT(&iface_ia_conf->iface_pd_list);
491 			SIMPLEQ_INSERT_TAIL(&iface_conf->iface_ia_list,
492 			    iface_ia_conf, entry);
493 			iface_ia_conf->id = iface_conf->ia_count++;
494 			if (iface_conf->ia_count > MAX_IA)
495 				fatalx("Too many prefix delegation requests.");
496 			break;
497 		case IMSG_RECONF_IFACE_PD:
498 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
499 			    iface_pd_conf))
500 				fatalx("%s: IMSG_RECONF_IFACE_PD wrong length: "
501 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
502 			if ((iface_pd_conf =
503 			    malloc(sizeof(struct iface_pd_conf))) == NULL)
504 				fatal(NULL);
505 			memcpy(iface_pd_conf, imsg.data, sizeof(struct
506 			    iface_pd_conf));
507 			SIMPLEQ_INSERT_TAIL(&iface_ia_conf->iface_pd_list,
508 			    iface_pd_conf, entry);
509 			break;
510 		case IMSG_RECONF_IFACE_IA_END:
511 			iface_ia_conf = NULL;
512 			break;
513 		case IMSG_RECONF_IFACE_END:
514 			iface_conf = NULL;
515 			break;
516 		case IMSG_RECONF_END: {
517 			struct dhcp6leased_iface	*iface;
518 			int			*ifaces;
519 			int			 i, if_index;
520 			char			*if_name;
521 			char			 ifnamebuf[IF_NAMESIZE];
522 
523 			if (nconf == NULL)
524 				fatalx("%s: IMSG_RECONF_END without "
525 				    "IMSG_RECONF_CONF", __func__);
526 			ifaces = changed_ifaces(engine_conf, nconf);
527 			merge_config(engine_conf, nconf);
528 			nconf = NULL;
529 			for (i = 0; ifaces[i] != 0; i++) {
530 				if_index = ifaces[i];
531 				if_name = if_indextoname(if_index, ifnamebuf);
532 				iface = get_dhcp6leased_iface_by_id(if_index);
533 				if (if_name == NULL || iface == NULL)
534 					continue;
535 				iface_conf = find_iface_conf(
536 				    &engine_conf->iface_list, if_name);
537 				if (iface_conf == NULL)
538 					continue;
539 			}
540 			free(ifaces);
541 			break;
542 		}
543 		default:
544 			log_debug("%s: unexpected imsg %d", __func__,
545 			    imsg.hdr.type);
546 			break;
547 		}
548 		imsg_free(&imsg);
549 	}
550 	if (!shut)
551 		imsg_event_add(iev);
552 	else {
553 		/* This pipe is dead. Remove its event handler. */
554 		event_del(&iev->ev);
555 		event_loopexit(NULL);
556 	}
557 }
558 
559 void
send_interface_info(struct dhcp6leased_iface * iface,pid_t pid)560 send_interface_info(struct dhcp6leased_iface *iface, pid_t pid)
561 {
562 	struct ctl_engine_info	 cei;
563 
564 	memset(&cei, 0, sizeof(cei));
565 	cei.if_index = iface->if_index;
566 	cei.running = iface->running;
567 	cei.link_state = iface->link_state;
568 	strlcpy(cei.state, if_state_name[iface->state], sizeof(cei.state));
569 	memcpy(&cei.request_time, &iface->request_time,
570 	    sizeof(cei.request_time));
571 	cei.lease_time = iface->lease_time;
572 	cei.t1 = iface->t1;
573 	cei.t2 = iface->t2;
574 	memcpy(&cei.pds, &iface->pds, sizeof(cei.pds));
575 	engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei,
576 	    sizeof(cei));
577 }
578 
579 void
engine_showinfo_ctl(struct imsg * imsg,uint32_t if_index)580 engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index)
581 {
582 	struct dhcp6leased_iface			*iface;
583 
584 	switch (imsg->hdr.type) {
585 	case IMSG_CTL_SHOW_INTERFACE_INFO:
586 		if ((iface = get_dhcp6leased_iface_by_id(if_index)) != NULL)
587 			send_interface_info(iface, imsg->hdr.pid);
588 		else
589 			engine_imsg_compose_frontend(IMSG_CTL_END,
590 			    imsg->hdr.pid, NULL, 0);
591 		break;
592 	default:
593 		log_debug("%s: error handling imsg", __func__);
594 		break;
595 	}
596 }
597 
598 void
engine_update_iface(struct imsg_ifinfo * imsg_ifinfo)599 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo)
600 {
601 	struct dhcp6leased_iface	*iface;
602 	struct iface_conf		*iface_conf;
603 	int				 need_refresh = 0;
604 	char				 ifnamebuf[IF_NAMESIZE], *if_name;
605 
606 	iface = get_dhcp6leased_iface_by_id(imsg_ifinfo->if_index);
607 
608 	if (iface == NULL) {
609 		if ((iface = calloc(1, sizeof(*iface))) == NULL)
610 			fatal("calloc");
611 		iface->state = IF_DOWN;
612 		arc4random_buf(iface->xid, sizeof(iface->xid));
613 		iface->timo.tv_usec = arc4random_uniform(1000000);
614 		evtimer_set(&iface->timer, iface_timeout, iface);
615 		iface->if_index = imsg_ifinfo->if_index;
616 		iface->rdomain = imsg_ifinfo->rdomain;
617 		iface->running = imsg_ifinfo->running;
618 		iface->link_state = imsg_ifinfo->link_state;
619 		LIST_INSERT_HEAD(&dhcp6leased_interfaces, iface, entries);
620 		need_refresh = 1;
621 	} else {
622 		if (imsg_ifinfo->rdomain != iface->rdomain) {
623 			iface->rdomain = imsg_ifinfo->rdomain;
624 			need_refresh = 1;
625 		}
626 		if (imsg_ifinfo->running != iface->running) {
627 			iface->running = imsg_ifinfo->running;
628 			need_refresh = 1;
629 		}
630 
631 		if (imsg_ifinfo->link_state != iface->link_state) {
632 			iface->link_state = imsg_ifinfo->link_state;
633 			need_refresh = 1;
634 		}
635 	}
636 
637 	if (!need_refresh)
638 		return;
639 
640 	if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) {
641 		log_debug("%s: unknown interface %d", __func__,
642 		    iface->if_index);
643 		return;
644 	}
645 
646 	if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name))
647 	    == NULL) {
648 		log_debug("%s: no interface configuration for %d", __func__,
649 		    iface->if_index);
650 		return;
651 	}
652 
653 	if (iface->running && LINK_STATE_IS_UP(iface->link_state)) {
654 		uint32_t	 i;
655 		int		 got_lease;
656 
657 		if (iface->pds[0].prefix_len == 0)
658 			memcpy(iface->pds, imsg_ifinfo->pds,
659 			    sizeof(iface->pds));
660 
661 		got_lease = 0;
662 		for (i = 0; i < iface_conf->ia_count; i++) {
663 			if (iface->pds[i].prefix_len > 0) {
664 				got_lease = 1;
665 				break;
666 			}
667 		}
668 		if (got_lease)
669 			state_transition(iface, IF_REBOOTING);
670 		else
671 			state_transition(iface, IF_INIT);
672 	} else
673 		state_transition(iface, IF_DOWN);
674 }
675 struct dhcp6leased_iface*
get_dhcp6leased_iface_by_id(uint32_t if_index)676 get_dhcp6leased_iface_by_id(uint32_t if_index)
677 {
678 	struct dhcp6leased_iface	*iface;
679 	LIST_FOREACH (iface, &dhcp6leased_interfaces, entries) {
680 		if (iface->if_index == if_index)
681 			return (iface);
682 	}
683 
684 	return (NULL);
685 }
686 
687 void
remove_dhcp6leased_iface(uint32_t if_index)688 remove_dhcp6leased_iface(uint32_t if_index)
689 {
690 	struct dhcp6leased_iface	*iface;
691 
692 	iface = get_dhcp6leased_iface_by_id(if_index);
693 
694 	if (iface == NULL)
695 		return;
696 
697 	deconfigure_interfaces(iface);
698 	LIST_REMOVE(iface, entries);
699 	evtimer_del(&iface->timer);
700 	free(iface);
701 }
702 
703 void
parse_dhcp(struct dhcp6leased_iface * iface,struct imsg_dhcp * dhcp)704 parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp)
705 {
706 	struct iface_conf	*iface_conf;
707 	struct iface_ia_conf	*ia_conf;
708 	struct dhcp_hdr		 hdr;
709 	struct dhcp_option_hdr	 opt_hdr;
710 	struct dhcp_iapd	 iapd;
711 	size_t			 rem;
712 	uint32_t		 t1, t2, lease_time;
713 	int			 serverid_len, rapid_commit = 0;
714 	uint8_t			 serverid[SERVERID_SIZE];
715 	uint8_t			*p;
716 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
717 	char			 ntopbuf[INET6_ADDRSTRLEN];
718 
719 	if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) {
720 		log_debug("%s: unknown interface %d", __func__,
721 		    iface->if_index);
722 		goto out;
723 	}
724 	if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name))
725 	    == NULL) {
726 		log_debug("%s: no interface configuration for %d", __func__,
727 		    iface->if_index);
728 		goto out;
729 	}
730 
731 	log_debug("%s: %s ia_count: %d", __func__, if_name,
732 	    iface_conf->ia_count);
733 
734 	serverid_len = t1 = t2 = lease_time = 0;
735 	memset(iface->new_pds, 0, sizeof(iface->new_pds));
736 
737 	p = dhcp->packet;
738 	rem = dhcp->len;
739 
740 	if (rem < sizeof(struct dhcp_hdr)) {
741 		log_warnx("%s: message too short", __func__);
742 		goto out;
743 	}
744 	memcpy(&hdr, p, sizeof(struct dhcp_hdr));
745 	p += sizeof(struct dhcp_hdr);
746 	rem -= sizeof(struct dhcp_hdr);
747 
748 	if (log_getverbose() > 1)
749 		log_debug("%s: %s, xid: 0x%02x%02x%02x", __func__,
750 		    dhcp_message_type2str(hdr.msg_type), hdr.xid[0], hdr.xid[1],
751 		    hdr.xid[2]);
752 
753 	while (rem >= sizeof(struct dhcp_option_hdr)) {
754 		memcpy(&opt_hdr, p, sizeof(struct dhcp_option_hdr));
755 		opt_hdr.code = ntohs(opt_hdr.code);
756 		opt_hdr.len = ntohs(opt_hdr.len);
757 		p += sizeof(struct dhcp_option_hdr);
758 		rem -= sizeof(struct dhcp_option_hdr);
759 		if (log_getverbose() > 1)
760 			log_debug("%s: %s, len: %u", __func__,
761 			    dhcp_option_type2str(opt_hdr.code), opt_hdr.len);
762 
763 		if (rem < opt_hdr.len) {
764 			log_warnx("%s: malformed packet, ignoring", __func__);
765 			goto out;
766 		}
767 
768 		switch (opt_hdr.code) {
769 		case DHO_CLIENTID:
770 			if (opt_hdr.len != sizeof(struct dhcp_duid) ||
771 			    memcmp(&duid, p, sizeof(struct dhcp_duid)) != 0) {
772 				log_debug("%s: message not for us", __func__);
773 				goto out;
774 			}
775 			break;
776 		case DHO_SERVERID:
777 			/*
778 			 * RFC 8415, 11.1:
779 			 * The length of the DUID (not including the type code)
780 			 * is at least 1 octet and at most 128 octets.
781 			 */
782 			if (opt_hdr.len < 2 + 1) {
783 				log_warnx("%s: SERVERID too short", __func__);
784 				goto out;
785 			}
786 			if (opt_hdr.len > SERVERID_SIZE) {
787 				log_warnx("%s: SERVERID too long", __func__);
788 				goto out;
789 			}
790 			log_debug("%s: SERVERID: %s", __func__,
791 			    dhcp_duid2str(opt_hdr.len, p));
792 			if (serverid_len != 0) {
793 				log_warnx("%s: duplicate SERVERID option",
794 				    __func__);
795 				goto out;
796 			}
797 			serverid_len = opt_hdr.len;
798 			memcpy(serverid, p, serverid_len);
799 			break;
800 		case DHO_IA_PD:
801 			if (opt_hdr.len < sizeof(struct dhcp_iapd)) {
802 				log_warnx("%s: IA_PD too short", __func__);
803 				goto out;
804 			}
805 			memcpy(&iapd, p, sizeof(struct dhcp_iapd));
806 
807 			if (t1 == 0 || t1 > ntohl(iapd.t1))
808 				t1 = ntohl(iapd.t1);
809 			if (t2 == 0 || t2 > ntohl(iapd.t2))
810 				t2 = ntohl(iapd.t2);
811 
812 			log_debug("%s: IA_PD, IAID: %08x, T1: %u, T2: %u",
813 			    __func__, ntohl(iapd.iaid), ntohl(iapd.t1),
814 			    ntohl(iapd.t2));
815 			if (ntohl(iapd.iaid) < iface_conf->ia_count) {
816 				int status_code;
817 				status_code = parse_ia_pd_options(p +
818 				    sizeof(struct dhcp_iapd), opt_hdr.len -
819 				    sizeof(struct dhcp_iapd),
820 				    &iface->new_pds[ntohl(iapd.iaid)]);
821 
822 				if (status_code != DHCP_STATUS_SUCCESS &&
823 				    iface->state == IF_RENEWING) {
824 					state_transition(iface, IF_REBINDING);
825 					goto out;
826 				}
827 			}
828 			break;
829 		case DHO_RAPID_COMMIT:
830 			if (opt_hdr.len != 0) {
831 				log_warnx("%s: invalid rapid commit option",
832 				    __func__);
833 				goto out;
834 			}
835 			rapid_commit = 1;
836 			break;
837 		default:
838 			log_debug("unhandled option: %u", opt_hdr.code);
839 			break;
840 		}
841 
842 		p += opt_hdr.len;
843 		rem -= opt_hdr.len;
844 	}
845 
846 	/* check that we got all the information we need */
847 	if (serverid_len == 0) {
848 		log_warnx("%s: Did not receive server identifier", __func__);
849 		goto out;
850 	}
851 
852 
853 	SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) {
854 		struct prefix	*pd = &iface->new_pds[ia_conf->id];
855 
856 		if (pd->prefix_len == 0) {
857 			log_warnx("%s: no IA for IAID %d found", __func__,
858 			    ia_conf->id);
859 			goto out;
860 		}
861 		if (pd->prefix_len > ia_conf->prefix_len) {
862 			log_warnx("%s: prefix for IAID %d too small: %d > %d",
863 			    __func__, ia_conf->id, pd->prefix_len,
864 			    ia_conf->prefix_len);
865 			goto out;
866 		}
867 
868 		if (lease_time < pd->vltime)
869 			lease_time = pd->vltime;
870 
871 		log_debug("%s: pltime: %u, vltime: %u, prefix: %s/%u",
872 		    __func__, pd->pltime, pd->vltime, inet_ntop(AF_INET6,
873 		    &pd->prefix, ntopbuf, INET6_ADDRSTRLEN), pd->prefix_len);
874 	}
875 
876 	switch (hdr.msg_type) {
877 	case DHCPSOLICIT:
878 	case DHCPREQUEST:
879 	case DHCPCONFIRM:
880 	case DHCPRENEW:
881 	case DHCPREBIND:
882 	case DHCPRELEASE:
883 	case DHCPDECLINE:
884 	case DHCPINFORMATIONREQUEST:
885 		log_warnx("%s: Ignoring client-only message (%s) from server",
886 		    __func__, dhcp_message_type2str(hdr.msg_type));
887 		goto out;
888 	case DHCPRELAYFORW:
889 	case DHCPRELAYREPL:
890 		log_warnx("%s: Ignoring relay-agent-only message (%s) from "
891 		    "server", __func__, dhcp_message_type2str(hdr.msg_type));
892 		goto out;
893 	case DHCPADVERTISE:
894 		if (iface->state != IF_INIT) {
895 			log_debug("%s: ignoring unexpected %s", __func__,
896 			    dhcp_message_type2str(hdr.msg_type));
897 			goto out;
898 		}
899 		iface->serverid_len = serverid_len;
900 		memcpy(iface->serverid, serverid, SERVERID_SIZE);
901 		memcpy(iface->pds, iface->new_pds, sizeof(iface->pds));
902 		state_transition(iface, IF_REQUESTING);
903 		break;
904 	case DHCPREPLY:
905 		switch (iface->state) {
906 		case IF_REQUESTING:
907 		case IF_RENEWING:
908 		case IF_REBINDING:
909 		case IF_REBOOTING:
910 			break;
911 		case IF_INIT:
912 			if (rapid_commit && engine_conf->rapid_commit)
913 				break;
914 			/* fall through */
915 		default:
916 			log_debug("%s: ignoring unexpected %s", __func__,
917 			    dhcp_message_type2str(hdr.msg_type));
918 			goto out;
919 		}
920 		iface->serverid_len = serverid_len;
921 		memcpy(iface->serverid, serverid, SERVERID_SIZE);
922 
923 		/* XXX handle t1 = 0 or t2 = 0 */
924 		iface->t1 = t1;
925 		iface->t2 = t2;
926 		iface->lease_time = lease_time;
927 		clock_gettime(CLOCK_MONOTONIC, &iface->request_time);
928 		state_transition(iface, IF_BOUND);
929 		break;
930 	case DHCPRECONFIGURE:
931 		log_warnx("%s: Ignoring %s from server",
932 		    __func__, dhcp_message_type2str(hdr.msg_type));
933 		goto out;
934 	default:
935 		fatalx("%s: %s unhandled",
936 		    __func__, dhcp_message_type2str(hdr.msg_type));
937 		break;
938 	}
939  out:
940 	return;
941 }
942 
943 int
parse_ia_pd_options(uint8_t * p,size_t len,struct prefix * prefix)944 parse_ia_pd_options(uint8_t *p, size_t len, struct prefix *prefix)
945 {
946 	struct dhcp_option_hdr	 opt_hdr;
947 	struct dhcp_iaprefix	 iaprefix;
948 	struct in6_addr		 mask;
949 	int			 i;
950 	uint16_t		 status_code = DHCP_STATUS_SUCCESS;
951 	char			 ntopbuf[INET6_ADDRSTRLEN], *visbuf;
952 
953 	while (len >= sizeof(struct dhcp_option_hdr)) {
954 		memcpy(&opt_hdr, p, sizeof(struct dhcp_option_hdr));
955 		opt_hdr.code = ntohs(opt_hdr.code);
956 		opt_hdr.len = ntohs(opt_hdr.len);
957 		p += sizeof(struct dhcp_option_hdr);
958 		len -= sizeof(struct dhcp_option_hdr);
959 		if (log_getverbose() > 1)
960 			log_debug("%s: %s, len: %u", __func__,
961 			    dhcp_option_type2str(opt_hdr.code), opt_hdr.len);
962 		if (len < opt_hdr.len) {
963 			log_warnx("%s: malformed packet, ignoring", __func__);
964 			return DHCP_STATUS_UNSPECFAIL;
965 		}
966 
967 		switch (opt_hdr.code) {
968 		case DHO_IA_PREFIX:
969 			if (len < sizeof(struct dhcp_iaprefix)) {
970 				log_warnx("%s: malformed packet, ignoring",
971 				    __func__);
972 				return DHCP_STATUS_UNSPECFAIL;
973 			}
974 
975 			memcpy(&iaprefix, p, sizeof(struct dhcp_iaprefix));
976 			log_debug("%s: pltime: %u, vltime: %u, prefix: %s/%u",
977 			    __func__, ntohl(iaprefix.pltime),
978 			    ntohl(iaprefix.vltime), inet_ntop(AF_INET6,
979 			    &iaprefix.prefix, ntopbuf, INET6_ADDRSTRLEN),
980 			    iaprefix.prefix_len);
981 
982 			if (ntohl(iaprefix.vltime) < ntohl(iaprefix.pltime)) {
983 				log_warnx("%s: vltime < pltime, ignoring IA_PD",
984 				    __func__);
985 				break;
986 			}
987 
988 			if (ntohl(iaprefix.vltime) == 0) {
989 				log_debug("%s: vltime == 0, ignoring IA_PD",
990 				    __func__);
991 				break;
992 			}
993 
994 			prefix->prefix = iaprefix.prefix;
995 			prefix->prefix_len = iaprefix.prefix_len;
996 			prefix->vltime = ntohl(iaprefix.vltime);
997 			prefix->pltime = ntohl(iaprefix.pltime);
998 
999 			/* make sure prefix is masked correctly */
1000 			memset(&mask, 0, sizeof(mask));
1001 			in6_prefixlen2mask(&mask, prefix->prefix_len);
1002 			for (i = 0; i < 16; i++)
1003 				prefix->prefix.s6_addr[i] &= mask.s6_addr[i];
1004 
1005 			break;
1006 		case DHO_STATUS_CODE:
1007 			/* XXX STATUS_CODE can also appear outside of options */
1008 			if (len < 2) {
1009 				log_warnx("%s: malformed packet, ignoring",
1010 				    __func__);
1011 				return DHCP_STATUS_UNSPECFAIL;
1012 			}
1013 			memcpy(&status_code, p, sizeof(uint16_t));
1014 			status_code = ntohs(status_code);
1015 			/* must be at least 4 * srclen + 1 long */
1016 			visbuf = calloc(4, opt_hdr.len - 2 + 1);
1017 			if (visbuf == NULL) {
1018 				log_warn("%s", __func__);
1019 				break;
1020 			}
1021 			strvisx(visbuf, p + 2, opt_hdr.len - 2, VIS_SAFE);
1022 			log_debug("%s: %s - %s", __func__,
1023 			    dhcp_status2str(status_code), visbuf);
1024 			break;
1025 		default:
1026 			log_debug("unhandled option: %u", opt_hdr.code);
1027 		}
1028 		p += opt_hdr.len;
1029 		len -= opt_hdr.len;
1030 	}
1031 	return status_code;
1032 }
1033 
1034 /* XXX check valid transitions */
1035 void
state_transition(struct dhcp6leased_iface * iface,enum if_state new_state)1036 state_transition(struct dhcp6leased_iface *iface, enum if_state new_state)
1037 {
1038 	enum if_state	 old_state = iface->state;
1039 	char		 ifnamebuf[IF_NAMESIZE], *if_name;
1040 
1041 	iface->state = new_state;
1042 
1043 	switch (new_state) {
1044 	case IF_DOWN:
1045 		/*
1046 		 * Nothing to do until iface comes up. IP addresses will expire.
1047 		 */
1048 		iface->timo.tv_sec = -1;
1049 		break;
1050 	case IF_INIT:
1051 		switch (old_state) {
1052 		case IF_INIT:
1053 			if (iface->timo.tv_sec < MAX_EXP_BACKOFF_SLOW)
1054 				iface->timo.tv_sec *= 2;
1055 			break;
1056 		case IF_REQUESTING:
1057 		case IF_RENEWING:
1058 		case IF_REBINDING:
1059 		case IF_REBOOTING:
1060 			/* lease expired, got DHCPNAK or timeout: delete IP */
1061 			deconfigure_interfaces(iface);
1062 			/* fall through */
1063 		case IF_DOWN:
1064 			iface->timo.tv_sec = START_EXP_BACKOFF;
1065 			clock_gettime(CLOCK_MONOTONIC,
1066 			    &iface->elapsed_time_start);
1067 			break;
1068 		case IF_BOUND:
1069 			fatal("invalid transition Bound -> Init");
1070 			break;
1071 		}
1072 		request_dhcp_discover(iface);
1073 		break;
1074 	case IF_REBOOTING:
1075 		if (old_state == IF_REBOOTING)
1076 			iface->timo.tv_sec *= 2;
1077 		else {
1078 			iface->timo.tv_sec = START_EXP_BACKOFF;
1079 			arc4random_buf(iface->xid, sizeof(iface->xid));
1080 		}
1081 		request_dhcp_request(iface);
1082 		break;
1083 	case IF_REQUESTING:
1084 		if (old_state == IF_REQUESTING)
1085 			iface->timo.tv_sec *= 2;
1086 		else {
1087 			iface->timo.tv_sec = START_EXP_BACKOFF;
1088 			clock_gettime(CLOCK_MONOTONIC,
1089 			    &iface->elapsed_time_start);
1090 		}
1091 		request_dhcp_request(iface);
1092 		break;
1093 	case IF_BOUND:
1094 		iface->timo.tv_sec = iface->t1;
1095 		switch (old_state) {
1096 		case IF_REQUESTING:
1097 		case IF_RENEWING:
1098 		case IF_REBINDING:
1099 		case IF_REBOOTING:
1100 			configure_interfaces(iface);
1101 			break;
1102 		case IF_INIT:
1103 			if (engine_conf->rapid_commit)
1104 				configure_interfaces(iface);
1105 			else
1106 				fatal("invalid transition Init -> Bound");
1107 			break;
1108 		default:
1109 			break;
1110 		}
1111 		break;
1112 	case IF_RENEWING:
1113 		if (old_state == IF_BOUND) {
1114 			iface->timo.tv_sec = (iface->t2 -
1115 			    iface->t1) / 2; /* RFC 2131 4.4.5 */
1116 			arc4random_buf(iface->xid, sizeof(iface->xid));
1117 		} else
1118 			iface->timo.tv_sec /= 2;
1119 
1120 		if (iface->timo.tv_sec < 60)
1121 			iface->timo.tv_sec = 60;
1122 		request_dhcp_request(iface);
1123 		break;
1124 	case IF_REBINDING:
1125 		if (old_state == IF_RENEWING) {
1126 			iface->timo.tv_sec = (iface->lease_time -
1127 			    iface->t2) / 2; /* RFC 2131 4.4.5 */
1128 		} else
1129 			iface->timo.tv_sec /= 2;
1130 		request_dhcp_request(iface);
1131 		break;
1132 	}
1133 
1134 	if_name = if_indextoname(iface->if_index, ifnamebuf);
1135 	log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ?
1136 	    "?" : if_name, if_state_name[old_state], if_state_name[new_state],
1137 	    iface->timo.tv_sec);
1138 
1139 	if (iface->timo.tv_sec == -1) {
1140 		if (evtimer_pending(&iface->timer, NULL))
1141 			evtimer_del(&iface->timer);
1142 	} else
1143 		evtimer_add(&iface->timer, &iface->timo);
1144 }
1145 
1146 void
iface_timeout(int fd,short events,void * arg)1147 iface_timeout(int fd, short events, void *arg)
1148 {
1149 	struct dhcp6leased_iface	*iface = (struct dhcp6leased_iface *)arg;
1150 	struct timespec		 now, res;
1151 
1152 	log_debug("%s[%d]: %s", __func__, iface->if_index,
1153 	    if_state_name[iface->state]);
1154 
1155 	switch (iface->state) {
1156 	case IF_DOWN:
1157 		state_transition(iface, IF_DOWN);
1158 		break;
1159 	case IF_INIT:
1160 		state_transition(iface, IF_INIT);
1161 		break;
1162 	case IF_REBOOTING:
1163 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST)
1164 			state_transition(iface, IF_INIT);
1165 		else
1166 			state_transition(iface, IF_REBOOTING);
1167 		break;
1168 	case IF_REQUESTING:
1169 		if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_SLOW)
1170 			state_transition(iface, IF_INIT);
1171 		else
1172 			state_transition(iface, IF_REQUESTING);
1173 		break;
1174 	case IF_BOUND:
1175 		state_transition(iface, IF_RENEWING);
1176 		break;
1177 	case IF_RENEWING:
1178 		clock_gettime(CLOCK_MONOTONIC, &now);
1179 		timespecsub(&now, &iface->request_time, &res);
1180 		log_debug("%s: res.tv_sec: %lld, t2: %u", __func__,
1181 		    res.tv_sec, iface->t2);
1182 		if (res.tv_sec >= iface->t2)
1183 			state_transition(iface, IF_REBINDING);
1184 		else
1185 			state_transition(iface, IF_RENEWING);
1186 		break;
1187 	case IF_REBINDING:
1188 		clock_gettime(CLOCK_MONOTONIC, &now);
1189 		timespecsub(&now, &iface->request_time, &res);
1190 		log_debug("%s: res.tv_sec: %lld, lease_time: %u", __func__,
1191 		    res.tv_sec, iface->lease_time);
1192 		if (res.tv_sec > iface->lease_time)
1193 			state_transition(iface, IF_INIT);
1194 		else
1195 			state_transition(iface, IF_REBINDING);
1196 		break;
1197 	}
1198 }
1199 
1200 /* XXX can this be merged into dhcp_request()? */
1201 void
request_dhcp_discover(struct dhcp6leased_iface * iface)1202 request_dhcp_discover(struct dhcp6leased_iface *iface)
1203 {
1204 	struct imsg_req_dhcp	 imsg;
1205 	struct timespec		 now, res;
1206 
1207 	memset(&imsg, 0, sizeof(imsg));
1208 	imsg.if_index = iface->if_index;
1209 	memcpy(imsg.xid, iface->xid, sizeof(imsg.xid));
1210 	clock_gettime(CLOCK_MONOTONIC, &now);
1211 	timespecsub(&now, &iface->elapsed_time_start, &res);
1212 	if (res.tv_sec * 100 > 0xffff)
1213 		imsg.elapsed_time = 0xffff;
1214 	else
1215 		imsg.elapsed_time = res.tv_sec * 100;
1216 	engine_imsg_compose_frontend(IMSG_SEND_SOLICIT, 0, &imsg, sizeof(imsg));
1217 }
1218 
1219 void
request_dhcp_request(struct dhcp6leased_iface * iface)1220 request_dhcp_request(struct dhcp6leased_iface *iface)
1221 {
1222 	struct imsg_req_dhcp	 imsg;
1223 	struct timespec		 now, res;
1224 
1225 	memset(&imsg, 0, sizeof(imsg));
1226 	imsg.if_index = iface->if_index;
1227 	memcpy(imsg.xid, iface->xid, sizeof(imsg.xid));
1228 
1229 	clock_gettime(CLOCK_MONOTONIC, &now);
1230 	timespecsub(&now, &iface->elapsed_time_start, &res);
1231 	if (res.tv_sec * 100 > 0xffff)
1232 		imsg.elapsed_time = 0xffff;
1233 	else
1234 		imsg.elapsed_time = res.tv_sec * 100;
1235 
1236 	switch (iface->state) {
1237 	case IF_DOWN:
1238 		fatalx("invalid state IF_DOWN in %s", __func__);
1239 		break;
1240 	case IF_INIT:
1241 		fatalx("invalid state IF_INIT in %s", __func__);
1242 		break;
1243 	case IF_BOUND:
1244 		fatalx("invalid state IF_BOUND in %s", __func__);
1245 		break;
1246 	case IF_REBOOTING:
1247 	case IF_REQUESTING:
1248 	case IF_RENEWING:
1249 	case IF_REBINDING:
1250 		imsg.serverid_len = iface->serverid_len;
1251 		memcpy(imsg.serverid, iface->serverid, SERVERID_SIZE);
1252 		memcpy(imsg.pds, iface->pds, sizeof(iface->pds));
1253 		break;
1254 	}
1255 	switch (iface->state) {
1256 	case IF_REQUESTING:
1257 		engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg,
1258 		    sizeof(imsg));
1259 		break;
1260 	case IF_RENEWING:
1261 		engine_imsg_compose_frontend(IMSG_SEND_RENEW, 0, &imsg,
1262 		    sizeof(imsg));
1263 		break;
1264 	case IF_REBOOTING:
1265 	case IF_REBINDING:
1266 		engine_imsg_compose_frontend(IMSG_SEND_REBIND, 0, &imsg,
1267 		    sizeof(imsg));
1268 		break;
1269 	default:
1270 		fatalx("%s: wrong state", __func__);
1271 	}
1272 }
1273 
1274 /* XXX we need to install a reject route for the delegated prefix */
1275 void
configure_interfaces(struct dhcp6leased_iface * iface)1276 configure_interfaces(struct dhcp6leased_iface *iface)
1277 {
1278 	struct iface_conf	*iface_conf;
1279 	struct iface_ia_conf	*ia_conf;
1280 	struct iface_pd_conf	*pd_conf;
1281 	struct imsg_lease_info	 imsg_lease_info;
1282 	uint32_t	 	 i;
1283 	char		 	 ntopbuf[INET6_ADDRSTRLEN];
1284 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
1285 
1286 	if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) {
1287 		log_debug("%s: unknown interface %d", __func__,
1288 		    iface->if_index);
1289 		return;
1290 	}
1291 	if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name))
1292 	    == NULL) {
1293 		log_debug("%s: no interface configuration for %d", __func__,
1294 		    iface->if_index);
1295 		return;
1296 	}
1297 
1298 	for (i = 0; i < iface_conf->ia_count; i++) {
1299 		struct prefix	*pd = &iface->new_pds[i];
1300 
1301 		log_info("prefix delegation #%d %s/%d received on %s from "
1302 		    "server %s", i, inet_ntop(AF_INET6, &pd->prefix, ntopbuf,
1303 		    INET6_ADDRSTRLEN), pd->prefix_len, if_name,
1304 		    dhcp_duid2str(iface->serverid_len, iface->serverid));
1305 	}
1306 
1307 	SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) {
1308 		struct prefix	*pd = &iface->new_pds[ia_conf->id];
1309 
1310 		SIMPLEQ_FOREACH(pd_conf, &ia_conf->iface_pd_list, entry) {
1311 			send_reconfigure_interface(pd_conf, pd, CONFIGURE);
1312 		}
1313 	}
1314 
1315 	if (prefixcmp(iface->pds, iface->new_pds, iface_conf->ia_count) != 0) {
1316 		log_info("Prefix delegations on %s from server %s changed",
1317 		    if_name, dhcp_duid2str(iface->serverid_len,
1318 		    iface->serverid));
1319 		for (i = 0; i < iface_conf->ia_count; i++) {
1320 			log_debug("%s: iface->pds [%d]: %s/%d", __func__, i,
1321 			    inet_ntop(AF_INET6, &iface->pds[i].prefix, ntopbuf,
1322 			    INET6_ADDRSTRLEN), iface->pds[i].prefix_len);
1323 			log_debug("%s:        pds [%d]: %s/%d", __func__, i,
1324 			    inet_ntop(AF_INET6, &iface->new_pds[i].prefix,
1325 			    ntopbuf, INET6_ADDRSTRLEN),
1326 			    iface->new_pds[i].prefix_len);
1327 		}
1328 		deconfigure_interfaces(iface);
1329 	}
1330 
1331 	memcpy(iface->pds, iface->new_pds, sizeof(iface->pds));
1332 	memset(iface->new_pds, 0, sizeof(iface->new_pds));
1333 
1334 	memset(&imsg_lease_info, 0, sizeof(imsg_lease_info));
1335 	imsg_lease_info.if_index = iface->if_index;
1336 	memcpy(imsg_lease_info.pds, iface->pds, sizeof(iface->pds));
1337 	engine_imsg_compose_main(IMSG_WRITE_LEASE, 0, &imsg_lease_info,
1338 	    sizeof(imsg_lease_info));
1339 }
1340 
1341 void
deconfigure_interfaces(struct dhcp6leased_iface * iface)1342 deconfigure_interfaces(struct dhcp6leased_iface *iface)
1343 {
1344 	struct iface_conf	*iface_conf;
1345 	struct iface_ia_conf	*ia_conf;
1346 	struct iface_pd_conf	*pd_conf;
1347 	uint32_t	 	 i;
1348 	char		 	 ntopbuf[INET6_ADDRSTRLEN];
1349 	char			 ifnamebuf[IF_NAMESIZE], *if_name;
1350 
1351 
1352 	if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) {
1353 		log_debug("%s: unknown interface %d", __func__,
1354 		    iface->if_index);
1355 		return;
1356 	}
1357 	if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name))
1358 	    == NULL) {
1359 		log_debug("%s: no interface configuration for %d", __func__,
1360 		    iface->if_index);
1361 		return;
1362 	}
1363 
1364 	for (i = 0; i < iface_conf->ia_count; i++) {
1365 		struct prefix *pd = &iface->pds[i];
1366 
1367 		log_info("Prefix delegation #%d %s/%d expired on %s from "
1368 		    "server %s", i, inet_ntop(AF_INET6, &pd->prefix, ntopbuf,
1369 		    INET6_ADDRSTRLEN), pd->prefix_len, if_name,
1370 		    dhcp_duid2str(iface->serverid_len, iface->serverid));
1371 	}
1372 
1373 	SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) {
1374 		struct prefix	*pd = &iface->pds[ia_conf->id];
1375 
1376 		SIMPLEQ_FOREACH(pd_conf, &ia_conf->iface_pd_list, entry) {
1377 			send_reconfigure_interface(pd_conf, pd, DECONFIGURE);
1378 		}
1379 	}
1380 	memset(iface->pds, 0, sizeof(iface->pds));
1381 }
1382 
1383 int
prefixcmp(struct prefix * a,struct prefix * b,int count)1384 prefixcmp(struct prefix *a, struct prefix *b, int count)
1385 {
1386 	int i;
1387 
1388 	for (i = 0; i < count; i++) {
1389 		if (a[i].prefix_len != b[i].prefix_len)
1390 			return 1;
1391 		if (memcmp(&a[i].prefix, &b[i].prefix,
1392 		    sizeof(struct in6_addr)) != 0)
1393 			return 1;
1394 	}
1395 	return 0;
1396 }
1397 
1398 void
send_reconfigure_interface(struct iface_pd_conf * pd_conf,struct prefix * pd,enum reconfigure_action action)1399 send_reconfigure_interface(struct iface_pd_conf *pd_conf, struct prefix *pd,
1400     enum reconfigure_action action)
1401 {
1402 	struct imsg_configure_address	 address;
1403 	uint32_t			 if_index;
1404 	int				 i;
1405 	char				 ntopbuf[INET6_ADDRSTRLEN];
1406 
1407 	if (pd->prefix_len == 0)
1408 		return;
1409 
1410 	if (strcmp(pd_conf->name, "reserve") == 0)
1411 		return;
1412 
1413 	if ((if_index = if_nametoindex(pd_conf->name)) == 0)
1414 		return;
1415 
1416 	memset(&address, 0, sizeof(address));
1417 
1418 	address.if_index = if_index;
1419 	address.addr.sin6_family = AF_INET6;
1420 	address.addr.sin6_len = sizeof(address.addr);
1421 	address.addr.sin6_addr = pd->prefix;
1422 
1423 	for (i = 0; i < 16; i++)
1424 		address.addr.sin6_addr.s6_addr[i] |=
1425 		    pd_conf->prefix_mask.s6_addr[i];
1426 
1427 	/* XXX make this configurable & use SOII */
1428 	address.addr.sin6_addr.s6_addr[15] |= 1;
1429 
1430 	in6_prefixlen2mask(&address.mask, pd_conf->prefix_len);
1431 
1432 	log_debug("%s: %s %s: %s/%d", __func__, pd_conf->name,
1433 	    reconfigure_action_name[action], inet_ntop(AF_INET6,
1434 	    &address.addr.sin6_addr, ntopbuf, INET6_ADDRSTRLEN),
1435 	    pd_conf->prefix_len);
1436 
1437 	address.vltime = pd->vltime;
1438 	address.pltime = pd->pltime;
1439 
1440 	if (action == CONFIGURE)
1441 		engine_imsg_compose_main(IMSG_CONFIGURE_ADDRESS, 0, &address,
1442 		    sizeof(address));
1443 	else
1444 		engine_imsg_compose_main(IMSG_DECONFIGURE_ADDRESS, 0, &address,
1445 		    sizeof(address));
1446 }
1447 
1448 const char *
dhcp_message_type2str(int type)1449 dhcp_message_type2str(int type)
1450 {
1451 	static char buf[sizeof("Unknown [255]")];
1452 
1453 	switch (type) {
1454 	case DHCPSOLICIT:
1455 		return "DHCPSOLICIT";
1456 	case DHCPADVERTISE:
1457 		return "DHCPADVERTISE";
1458 	case DHCPREQUEST:
1459 		return "DHCPREQUEST";
1460 	case DHCPCONFIRM:
1461 		return "DHCPCONFIRM";
1462 	case DHCPRENEW:
1463 		return "DHCPRENEW";
1464 	case DHCPREBIND:
1465 		return "DHCPREBIND";
1466 	case DHCPREPLY:
1467 		return "DHCPREPLY";
1468 	case DHCPRELEASE:
1469 		return "DHCPRELEASE";
1470 	case DHCPDECLINE:
1471 		return "DHCPDECLINE";
1472 	case DHCPRECONFIGURE:
1473 		return "DHCPRECONFIGURE";
1474 	case DHCPINFORMATIONREQUEST:
1475 		return "DHCPINFORMATIONREQUEST";
1476 	case DHCPRELAYFORW:
1477 		return "DHCPRELAYFORW";
1478 	case DHCPRELAYREPL:
1479 		return "DHCPRELAYREPL";
1480 	default:
1481 		snprintf(buf, sizeof(buf), "Unknown [%u]", type & 0xff);
1482 		return buf;
1483 	}
1484 }
1485 
1486 const char *
dhcp_option_type2str(int code)1487 dhcp_option_type2str(int code)
1488 {
1489 	static char buf[sizeof("Unknown [65535]")];
1490 	switch (code) {
1491 	case DHO_CLIENTID:
1492 		return "DHO_CLIENTID";
1493 	case DHO_SERVERID:
1494 		return "DHO_SERVERID";
1495 	case DHO_ORO:
1496 		return "DHO_ORO";
1497 	case DHO_ELAPSED_TIME:
1498 		return "DHO_ELAPSED_TIME";
1499 	case DHO_STATUS_CODE:
1500 		return "DHO_STATUS_CODE";
1501 	case DHO_RAPID_COMMIT:
1502 		return "DHO_RAPID_COMMIT";
1503 	case DHO_VENDOR_CLASS:
1504 		return "DHO_VENDOR_CLASS";
1505 	case DHO_IA_PD:
1506 		return "DHO_IA_PD";
1507 	case DHO_IA_PREFIX:
1508 		return "DHO_IA_PREFIX";
1509 	case DHO_SOL_MAX_RT:
1510 		return "DHO_SOL_MAX_RT";
1511 	case DHO_INF_MAX_RT:
1512 		return "DHO_INF_MAX_RT";
1513 	default:
1514 		snprintf(buf, sizeof(buf), "Unknown [%u]", code &0xffff);
1515 		return buf;
1516 	}
1517 }
1518 
1519 const char*
dhcp_duid2str(int len,uint8_t * p)1520 dhcp_duid2str(int len, uint8_t *p)
1521 {
1522 	static char	 buf[2 * 130];
1523 	int		 i, rem;
1524 	char		*pbuf;
1525 
1526 	if (len > 130)
1527 		return "invalid";
1528 
1529 	pbuf = buf;
1530 	rem = sizeof(buf);
1531 	for (i = 0; i < len && rem > 0; i++, pbuf += 2, rem -=2)
1532 		snprintf(pbuf, rem, "%02x", p[i]);
1533 
1534 	return buf;
1535 }
1536 
1537 const char*
dhcp_status2str(int status)1538 dhcp_status2str(int status)
1539 {
1540 	static char buf[sizeof("Unknown [255]")];
1541 
1542 	switch (status) {
1543 	case DHCP_STATUS_SUCCESS:
1544 		return "Success";
1545 	case DHCP_STATUS_UNSPECFAIL:
1546 		return "UnspecFail";
1547 	case DHCP_STATUS_NOADDRSAVAIL:
1548 		return "NoAddrsAvail";
1549 	case DHCP_STATUS_NOBINDING:
1550 		return "NoBinding";
1551 	case DHCP_STATUS_NOTONLINK:
1552 		return "NotOnLink";
1553 	case DHCP_STATUS_USEMULTICAST:
1554 		return "UseMulticast";
1555 	case DHCP_STATUS_NOPREFIXAVAIL:
1556 		return "NoPrefixAvail";
1557 	default:
1558 		snprintf(buf, sizeof(buf), "Unknown [%u]", status & 0xff);
1559 		return buf;
1560     }
1561 }
1562 
1563 /* from sys/netinet6/in6.c */
1564 /*
1565  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
1566  * All rights reserved.
1567  *
1568  * Redistribution and use in source and binary forms, with or without
1569  * modification, are permitted provided that the following conditions
1570  * are met:
1571  * 1. Redistributions of source code must retain the above copyright
1572  *    notice, this list of conditions and the following disclaimer.
1573  * 2. Redistributions in binary form must reproduce the above copyright
1574  *    notice, this list of conditions and the following disclaimer in the
1575  *    documentation and/or other materials provided with the distribution.
1576  * 3. Neither the name of the project nor the names of its contributors
1577  *    may be used to endorse or promote products derived from this software
1578  *    without specific prior written permission.
1579  *
1580  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1581  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1582  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1583  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
1584  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1585  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1586  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1587  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1588  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1589  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1590  * SUCH DAMAGE.
1591  */
1592 void
in6_prefixlen2mask(struct in6_addr * maskp,int len)1593 in6_prefixlen2mask(struct in6_addr *maskp, int len)
1594 {
1595 	u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
1596 	int bytelen, bitlen, i;
1597 
1598 	if (0 > len || len > 128)
1599 		fatalx("%s: invalid prefix length(%d)\n", __func__, len);
1600 
1601 	bzero(maskp, sizeof(*maskp));
1602 	bytelen = len / 8;
1603 	bitlen = len % 8;
1604 	for (i = 0; i < bytelen; i++)
1605 		maskp->s6_addr[i] = 0xff;
1606 	/* len == 128 is ok because bitlen == 0 then */
1607 	if (bitlen)
1608 		maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
1609 }
1610