1 /* $OpenBSD: engine.c,v 1.20 2022/03/23 15:26:08 florian 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 imsg_init(&iev_main->ibuf, 3); 138 iev_main->handler = engine_dispatch_main; 139 140 /* Setup event handlers. */ 141 iev_main->events = EV_READ; 142 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 143 iev_main->handler, iev_main); 144 event_add(&iev_main->ev, NULL); 145 146 all_nodes.sin6_len = sizeof(all_nodes); 147 all_nodes.sin6_family = AF_INET6; 148 if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1) 149 fatal("inet_pton"); 150 151 TAILQ_INIT(&engine_interfaces); 152 153 event_dispatch(); 154 155 engine_shutdown(); 156 } 157 158 __dead void 159 engine_shutdown(void) 160 { 161 /* Close pipes. */ 162 msgbuf_clear(&iev_frontend->ibuf.w); 163 close(iev_frontend->ibuf.fd); 164 msgbuf_clear(&iev_main->ibuf.w); 165 close(iev_main->ibuf.fd); 166 167 config_clear(engine_conf); 168 169 free(iev_frontend); 170 free(iev_main); 171 172 log_info("engine exiting"); 173 exit(0); 174 } 175 176 int 177 engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 178 { 179 return (imsg_compose_event(iev_frontend, type, 0, pid, -1, 180 data, datalen)); 181 } 182 183 void 184 engine_dispatch_frontend(int fd, short event, void *bula) 185 { 186 struct imsgev *iev = bula; 187 struct imsgbuf *ibuf; 188 struct imsg imsg; 189 struct imsg_ra_rs ra_rs; 190 ssize_t n; 191 uint32_t if_index; 192 int shut = 0, verbose; 193 194 ibuf = &iev->ibuf; 195 196 if (event & EV_READ) { 197 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 198 fatal("imsg_read error"); 199 if (n == 0) /* Connection closed. */ 200 shut = 1; 201 } 202 if (event & EV_WRITE) { 203 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 204 fatal("msgbuf_write"); 205 if (n == 0) /* Connection closed. */ 206 shut = 1; 207 } 208 209 for (;;) { 210 if ((n = imsg_get(ibuf, &imsg)) == -1) 211 fatal("%s: imsg_get error", __func__); 212 if (n == 0) /* No more messages. */ 213 break; 214 215 switch (imsg.hdr.type) { 216 case IMSG_RA_RS: 217 if (IMSG_DATA_SIZE(imsg) != sizeof(ra_rs)) 218 fatalx("%s: IMSG_RA_RS wrong length: %lu", 219 __func__, IMSG_DATA_SIZE(imsg)); 220 memcpy(&ra_rs, imsg.data, sizeof(ra_rs)); 221 parse_ra_rs(&ra_rs); 222 break; 223 case IMSG_UPDATE_IF: 224 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 225 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 226 __func__, IMSG_DATA_SIZE(imsg)); 227 memcpy(&if_index, imsg.data, sizeof(if_index)); 228 update_iface(if_index); 229 break; 230 case IMSG_REMOVE_IF: 231 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 232 fatalx("%s: IMSG_REMOVE_IF wrong length: %lu", 233 __func__, IMSG_DATA_SIZE(imsg)); 234 memcpy(&if_index, imsg.data, sizeof(if_index)); 235 remove_iface(if_index); 236 break; 237 case IMSG_CTL_LOG_VERBOSE: 238 if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 239 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 240 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 241 memcpy(&verbose, imsg.data, sizeof(verbose)); 242 log_setverbose(verbose); 243 break; 244 default: 245 log_debug("%s: unexpected imsg %d", __func__, 246 imsg.hdr.type); 247 break; 248 } 249 imsg_free(&imsg); 250 } 251 if (!shut) 252 imsg_event_add(iev); 253 else { 254 /* This pipe is dead. Remove its event handler. */ 255 event_del(&iev->ev); 256 event_loopexit(NULL); 257 } 258 } 259 260 void 261 engine_dispatch_main(int fd, short event, void *bula) 262 { 263 static struct rad_conf *nconf; 264 static struct ra_iface_conf *ra_iface_conf; 265 static struct ra_options_conf *ra_options; 266 struct imsg imsg; 267 struct imsgev *iev = bula; 268 struct imsgbuf *ibuf; 269 struct ra_prefix_conf *ra_prefix_conf; 270 struct ra_rdnss_conf *ra_rdnss_conf; 271 struct ra_dnssl_conf *ra_dnssl_conf; 272 ssize_t n; 273 int shut = 0; 274 275 ibuf = &iev->ibuf; 276 277 if (event & EV_READ) { 278 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 279 fatal("imsg_read error"); 280 if (n == 0) /* Connection closed. */ 281 shut = 1; 282 } 283 if (event & EV_WRITE) { 284 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 285 fatal("msgbuf_write"); 286 if (n == 0) /* Connection closed. */ 287 shut = 1; 288 } 289 290 for (;;) { 291 if ((n = imsg_get(ibuf, &imsg)) == -1) 292 fatal("%s: imsg_get error", __func__); 293 if (n == 0) /* No more messages. */ 294 break; 295 296 switch (imsg.hdr.type) { 297 case IMSG_SOCKET_IPC: 298 /* 299 * Setup pipe and event handler to the frontend 300 * process. 301 */ 302 if (iev_frontend) 303 fatalx("%s: received unexpected imsg fd " 304 "to engine", __func__); 305 306 if ((fd = imsg.fd) == -1) 307 fatalx("%s: expected to receive imsg fd to " 308 "engine but didn't receive any", __func__); 309 310 iev_frontend = malloc(sizeof(struct imsgev)); 311 if (iev_frontend == NULL) 312 fatal(NULL); 313 314 imsg_init(&iev_frontend->ibuf, fd); 315 iev_frontend->handler = engine_dispatch_frontend; 316 iev_frontend->events = EV_READ; 317 318 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 319 iev_frontend->events, iev_frontend->handler, 320 iev_frontend); 321 event_add(&iev_frontend->ev, NULL); 322 break; 323 case IMSG_RECONF_CONF: 324 if (nconf != NULL) 325 fatalx("%s: IMSG_RECONF_CONF already in " 326 "progress", __func__); 327 if (IMSG_DATA_SIZE(imsg) != sizeof(struct rad_conf)) 328 fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 329 __func__, IMSG_DATA_SIZE(imsg)); 330 if ((nconf = malloc(sizeof(struct rad_conf))) == NULL) 331 fatal(NULL); 332 memcpy(nconf, imsg.data, sizeof(struct rad_conf)); 333 SIMPLEQ_INIT(&nconf->ra_iface_list); 334 SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list); 335 SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list); 336 ra_options = &nconf->ra_options; 337 break; 338 case IMSG_RECONF_RA_IFACE: 339 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 340 ra_iface_conf)) 341 fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: " 342 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 343 if ((ra_iface_conf = malloc(sizeof(struct 344 ra_iface_conf))) == NULL) 345 fatal(NULL); 346 memcpy(ra_iface_conf, imsg.data, 347 sizeof(struct ra_iface_conf)); 348 ra_iface_conf->autoprefix = NULL; 349 SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list); 350 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list); 351 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list); 352 SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list, 353 ra_iface_conf, entry); 354 ra_options = &ra_iface_conf->ra_options; 355 break; 356 case IMSG_RECONF_RA_AUTOPREFIX: 357 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 358 ra_prefix_conf)) 359 fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong " 360 "length: %lu", __func__, 361 IMSG_DATA_SIZE(imsg)); 362 if ((ra_iface_conf->autoprefix = malloc(sizeof(struct 363 ra_prefix_conf))) == NULL) 364 fatal(NULL); 365 memcpy(ra_iface_conf->autoprefix, imsg.data, 366 sizeof(struct ra_prefix_conf)); 367 break; 368 case IMSG_RECONF_RA_PREFIX: 369 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 370 ra_prefix_conf)) 371 fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " 372 "length: %lu", __func__, 373 IMSG_DATA_SIZE(imsg)); 374 if ((ra_prefix_conf = malloc(sizeof(struct 375 ra_prefix_conf))) == NULL) 376 fatal(NULL); 377 memcpy(ra_prefix_conf, imsg.data, sizeof(struct 378 ra_prefix_conf)); 379 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, 380 ra_prefix_conf, entry); 381 break; 382 case IMSG_RECONF_RA_RDNSS: 383 if(IMSG_DATA_SIZE(imsg) != sizeof(struct 384 ra_rdnss_conf)) 385 fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: " 386 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 387 if ((ra_rdnss_conf = malloc(sizeof(struct 388 ra_rdnss_conf))) == NULL) 389 fatal(NULL); 390 memcpy(ra_rdnss_conf, imsg.data, sizeof(struct 391 ra_rdnss_conf)); 392 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 393 ra_rdnss_conf, entry); 394 break; 395 case IMSG_RECONF_RA_DNSSL: 396 if(IMSG_DATA_SIZE(imsg) != sizeof(struct 397 ra_dnssl_conf)) 398 fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: " 399 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 400 if ((ra_dnssl_conf = malloc(sizeof(struct 401 ra_dnssl_conf))) == NULL) 402 fatal(NULL); 403 memcpy(ra_dnssl_conf, imsg.data, sizeof(struct 404 ra_dnssl_conf)); 405 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 406 ra_dnssl_conf, entry); 407 break; 408 case IMSG_RECONF_END: 409 if (nconf == NULL) 410 fatalx("%s: IMSG_RECONF_END without " 411 "IMSG_RECONF_CONF", __func__); 412 merge_config(engine_conf, nconf); 413 nconf = NULL; 414 break; 415 default: 416 log_debug("%s: unexpected imsg %d", __func__, 417 imsg.hdr.type); 418 break; 419 } 420 imsg_free(&imsg); 421 } 422 if (!shut) 423 imsg_event_add(iev); 424 else { 425 /* This pipe is dead. Remove its event handler. */ 426 event_del(&iev->ev); 427 event_loopexit(NULL); 428 } 429 } 430 431 432 void 433 parse_ra_rs(struct imsg_ra_rs *ra_rs) 434 { 435 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 436 struct icmp6_hdr *hdr; 437 438 hdr = (struct icmp6_hdr *) ra_rs->packet; 439 440 switch (hdr->icmp6_type) { 441 case ND_ROUTER_ADVERT: 442 parse_ra(ra_rs); 443 break; 444 case ND_ROUTER_SOLICIT: 445 parse_rs(ra_rs); 446 break; 447 default: 448 log_warnx("unexpected icmp6_type: %d from %s on %s", 449 hdr->icmp6_type, inet_ntop(AF_INET6, &ra_rs->from.sin6_addr, 450 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(ra_rs->if_index, 451 ifnamebuf)); 452 break; 453 } 454 } 455 456 void 457 parse_ra(struct imsg_ra_rs *ra) 458 { 459 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 460 log_debug("got RA from %s on %s", 461 inet_ntop(AF_INET6, &ra->from.sin6_addr, ntopbuf, 462 INET6_ADDRSTRLEN), if_indextoname(ra->if_index, 463 ifnamebuf)); 464 /* XXX not yet */ 465 } 466 467 void 468 parse_rs(struct imsg_ra_rs *rs) 469 { 470 struct nd_router_solicit *nd_rs; 471 struct engine_iface *engine_iface; 472 ssize_t len; 473 int unicast_ra = 0; 474 const char *hbuf; 475 char ifnamebuf[IFNAMSIZ]; 476 uint8_t *p; 477 478 hbuf = sin6_to_str(&rs->from); 479 480 log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, 481 ifnamebuf)); 482 483 if ((engine_iface = find_engine_iface_by_id(rs->if_index)) == NULL) 484 return; 485 486 len = rs->len; 487 488 if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr) || 489 IN6_IS_ADDR_UNSPECIFIED(&rs->from.sin6_addr))) { 490 log_warnx("RA from invalid address %s on %s", hbuf, 491 if_indextoname(rs->if_index, ifnamebuf)); 492 return; 493 } 494 495 if ((size_t)len < sizeof(struct nd_router_solicit)) { 496 log_warnx("received too short message (%ld) from %s", len, 497 hbuf); 498 return; 499 } 500 501 p = rs->packet; 502 nd_rs = (struct nd_router_solicit *)p; 503 len -= sizeof(struct nd_router_solicit); 504 p += sizeof(struct nd_router_solicit); 505 506 if (nd_rs->nd_rs_code != 0) { 507 log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_code, 508 hbuf); 509 return; 510 } 511 while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 512 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 513 514 len -= sizeof(struct nd_opt_hdr); 515 p += sizeof(struct nd_opt_hdr); 516 517 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 518 log_warnx("invalid option len: %u > %ld", 519 nd_opt_hdr->nd_opt_len, len); 520 return; 521 } 522 switch (nd_opt_hdr->nd_opt_type) { 523 case ND_OPT_SOURCE_LINKADDR: 524 log_debug("got RS with source linkaddr option"); 525 unicast_ra = 1; 526 break; 527 default: 528 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 529 break; 530 } 531 len -= nd_opt_hdr->nd_opt_len * 8 - 2; 532 p += nd_opt_hdr->nd_opt_len * 8 - 2; 533 } 534 535 if (unicast_ra) { 536 struct imsg_send_ra send_ra; 537 538 send_ra.if_index = rs->if_index; 539 memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); 540 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 541 sizeof(send_ra)); 542 } else { 543 struct timespec now, diff, ra_delay = {MIN_DELAY_BETWEEN_RAS, 0}; 544 struct timeval tv = {0, 0}; 545 546 /* a multicast RA is already scheduled within the next 3 seconds */ 547 if (engine_iface->ras_delayed) 548 return; 549 550 engine_iface->ras_delayed = 1; 551 clock_gettime(CLOCK_MONOTONIC, &now); 552 timespecsub(&now, &engine_iface->last_ra, &diff); 553 554 if (timespeccmp(&diff, &ra_delay, <)) { 555 timespecsub(&ra_delay, &diff, &ra_delay); 556 TIMESPEC_TO_TIMEVAL(&tv, &ra_delay); 557 } 558 559 tv.tv_usec = arc4random_uniform(MAX_RA_DELAY_TIME * 1000); 560 evtimer_add(&engine_iface->timer, &tv); 561 } 562 } 563 564 struct engine_iface* 565 find_engine_iface_by_id(uint32_t if_index) 566 { 567 struct engine_iface *engine_iface; 568 569 TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) { 570 if (engine_iface->if_index == if_index) 571 return engine_iface; 572 } 573 return (NULL); 574 } 575 576 void 577 update_iface(uint32_t if_index) 578 { 579 struct engine_iface *engine_iface; 580 struct timeval tv; 581 582 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 583 engine_iface = calloc(1, sizeof(*engine_iface)); 584 engine_iface->if_index = if_index; 585 evtimer_set(&engine_iface->timer, iface_timeout, engine_iface); 586 TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry); 587 } 588 589 tv.tv_sec = 0; 590 tv.tv_usec = arc4random_uniform(1000000); 591 evtimer_add(&engine_iface->timer, &tv); 592 } 593 594 void 595 remove_iface(uint32_t if_index) 596 { 597 struct engine_iface *engine_iface; 598 struct imsg_send_ra send_ra; 599 char if_name[IF_NAMESIZE]; 600 601 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 602 /* we don't know this interface, frontend can delete it */ 603 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 604 &if_index, sizeof(if_index)); 605 return; 606 } 607 608 send_ra.if_index = engine_iface->if_index; 609 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 610 611 TAILQ_REMOVE(&engine_interfaces, engine_iface, entry); 612 evtimer_del(&engine_iface->timer); 613 614 if (if_indextoname(if_index, if_name) != NULL) 615 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 616 sizeof(send_ra)); 617 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 618 &engine_iface->if_index, sizeof(engine_iface->if_index)); 619 free(engine_iface); 620 } 621 622 void 623 iface_timeout(int fd, short events, void *arg) 624 { 625 struct engine_iface *engine_iface = (struct engine_iface *)arg; 626 struct imsg_send_ra send_ra; 627 struct timeval tv; 628 629 tv.tv_sec = MIN_RTR_ADV_INTERVAL + 630 arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL); 631 tv.tv_usec = arc4random_uniform(1000000); 632 633 log_debug("%s new timeout in %lld", __func__, tv.tv_sec); 634 635 evtimer_add(&engine_iface->timer, &tv); 636 637 send_ra.if_index = engine_iface->if_index; 638 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 639 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 640 sizeof(send_ra)); 641 clock_gettime(CLOCK_MONOTONIC, &engine_iface->last_ra); 642 engine_iface->ras_delayed = 0; 643 } 644