jcs's openbsd hax
openbsd
at jcs 673 lines 18 kB view raw
1/* $OpenBSD: engine.c,v 1.29 2025/04/27 16:23:04 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 48struct 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 56TAILQ_HEAD(, engine_iface) engine_interfaces; 57 58 59__dead void engine_shutdown(void); 60void engine_sig_handler(int sig, short, void *); 61void engine_dispatch_frontend(int, short, void *); 62void engine_dispatch_main(int, short, void *); 63void parse_ra_rs(struct imsg_ra_rs *); 64void parse_ra(struct imsg_ra_rs *); 65void parse_rs(struct imsg_ra_rs *); 66void update_iface(uint32_t); 67void remove_iface(uint32_t); 68struct engine_iface *find_engine_iface_by_id(uint32_t); 69void iface_timeout(int, short, void *); 70 71struct rad_conf *engine_conf; 72static struct imsgev *iev_frontend; 73static struct imsgev *iev_main; 74struct sockaddr_in6 all_nodes; 75 76void 77engine_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 93void 94engine(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 161engine_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 178int 179engine_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 185void 186engine_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 264void 265engine_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 if (ra_iface_conf->name[IF_NAMESIZE - 1] != '\0') 358 fatalx("%s: IMSG_RECONF_RA_IFACE invalid name", 359 __func__); 360 361 ra_iface_conf->autoprefix = NULL; 362 SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list); 363 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list); 364 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list); 365 SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list); 366 SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list, 367 ra_iface_conf, entry); 368 ra_options = &ra_iface_conf->ra_options; 369 break; 370 case IMSG_RECONF_RA_AUTOPREFIX: 371 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 372 ra_prefix_conf)) 373 fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong " 374 "length: %lu", __func__, 375 IMSG_DATA_SIZE(imsg)); 376 if ((ra_iface_conf->autoprefix = malloc(sizeof(struct 377 ra_prefix_conf))) == NULL) 378 fatal(NULL); 379 memcpy(ra_iface_conf->autoprefix, imsg.data, 380 sizeof(struct ra_prefix_conf)); 381 break; 382 case IMSG_RECONF_RA_PREFIX: 383 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 384 ra_prefix_conf)) 385 fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " 386 "length: %lu", __func__, 387 IMSG_DATA_SIZE(imsg)); 388 if ((ra_prefix_conf = malloc(sizeof(struct 389 ra_prefix_conf))) == NULL) 390 fatal(NULL); 391 memcpy(ra_prefix_conf, imsg.data, sizeof(struct 392 ra_prefix_conf)); 393 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, 394 ra_prefix_conf, entry); 395 break; 396 case IMSG_RECONF_RA_RDNSS: 397 if(IMSG_DATA_SIZE(imsg) != sizeof(struct 398 ra_rdnss_conf)) 399 fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: " 400 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 401 if ((ra_rdnss_conf = malloc(sizeof(struct 402 ra_rdnss_conf))) == NULL) 403 fatal(NULL); 404 memcpy(ra_rdnss_conf, imsg.data, sizeof(struct 405 ra_rdnss_conf)); 406 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 407 ra_rdnss_conf, entry); 408 break; 409 case IMSG_RECONF_RA_DNSSL: 410 if(IMSG_DATA_SIZE(imsg) != sizeof(struct 411 ra_dnssl_conf)) 412 fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: " 413 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 414 if ((ra_dnssl_conf = malloc(sizeof(struct 415 ra_dnssl_conf))) == NULL) 416 fatal(NULL); 417 memcpy(ra_dnssl_conf, imsg.data, sizeof(struct 418 ra_dnssl_conf)); 419 if (ra_dnssl_conf->search[MAX_SEARCH - 1] != '\0') 420 fatalx("%s: IMSG_RECONF_RA_DNSSL invalid " 421 "search list", __func__); 422 423 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 424 ra_dnssl_conf, entry); 425 break; 426 case IMSG_RECONF_RA_PREF64: 427 if(IMSG_DATA_SIZE(imsg) != sizeof(struct 428 ra_pref64_conf)) 429 fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: " 430 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 431 if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) == 432 NULL) 433 fatal(NULL); 434 memcpy(pref64, imsg.data, sizeof(struct ra_pref64_conf)); 435 SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, 436 entry); 437 break; 438 case IMSG_RECONF_END: 439 if (nconf == NULL) 440 fatalx("%s: IMSG_RECONF_END without " 441 "IMSG_RECONF_CONF", __func__); 442 merge_config(engine_conf, nconf); 443 nconf = NULL; 444 break; 445 default: 446 log_debug("%s: unexpected imsg %d", __func__, 447 imsg.hdr.type); 448 break; 449 } 450 imsg_free(&imsg); 451 } 452 if (!shut) 453 imsg_event_add(iev); 454 else { 455 /* This pipe is dead. Remove its event handler. */ 456 event_del(&iev->ev); 457 event_loopexit(NULL); 458 } 459} 460 461 462void 463parse_ra_rs(struct imsg_ra_rs *ra_rs) 464{ 465 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 466 struct icmp6_hdr *hdr; 467 468 hdr = (struct icmp6_hdr *) ra_rs->packet; 469 470 switch (hdr->icmp6_type) { 471 case ND_ROUTER_ADVERT: 472 parse_ra(ra_rs); 473 break; 474 case ND_ROUTER_SOLICIT: 475 parse_rs(ra_rs); 476 break; 477 default: 478 log_warnx("unexpected icmp6_type: %d from %s on %s", 479 hdr->icmp6_type, inet_ntop(AF_INET6, &ra_rs->from.sin6_addr, 480 ntopbuf, INET6_ADDRSTRLEN), if_indextoname(ra_rs->if_index, 481 ifnamebuf)); 482 break; 483 } 484} 485 486void 487parse_ra(struct imsg_ra_rs *ra) 488{ 489 char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 490 log_debug("got RA from %s on %s", 491 inet_ntop(AF_INET6, &ra->from.sin6_addr, ntopbuf, 492 INET6_ADDRSTRLEN), if_indextoname(ra->if_index, 493 ifnamebuf)); 494 /* XXX not yet */ 495} 496 497void 498parse_rs(struct imsg_ra_rs *rs) 499{ 500 struct nd_router_solicit *nd_rs; 501 struct engine_iface *engine_iface; 502 ssize_t len; 503 int unicast_ra = 0; 504 const char *hbuf; 505 char ifnamebuf[IFNAMSIZ]; 506 uint8_t *p; 507 508 hbuf = sin6_to_str(&rs->from); 509 510 log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, 511 ifnamebuf)); 512 513 if ((engine_iface = find_engine_iface_by_id(rs->if_index)) == NULL) 514 return; 515 516 len = rs->len; 517 518 if (!(IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr) || 519 IN6_IS_ADDR_UNSPECIFIED(&rs->from.sin6_addr))) { 520 log_warnx("RA from invalid address %s on %s", hbuf, 521 if_indextoname(rs->if_index, ifnamebuf)); 522 return; 523 } 524 525 if ((size_t)len < sizeof(struct nd_router_solicit)) { 526 log_warnx("received too short message (%ld) from %s", len, 527 hbuf); 528 return; 529 } 530 531 p = rs->packet; 532 nd_rs = (struct nd_router_solicit *)p; 533 len -= sizeof(struct nd_router_solicit); 534 p += sizeof(struct nd_router_solicit); 535 536 if (nd_rs->nd_rs_code != 0) { 537 log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_code, 538 hbuf); 539 return; 540 } 541 while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 542 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 543 544 len -= sizeof(struct nd_opt_hdr); 545 p += sizeof(struct nd_opt_hdr); 546 547 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 548 log_warnx("invalid option len: %u > %ld", 549 nd_opt_hdr->nd_opt_len, len); 550 return; 551 } 552 switch (nd_opt_hdr->nd_opt_type) { 553 case ND_OPT_SOURCE_LINKADDR: 554 log_debug("got RS with source linkaddr option"); 555 unicast_ra = 1; 556 break; 557 default: 558 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 559 break; 560 } 561 len -= nd_opt_hdr->nd_opt_len * 8 - 2; 562 p += nd_opt_hdr->nd_opt_len * 8 - 2; 563 } 564 565 if (unicast_ra) { 566 struct imsg_send_ra send_ra; 567 568 send_ra.if_index = rs->if_index; 569 memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); 570 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 571 sizeof(send_ra)); 572 } else { 573 struct timespec now, diff, ra_delay = {MIN_DELAY_BETWEEN_RAS, 0}; 574 struct timeval tv = {0, 0}; 575 576 /* a multicast RA is already scheduled within the next 3 seconds */ 577 if (engine_iface->ras_delayed) 578 return; 579 580 engine_iface->ras_delayed = 1; 581 clock_gettime(CLOCK_MONOTONIC, &now); 582 timespecsub(&now, &engine_iface->last_ra, &diff); 583 584 if (timespeccmp(&diff, &ra_delay, <)) { 585 timespecsub(&ra_delay, &diff, &ra_delay); 586 TIMESPEC_TO_TIMEVAL(&tv, &ra_delay); 587 } 588 589 tv.tv_usec = arc4random_uniform(MAX_RA_DELAY_TIME * 1000); 590 evtimer_add(&engine_iface->timer, &tv); 591 } 592} 593 594struct engine_iface* 595find_engine_iface_by_id(uint32_t if_index) 596{ 597 struct engine_iface *engine_iface; 598 599 TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) { 600 if (engine_iface->if_index == if_index) 601 return engine_iface; 602 } 603 return (NULL); 604} 605 606void 607update_iface(uint32_t if_index) 608{ 609 struct engine_iface *engine_iface; 610 struct timeval tv; 611 612 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 613 engine_iface = calloc(1, sizeof(*engine_iface)); 614 engine_iface->if_index = if_index; 615 evtimer_set(&engine_iface->timer, iface_timeout, engine_iface); 616 TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry); 617 } 618 619 tv.tv_sec = 0; 620 tv.tv_usec = arc4random_uniform(1000000); 621 evtimer_add(&engine_iface->timer, &tv); 622} 623 624void 625remove_iface(uint32_t if_index) 626{ 627 struct engine_iface *engine_iface; 628 struct imsg_send_ra send_ra; 629 char if_name[IF_NAMESIZE]; 630 631 if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 632 /* we don't know this interface, frontend can delete it */ 633 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 634 &if_index, sizeof(if_index)); 635 return; 636 } 637 638 send_ra.if_index = engine_iface->if_index; 639 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 640 641 TAILQ_REMOVE(&engine_interfaces, engine_iface, entry); 642 evtimer_del(&engine_iface->timer); 643 644 if (if_indextoname(if_index, if_name) != NULL) 645 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 646 sizeof(send_ra)); 647 engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0, 648 &engine_iface->if_index, sizeof(engine_iface->if_index)); 649 free(engine_iface); 650} 651 652void 653iface_timeout(int fd, short events, void *arg) 654{ 655 struct engine_iface *engine_iface = (struct engine_iface *)arg; 656 struct imsg_send_ra send_ra; 657 struct timeval tv; 658 659 tv.tv_sec = MIN_RTR_ADV_INTERVAL + 660 arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL); 661 tv.tv_usec = arc4random_uniform(1000000); 662 663 log_debug("%s new timeout in %lld", __func__, tv.tv_sec); 664 665 evtimer_add(&engine_iface->timer, &tv); 666 667 send_ra.if_index = engine_iface->if_index; 668 memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 669 engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 670 sizeof(send_ra)); 671 clock_gettime(CLOCK_MONOTONIC, &engine_iface->last_ra); 672 engine_iface->ras_delayed = 0; 673}