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