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
engine_sig_handler(int sig,short event,void * arg)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
engine(int debug,int verbose)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
engine_shutdown(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
engine_imsg_compose_frontend(int type,pid_t pid,void * data,uint16_t datalen)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
engine_dispatch_frontend(int fd,short event,void * bula)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
engine_dispatch_main(int fd,short event,void * bula)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
parse_ra_rs(struct imsg_ra_rs * ra_rs)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
parse_ra(struct imsg_ra_rs * ra)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
parse_rs(struct imsg_ra_rs * rs)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*
find_engine_iface_by_id(uint32_t if_index)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
update_iface(uint32_t if_index)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
remove_iface(uint32_t if_index)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
iface_timeout(int fd,short events,void * arg)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