xref: /openbsd-src/usr.sbin/rad/engine.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1 /*	$OpenBSD: engine.c,v 1.28 2024/11/21 13:38:15 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2018 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/time.h>
27 #include <sys/uio.h>
28 
29 #include <netinet/in.h>
30 #include <net/if.h>
31 #include <arpa/inet.h>
32 #include <netinet/icmp6.h>
33 
34 #include <errno.h>
35 #include <event.h>
36 #include <imsg.h>
37 #include <pwd.h>
38 #include <signal.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 
44 #include "log.h"
45 #include "rad.h"
46 #include "engine.h"
47 
48 struct engine_iface {
49 	TAILQ_ENTRY(engine_iface)	entry;
50 	struct event			timer;
51 	struct timespec			last_ra;
52 	uint32_t			if_index;
53 	int				ras_delayed;
54 };
55 
56 TAILQ_HEAD(, engine_iface)	engine_interfaces;
57 
58 
59 __dead void		 engine_shutdown(void);
60 void			 engine_sig_handler(int sig, short, void *);
61 void			 engine_dispatch_frontend(int, short, void *);
62 void			 engine_dispatch_main(int, short, void *);
63 void			 parse_ra_rs(struct imsg_ra_rs *);
64 void			 parse_ra(struct imsg_ra_rs *);
65 void			 parse_rs(struct imsg_ra_rs *);
66 void			 update_iface(uint32_t);
67 void			 remove_iface(uint32_t);
68 struct engine_iface	*find_engine_iface_by_id(uint32_t);
69 void			 iface_timeout(int, short, void *);
70 
71 struct rad_conf		*engine_conf;
72 static struct imsgev	*iev_frontend;
73 static struct imsgev	*iev_main;
74 struct sockaddr_in6	 all_nodes;
75 
76 void
77 engine_sig_handler(int sig, short event, void *arg)
78 {
79 	/*
80 	 * Normal signal handler rules don't apply because libevent
81 	 * decouples for us.
82 	 */
83 
84 	switch (sig) {
85 	case SIGINT:
86 	case SIGTERM:
87 		engine_shutdown();
88 	default:
89 		fatalx("unexpected signal");
90 	}
91 }
92 
93 void
94 engine(int debug, int verbose)
95 {
96 	struct event		 ev_sigint, ev_sigterm;
97 	struct passwd		*pw;
98 
99 	engine_conf = config_new_empty();
100 
101 	log_init(debug, LOG_DAEMON);
102 	log_setverbose(verbose);
103 
104 	if ((pw = getpwnam(RAD_USER)) == NULL)
105 		fatal("getpwnam");
106 
107 	if (chroot(pw->pw_dir) == -1)
108 		fatal("chroot");
109 	if (chdir("/") == -1)
110 		fatal("chdir(\"/\")");
111 
112 	setproctitle("%s", "engine");
113 	log_procinit("engine");
114 
115 	if (setgroups(1, &pw->pw_gid) ||
116 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
117 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
118 		fatal("can't drop privileges");
119 
120 	if (pledge("stdio recvfd", NULL) == -1)
121 		fatal("pledge");
122 
123 	event_init();
124 
125 	/* Setup signal handler(s). */
126 	signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL);
127 	signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL);
128 	signal_add(&ev_sigint, NULL);
129 	signal_add(&ev_sigterm, NULL);
130 	signal(SIGPIPE, SIG_IGN);
131 	signal(SIGHUP, SIG_IGN);
132 
133 	/* Setup pipe and event handler to the main process. */
134 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
135 		fatal(NULL);
136 
137 	if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
138 		fatal(NULL);
139 	imsgbuf_allow_fdpass(&iev_main->ibuf);
140 	iev_main->handler = engine_dispatch_main;
141 
142 	/* Setup event handlers. */
143 	iev_main->events = EV_READ;
144 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
145 	    iev_main->handler, iev_main);
146 	event_add(&iev_main->ev, NULL);
147 
148 	all_nodes.sin6_len = sizeof(all_nodes);
149 	all_nodes.sin6_family = AF_INET6;
150 	if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1)
151 		fatal("inet_pton");
152 
153 	TAILQ_INIT(&engine_interfaces);
154 
155 	event_dispatch();
156 
157 	engine_shutdown();
158 }
159 
160 __dead void
161 engine_shutdown(void)
162 {
163 	/* Close pipes. */
164 	imsgbuf_clear(&iev_frontend->ibuf);
165 	close(iev_frontend->ibuf.fd);
166 	imsgbuf_clear(&iev_main->ibuf);
167 	close(iev_main->ibuf.fd);
168 
169 	config_clear(engine_conf);
170 
171 	free(iev_frontend);
172 	free(iev_main);
173 
174 	log_info("engine exiting");
175 	exit(0);
176 }
177 
178 int
179 engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen)
180 {
181 	return (imsg_compose_event(iev_frontend, type, 0, pid, -1,
182 	    data, datalen));
183 }
184 
185 void
186 engine_dispatch_frontend(int fd, short event, void *bula)
187 {
188 	struct imsgev		*iev = bula;
189 	struct imsgbuf		*ibuf;
190 	struct imsg		 imsg;
191 	struct imsg_ra_rs	 ra_rs;
192 	ssize_t			 n;
193 	uint32_t		 if_index;
194 	int			 shut = 0, verbose;
195 
196 	ibuf = &iev->ibuf;
197 
198 	if (event & EV_READ) {
199 		if ((n = imsgbuf_read(ibuf)) == -1)
200 			fatal("imsgbuf_read error");
201 		if (n == 0)	/* Connection closed. */
202 			shut = 1;
203 	}
204 	if (event & EV_WRITE) {
205 		if (imsgbuf_write(ibuf) == -1) {
206 			if (errno == EPIPE)	/* connection closed */
207 				shut = 1;
208 			else
209 				fatal("imsgbuf_write");
210 		}
211 	}
212 
213 	for (;;) {
214 		if ((n = imsg_get(ibuf, &imsg)) == -1)
215 			fatal("%s: imsg_get error", __func__);
216 		if (n == 0)	/* No more messages. */
217 			break;
218 
219 		switch (imsg.hdr.type) {
220 		case IMSG_RA_RS:
221 			if (IMSG_DATA_SIZE(imsg) != sizeof(ra_rs))
222 				fatalx("%s: IMSG_RA_RS wrong length: %lu",
223 				    __func__, IMSG_DATA_SIZE(imsg));
224 			memcpy(&ra_rs, imsg.data, sizeof(ra_rs));
225 			parse_ra_rs(&ra_rs);
226 			break;
227 		case IMSG_UPDATE_IF:
228 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
229 				fatalx("%s: IMSG_UPDATE_IF wrong length: %lu",
230 				    __func__, IMSG_DATA_SIZE(imsg));
231 			memcpy(&if_index, imsg.data, sizeof(if_index));
232 			update_iface(if_index);
233 			break;
234 		case IMSG_REMOVE_IF:
235 			if (IMSG_DATA_SIZE(imsg) != sizeof(if_index))
236 				fatalx("%s: IMSG_REMOVE_IF wrong length: %lu",
237 				    __func__, IMSG_DATA_SIZE(imsg));
238 			memcpy(&if_index, imsg.data, sizeof(if_index));
239 			remove_iface(if_index);
240 			break;
241 		case IMSG_CTL_LOG_VERBOSE:
242 			if (IMSG_DATA_SIZE(imsg) != sizeof(verbose))
243 				fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: "
244 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
245 			memcpy(&verbose, imsg.data, sizeof(verbose));
246 			log_setverbose(verbose);
247 			break;
248 		default:
249 			log_debug("%s: unexpected imsg %d", __func__,
250 			    imsg.hdr.type);
251 			break;
252 		}
253 		imsg_free(&imsg);
254 	}
255 	if (!shut)
256 		imsg_event_add(iev);
257 	else {
258 		/* This pipe is dead. Remove its event handler. */
259 		event_del(&iev->ev);
260 		event_loopexit(NULL);
261 	}
262 }
263 
264 void
265 engine_dispatch_main(int fd, short event, void *bula)
266 {
267 	static struct rad_conf		*nconf;
268 	static struct ra_iface_conf	*ra_iface_conf;
269 	static struct ra_options_conf	*ra_options;
270 	struct imsg			 imsg;
271 	struct imsgev			*iev = bula;
272 	struct imsgbuf			*ibuf;
273 	struct ra_prefix_conf		*ra_prefix_conf;
274 	struct ra_rdnss_conf		*ra_rdnss_conf;
275 	struct ra_dnssl_conf		*ra_dnssl_conf;
276 	struct ra_pref64_conf		*pref64;
277 	ssize_t				 n;
278 	int				 shut = 0;
279 
280 	ibuf = &iev->ibuf;
281 
282 	if (event & EV_READ) {
283 		if ((n = imsgbuf_read(ibuf)) == -1)
284 			fatal("imsgbuf_read error");
285 		if (n == 0)	/* Connection closed. */
286 			shut = 1;
287 	}
288 	if (event & EV_WRITE) {
289 		if (imsgbuf_write(ibuf) == -1) {
290 			if (errno == EPIPE)	/* connection closed */
291 				shut = 1;
292 			else
293 				fatal("imsgbuf_write");
294 		}
295 	}
296 
297 	for (;;) {
298 		if ((n = imsg_get(ibuf, &imsg)) == -1)
299 			fatal("%s: imsg_get error", __func__);
300 		if (n == 0)	/* No more messages. */
301 			break;
302 
303 		switch (imsg.hdr.type) {
304 		case IMSG_SOCKET_IPC:
305 			/*
306 			 * Setup pipe and event handler to the frontend
307 			 * process.
308 			 */
309 			if (iev_frontend)
310 				fatalx("%s: received unexpected imsg fd "
311 				    "to engine", __func__);
312 
313 			if ((fd = imsg_get_fd(&imsg)) == -1)
314 				fatalx("%s: expected to receive imsg fd to "
315 				   "engine but didn't receive any", __func__);
316 
317 			iev_frontend = malloc(sizeof(struct imsgev));
318 			if (iev_frontend == NULL)
319 				fatal(NULL);
320 
321 			if (imsgbuf_init(&iev_frontend->ibuf, fd) == -1)
322 				fatal(NULL);
323 			iev_frontend->handler = engine_dispatch_frontend;
324 			iev_frontend->events = EV_READ;
325 
326 			event_set(&iev_frontend->ev, iev_frontend->ibuf.fd,
327 			iev_frontend->events, iev_frontend->handler,
328 			    iev_frontend);
329 			event_add(&iev_frontend->ev, NULL);
330 			break;
331 		case IMSG_RECONF_CONF:
332 			if (nconf != NULL)
333 				fatalx("%s: IMSG_RECONF_CONF already in "
334 				    "progress", __func__);
335 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct rad_conf))
336 				fatalx("%s: IMSG_RECONF_CONF wrong length: %lu",
337 				    __func__, IMSG_DATA_SIZE(imsg));
338 			if ((nconf = malloc(sizeof(struct rad_conf))) == NULL)
339 				fatal(NULL);
340 			memcpy(nconf, imsg.data, sizeof(struct rad_conf));
341 			SIMPLEQ_INIT(&nconf->ra_iface_list);
342 			SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list);
343 			SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list);
344 			SIMPLEQ_INIT(&nconf->ra_options.ra_pref64_list);
345 			ra_options = &nconf->ra_options;
346 			break;
347 		case IMSG_RECONF_RA_IFACE:
348 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
349 			    ra_iface_conf))
350 				fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: "
351 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
352 			if ((ra_iface_conf = malloc(sizeof(struct
353 			    ra_iface_conf))) == NULL)
354 				fatal(NULL);
355 			memcpy(ra_iface_conf, imsg.data,
356 			    sizeof(struct ra_iface_conf));
357 			ra_iface_conf->autoprefix = NULL;
358 			SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list);
359 			SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list);
360 			SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list);
361 			SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list);
362 			SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list,
363 			    ra_iface_conf, entry);
364 			ra_options = &ra_iface_conf->ra_options;
365 			break;
366 		case IMSG_RECONF_RA_AUTOPREFIX:
367 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
368 			    ra_prefix_conf))
369 				fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong "
370 				    "length: %lu", __func__,
371 				    IMSG_DATA_SIZE(imsg));
372 			if ((ra_iface_conf->autoprefix = malloc(sizeof(struct
373 			    ra_prefix_conf))) == NULL)
374 				fatal(NULL);
375 			memcpy(ra_iface_conf->autoprefix, imsg.data,
376 			    sizeof(struct ra_prefix_conf));
377 			break;
378 		case IMSG_RECONF_RA_PREFIX:
379 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct
380 			    ra_prefix_conf))
381 				fatalx("%s: IMSG_RECONF_RA_PREFIX wrong "
382 				    "length: %lu", __func__,
383 				    IMSG_DATA_SIZE(imsg));
384 			if ((ra_prefix_conf = malloc(sizeof(struct
385 			    ra_prefix_conf))) == NULL)
386 				fatal(NULL);
387 			memcpy(ra_prefix_conf, imsg.data, sizeof(struct
388 			    ra_prefix_conf));
389 			SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list,
390 			    ra_prefix_conf, entry);
391 			break;
392 		case IMSG_RECONF_RA_RDNSS:
393 			if(IMSG_DATA_SIZE(imsg) != sizeof(struct
394 			    ra_rdnss_conf))
395 				fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: "
396 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
397 			if ((ra_rdnss_conf = malloc(sizeof(struct
398 			    ra_rdnss_conf))) == NULL)
399 				fatal(NULL);
400 			memcpy(ra_rdnss_conf, imsg.data, sizeof(struct
401 			    ra_rdnss_conf));
402 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,
403 			    ra_rdnss_conf, entry);
404 			break;
405 		case IMSG_RECONF_RA_DNSSL:
406 			if(IMSG_DATA_SIZE(imsg) != sizeof(struct
407 			    ra_dnssl_conf))
408 				fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: "
409 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
410 			if ((ra_dnssl_conf = malloc(sizeof(struct
411 			    ra_dnssl_conf))) == NULL)
412 				fatal(NULL);
413 			memcpy(ra_dnssl_conf, imsg.data, sizeof(struct
414 			    ra_dnssl_conf));
415 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
416 			    ra_dnssl_conf, entry);
417 			break;
418 		case IMSG_RECONF_RA_PREF64:
419 			if(IMSG_DATA_SIZE(imsg) != sizeof(struct
420 			    ra_pref64_conf))
421 				fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: "
422 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
423 			if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) ==
424 			    NULL)
425 				fatal(NULL);
426 			memcpy(pref64, imsg.data, sizeof(struct ra_pref64_conf));
427 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64,
428 			    entry);
429 			break;
430 		case IMSG_RECONF_END:
431 			if (nconf == NULL)
432 				fatalx("%s: IMSG_RECONF_END without "
433 				    "IMSG_RECONF_CONF", __func__);
434 			merge_config(engine_conf, nconf);
435 			nconf = NULL;
436 			break;
437 		default:
438 			log_debug("%s: unexpected imsg %d", __func__,
439 			    imsg.hdr.type);
440 			break;
441 		}
442 		imsg_free(&imsg);
443 	}
444 	if (!shut)
445 		imsg_event_add(iev);
446 	else {
447 		/* This pipe is dead. Remove its event handler. */
448 		event_del(&iev->ev);
449 		event_loopexit(NULL);
450 	}
451 }
452 
453 
454 void
455 parse_ra_rs(struct imsg_ra_rs *ra_rs)
456 {
457 	char			 ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
458 	struct icmp6_hdr	*hdr;
459 
460 	hdr = (struct icmp6_hdr *) ra_rs->packet;
461 
462 	switch (hdr->icmp6_type) {
463 	case ND_ROUTER_ADVERT:
464 		parse_ra(ra_rs);
465 		break;
466 	case ND_ROUTER_SOLICIT:
467 		parse_rs(ra_rs);
468 		break;
469 	default:
470 		log_warnx("unexpected icmp6_type: %d from %s on %s",
471 		    hdr->icmp6_type, inet_ntop(AF_INET6, &ra_rs->from.sin6_addr,
472 		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(ra_rs->if_index,
473 		    ifnamebuf));
474 		break;
475 	}
476 }
477 
478 void
479 parse_ra(struct imsg_ra_rs *ra)
480 {
481 	char			 ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
482 	log_debug("got RA from %s on %s",
483 	    inet_ntop(AF_INET6, &ra->from.sin6_addr, ntopbuf,
484 	    INET6_ADDRSTRLEN), if_indextoname(ra->if_index,
485 	    ifnamebuf));
486 	/* XXX not yet */
487 }
488 
489 void
490 parse_rs(struct imsg_ra_rs *rs)
491 {
492 	struct nd_router_solicit	*nd_rs;
493 	struct engine_iface		*engine_iface;
494 	ssize_t				 len;
495 	int				 unicast_ra = 0;
496 	const char			*hbuf;
497 	char				 ifnamebuf[IFNAMSIZ];
498 	uint8_t				*p;
499 
500 	hbuf = sin6_to_str(&rs->from);
501 
502 	log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index,
503 	    ifnamebuf));
504 
505 	if ((engine_iface = find_engine_iface_by_id(rs->if_index)) == NULL)
506 		return;
507 
508 	len = rs->len;
509 
510 	if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr) ||
511 	    IN6_IS_ADDR_UNSPECIFIED(&rs->from.sin6_addr))) {
512 		log_warnx("RA from invalid address %s on %s", hbuf,
513 		    if_indextoname(rs->if_index, ifnamebuf));
514 		return;
515 	}
516 
517 	if ((size_t)len < sizeof(struct nd_router_solicit)) {
518 		log_warnx("received too short message (%ld) from %s", len,
519 		    hbuf);
520 		return;
521 	}
522 
523 	p = rs->packet;
524 	nd_rs = (struct nd_router_solicit *)p;
525 	len -= sizeof(struct nd_router_solicit);
526 	p += sizeof(struct nd_router_solicit);
527 
528 	if (nd_rs->nd_rs_code != 0) {
529 		log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_code,
530 		    hbuf);
531 		return;
532 	}
533 	while ((size_t)len >= sizeof(struct nd_opt_hdr)) {
534 		struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p;
535 
536 		len -= sizeof(struct nd_opt_hdr);
537 		p += sizeof(struct nd_opt_hdr);
538 
539 		if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) {
540 			log_warnx("invalid option len: %u > %ld",
541 			    nd_opt_hdr->nd_opt_len, len);
542 			return;
543 		}
544 		switch (nd_opt_hdr->nd_opt_type) {
545 		case ND_OPT_SOURCE_LINKADDR:
546 			log_debug("got RS with source linkaddr option");
547 			unicast_ra = 1;
548 			break;
549 		default:
550 			log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type);
551 			break;
552 		}
553 		len -= nd_opt_hdr->nd_opt_len * 8 - 2;
554 		p += nd_opt_hdr->nd_opt_len * 8 - 2;
555 	}
556 
557 	if (unicast_ra) {
558 		struct imsg_send_ra	 send_ra;
559 
560 		send_ra.if_index = rs->if_index;
561 		memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to));
562 		engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
563 		    sizeof(send_ra));
564 	} else {
565 		struct timespec	 now, diff, ra_delay = {MIN_DELAY_BETWEEN_RAS, 0};
566 		struct timeval	 tv = {0, 0};
567 
568 		/* a multicast RA is already scheduled within the next 3 seconds */
569 		if (engine_iface->ras_delayed)
570 			return;
571 
572 		engine_iface->ras_delayed = 1;
573 		clock_gettime(CLOCK_MONOTONIC, &now);
574 		timespecsub(&now, &engine_iface->last_ra, &diff);
575 
576 		if (timespeccmp(&diff, &ra_delay, <)) {
577 			timespecsub(&ra_delay, &diff, &ra_delay);
578 			TIMESPEC_TO_TIMEVAL(&tv, &ra_delay);
579 		}
580 
581 		tv.tv_usec = arc4random_uniform(MAX_RA_DELAY_TIME * 1000);
582 		evtimer_add(&engine_iface->timer, &tv);
583 	}
584 }
585 
586 struct engine_iface*
587 find_engine_iface_by_id(uint32_t if_index)
588 {
589 	struct engine_iface	*engine_iface;
590 
591 	TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) {
592 		if (engine_iface->if_index == if_index)
593 			return engine_iface;
594 	}
595 	return (NULL);
596 }
597 
598 void
599 update_iface(uint32_t if_index)
600 {
601 	struct engine_iface	*engine_iface;
602 	struct timeval		 tv;
603 
604 	if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) {
605 		engine_iface = calloc(1, sizeof(*engine_iface));
606 		engine_iface->if_index = if_index;
607 		evtimer_set(&engine_iface->timer, iface_timeout, engine_iface);
608 		TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry);
609 	}
610 
611 	tv.tv_sec = 0;
612 	tv.tv_usec = arc4random_uniform(1000000);
613 	evtimer_add(&engine_iface->timer, &tv);
614 }
615 
616 void
617 remove_iface(uint32_t if_index)
618 {
619 	struct engine_iface	*engine_iface;
620 	struct imsg_send_ra	 send_ra;
621 	char			 if_name[IF_NAMESIZE];
622 
623 	if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) {
624 		/* we don't know this interface, frontend can delete it */
625 		engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
626 		    &if_index, sizeof(if_index));
627 		return;
628 	}
629 
630 	send_ra.if_index = engine_iface->if_index;
631 	memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
632 
633 	TAILQ_REMOVE(&engine_interfaces, engine_iface, entry);
634 	evtimer_del(&engine_iface->timer);
635 
636 	if (if_indextoname(if_index, if_name) != NULL)
637 		engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
638 		    sizeof(send_ra));
639 	engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
640 	    &engine_iface->if_index, sizeof(engine_iface->if_index));
641 	free(engine_iface);
642 }
643 
644 void
645 iface_timeout(int fd, short events, void *arg)
646 {
647 	struct engine_iface	*engine_iface = (struct engine_iface *)arg;
648 	struct imsg_send_ra	 send_ra;
649 	struct timeval		 tv;
650 
651 	tv.tv_sec = MIN_RTR_ADV_INTERVAL +
652 	    arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL);
653 	tv.tv_usec = arc4random_uniform(1000000);
654 
655 	log_debug("%s new timeout in %lld", __func__, tv.tv_sec);
656 
657 	evtimer_add(&engine_iface->timer, &tv);
658 
659 	send_ra.if_index = engine_iface->if_index;
660 	memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
661 	engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
662 	    sizeof(send_ra));
663 	clock_gettime(CLOCK_MONOTONIC, &engine_iface->last_ra);
664 	engine_iface->ras_delayed = 0;
665 }
666