1/* $OpenBSD: engine.c,v 1.89 2024/04/21 17:33:05 florian Exp $ */ 2 3/* 4 * Copyright (c) 2017 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/* 23 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 24 * All rights reserved. 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that the following conditions 28 * are met: 29 * 1. Redistributions of source code must retain the above copyright 30 * notice, this list of conditions and the following disclaimer. 31 * 2. Redistributions in binary form must reproduce the above copyright 32 * notice, this list of conditions and the following disclaimer in the 33 * documentation and/or other materials provided with the distribution. 34 * 3. Neither the name of the project nor the names of its contributors 35 * may be used to endorse or promote products derived from this software 36 * without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 */ 50 51#include <sys/types.h> 52#include <sys/queue.h> 53#include <sys/socket.h> 54#include <sys/syslog.h> 55#include <sys/uio.h> 56 57#include <net/if.h> 58#include <net/route.h> 59#include <arpa/inet.h> 60#include <netinet/in.h> 61#include <netinet/if_ether.h> 62#include <netinet/ip6.h> 63#include <netinet6/nd6.h> 64#include <netinet/icmp6.h> 65 66#include <crypto/sha2.h> 67 68#include <errno.h> 69#include <event.h> 70#include <imsg.h> 71#include <pwd.h> 72#include <signal.h> 73#include <stddef.h> 74#include <stdlib.h> 75#include <string.h> 76#include <time.h> 77#include <unistd.h> 78 79#include "log.h" 80#include "slaacd.h" 81#include "engine.h" 82 83#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 84 85#define MAX_RTR_SOLICITATION_DELAY 1 86#define MAX_RTR_SOLICITATION_DELAY_USEC MAX_RTR_SOLICITATION_DELAY * 1000000 87#define RTR_SOLICITATION_INTERVAL 4 88#define MAX_RTR_SOLICITATIONS 3 89 90/* 91 * Constants for RFC 8981 temporary address extensions 92 * 93 * PRIV_PREFERRED_LIFETIME > (PRIV_MAX_DESYNC_FACTOR + PRIV_REGEN_ADVANCE) 94 */ 95#define PRIV_VALID_LIFETIME 172800 /* 2 days */ 96#define PRIV_PREFERRED_LIFETIME 86400 /* 1 day */ 97#define PRIV_MAX_DESYNC_FACTOR 34560 /* PRIV_PREFERRED_LIFETIME * 0.4 */ 98#define PRIV_REGEN_ADVANCE 5 /* 5 seconds */ 99 100enum if_state { 101 IF_DOWN, 102 IF_INIT, 103 IF_BOUND, 104}; 105 106enum proposal_state { 107 PROPOSAL_IF_DOWN, 108 PROPOSAL_NOT_CONFIGURED, 109 PROPOSAL_CONFIGURED, 110 PROPOSAL_NEARLY_EXPIRED, 111 PROPOSAL_WITHDRAWN, 112 PROPOSAL_DUPLICATED, 113 PROPOSAL_STALE, 114}; 115 116const char* rpref_name[] = { 117 "Low", 118 "Medium", 119 "High", 120}; 121 122struct radv_prefix { 123 LIST_ENTRY(radv_prefix) entries; 124 struct in6_addr prefix; 125 uint8_t prefix_len; /*XXX int */ 126 int onlink; 127 int autonomous; 128 uint32_t vltime; 129 uint32_t pltime; 130 int dad_counter; 131}; 132 133struct radv_rdns { 134 LIST_ENTRY(radv_rdns) entries; 135 struct in6_addr rdns; 136}; 137 138struct radv { 139 LIST_ENTRY(radv) entries; 140 struct sockaddr_in6 from; 141 struct timespec when; 142 struct timespec uptime; 143 struct event timer; 144 uint32_t min_lifetime; 145 uint8_t curhoplimit; 146 int managed; 147 int other; 148 enum rpref rpref; 149 uint16_t router_lifetime; /* in seconds */ 150 uint32_t reachable_time; /* in milliseconds */ 151 uint32_t retrans_time; /* in milliseconds */ 152 LIST_HEAD(, radv_prefix) prefixes; 153 uint32_t rdns_lifetime; 154 LIST_HEAD(, radv_rdns) rdns_servers; 155 uint32_t mtu; 156}; 157 158struct address_proposal { 159 LIST_ENTRY(address_proposal) entries; 160 struct event timer; 161 int64_t id; 162 enum proposal_state state; 163 struct timeval timo; 164 struct timespec created; 165 struct timespec when; 166 struct timespec uptime; 167 uint32_t if_index; 168 struct ether_addr hw_address; 169 struct sockaddr_in6 from; 170 struct sockaddr_in6 addr; 171 struct in6_addr mask; 172 struct in6_addr prefix; 173 int temporary; 174 uint8_t prefix_len; 175 uint32_t vltime; 176 uint32_t pltime; 177 uint32_t desync_factor; 178 uint8_t soiikey[SLAACD_SOIIKEY_LEN]; 179 uint32_t mtu; 180}; 181 182struct dfr_proposal { 183 LIST_ENTRY(dfr_proposal) entries; 184 struct event timer; 185 int64_t id; 186 enum proposal_state state; 187 struct timeval timo; 188 struct timespec when; 189 struct timespec uptime; 190 uint32_t if_index; 191 int rdomain; 192 struct sockaddr_in6 addr; 193 uint32_t router_lifetime; 194 enum rpref rpref; 195}; 196 197struct rdns_proposal { 198 LIST_ENTRY(rdns_proposal) entries; 199 struct event timer; 200 int64_t id; 201 enum proposal_state state; 202 struct timeval timo; 203 struct timespec when; 204 struct timespec uptime; 205 uint32_t if_index; 206 int rdomain; 207 struct sockaddr_in6 from; 208 int rdns_count; 209 struct in6_addr rdns[MAX_RDNS_COUNT]; 210 uint32_t rdns_lifetime; 211}; 212 213struct slaacd_iface { 214 LIST_ENTRY(slaacd_iface) entries; 215 enum if_state state; 216 struct event timer; 217 struct timeval timo; 218 struct timespec last_sol; 219 int probes; 220 uint32_t if_index; 221 uint32_t rdomain; 222 int running; 223 int autoconf; 224 int temporary; 225 int soii; 226 struct ether_addr hw_address; 227 struct sockaddr_in6 ll_address; 228 uint8_t soiikey[SLAACD_SOIIKEY_LEN]; 229 int link_state; 230 uint32_t cur_mtu; 231 LIST_HEAD(, radv) radvs; 232 LIST_HEAD(, address_proposal) addr_proposals; 233 LIST_HEAD(, dfr_proposal) dfr_proposals; 234 LIST_HEAD(, rdns_proposal) rdns_proposals; 235}; 236 237LIST_HEAD(, slaacd_iface) slaacd_interfaces; 238 239__dead void engine_shutdown(void); 240void engine_sig_handler(int sig, short, void *); 241void engine_dispatch_frontend(int, short, void *); 242void engine_dispatch_main(int, short, void *); 243#ifndef SMALL 244void send_interface_info(struct slaacd_iface *, pid_t); 245void engine_showinfo_ctl(struct imsg *, uint32_t); 246void debug_log_ra(struct imsg_ra *); 247int in6_mask2prefixlen(struct in6_addr *); 248#endif /* SMALL */ 249struct slaacd_iface *get_slaacd_iface_by_id(uint32_t); 250void remove_slaacd_iface(uint32_t); 251void free_ra(struct radv *); 252void iface_state_transition(struct slaacd_iface *, enum 253 if_state); 254void addr_proposal_state_transition(struct 255 address_proposal *, enum proposal_state); 256void dfr_proposal_state_transition(struct dfr_proposal *, 257 enum proposal_state); 258void rdns_proposal_state_transition(struct rdns_proposal *, 259 enum proposal_state); 260void engine_update_iface(struct imsg_ifinfo *); 261void request_solicitation(struct slaacd_iface *); 262void parse_ra(struct slaacd_iface *, struct imsg_ra *); 263void gen_addr(struct slaacd_iface *, struct radv_prefix *, 264 struct address_proposal *, int); 265void gen_address_proposal(struct slaacd_iface *, struct 266 radv *, struct radv_prefix *, int); 267void free_address_proposal(struct address_proposal *); 268void withdraw_addr(struct address_proposal *); 269void configure_address(struct address_proposal *); 270void in6_prefixlen2mask(struct in6_addr *, int len); 271void gen_dfr_proposal(struct slaacd_iface *, struct 272 radv *); 273void configure_dfr(struct dfr_proposal *); 274void free_dfr_proposal(struct dfr_proposal *); 275void withdraw_dfr(struct dfr_proposal *); 276void update_iface_ra_rdns(struct slaacd_iface *, 277 struct radv *); 278void gen_rdns_proposal(struct slaacd_iface *, struct 279 radv *); 280void free_rdns_proposal(struct rdns_proposal *); 281void withdraw_rdns(struct rdns_proposal *); 282void compose_rdns_proposal(uint32_t, int); 283void update_iface_ra(struct slaacd_iface *, struct radv *); 284void update_iface_ra_dfr(struct slaacd_iface *, 285 struct radv *); 286void update_iface_ra_prefix(struct slaacd_iface *, 287 struct radv *, struct radv_prefix *prefix); 288void address_proposal_timeout(int, short, void *); 289void dfr_proposal_timeout(int, short, void *); 290void rdns_proposal_timeout(int, short, void *); 291void iface_timeout(int, short, void *); 292struct radv *find_ra(struct slaacd_iface *, struct sockaddr_in6 *); 293struct address_proposal *find_address_proposal_by_addr(struct slaacd_iface *, 294 struct sockaddr_in6 *); 295struct dfr_proposal *find_dfr_proposal_by_gw(struct slaacd_iface *, 296 struct sockaddr_in6 *); 297struct rdns_proposal *find_rdns_proposal_by_gw(struct slaacd_iface *, 298 struct sockaddr_in6 *); 299struct radv_prefix *find_prefix(struct radv *, struct in6_addr *, uint8_t); 300int engine_imsg_compose_main(int, pid_t, void *, uint16_t); 301uint32_t real_lifetime(struct timespec *, uint32_t); 302void merge_dad_couters(struct radv *, struct radv *); 303 304static struct imsgev *iev_frontend; 305static struct imsgev *iev_main; 306int64_t proposal_id; 307 308 309#define CASE(x) case x : return #x 310 311#ifndef SMALL 312static const char* 313if_state_name(enum if_state ifs) 314{ 315 switch (ifs) { 316 CASE(IF_DOWN); 317 CASE(IF_INIT); 318 CASE(IF_BOUND); 319 } 320} 321 322static const char* 323proposal_state_name(enum proposal_state ps) 324{ 325 switch (ps) { 326 CASE(PROPOSAL_IF_DOWN); 327 CASE(PROPOSAL_NOT_CONFIGURED); 328 CASE(PROPOSAL_CONFIGURED); 329 CASE(PROPOSAL_NEARLY_EXPIRED); 330 CASE(PROPOSAL_WITHDRAWN); 331 CASE(PROPOSAL_DUPLICATED); 332 CASE(PROPOSAL_STALE); 333 } 334} 335#endif 336 337void 338engine_sig_handler(int sig, short event, void *arg) 339{ 340 /* 341 * Normal signal handler rules don't apply because libevent 342 * decouples for us. 343 */ 344 345 switch (sig) { 346 case SIGINT: 347 case SIGTERM: 348 engine_shutdown(); 349 default: 350 fatalx("unexpected signal"); 351 } 352} 353 354void 355engine(int debug, int verbose) 356{ 357 struct event ev_sigint, ev_sigterm; 358 struct passwd *pw; 359 360 log_init(debug, LOG_DAEMON); 361 log_setverbose(verbose); 362 363 if ((pw = getpwnam(SLAACD_USER)) == NULL) 364 fatal("getpwnam"); 365 366 if (chdir("/") == -1) 367 fatal("chdir(\"/\")"); 368 369 if (unveil("/", "") == -1) 370 fatal("unveil /"); 371 if (unveil(NULL, NULL) == -1) 372 fatal("unveil"); 373 374 setproctitle("%s", "engine"); 375 log_procinit("engine"); 376 377 if (setgroups(1, &pw->pw_gid) || 378 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 379 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 380 fatal("can't drop privileges"); 381 382 if (pledge("stdio recvfd", NULL) == -1) 383 fatal("pledge"); 384 385 event_init(); 386 387 /* Setup signal handler(s). */ 388 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); 389 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); 390 signal_add(&ev_sigint, NULL); 391 signal_add(&ev_sigterm, NULL); 392 signal(SIGPIPE, SIG_IGN); 393 signal(SIGHUP, SIG_IGN); 394 395 /* Setup pipe and event handler to the main process. */ 396 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 397 fatal(NULL); 398 399 imsg_init(&iev_main->ibuf, 3); 400 iev_main->handler = engine_dispatch_main; 401 402 /* Setup event handlers. */ 403 iev_main->events = EV_READ; 404 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 405 iev_main->handler, iev_main); 406 event_add(&iev_main->ev, NULL); 407 408 LIST_INIT(&slaacd_interfaces); 409 410 event_dispatch(); 411 412 engine_shutdown(); 413} 414 415__dead void 416engine_shutdown(void) 417{ 418 /* Close pipes. */ 419 msgbuf_clear(&iev_frontend->ibuf.w); 420 close(iev_frontend->ibuf.fd); 421 msgbuf_clear(&iev_main->ibuf.w); 422 close(iev_main->ibuf.fd); 423 424 free(iev_frontend); 425 free(iev_main); 426 427 log_info("engine exiting"); 428 exit(0); 429} 430 431int 432engine_imsg_compose_frontend(int type, pid_t pid, void *data, 433 uint16_t datalen) 434{ 435 return (imsg_compose_event(iev_frontend, type, 0, pid, -1, 436 data, datalen)); 437} 438 439int 440engine_imsg_compose_main(int type, pid_t pid, void *data, 441 uint16_t datalen) 442{ 443 return (imsg_compose_event(iev_main, type, 0, pid, -1, 444 data, datalen)); 445} 446 447void 448engine_dispatch_frontend(int fd, short event, void *bula) 449{ 450 struct imsgev *iev = bula; 451 struct imsgbuf *ibuf = &iev->ibuf; 452 struct imsg imsg; 453 struct slaacd_iface *iface; 454 struct imsg_ra ra; 455 struct address_proposal *addr_proposal = NULL; 456 struct dfr_proposal *dfr_proposal = NULL; 457 struct imsg_del_addr del_addr; 458 struct imsg_del_route del_route; 459 struct imsg_dup_addr dup_addr; 460 ssize_t n; 461 int shut = 0; 462#ifndef SMALL 463 int verbose; 464#endif /* SMALL */ 465 uint32_t if_index; 466 467 if (event & EV_READ) { 468 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 469 fatal("imsg_read error"); 470 if (n == 0) /* Connection closed. */ 471 shut = 1; 472 } 473 if (event & EV_WRITE) { 474 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 475 fatal("msgbuf_write"); 476 if (n == 0) /* Connection closed. */ 477 shut = 1; 478 } 479 480 for (;;) { 481 if ((n = imsg_get(ibuf, &imsg)) == -1) 482 fatal("%s: imsg_get error", __func__); 483 if (n == 0) /* No more messages. */ 484 break; 485 486 switch (imsg.hdr.type) { 487#ifndef SMALL 488 case IMSG_CTL_LOG_VERBOSE: 489 if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 490 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 491 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 492 memcpy(&verbose, imsg.data, sizeof(verbose)); 493 log_setverbose(verbose); 494 break; 495 case IMSG_CTL_SHOW_INTERFACE_INFO: 496 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 497 fatalx("%s: IMSG_CTL_SHOW_INTERFACE_INFO wrong " 498 "length: %lu", __func__, 499 IMSG_DATA_SIZE(imsg)); 500 memcpy(&if_index, imsg.data, sizeof(if_index)); 501 engine_showinfo_ctl(&imsg, if_index); 502 break; 503#endif /* SMALL */ 504 case IMSG_REMOVE_IF: 505 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 506 fatalx("%s: IMSG_REMOVE_IF wrong length: %lu", 507 __func__, IMSG_DATA_SIZE(imsg)); 508 memcpy(&if_index, imsg.data, sizeof(if_index)); 509 remove_slaacd_iface(if_index); 510 break; 511 case IMSG_RA: 512 if (IMSG_DATA_SIZE(imsg) != sizeof(ra)) 513 fatalx("%s: IMSG_RA wrong length: %lu", 514 __func__, IMSG_DATA_SIZE(imsg)); 515 memcpy(&ra, imsg.data, sizeof(ra)); 516 iface = get_slaacd_iface_by_id(ra.if_index); 517 518 /* 519 * Ignore unsolicitated router advertisements 520 * if we think the interface is still down. 521 * Otherwise we confuse the state machine. 522 */ 523 if (iface != NULL && iface->state != IF_DOWN) 524 parse_ra(iface, &ra); 525 break; 526 case IMSG_CTL_SEND_SOLICITATION: 527 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 528 fatalx("%s: IMSG_CTL_SEND_SOLICITATION wrong " 529 "length: %lu", __func__, 530 IMSG_DATA_SIZE(imsg)); 531 memcpy(&if_index, imsg.data, sizeof(if_index)); 532 iface = get_slaacd_iface_by_id(if_index); 533 if (iface == NULL) 534 log_warnx("requested to send solicitation on " 535 "non-autoconf interface: %u", if_index); 536 else { 537 iface->last_sol.tv_sec = 0; /* no rate limit */ 538 request_solicitation(iface); 539 } 540 break; 541 case IMSG_DEL_ADDRESS: 542 if (IMSG_DATA_SIZE(imsg) != sizeof(del_addr)) 543 fatalx("%s: IMSG_DEL_ADDRESS wrong length: %lu", 544 __func__, IMSG_DATA_SIZE(imsg)); 545 memcpy(&del_addr, imsg.data, sizeof(del_addr)); 546 iface = get_slaacd_iface_by_id(del_addr.if_index); 547 if (iface == NULL) { 548 log_debug("IMSG_DEL_ADDRESS: unknown interface" 549 ", ignoring"); 550 break; 551 } 552 553 addr_proposal = find_address_proposal_by_addr(iface, 554 &del_addr.addr); 555 /* 556 * If it's in state PROPOSAL_WITHDRAWN we just 557 * deleted it ourself but want to keep it around 558 * so we can renew it 559 */ 560 if (addr_proposal && addr_proposal->state != 561 PROPOSAL_WITHDRAWN) 562 free_address_proposal(addr_proposal); 563 break; 564 case IMSG_DEL_ROUTE: 565 if (IMSG_DATA_SIZE(imsg) != sizeof(del_route)) 566 fatalx("%s: IMSG_DEL_ROUTE wrong length: %lu", 567 __func__, IMSG_DATA_SIZE(imsg)); 568 memcpy(&del_route, imsg.data, sizeof(del_route)); 569 iface = get_slaacd_iface_by_id(del_route.if_index); 570 if (iface == NULL) { 571 log_debug("IMSG_DEL_ROUTE: unknown interface" 572 ", ignoring"); 573 break; 574 } 575 576 dfr_proposal = find_dfr_proposal_by_gw(iface, 577 &del_route.gw); 578 579 if (dfr_proposal) { 580 dfr_proposal->state = PROPOSAL_WITHDRAWN; 581 free_dfr_proposal(dfr_proposal); 582 } 583 break; 584 case IMSG_DUP_ADDRESS: 585 if (IMSG_DATA_SIZE(imsg) != sizeof(dup_addr)) 586 fatalx("%s: IMSG_DUP_ADDRESS wrong length: %lu", 587 __func__, IMSG_DATA_SIZE(imsg)); 588 memcpy(&dup_addr, imsg.data, sizeof(dup_addr)); 589 iface = get_slaacd_iface_by_id(dup_addr.if_index); 590 if (iface == NULL) { 591 log_debug("IMSG_DUP_ADDRESS: unknown interface" 592 ", ignoring"); 593 break; 594 } 595 596 addr_proposal = find_address_proposal_by_addr(iface, 597 &dup_addr.addr); 598 599 if (addr_proposal) 600 addr_proposal_state_transition(addr_proposal, 601 PROPOSAL_DUPLICATED); 602 break; 603 case IMSG_REPROPOSE_RDNS: 604 LIST_FOREACH (iface, &slaacd_interfaces, entries) 605 compose_rdns_proposal(iface->if_index, 606 iface->rdomain); 607 break; 608 default: 609 log_debug("%s: unexpected imsg %d", __func__, 610 imsg.hdr.type); 611 break; 612 } 613 imsg_free(&imsg); 614 } 615 if (!shut) 616 imsg_event_add(iev); 617 else { 618 /* This pipe is dead. Remove its event handler. */ 619 event_del(&iev->ev); 620 event_loopexit(NULL); 621 } 622} 623 624void 625engine_dispatch_main(int fd, short event, void *bula) 626{ 627 struct imsg imsg; 628 struct imsgev *iev = bula; 629 struct imsgbuf *ibuf = &iev->ibuf; 630 struct imsg_ifinfo imsg_ifinfo; 631 ssize_t n; 632 int shut = 0; 633 634 if (event & EV_READ) { 635 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 636 fatal("imsg_read error"); 637 if (n == 0) /* Connection closed. */ 638 shut = 1; 639 } 640 if (event & EV_WRITE) { 641 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 642 fatal("msgbuf_write"); 643 if (n == 0) /* Connection closed. */ 644 shut = 1; 645 } 646 647 for (;;) { 648 if ((n = imsg_get(ibuf, &imsg)) == -1) 649 fatal("%s: imsg_get error", __func__); 650 if (n == 0) /* No more messages. */ 651 break; 652 653 switch (imsg.hdr.type) { 654 case IMSG_SOCKET_IPC: 655 /* 656 * Setup pipe and event handler to the frontend 657 * process. 658 */ 659 if (iev_frontend) 660 fatalx("%s: received unexpected imsg fd " 661 "to engine", __func__); 662 663 if ((fd = imsg_get_fd(&imsg)) == -1) 664 fatalx("%s: expected to receive imsg fd to " 665 "engine but didn't receive any", __func__); 666 667 iev_frontend = malloc(sizeof(struct imsgev)); 668 if (iev_frontend == NULL) 669 fatal(NULL); 670 671 imsg_init(&iev_frontend->ibuf, fd); 672 iev_frontend->handler = engine_dispatch_frontend; 673 iev_frontend->events = EV_READ; 674 675 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 676 iev_frontend->events, iev_frontend->handler, 677 iev_frontend); 678 event_add(&iev_frontend->ev, NULL); 679 680 if (pledge("stdio", NULL) == -1) 681 fatal("pledge"); 682 break; 683 case IMSG_UPDATE_IF: 684 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo)) 685 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 686 __func__, IMSG_DATA_SIZE(imsg)); 687 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); 688 engine_update_iface(&imsg_ifinfo); 689 break; 690 default: 691 log_debug("%s: unexpected imsg %d", __func__, 692 imsg.hdr.type); 693 break; 694 } 695 imsg_free(&imsg); 696 } 697 if (!shut) 698 imsg_event_add(iev); 699 else { 700 /* This pipe is dead. Remove its event handler. */ 701 event_del(&iev->ev); 702 event_loopexit(NULL); 703 } 704} 705 706#ifndef SMALL 707void 708send_interface_info(struct slaacd_iface *iface, pid_t pid) 709{ 710 struct ctl_engine_info cei; 711 struct ctl_engine_info_ra cei_ra; 712 struct ctl_engine_info_ra_prefix cei_ra_prefix; 713 struct ctl_engine_info_ra_rdns cei_ra_rdns; 714 struct ctl_engine_info_address_proposal cei_addr_proposal; 715 struct ctl_engine_info_dfr_proposal cei_dfr_proposal; 716 struct ctl_engine_info_rdns_proposal cei_rdns_proposal; 717 struct radv *ra; 718 struct radv_prefix *prefix; 719 struct radv_rdns *rdns; 720 struct address_proposal *addr_proposal; 721 struct dfr_proposal *dfr_proposal; 722 struct rdns_proposal *rdns_proposal; 723 724 memset(&cei, 0, sizeof(cei)); 725 cei.if_index = iface->if_index; 726 cei.running = iface->running; 727 cei.autoconf = iface->autoconf; 728 cei.temporary = iface->temporary; 729 cei.soii = iface->soii; 730 memcpy(&cei.hw_address, &iface->hw_address, sizeof(struct ether_addr)); 731 memcpy(&cei.ll_address, &iface->ll_address, 732 sizeof(struct sockaddr_in6)); 733 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei, 734 sizeof(cei)); 735 LIST_FOREACH(ra, &iface->radvs, entries) { 736 memset(&cei_ra, 0, sizeof(cei_ra)); 737 memcpy(&cei_ra.from, &ra->from, sizeof(cei_ra.from)); 738 memcpy(&cei_ra.when, &ra->when, sizeof(cei_ra.when)); 739 memcpy(&cei_ra.uptime, &ra->uptime, sizeof(cei_ra.uptime)); 740 cei_ra.curhoplimit = ra->curhoplimit; 741 cei_ra.managed = ra->managed; 742 cei_ra.other = ra->other; 743 if (strlcpy(cei_ra.rpref, rpref_name[ra->rpref], sizeof( 744 cei_ra.rpref)) >= sizeof(cei_ra.rpref)) 745 log_warnx("truncated router preference"); 746 cei_ra.router_lifetime = ra->router_lifetime; 747 cei_ra.reachable_time = ra->reachable_time; 748 cei_ra.retrans_time = ra->retrans_time; 749 cei_ra.mtu = ra->mtu; 750 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO_RA, 751 pid, &cei_ra, sizeof(cei_ra)); 752 753 LIST_FOREACH(prefix, &ra->prefixes, entries) { 754 memset(&cei_ra_prefix, 0, sizeof(cei_ra_prefix)); 755 756 cei_ra_prefix.prefix = prefix->prefix; 757 cei_ra_prefix.prefix_len = prefix->prefix_len; 758 cei_ra_prefix.onlink = prefix->onlink; 759 cei_ra_prefix.autonomous = prefix->autonomous; 760 cei_ra_prefix.vltime = prefix->vltime; 761 cei_ra_prefix.pltime = prefix->pltime; 762 engine_imsg_compose_frontend( 763 IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX, pid, 764 &cei_ra_prefix, sizeof(cei_ra_prefix)); 765 } 766 767 LIST_FOREACH(rdns, &ra->rdns_servers, entries) { 768 memset(&cei_ra_rdns, 0, sizeof(cei_ra_rdns)); 769 memcpy(&cei_ra_rdns.rdns, &rdns->rdns, 770 sizeof(cei_ra_rdns.rdns)); 771 cei_ra_rdns.lifetime = ra->rdns_lifetime; 772 engine_imsg_compose_frontend( 773 IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS, pid, 774 &cei_ra_rdns, sizeof(cei_ra_rdns)); 775 } 776 } 777 778 if (!LIST_EMPTY(&iface->addr_proposals)) 779 engine_imsg_compose_frontend( 780 IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS, pid, NULL, 0); 781 782 LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) { 783 memset(&cei_addr_proposal, 0, sizeof(cei_addr_proposal)); 784 cei_addr_proposal.id = addr_proposal->id; 785 if(strlcpy(cei_addr_proposal.state, 786 proposal_state_name(addr_proposal->state), 787 sizeof(cei_addr_proposal.state)) >= 788 sizeof(cei_addr_proposal.state)) 789 log_warnx("truncated state name"); 790 cei_addr_proposal.next_timeout = addr_proposal->timo.tv_sec; 791 cei_addr_proposal.when = addr_proposal->when; 792 cei_addr_proposal.uptime = addr_proposal->uptime; 793 memcpy(&cei_addr_proposal.addr, &addr_proposal->addr, sizeof( 794 cei_addr_proposal.addr)); 795 memcpy(&cei_addr_proposal.prefix, &addr_proposal->prefix, 796 sizeof(cei_addr_proposal.prefix)); 797 cei_addr_proposal.prefix_len = addr_proposal->prefix_len; 798 cei_addr_proposal.temporary = addr_proposal->temporary; 799 cei_addr_proposal.vltime = addr_proposal->vltime; 800 cei_addr_proposal.pltime = addr_proposal->pltime; 801 802 engine_imsg_compose_frontend( 803 IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL, pid, 804 &cei_addr_proposal, sizeof(cei_addr_proposal)); 805 } 806 807 if (!LIST_EMPTY(&iface->dfr_proposals)) 808 engine_imsg_compose_frontend( 809 IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS, pid, NULL, 0); 810 811 LIST_FOREACH(dfr_proposal, &iface->dfr_proposals, entries) { 812 memset(&cei_dfr_proposal, 0, sizeof(cei_dfr_proposal)); 813 cei_dfr_proposal.id = dfr_proposal->id; 814 if(strlcpy(cei_dfr_proposal.state, 815 proposal_state_name(dfr_proposal->state), 816 sizeof(cei_dfr_proposal.state)) >= 817 sizeof(cei_dfr_proposal.state)) 818 log_warnx("truncated state name"); 819 cei_dfr_proposal.next_timeout = dfr_proposal->timo.tv_sec; 820 cei_dfr_proposal.when = dfr_proposal->when; 821 cei_dfr_proposal.uptime = dfr_proposal->uptime; 822 memcpy(&cei_dfr_proposal.addr, &dfr_proposal->addr, sizeof( 823 cei_dfr_proposal.addr)); 824 cei_dfr_proposal.router_lifetime = 825 dfr_proposal->router_lifetime; 826 if(strlcpy(cei_dfr_proposal.rpref, 827 rpref_name[dfr_proposal->rpref], 828 sizeof(cei_dfr_proposal.rpref)) >= 829 sizeof(cei_dfr_proposal.rpref)) 830 log_warnx("truncated router preference"); 831 engine_imsg_compose_frontend( 832 IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL, pid, 833 &cei_dfr_proposal, sizeof(cei_dfr_proposal)); 834 } 835 836 if (!LIST_EMPTY(&iface->rdns_proposals)) 837 engine_imsg_compose_frontend( 838 IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS, pid, NULL, 0); 839 840 LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) { 841 memset(&cei_rdns_proposal, 0, sizeof(cei_rdns_proposal)); 842 cei_rdns_proposal.id = rdns_proposal->id; 843 if(strlcpy(cei_rdns_proposal.state, 844 proposal_state_name(rdns_proposal->state), 845 sizeof(cei_rdns_proposal.state)) >= 846 sizeof(cei_rdns_proposal.state)) 847 log_warnx("truncated state name"); 848 cei_rdns_proposal.next_timeout = rdns_proposal->timo.tv_sec; 849 cei_rdns_proposal.when = rdns_proposal->when; 850 cei_rdns_proposal.uptime = rdns_proposal->uptime; 851 memcpy(&cei_rdns_proposal.from, &rdns_proposal->from, sizeof( 852 cei_rdns_proposal.from)); 853 cei_rdns_proposal.rdns_count = rdns_proposal->rdns_count; 854 memcpy(&cei_rdns_proposal.rdns, 855 &rdns_proposal->rdns, sizeof(cei_rdns_proposal.rdns)); 856 cei_rdns_proposal.rdns_lifetime = 857 rdns_proposal->rdns_lifetime; 858 engine_imsg_compose_frontend( 859 IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL, pid, 860 &cei_rdns_proposal, sizeof(cei_rdns_proposal)); 861 } 862} 863 864void 865engine_showinfo_ctl(struct imsg *imsg, uint32_t if_index) 866{ 867 struct slaacd_iface *iface; 868 869 switch (imsg->hdr.type) { 870 case IMSG_CTL_SHOW_INTERFACE_INFO: 871 if (if_index == 0) { 872 LIST_FOREACH (iface, &slaacd_interfaces, entries) 873 send_interface_info(iface, imsg->hdr.pid); 874 } else { 875 if ((iface = get_slaacd_iface_by_id(if_index)) != NULL) 876 send_interface_info(iface, imsg->hdr.pid); 877 } 878 engine_imsg_compose_frontend(IMSG_CTL_END, imsg->hdr.pid, NULL, 879 0); 880 break; 881 default: 882 log_debug("%s: error handling imsg", __func__); 883 break; 884 } 885} 886 887#endif /* SMALL */ 888 889struct slaacd_iface* 890get_slaacd_iface_by_id(uint32_t if_index) 891{ 892 struct slaacd_iface *iface; 893 LIST_FOREACH (iface, &slaacd_interfaces, entries) { 894 if (iface->if_index == if_index) 895 return (iface); 896 } 897 898 return (NULL); 899} 900 901void 902remove_slaacd_iface(uint32_t if_index) 903{ 904 struct slaacd_iface *iface; 905 struct radv *ra; 906 struct address_proposal *addr_proposal; 907 struct dfr_proposal *dfr_proposal; 908 struct rdns_proposal *rdns_proposal; 909 910 iface = get_slaacd_iface_by_id(if_index); 911 912 if (iface == NULL) 913 return; 914 915 LIST_REMOVE(iface, entries); 916 while(!LIST_EMPTY(&iface->radvs)) { 917 ra = LIST_FIRST(&iface->radvs); 918 LIST_REMOVE(ra, entries); 919 free_ra(ra); 920 } 921 while(!LIST_EMPTY(&iface->addr_proposals)) { 922 addr_proposal = LIST_FIRST(&iface->addr_proposals); 923 free_address_proposal(addr_proposal); 924 } 925 while(!LIST_EMPTY(&iface->dfr_proposals)) { 926 dfr_proposal = LIST_FIRST(&iface->dfr_proposals); 927 free_dfr_proposal(dfr_proposal); 928 } 929 while(!LIST_EMPTY(&iface->rdns_proposals)) { 930 rdns_proposal = LIST_FIRST(&iface->rdns_proposals); 931 free_rdns_proposal(rdns_proposal); 932 } 933 compose_rdns_proposal(iface->if_index, iface->rdomain); 934 evtimer_del(&iface->timer); 935 free(iface); 936} 937 938void 939free_ra(struct radv *ra) 940{ 941 struct radv_prefix *prefix; 942 struct radv_rdns *rdns; 943 944 if (ra == NULL) 945 return; 946 947 evtimer_del(&ra->timer); 948 949 while (!LIST_EMPTY(&ra->prefixes)) { 950 prefix = LIST_FIRST(&ra->prefixes); 951 LIST_REMOVE(prefix, entries); 952 free(prefix); 953 } 954 955 while (!LIST_EMPTY(&ra->rdns_servers)) { 956 rdns = LIST_FIRST(&ra->rdns_servers); 957 LIST_REMOVE(rdns, entries); 958 free(rdns); 959 } 960 961 free(ra); 962} 963 964void 965iface_state_transition(struct slaacd_iface *iface, enum if_state new_state) 966{ 967 enum if_state old_state = iface->state; 968 struct address_proposal *addr_proposal; 969 struct dfr_proposal *dfr_proposal; 970 struct rdns_proposal *rdns_proposal; 971 char ifnamebuf[IF_NAMESIZE], *if_name; 972 973 iface->state = new_state; 974 975 switch (new_state) { 976 case IF_DOWN: 977 if (old_state != IF_DOWN) { 978 LIST_FOREACH (addr_proposal, &iface->addr_proposals, 979 entries) 980 addr_proposal_state_transition(addr_proposal, 981 PROPOSAL_IF_DOWN); 982 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, 983 entries) 984 dfr_proposal_state_transition(dfr_proposal, 985 PROPOSAL_IF_DOWN); 986 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, 987 entries) 988 rdns_proposal_state_transition(rdns_proposal, 989 PROPOSAL_IF_DOWN); 990 } 991 992 /* nothing else to do until interface comes back up */ 993 iface->timo.tv_sec = -1; 994 break; 995 case IF_INIT: 996 switch (old_state) { 997 case IF_INIT: 998 iface->probes++; 999 break; 1000 case IF_DOWN: 1001 LIST_FOREACH (addr_proposal, &iface->addr_proposals, 1002 entries) 1003 addr_proposal_state_transition(addr_proposal, 1004 PROPOSAL_WITHDRAWN); 1005 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, 1006 entries) 1007 dfr_proposal_state_transition(dfr_proposal, 1008 PROPOSAL_WITHDRAWN); 1009 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, 1010 entries) 1011 rdns_proposal_state_transition(rdns_proposal, 1012 PROPOSAL_WITHDRAWN); 1013 default: 1014 iface->probes = 0; 1015 } 1016 if (iface->probes < MAX_RTR_SOLICITATIONS) { 1017 iface->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1018 request_solicitation(iface); 1019 } else 1020 /* no router available, stop probing */ 1021 iface->timo.tv_sec = -1; 1022 break; 1023 case IF_BOUND: 1024 iface->timo.tv_sec = -1; 1025 break; 1026 } 1027 1028 if_name = if_indextoname(iface->if_index, ifnamebuf); 1029 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ? 1030 "?" : if_name, if_state_name(old_state), if_state_name(new_state), 1031 iface->timo.tv_sec); 1032 1033 if (iface->timo.tv_sec == -1) { 1034 if (evtimer_pending(&iface->timer, NULL)) 1035 evtimer_del(&iface->timer); 1036 } else 1037 evtimer_add(&iface->timer, &iface->timo); 1038} 1039 1040void addr_proposal_state_transition(struct address_proposal *addr_proposal, 1041 enum proposal_state new_state) 1042{ 1043 enum proposal_state old_state = addr_proposal->state; 1044 struct slaacd_iface *iface; 1045 uint32_t lifetime; 1046 char ifnamebuf[IF_NAMESIZE], *if_name; 1047 1048 addr_proposal->state = new_state; 1049 1050 if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) == NULL) 1051 return; 1052 1053 switch (addr_proposal->state) { 1054 case PROPOSAL_IF_DOWN: 1055 if (old_state == PROPOSAL_IF_DOWN) { 1056 withdraw_addr(addr_proposal); 1057 addr_proposal->timo.tv_sec = -1; 1058 } else { 1059 addr_proposal->timo.tv_sec = 1060 real_lifetime(&addr_proposal->uptime, 1061 addr_proposal->vltime); 1062 } 1063 break; 1064 case PROPOSAL_NOT_CONFIGURED: 1065 break; 1066 case PROPOSAL_CONFIGURED: 1067 lifetime = real_lifetime(&addr_proposal->uptime, 1068 addr_proposal->pltime); 1069 if (lifetime == 0) 1070 lifetime = real_lifetime(&addr_proposal->uptime, 1071 addr_proposal->vltime); 1072 if (lifetime > MAX_RTR_SOLICITATIONS * 1073 (RTR_SOLICITATION_INTERVAL + 1)) 1074 addr_proposal->timo.tv_sec = lifetime - 1075 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1076 else 1077 addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1078 break; 1079 case PROPOSAL_NEARLY_EXPIRED: 1080 lifetime = real_lifetime(&addr_proposal->uptime, 1081 addr_proposal->pltime); 1082 if (lifetime == 0) 1083 lifetime = real_lifetime(&addr_proposal->uptime, 1084 addr_proposal->vltime); 1085 if (lifetime > MAX_RTR_SOLICITATIONS * 1086 (RTR_SOLICITATION_INTERVAL + 1)) 1087 addr_proposal->timo.tv_sec = lifetime - 1088 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1089 else 1090 addr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1091 request_solicitation(iface); 1092 break; 1093 case PROPOSAL_WITHDRAWN: 1094 withdraw_addr(addr_proposal); 1095 addr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS * 1096 RTR_SOLICITATION_INTERVAL; 1097 break; 1098 case PROPOSAL_DUPLICATED: 1099 addr_proposal->timo.tv_sec = 0; 1100 break; 1101 case PROPOSAL_STALE: 1102 addr_proposal->timo.tv_sec = 0; /* remove immediately */ 1103 break; 1104 } 1105 1106 if_name = if_indextoname(addr_proposal->if_index, ifnamebuf); 1107 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ? 1108 "?" : if_name, proposal_state_name(old_state), 1109 proposal_state_name(new_state), 1110 addr_proposal->timo.tv_sec); 1111 1112 if (addr_proposal->timo.tv_sec == -1) { 1113 if (evtimer_pending(&addr_proposal->timer, NULL)) 1114 evtimer_del(&addr_proposal->timer); 1115 } else 1116 evtimer_add(&addr_proposal->timer, &addr_proposal->timo); 1117} 1118 1119void dfr_proposal_state_transition(struct dfr_proposal *dfr_proposal, 1120 enum proposal_state new_state) 1121{ 1122 enum proposal_state old_state = dfr_proposal->state; 1123 struct slaacd_iface *iface; 1124 uint32_t lifetime; 1125 char ifnamebuf[IF_NAMESIZE], *if_name; 1126 1127 dfr_proposal->state = new_state; 1128 1129 if ((iface = get_slaacd_iface_by_id(dfr_proposal->if_index)) == NULL) 1130 return; 1131 1132 switch (dfr_proposal->state) { 1133 case PROPOSAL_IF_DOWN: 1134 if (old_state == PROPOSAL_IF_DOWN) { 1135 withdraw_dfr(dfr_proposal); 1136 dfr_proposal->timo.tv_sec = -1; 1137 } else { 1138 dfr_proposal->timo.tv_sec = 1139 real_lifetime(&dfr_proposal->uptime, 1140 dfr_proposal->router_lifetime); 1141 } 1142 break; 1143 case PROPOSAL_NOT_CONFIGURED: 1144 break; 1145 case PROPOSAL_CONFIGURED: 1146 lifetime = real_lifetime(&dfr_proposal->uptime, 1147 dfr_proposal->router_lifetime); 1148 if (lifetime > MAX_RTR_SOLICITATIONS * 1149 (RTR_SOLICITATION_INTERVAL + 1)) 1150 dfr_proposal->timo.tv_sec = lifetime - 1151 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1152 else 1153 dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1154 break; 1155 case PROPOSAL_NEARLY_EXPIRED: 1156 lifetime = real_lifetime(&dfr_proposal->uptime, 1157 dfr_proposal->router_lifetime); 1158 if (lifetime > MAX_RTR_SOLICITATIONS * 1159 (RTR_SOLICITATION_INTERVAL + 1)) 1160 dfr_proposal->timo.tv_sec = lifetime - 1161 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1162 else 1163 dfr_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1164 request_solicitation(iface); 1165 break; 1166 case PROPOSAL_WITHDRAWN: 1167 withdraw_dfr(dfr_proposal); 1168 dfr_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS * 1169 RTR_SOLICITATION_INTERVAL; 1170 break; 1171 case PROPOSAL_STALE: 1172 dfr_proposal->timo.tv_sec = 0; /* remove immediately */ 1173 break; 1174 case PROPOSAL_DUPLICATED: 1175 fatalx("invalid dfr state: PROPOSAL_DUPLICATED"); 1176 break; 1177 } 1178 1179 if_name = if_indextoname(dfr_proposal->if_index, ifnamebuf); 1180 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ? 1181 "?" : if_name, proposal_state_name(old_state), 1182 proposal_state_name(new_state), 1183 dfr_proposal->timo.tv_sec); 1184 1185 if (dfr_proposal->timo.tv_sec == -1) { 1186 if (evtimer_pending(&dfr_proposal->timer, NULL)) 1187 evtimer_del(&dfr_proposal->timer); 1188 } else 1189 evtimer_add(&dfr_proposal->timer, &dfr_proposal->timo); 1190 1191} 1192 1193void rdns_proposal_state_transition(struct rdns_proposal *rdns_proposal, 1194 enum proposal_state new_state) 1195{ 1196 enum proposal_state old_state = rdns_proposal->state; 1197 struct slaacd_iface *iface; 1198 uint32_t lifetime; 1199 char ifnamebuf[IF_NAMESIZE], *if_name; 1200 1201 rdns_proposal->state = new_state; 1202 1203 if ((iface = get_slaacd_iface_by_id(rdns_proposal->if_index)) == NULL) 1204 return; 1205 1206 switch (rdns_proposal->state) { 1207 case PROPOSAL_IF_DOWN: 1208 if (old_state == PROPOSAL_IF_DOWN) { 1209 withdraw_rdns(rdns_proposal); 1210 rdns_proposal->timo.tv_sec = -1; 1211 } else { 1212 rdns_proposal->timo.tv_sec = 1213 real_lifetime(&rdns_proposal->uptime, 1214 rdns_proposal->rdns_lifetime); 1215 } 1216 break; 1217 case PROPOSAL_NOT_CONFIGURED: 1218 break; 1219 case PROPOSAL_CONFIGURED: 1220 lifetime = real_lifetime(&rdns_proposal->uptime, 1221 rdns_proposal->rdns_lifetime); 1222 if (lifetime > MAX_RTR_SOLICITATIONS * 1223 (RTR_SOLICITATION_INTERVAL + 1)) 1224 rdns_proposal->timo.tv_sec = lifetime - 1225 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1226 else 1227 rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1228 break; 1229 case PROPOSAL_NEARLY_EXPIRED: 1230 lifetime = real_lifetime(&rdns_proposal->uptime, 1231 rdns_proposal->rdns_lifetime); 1232 if (lifetime > MAX_RTR_SOLICITATIONS * 1233 (RTR_SOLICITATION_INTERVAL + 1)) 1234 rdns_proposal->timo.tv_sec = lifetime - 1235 MAX_RTR_SOLICITATIONS * RTR_SOLICITATION_INTERVAL; 1236 else 1237 rdns_proposal->timo.tv_sec = RTR_SOLICITATION_INTERVAL; 1238 request_solicitation(iface); 1239 break; 1240 case PROPOSAL_WITHDRAWN: 1241 withdraw_rdns(rdns_proposal); 1242 rdns_proposal->timo.tv_sec = MAX_RTR_SOLICITATIONS * 1243 RTR_SOLICITATION_INTERVAL; 1244 break; 1245 case PROPOSAL_STALE: 1246 rdns_proposal->timo.tv_sec = 0; /* remove immediately */ 1247 break; 1248 case PROPOSAL_DUPLICATED: 1249 fatalx("invalid rdns state: PROPOSAL_DUPLICATED"); 1250 break; 1251 } 1252 1253 if_name = if_indextoname(rdns_proposal->if_index, ifnamebuf); 1254 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ? 1255 "?" : if_name, proposal_state_name(old_state), 1256 proposal_state_name(new_state), 1257 rdns_proposal->timo.tv_sec); 1258 1259 if (rdns_proposal->timo.tv_sec == -1) { 1260 if (evtimer_pending(&rdns_proposal->timer, NULL)) 1261 evtimer_del(&rdns_proposal->timer); 1262 } else 1263 evtimer_add(&rdns_proposal->timer, &rdns_proposal->timo); 1264} 1265 1266void 1267request_solicitation(struct slaacd_iface *iface) 1268{ 1269 struct timespec now, diff, sol_delay = {RTR_SOLICITATION_INTERVAL, 0}; 1270 1271 clock_gettime(CLOCK_MONOTONIC, &now); 1272 timespecsub(&now, &iface->last_sol, &diff); 1273 if (timespeccmp(&diff, &sol_delay, <)) { 1274 log_debug("last solicitation less than %d seconds ago", 1275 RTR_SOLICITATION_INTERVAL); 1276 return; 1277 } 1278 1279 iface->last_sol = now; 1280 engine_imsg_compose_frontend(IMSG_CTL_SEND_SOLICITATION, 0, 1281 &iface->if_index, sizeof(iface->if_index)); 1282} 1283 1284void 1285engine_update_iface(struct imsg_ifinfo *imsg_ifinfo) 1286{ 1287 struct slaacd_iface *iface; 1288 int need_refresh = 0; 1289 1290 iface = get_slaacd_iface_by_id(imsg_ifinfo->if_index); 1291 if (iface == NULL) { 1292 if ((iface = calloc(1, sizeof(*iface))) == NULL) 1293 fatal("calloc"); 1294 iface->state = IF_DOWN; 1295 iface->timo.tv_usec = arc4random_uniform(1000000); 1296 evtimer_set(&iface->timer, iface_timeout, iface); 1297 iface->if_index = imsg_ifinfo->if_index; 1298 iface->rdomain = imsg_ifinfo->rdomain; 1299 iface->running = imsg_ifinfo->running; 1300 iface->link_state = imsg_ifinfo->link_state; 1301 iface->autoconf = imsg_ifinfo->autoconf; 1302 iface->temporary = imsg_ifinfo->temporary; 1303 iface->soii = imsg_ifinfo->soii; 1304 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address, 1305 sizeof(struct ether_addr)); 1306 memcpy(&iface->ll_address, &imsg_ifinfo->ll_address, 1307 sizeof(struct sockaddr_in6)); 1308 memcpy(iface->soiikey, imsg_ifinfo->soiikey, 1309 sizeof(iface->soiikey)); 1310 LIST_INIT(&iface->radvs); 1311 LIST_INSERT_HEAD(&slaacd_interfaces, iface, entries); 1312 LIST_INIT(&iface->addr_proposals); 1313 LIST_INIT(&iface->dfr_proposals); 1314 LIST_INIT(&iface->rdns_proposals); 1315 need_refresh = 1; 1316 } else { 1317 memcpy(&iface->ll_address, &imsg_ifinfo->ll_address, 1318 sizeof(struct sockaddr_in6)); 1319 1320 if (iface->autoconf != imsg_ifinfo->autoconf) { 1321 iface->autoconf = imsg_ifinfo->autoconf; 1322 need_refresh = 1; 1323 } 1324 1325 if (iface->temporary != imsg_ifinfo->temporary) { 1326 iface->temporary = imsg_ifinfo->temporary; 1327 need_refresh = 1; 1328 } 1329 1330 if (iface->soii != imsg_ifinfo->soii) { 1331 iface->soii = imsg_ifinfo->soii; 1332 need_refresh = 1; 1333 } 1334 1335 if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address, 1336 sizeof(struct ether_addr)) != 0) { 1337 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address, 1338 sizeof(struct ether_addr)); 1339 need_refresh = 1; 1340 } 1341 1342 if (memcmp(iface->soiikey, imsg_ifinfo->soiikey, 1343 sizeof(iface->soiikey)) != 0) { 1344 memcpy(iface->soiikey, imsg_ifinfo->soiikey, 1345 sizeof(iface->soiikey)); 1346 need_refresh = 1; 1347 } 1348 1349 if (imsg_ifinfo->running != iface->running) { 1350 iface->running = imsg_ifinfo->running; 1351 need_refresh = 1; 1352 } 1353 if (imsg_ifinfo->link_state != iface->link_state) { 1354 iface->link_state = imsg_ifinfo->link_state; 1355 need_refresh = 1; 1356 } 1357 } 1358 1359 if (!need_refresh) 1360 return; 1361 1362 if (iface->running && LINK_STATE_IS_UP(iface->link_state)) 1363 iface_state_transition(iface, IF_INIT); 1364 1365 else 1366 iface_state_transition(iface, IF_DOWN); 1367} 1368 1369void 1370parse_ra(struct slaacd_iface *iface, struct imsg_ra *ra) 1371{ 1372 struct icmp6_hdr *icmp6_hdr; 1373 struct nd_router_advert *nd_ra; 1374 struct radv *radv; 1375 struct radv_prefix *prefix; 1376 struct radv_rdns *rdns; 1377 ssize_t len = ra->len; 1378 const char *hbuf; 1379 uint8_t *p; 1380 1381#ifndef SMALL 1382 if (log_getverbose() > 1) 1383 debug_log_ra(ra); 1384#endif /* SMALL */ 1385 1386 hbuf = sin6_to_str(&ra->from); 1387 if ((size_t)len < sizeof(struct icmp6_hdr)) { 1388 log_warnx("received too short message (%ld) from %s", len, 1389 hbuf); 1390 return; 1391 } 1392 1393 p = ra->packet; 1394 icmp6_hdr = (struct icmp6_hdr *)p; 1395 if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT) 1396 return; 1397 1398 if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) { 1399 log_debug("RA from non link local address %s", hbuf); 1400 return; 1401 } 1402 1403 if ((size_t)len < sizeof(struct nd_router_advert)) { 1404 log_warnx("received too short message (%ld) from %s", len, 1405 hbuf); 1406 return; 1407 } 1408 1409 if ((radv = calloc(1, sizeof(*radv))) == NULL) 1410 fatal("calloc"); 1411 1412 LIST_INIT(&radv->prefixes); 1413 LIST_INIT(&radv->rdns_servers); 1414 1415 radv->min_lifetime = UINT32_MAX; 1416 1417 nd_ra = (struct nd_router_advert *)p; 1418 len -= sizeof(struct nd_router_advert); 1419 p += sizeof(struct nd_router_advert); 1420 1421 log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld", 1422 nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len); 1423 1424 if (nd_ra->nd_ra_code != 0) { 1425 log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code, 1426 hbuf); 1427 goto err; 1428 } 1429 1430 memcpy(&radv->from, &ra->from, sizeof(ra->from)); 1431 1432 if (clock_gettime(CLOCK_REALTIME, &radv->when)) 1433 fatal("clock_gettime"); 1434 if (clock_gettime(CLOCK_MONOTONIC, &radv->uptime)) 1435 fatal("clock_gettime"); 1436 1437 radv->curhoplimit = nd_ra->nd_ra_curhoplimit; 1438 radv->managed = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED; 1439 radv->other = nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER; 1440 1441 switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) { 1442 case ND_RA_FLAG_RTPREF_HIGH: 1443 radv->rpref=HIGH; 1444 break; 1445 case ND_RA_FLAG_RTPREF_LOW: 1446 radv->rpref=LOW; 1447 break; 1448 case ND_RA_FLAG_RTPREF_MEDIUM: 1449 /* fallthrough */ 1450 default: 1451 radv->rpref=MEDIUM; 1452 break; 1453 } 1454 radv->router_lifetime = ntohs(nd_ra->nd_ra_router_lifetime); 1455 if (radv->router_lifetime != 0) 1456 radv->min_lifetime = radv->router_lifetime; 1457 radv->reachable_time = ntohl(nd_ra->nd_ra_reachable); 1458 radv->retrans_time = ntohl(nd_ra->nd_ra_retransmit); 1459 1460 while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 1461 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 1462 struct nd_opt_prefix_info *prf; 1463 struct nd_opt_rdnss *rdnss; 1464 struct nd_opt_mtu *mtu; 1465 struct in6_addr *in6; 1466 int i; 1467 1468 len -= sizeof(struct nd_opt_hdr); 1469 p += sizeof(struct nd_opt_hdr); 1470 1471 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 1472 log_warnx("invalid option len: %u > %ld", 1473 nd_opt_hdr->nd_opt_len, len); 1474 goto err; 1475 } 1476 1477 switch (nd_opt_hdr->nd_opt_type) { 1478 case ND_OPT_PREFIX_INFORMATION: 1479 if (nd_opt_hdr->nd_opt_len != 4) { 1480 log_warnx("invalid ND_OPT_PREFIX_INFORMATION: " 1481 "len != 4"); 1482 goto err; 1483 } 1484 1485 if ((prefix = calloc(1, sizeof(*prefix))) == NULL) 1486 fatal("calloc"); 1487 1488 prf = (struct nd_opt_prefix_info*) nd_opt_hdr; 1489 prefix->prefix = prf->nd_opt_pi_prefix; 1490 prefix->prefix_len = prf->nd_opt_pi_prefix_len; 1491 prefix->onlink = prf->nd_opt_pi_flags_reserved & 1492 ND_OPT_PI_FLAG_ONLINK; 1493 prefix->autonomous = prf->nd_opt_pi_flags_reserved & 1494 ND_OPT_PI_FLAG_AUTO; 1495 prefix->vltime = ntohl(prf->nd_opt_pi_valid_time); 1496 prefix->pltime = ntohl(prf->nd_opt_pi_preferred_time); 1497 if (radv->min_lifetime > prefix->pltime) 1498 radv->min_lifetime = prefix->pltime; 1499 1500 LIST_INSERT_HEAD(&radv->prefixes, prefix, entries); 1501 1502 break; 1503 1504 case ND_OPT_RDNSS: 1505 if (nd_opt_hdr->nd_opt_len < 3) { 1506 log_warnx("invalid ND_OPT_RDNSS: len < 24"); 1507 goto err; 1508 } 1509 1510 if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) { 1511 log_warnx("invalid ND_OPT_RDNSS: length with" 1512 "out header is not multiply of 16: %d", 1513 (nd_opt_hdr->nd_opt_len - 1) * 8); 1514 goto err; 1515 } 1516 1517 rdnss = (struct nd_opt_rdnss*) nd_opt_hdr; 1518 1519 radv->rdns_lifetime = ntohl( 1520 rdnss->nd_opt_rdnss_lifetime); 1521 if (radv->min_lifetime > radv->rdns_lifetime) 1522 radv->min_lifetime = radv->rdns_lifetime; 1523 1524 in6 = (struct in6_addr*) (p + 6); 1525 for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++, 1526 in6++) { 1527 if((rdns = calloc(1, sizeof(*rdns))) == NULL) 1528 fatal("calloc"); 1529 memcpy(&rdns->rdns, in6, sizeof(rdns->rdns)); 1530 LIST_INSERT_HEAD(&radv->rdns_servers, rdns, 1531 entries); 1532 } 1533 break; 1534 case ND_OPT_MTU: 1535 if (nd_opt_hdr->nd_opt_len != 1) { 1536 log_warnx("invalid ND_OPT_MTU: len != 1"); 1537 goto err; 1538 } 1539 mtu = (struct nd_opt_mtu*) nd_opt_hdr; 1540 radv->mtu = ntohl(mtu->nd_opt_mtu_mtu); 1541 1542 /* path MTU cannot be less than IPV6_MMTU */ 1543 if (radv->mtu < IPV6_MMTU) { 1544 radv->mtu = 0; 1545 log_warnx("invalid advertised MTU"); 1546 } 1547 1548 break; 1549 case ND_OPT_DNSSL: 1550 case ND_OPT_REDIRECTED_HEADER: 1551 case ND_OPT_SOURCE_LINKADDR: 1552 case ND_OPT_TARGET_LINKADDR: 1553 case ND_OPT_ROUTE_INFO: 1554#if 0 1555 log_debug("\tOption: %u (len: %u) not implemented", 1556 nd_opt_hdr->nd_opt_type, nd_opt_hdr->nd_opt_len * 1557 8); 1558#endif 1559 break; 1560 default: 1561 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 1562 break; 1563 1564 } 1565 len -= nd_opt_hdr->nd_opt_len * 8 - 2; 1566 p += nd_opt_hdr->nd_opt_len * 8 - 2; 1567 } 1568 update_iface_ra(iface, radv); 1569 return; 1570 1571err: 1572 free_ra(radv); 1573} 1574 1575void 1576gen_addr(struct slaacd_iface *iface, struct radv_prefix *prefix, struct 1577 address_proposal *addr_proposal, int temporary) 1578{ 1579 SHA2_CTX ctx; 1580 struct in6_addr iid; 1581 int i; 1582 u_int8_t digest[SHA512_DIGEST_LENGTH]; 1583 1584 memset(&iid, 0, sizeof(iid)); 1585 1586 /* from in6_ifadd() in nd6_rtr.c */ 1587 /* XXX from in6.h, guarded by #ifdef _KERNEL XXX nonstandard */ 1588#define s6_addr32 __u6_addr.__u6_addr32 1589 1590 in6_prefixlen2mask(&addr_proposal->mask, addr_proposal->prefix_len); 1591 1592 memset(&addr_proposal->addr, 0, sizeof(addr_proposal->addr)); 1593 1594 addr_proposal->addr.sin6_family = AF_INET6; 1595 addr_proposal->addr.sin6_len = sizeof(addr_proposal->addr); 1596 1597 memcpy(&addr_proposal->addr.sin6_addr, &prefix->prefix, 1598 sizeof(addr_proposal->addr.sin6_addr)); 1599 1600 for (i = 0; i < 4; i++) 1601 addr_proposal->addr.sin6_addr.s6_addr32[i] &= 1602 addr_proposal->mask.s6_addr32[i]; 1603 1604 if (temporary) { 1605 arc4random_buf(&iid.s6_addr, sizeof(iid.s6_addr)); 1606 } else if (iface->soii) { 1607 SHA512Init(&ctx); 1608 SHA512Update(&ctx, &prefix->prefix, 1609 sizeof(prefix->prefix)); 1610 SHA512Update(&ctx, &iface->hw_address, 1611 sizeof(iface->hw_address)); 1612 SHA512Update(&ctx, &prefix->dad_counter, 1613 sizeof(prefix->dad_counter)); 1614 SHA512Update(&ctx, addr_proposal->soiikey, 1615 sizeof(addr_proposal->soiikey)); 1616 SHA512Final(digest, &ctx); 1617 1618 memcpy(&iid.s6_addr, digest + (sizeof(digest) - 1619 sizeof(iid.s6_addr)), sizeof(iid.s6_addr)); 1620 } else { 1621 /* This is safe, because we have a 64 prefix len */ 1622 memcpy(&iid.s6_addr, &iface->ll_address.sin6_addr, 1623 sizeof(iid.s6_addr)); 1624 } 1625 1626 for (i = 0; i < 4; i++) 1627 addr_proposal->addr.sin6_addr.s6_addr32[i] |= 1628 (iid.s6_addr32[i] & ~addr_proposal->mask.s6_addr32[i]); 1629#undef s6_addr32 1630} 1631 1632/* from sys/netinet6/in6.c */ 1633void 1634in6_prefixlen2mask(struct in6_addr *maskp, int len) 1635{ 1636 u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 1637 int bytelen, bitlen, i; 1638 1639 if (0 > len || len > 128) 1640 fatalx("%s: invalid prefix length(%d)\n", __func__, len); 1641 1642 bzero(maskp, sizeof(*maskp)); 1643 bytelen = len / 8; 1644 bitlen = len % 8; 1645 for (i = 0; i < bytelen; i++) 1646 maskp->s6_addr[i] = 0xff; 1647 /* len == 128 is ok because bitlen == 0 then */ 1648 if (bitlen) 1649 maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 1650} 1651 1652#ifndef SMALL 1653/* from kame via ifconfig, where it's called prefix() */ 1654int 1655in6_mask2prefixlen(struct in6_addr *in6) 1656{ 1657 u_char *nam = (u_char *)in6; 1658 int byte, bit, plen = 0, size = sizeof(struct in6_addr); 1659 1660 for (byte = 0; byte < size; byte++, plen += 8) 1661 if (nam[byte] != 0xff) 1662 break; 1663 if (byte == size) 1664 return (plen); 1665 for (bit = 7; bit != 0; bit--, plen++) 1666 if (!(nam[byte] & (1 << bit))) 1667 break; 1668 for (; bit != 0; bit--) 1669 if (nam[byte] & (1 << bit)) 1670 return (0); 1671 byte++; 1672 for (; byte < size; byte++) 1673 if (nam[byte]) 1674 return (0); 1675 return (plen); 1676} 1677 1678void 1679debug_log_ra(struct imsg_ra *ra) 1680{ 1681 struct nd_router_advert *nd_ra; 1682 ssize_t len = ra->len; 1683 char ntopbuf[INET6_ADDRSTRLEN]; 1684 const char *hbuf; 1685 uint8_t *p; 1686 1687 hbuf = sin6_to_str(&ra->from); 1688 1689 if (!IN6_IS_ADDR_LINKLOCAL(&ra->from.sin6_addr)) { 1690 log_warnx("RA from non link local address %s", hbuf); 1691 return; 1692 } 1693 1694 if ((size_t)len < sizeof(struct nd_router_advert)) { 1695 log_warnx("received too short message (%ld) from %s", len, 1696 hbuf); 1697 return; 1698 } 1699 1700 p = ra->packet; 1701 nd_ra = (struct nd_router_advert *)p; 1702 len -= sizeof(struct nd_router_advert); 1703 p += sizeof(struct nd_router_advert); 1704 1705 log_debug("ICMPv6 type(%d), code(%d) from %s of length %ld", 1706 nd_ra->nd_ra_type, nd_ra->nd_ra_code, hbuf, len); 1707 1708 if (nd_ra->nd_ra_type != ND_ROUTER_ADVERT) { 1709 log_warnx("invalid ICMPv6 type (%d) from %s", nd_ra->nd_ra_type, 1710 hbuf); 1711 return; 1712 } 1713 1714 if (nd_ra->nd_ra_code != 0) { 1715 log_warnx("invalid ICMPv6 code (%d) from %s", nd_ra->nd_ra_code, 1716 hbuf); 1717 return; 1718 } 1719 1720 log_debug("---"); 1721 log_debug("RA from %s", hbuf); 1722 log_debug("\tCur Hop Limit: %u", nd_ra->nd_ra_curhoplimit); 1723 log_debug("\tManaged address configuration: %d", 1724 (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? 1 : 0); 1725 log_debug("\tOther configuration: %d", 1726 (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? 1 : 0); 1727 switch (nd_ra->nd_ra_flags_reserved & ND_RA_FLAG_RTPREF_MASK) { 1728 case ND_RA_FLAG_RTPREF_HIGH: 1729 log_debug("\tRouter Preference: high"); 1730 break; 1731 case ND_RA_FLAG_RTPREF_MEDIUM: 1732 log_debug("\tRouter Preference: medium"); 1733 break; 1734 case ND_RA_FLAG_RTPREF_LOW: 1735 log_debug("\tRouter Preference: low"); 1736 break; 1737 case ND_RA_FLAG_RTPREF_RSV: 1738 log_debug("\tRouter Preference: reserved"); 1739 break; 1740 } 1741 log_debug("\tRouter Lifetime: %hds", 1742 ntohs(nd_ra->nd_ra_router_lifetime)); 1743 log_debug("\tReachable Time: %ums", ntohl(nd_ra->nd_ra_reachable)); 1744 log_debug("\tRetrans Timer: %ums", ntohl(nd_ra->nd_ra_retransmit)); 1745 1746 while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 1747 struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 1748 struct nd_opt_mtu *mtu; 1749 struct nd_opt_prefix_info *prf; 1750 struct nd_opt_rdnss *rdnss; 1751 struct in6_addr *in6; 1752 int i; 1753 1754 len -= sizeof(struct nd_opt_hdr); 1755 p += sizeof(struct nd_opt_hdr); 1756 if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 1757 log_warnx("invalid option len: %u > %ld", 1758 nd_opt_hdr->nd_opt_len, len); 1759 return; 1760 } 1761 log_debug("\tOption: %u (len: %u)", nd_opt_hdr->nd_opt_type, 1762 nd_opt_hdr->nd_opt_len * 8); 1763 switch (nd_opt_hdr->nd_opt_type) { 1764 case ND_OPT_SOURCE_LINKADDR: 1765 if (nd_opt_hdr->nd_opt_len == 1) 1766 log_debug("\t\tND_OPT_SOURCE_LINKADDR: " 1767 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 1768 p[0], p[1], p[2], p[3], p[4], p[5], p[6], 1769 p[7]); 1770 else 1771 log_debug("\t\tND_OPT_SOURCE_LINKADDR"); 1772 break; 1773 case ND_OPT_TARGET_LINKADDR: 1774 if (nd_opt_hdr->nd_opt_len == 1) 1775 log_debug("\t\tND_OPT_TARGET_LINKADDR: " 1776 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 1777 p[0], p[1], p[2], p[3], p[4], p[5], p[6], 1778 p[7]); 1779 else 1780 log_debug("\t\tND_OPT_TARGET_LINKADDR"); 1781 break; 1782 case ND_OPT_PREFIX_INFORMATION: 1783 if (nd_opt_hdr->nd_opt_len != 4) { 1784 log_warnx("invalid ND_OPT_PREFIX_INFORMATION: " 1785 "len != 4"); 1786 return; 1787 } 1788 prf = (struct nd_opt_prefix_info*) nd_opt_hdr; 1789 1790 log_debug("\t\tND_OPT_PREFIX_INFORMATION: %s/%u", 1791 inet_ntop(AF_INET6, &prf->nd_opt_pi_prefix, 1792 ntopbuf, INET6_ADDRSTRLEN), 1793 prf->nd_opt_pi_prefix_len); 1794 log_debug("\t\t\tOn-link: %d", 1795 prf->nd_opt_pi_flags_reserved & 1796 ND_OPT_PI_FLAG_ONLINK ? 1:0); 1797 log_debug("\t\t\tAutonomous address-configuration: %d", 1798 prf->nd_opt_pi_flags_reserved & 1799 ND_OPT_PI_FLAG_AUTO ? 1 : 0); 1800 log_debug("\t\t\tvltime: %u", 1801 ntohl(prf->nd_opt_pi_valid_time)); 1802 log_debug("\t\t\tpltime: %u", 1803 ntohl(prf->nd_opt_pi_preferred_time)); 1804 break; 1805 case ND_OPT_REDIRECTED_HEADER: 1806 log_debug("\t\tND_OPT_REDIRECTED_HEADER"); 1807 break; 1808 case ND_OPT_MTU: 1809 if (nd_opt_hdr->nd_opt_len != 1) { 1810 log_warnx("invalid ND_OPT_MTU: len != 1"); 1811 return; 1812 } 1813 mtu = (struct nd_opt_mtu*) nd_opt_hdr; 1814 log_debug("\t\tND_OPT_MTU: %u", 1815 ntohl(mtu->nd_opt_mtu_mtu)); 1816 break; 1817 case ND_OPT_ROUTE_INFO: 1818 log_debug("\t\tND_OPT_ROUTE_INFO"); 1819 break; 1820 case ND_OPT_RDNSS: 1821 if (nd_opt_hdr->nd_opt_len < 3) { 1822 log_warnx("invalid ND_OPT_RDNSS: len < 24"); 1823 return; 1824 } 1825 if ((nd_opt_hdr->nd_opt_len - 1) % 2 != 0) { 1826 log_warnx("invalid ND_OPT_RDNSS: length with" 1827 "out header is not multiply of 16: %d", 1828 (nd_opt_hdr->nd_opt_len - 1) * 8); 1829 return; 1830 } 1831 rdnss = (struct nd_opt_rdnss*) nd_opt_hdr; 1832 log_debug("\t\tND_OPT_RDNSS: lifetime: %u", ntohl( 1833 rdnss->nd_opt_rdnss_lifetime)); 1834 in6 = (struct in6_addr*) (p + 6); 1835 for (i=0; i < (nd_opt_hdr->nd_opt_len - 1)/2; i++, 1836 in6++) { 1837 log_debug("\t\t\t%s", inet_ntop(AF_INET6, in6, 1838 ntopbuf, INET6_ADDRSTRLEN)); 1839 } 1840 break; 1841 default: 1842 log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 1843 break; 1844 1845 } 1846 len -= nd_opt_hdr->nd_opt_len * 8 - 2; 1847 p += nd_opt_hdr->nd_opt_len * 8 - 2; 1848 } 1849} 1850#endif /* SMALL */ 1851 1852void update_iface_ra(struct slaacd_iface *iface, struct radv *ra) 1853{ 1854 struct radv *old_ra; 1855 struct radv_prefix *prefix; 1856 1857 if ((old_ra = find_ra(iface, &ra->from)) == NULL) 1858 LIST_INSERT_HEAD(&iface->radvs, ra, entries); 1859 else { 1860 LIST_REPLACE(old_ra, ra, entries); 1861 merge_dad_couters(old_ra, ra); 1862 free_ra(old_ra); 1863 } 1864 1865 update_iface_ra_dfr(iface, ra); 1866 1867 LIST_FOREACH(prefix, &ra->prefixes, entries) { 1868 if (!prefix->autonomous || prefix->vltime == 0 || 1869 prefix->pltime > prefix->vltime || 1870 IN6_IS_ADDR_LINKLOCAL(&prefix->prefix)) 1871 continue; 1872 update_iface_ra_prefix(iface, ra, prefix); 1873 } 1874 1875 update_iface_ra_rdns(iface, ra); 1876} 1877 1878void 1879update_iface_ra_dfr(struct slaacd_iface *iface, struct radv *ra) 1880{ 1881 struct dfr_proposal *dfr_proposal; 1882 1883 dfr_proposal = find_dfr_proposal_by_gw(iface, &ra->from); 1884 1885 if (ra->router_lifetime == 0) { 1886 free_dfr_proposal(dfr_proposal); 1887 return; 1888 } 1889 1890 if (!dfr_proposal) { 1891 /* new proposal */ 1892 gen_dfr_proposal(iface, ra); 1893 return; 1894 } 1895 1896 dfr_proposal->when = ra->when; 1897 dfr_proposal->uptime = ra->uptime; 1898 dfr_proposal->router_lifetime = ra->router_lifetime; 1899 1900 log_debug("%s, dfr state: %s, rl: %d", __func__, 1901 proposal_state_name(dfr_proposal->state), 1902 real_lifetime(&dfr_proposal->uptime, 1903 dfr_proposal->router_lifetime)); 1904 1905 switch (dfr_proposal->state) { 1906 case PROPOSAL_CONFIGURED: 1907 case PROPOSAL_NEARLY_EXPIRED: 1908 /* routes do not expire in the kernel, update timeout */ 1909 dfr_proposal_state_transition(dfr_proposal, 1910 PROPOSAL_CONFIGURED); 1911 break; 1912 case PROPOSAL_IF_DOWN: 1913 case PROPOSAL_WITHDRAWN: 1914 log_debug("updating dfr"); 1915 configure_dfr(dfr_proposal); 1916 break; 1917 default: 1918 log_debug("%s: iface %d: %s", __func__, iface->if_index, 1919 sin6_to_str(&dfr_proposal->addr)); 1920 break; 1921 } 1922} 1923 1924void 1925update_iface_ra_prefix(struct slaacd_iface *iface, struct radv *ra, 1926 struct radv_prefix *prefix) 1927{ 1928 struct address_proposal *addr_proposal; 1929 uint32_t pltime, vltime; 1930 int found, found_temporary, duplicate_found; 1931 1932 found = found_temporary = duplicate_found = 0; 1933 1934 if (!!iface->autoconf != !!iface->temporary) { 1935 struct address_proposal *tmp; 1936 /* 1937 * If only the autoconf or temporary flag is set, check if we 1938 * have the "other kind" of address configured and delete it. 1939 */ 1940 LIST_FOREACH_SAFE (addr_proposal, &iface->addr_proposals, 1941 entries, tmp) { 1942 if ((!addr_proposal->temporary && !iface->autoconf) || 1943 (addr_proposal->temporary && !iface->temporary)) 1944 free_address_proposal(addr_proposal); 1945 } 1946 } 1947 1948 LIST_FOREACH(addr_proposal, &iface->addr_proposals, entries) { 1949 if (prefix->prefix_len == addr_proposal-> prefix_len && 1950 memcmp(&prefix->prefix, &addr_proposal->prefix, 1951 sizeof(struct in6_addr)) != 0) 1952 continue; 1953 1954 if (memcmp(&addr_proposal->hw_address, 1955 &iface->hw_address, 1956 sizeof(addr_proposal->hw_address)) != 0) 1957 continue; 1958 1959 if (memcmp(&addr_proposal->soiikey, &iface->soiikey, 1960 sizeof(addr_proposal->soiikey)) != 0) 1961 continue; 1962 1963 if (addr_proposal->state == PROPOSAL_DUPLICATED) { 1964 duplicate_found = 1; 1965 continue; 1966 } 1967 1968 vltime = prefix->vltime; 1969 1970 if (addr_proposal->temporary) { 1971 struct timespec now; 1972 int64_t ltime, mtime; 1973 1974 if (clock_gettime(CLOCK_MONOTONIC, &now)) 1975 fatal("clock_gettime"); 1976 1977 mtime = addr_proposal->created.tv_sec + 1978 PRIV_PREFERRED_LIFETIME - 1979 addr_proposal->desync_factor; 1980 1981 ltime = MINIMUM(mtime, now.tv_sec + prefix->pltime) - 1982 now.tv_sec; 1983 1984 pltime = ltime > 0 ? ltime : 0; 1985 1986 ltime = MINIMUM(addr_proposal->created.tv_sec + 1987 PRIV_VALID_LIFETIME, now.tv_sec + vltime) - 1988 now.tv_sec; 1989 vltime = ltime > 0 ? ltime : 0; 1990 1991 if ((mtime - now.tv_sec) > PRIV_REGEN_ADVANCE) 1992 found_temporary = 1; 1993 } else { 1994 pltime = prefix->pltime; 1995 found = 1; 1996 } 1997 1998 addr_proposal->from = ra->from; 1999 addr_proposal->when = ra->when; 2000 addr_proposal->uptime = ra->uptime; 2001 2002 addr_proposal->vltime = vltime; 2003 addr_proposal->pltime = pltime; 2004 2005 if (ra->mtu == iface->cur_mtu) 2006 addr_proposal->mtu = 0; 2007 else { 2008 addr_proposal->mtu = ra->mtu; 2009 iface->cur_mtu = ra->mtu; 2010 } 2011 2012 log_debug("%s, addr state: %s", __func__, 2013 proposal_state_name(addr_proposal->state)); 2014 2015 switch (addr_proposal->state) { 2016 case PROPOSAL_CONFIGURED: 2017 case PROPOSAL_NEARLY_EXPIRED: 2018 case PROPOSAL_IF_DOWN: 2019 case PROPOSAL_WITHDRAWN: 2020 log_debug("updating address"); 2021 configure_address(addr_proposal); 2022 break; 2023 default: 2024 log_debug("%s: iface %d: %s", __func__, iface->if_index, 2025 sin6_to_str(&addr_proposal->addr)); 2026 break; 2027 } 2028 } 2029 2030 if (!found && iface->autoconf && duplicate_found && iface->soii) { 2031 prefix->dad_counter++; 2032 log_debug("%s dad_counter: %d", __func__, prefix->dad_counter); 2033 gen_address_proposal(iface, ra, prefix, 0); 2034 } else if (!found && iface->autoconf && (iface->soii || 2035 prefix->prefix_len <= 64)) 2036 /* new proposal */ 2037 gen_address_proposal(iface, ra, prefix, 0); 2038 2039 /* temporary addresses do not depend on eui64 */ 2040 if (!found_temporary && iface->temporary) { 2041 if (prefix->pltime >= PRIV_REGEN_ADVANCE) { 2042 /* new temporary proposal */ 2043 gen_address_proposal(iface, ra, prefix, 1); 2044 } else if (prefix->pltime > 0) { 2045 log_warnx("%s: pltime from %s is too small: %d < %d; " 2046 "not generating temporary address", __func__, 2047 sin6_to_str(&ra->from), prefix->pltime, 2048 PRIV_REGEN_ADVANCE); 2049 } 2050 } 2051} 2052 2053void 2054update_iface_ra_rdns(struct slaacd_iface *iface, struct radv *ra) 2055{ 2056 struct rdns_proposal *rdns_proposal; 2057 struct radv_rdns *radv_rdns; 2058 struct in6_addr rdns[MAX_RDNS_COUNT]; 2059 int rdns_count; 2060 2061 rdns_proposal = find_rdns_proposal_by_gw(iface, &ra->from); 2062 2063 if (!rdns_proposal) { 2064 /* new proposal */ 2065 if (!LIST_EMPTY(&ra->rdns_servers)) 2066 gen_rdns_proposal(iface, ra); 2067 return; 2068 } 2069 2070 rdns_count = 0; 2071 memset(&rdns, 0, sizeof(rdns)); 2072 LIST_FOREACH(radv_rdns, &ra->rdns_servers, entries) { 2073 memcpy(&rdns[rdns_count++], 2074 &radv_rdns->rdns, sizeof(struct in6_addr)); 2075 if (rdns_proposal->rdns_count == MAX_RDNS_COUNT) 2076 break; 2077 } 2078 2079 if (rdns_count == 0) { 2080 free_rdns_proposal(rdns_proposal); 2081 return; 2082 } 2083 2084 if (rdns_proposal->rdns_count != rdns_count || 2085 memcmp(&rdns_proposal->rdns, &rdns, sizeof(rdns)) != 0) { 2086 memcpy(&rdns_proposal->rdns, &rdns, sizeof(rdns)); 2087 rdns_proposal->rdns_count = rdns_count; 2088 rdns_proposal->state = PROPOSAL_NOT_CONFIGURED; 2089 } 2090 rdns_proposal->when = ra->when; 2091 rdns_proposal->uptime = ra->uptime; 2092 rdns_proposal->rdns_lifetime = ra->rdns_lifetime; 2093 2094 log_debug("%s, rdns state: %s, rl: %d", __func__, 2095 proposal_state_name(rdns_proposal->state), 2096 real_lifetime(&rdns_proposal->uptime, 2097 rdns_proposal->rdns_lifetime)); 2098 2099 switch (rdns_proposal->state) { 2100 case PROPOSAL_CONFIGURED: 2101 case PROPOSAL_NEARLY_EXPIRED: 2102 /* rdns are not expired by the kernel, update timeout */ 2103 rdns_proposal_state_transition(rdns_proposal, 2104 PROPOSAL_CONFIGURED); 2105 break; 2106 case PROPOSAL_IF_DOWN: 2107 case PROPOSAL_WITHDRAWN: 2108 case PROPOSAL_NOT_CONFIGURED: 2109 log_debug("updating rdns"); 2110 rdns_proposal_state_transition(rdns_proposal, 2111 PROPOSAL_CONFIGURED); 2112 compose_rdns_proposal(rdns_proposal->if_index, 2113 rdns_proposal->rdomain); 2114 break; 2115 default: 2116 log_debug("%s: iface %d: %s", __func__, iface->if_index, 2117 sin6_to_str(&rdns_proposal->from)); 2118 break; 2119 } 2120} 2121 2122 2123void 2124configure_address(struct address_proposal *addr_proposal) 2125{ 2126 struct imsg_configure_address address; 2127 struct slaacd_iface *iface; 2128 2129 log_debug("%s: %d", __func__, addr_proposal->if_index); 2130 2131 address.if_index = addr_proposal->if_index; 2132 memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr)); 2133 memcpy(&address.gw, &addr_proposal->from, sizeof(address.gw)); 2134 memcpy(&address.mask, &addr_proposal->mask, sizeof(address.mask)); 2135 address.vltime = addr_proposal->vltime; 2136 address.pltime = addr_proposal->pltime; 2137 address.temporary = addr_proposal->temporary; 2138 address.mtu = addr_proposal->mtu; 2139 2140 engine_imsg_compose_main(IMSG_CONFIGURE_ADDRESS, 0, &address, 2141 sizeof(address)); 2142 2143 if ((iface = get_slaacd_iface_by_id(addr_proposal->if_index)) != NULL) 2144 iface_state_transition(iface, IF_BOUND); 2145 addr_proposal_state_transition(addr_proposal, PROPOSAL_CONFIGURED); 2146} 2147 2148void 2149gen_address_proposal(struct slaacd_iface *iface, struct radv *ra, struct 2150 radv_prefix *prefix, int temporary) 2151{ 2152 struct address_proposal *addr_proposal; 2153 const char *hbuf; 2154 2155 if ((addr_proposal = calloc(1, sizeof(*addr_proposal))) == NULL) 2156 fatal("calloc"); 2157 addr_proposal->id = ++proposal_id; 2158 evtimer_set(&addr_proposal->timer, address_proposal_timeout, 2159 addr_proposal); 2160 addr_proposal->timo.tv_sec = 1; 2161 addr_proposal->timo.tv_usec = arc4random_uniform(1000000); 2162 addr_proposal->state = PROPOSAL_NOT_CONFIGURED; 2163 if (clock_gettime(CLOCK_MONOTONIC, &addr_proposal->created)) 2164 fatal("clock_gettime"); 2165 addr_proposal->when = ra->when; 2166 addr_proposal->uptime = ra->uptime; 2167 addr_proposal->if_index = iface->if_index; 2168 memcpy(&addr_proposal->from, &ra->from, 2169 sizeof(addr_proposal->from)); 2170 memcpy(&addr_proposal->hw_address, &iface->hw_address, 2171 sizeof(addr_proposal->hw_address)); 2172 memcpy(&addr_proposal->soiikey, &iface->soiikey, 2173 sizeof(addr_proposal->soiikey)); 2174 addr_proposal->temporary = temporary; 2175 memcpy(&addr_proposal->prefix, &prefix->prefix, 2176 sizeof(addr_proposal->prefix)); 2177 addr_proposal->prefix_len = prefix->prefix_len; 2178 2179 if (temporary) { 2180 addr_proposal->vltime = MINIMUM(prefix->vltime, 2181 PRIV_VALID_LIFETIME); 2182 addr_proposal->desync_factor = 2183 arc4random_uniform(PRIV_MAX_DESYNC_FACTOR); 2184 2185 addr_proposal->pltime = MINIMUM(prefix->pltime, 2186 PRIV_PREFERRED_LIFETIME - addr_proposal->desync_factor); 2187 } else { 2188 addr_proposal->vltime = prefix->vltime; 2189 addr_proposal->pltime = prefix->pltime; 2190 } 2191 2192 if (ra->mtu == iface->cur_mtu) 2193 addr_proposal->mtu = 0; 2194 else { 2195 addr_proposal->mtu = ra->mtu; 2196 iface->cur_mtu = ra->mtu; 2197 } 2198 2199 gen_addr(iface, prefix, addr_proposal, temporary); 2200 2201 LIST_INSERT_HEAD(&iface->addr_proposals, addr_proposal, entries); 2202 configure_address(addr_proposal); 2203 2204 hbuf = sin6_to_str(&addr_proposal->addr); 2205 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf); 2206} 2207 2208void 2209free_address_proposal(struct address_proposal *addr_proposal) 2210{ 2211 if (addr_proposal == NULL) 2212 return; 2213 2214 LIST_REMOVE(addr_proposal, entries); 2215 evtimer_del(&addr_proposal->timer); 2216 switch (addr_proposal->state) { 2217 case PROPOSAL_CONFIGURED: 2218 case PROPOSAL_NEARLY_EXPIRED: 2219 case PROPOSAL_STALE: 2220 withdraw_addr(addr_proposal); 2221 break; 2222 default: 2223 break; 2224 } 2225 free(addr_proposal); 2226} 2227 2228void 2229withdraw_addr(struct address_proposal *addr_proposal) 2230{ 2231 struct imsg_configure_address address; 2232 2233 log_debug("%s: %d", __func__, addr_proposal->if_index); 2234 memset(&address, 0, sizeof(address)); 2235 address.if_index = addr_proposal->if_index; 2236 memcpy(&address.addr, &addr_proposal->addr, sizeof(address.addr)); 2237 2238 engine_imsg_compose_main(IMSG_WITHDRAW_ADDRESS, 0, &address, 2239 sizeof(address)); 2240} 2241 2242void 2243gen_dfr_proposal(struct slaacd_iface *iface, struct radv *ra) 2244{ 2245 struct dfr_proposal *dfr_proposal; 2246 const char *hbuf; 2247 2248 if ((dfr_proposal = calloc(1, sizeof(*dfr_proposal))) == NULL) 2249 fatal("calloc"); 2250 dfr_proposal->id = ++proposal_id; 2251 evtimer_set(&dfr_proposal->timer, dfr_proposal_timeout, 2252 dfr_proposal); 2253 dfr_proposal->timo.tv_sec = 1; 2254 dfr_proposal->timo.tv_usec = arc4random_uniform(1000000); 2255 dfr_proposal->state = PROPOSAL_NOT_CONFIGURED; 2256 dfr_proposal->when = ra->when; 2257 dfr_proposal->uptime = ra->uptime; 2258 dfr_proposal->if_index = iface->if_index; 2259 dfr_proposal->rdomain = iface->rdomain; 2260 memcpy(&dfr_proposal->addr, &ra->from, 2261 sizeof(dfr_proposal->addr)); 2262 dfr_proposal->router_lifetime = ra->router_lifetime; 2263 dfr_proposal->rpref = ra->rpref; 2264 2265 LIST_INSERT_HEAD(&iface->dfr_proposals, dfr_proposal, entries); 2266 configure_dfr(dfr_proposal); 2267 2268 hbuf = sin6_to_str(&dfr_proposal->addr); 2269 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf); 2270} 2271 2272void 2273configure_dfr(struct dfr_proposal *dfr_proposal) 2274{ 2275 struct imsg_configure_dfr dfr; 2276 2277 log_debug("%s: %d", __func__, dfr_proposal->if_index); 2278 2279 dfr.if_index = dfr_proposal->if_index; 2280 dfr.rdomain = dfr_proposal->rdomain; 2281 memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr)); 2282 dfr.router_lifetime = dfr_proposal->router_lifetime; 2283 2284 engine_imsg_compose_main(IMSG_CONFIGURE_DFR, 0, &dfr, sizeof(dfr)); 2285 2286 dfr_proposal_state_transition(dfr_proposal, PROPOSAL_CONFIGURED); 2287} 2288 2289void 2290withdraw_dfr(struct dfr_proposal *dfr_proposal) 2291{ 2292 struct imsg_configure_dfr dfr; 2293 2294 log_debug("%s: %d", __func__, dfr_proposal->if_index); 2295 2296 dfr.if_index = dfr_proposal->if_index; 2297 dfr.rdomain = dfr_proposal->rdomain; 2298 memcpy(&dfr.addr, &dfr_proposal->addr, sizeof(dfr.addr)); 2299 dfr.router_lifetime = dfr_proposal->router_lifetime; 2300 2301 engine_imsg_compose_main(IMSG_WITHDRAW_DFR, 0, &dfr, sizeof(dfr)); 2302} 2303 2304void 2305free_dfr_proposal(struct dfr_proposal *dfr_proposal) 2306{ 2307 if (dfr_proposal == NULL) 2308 return; 2309 2310 LIST_REMOVE(dfr_proposal, entries); 2311 evtimer_del(&dfr_proposal->timer); 2312 switch (dfr_proposal->state) { 2313 case PROPOSAL_CONFIGURED: 2314 case PROPOSAL_NEARLY_EXPIRED: 2315 case PROPOSAL_STALE: 2316 withdraw_dfr(dfr_proposal); 2317 break; 2318 default: 2319 break; 2320 } 2321 free(dfr_proposal); 2322} 2323 2324void 2325gen_rdns_proposal(struct slaacd_iface *iface, struct radv *ra) 2326{ 2327 struct rdns_proposal *rdns_proposal; 2328 struct radv_rdns *rdns; 2329 const char *hbuf; 2330 2331 if ((rdns_proposal = calloc(1, sizeof(*rdns_proposal))) == NULL) 2332 fatal("calloc"); 2333 rdns_proposal->id = ++proposal_id; 2334 evtimer_set(&rdns_proposal->timer, rdns_proposal_timeout, 2335 rdns_proposal); 2336 rdns_proposal->timo.tv_sec = 1; 2337 rdns_proposal->timo.tv_usec = arc4random_uniform(1000000); 2338 rdns_proposal->state = PROPOSAL_NOT_CONFIGURED; 2339 rdns_proposal->when = ra->when; 2340 rdns_proposal->uptime = ra->uptime; 2341 rdns_proposal->if_index = iface->if_index; 2342 rdns_proposal->rdomain = iface->rdomain; 2343 memcpy(&rdns_proposal->from, &ra->from, 2344 sizeof(rdns_proposal->from)); 2345 rdns_proposal->rdns_lifetime = ra->rdns_lifetime; 2346 LIST_FOREACH(rdns, &ra->rdns_servers, entries) { 2347 memcpy(&rdns_proposal->rdns[rdns_proposal->rdns_count++], 2348 &rdns->rdns, sizeof(struct in6_addr)); 2349 if (rdns_proposal->rdns_count == MAX_RDNS_COUNT) 2350 break; 2351 } 2352 2353 LIST_INSERT_HEAD(&iface->rdns_proposals, rdns_proposal, entries); 2354 compose_rdns_proposal(iface->if_index, iface->rdomain); 2355 2356 hbuf = sin6_to_str(&rdns_proposal->from); 2357 log_debug("%s: iface %d: %s", __func__, iface->if_index, hbuf); 2358} 2359 2360void 2361compose_rdns_proposal(uint32_t if_index, int rdomain) 2362{ 2363 struct imsg_propose_rdns rdns; 2364 struct slaacd_iface *iface; 2365 struct rdns_proposal *rdns_proposal; 2366 int i; 2367 2368 memset(&rdns, 0, sizeof(rdns)); 2369 rdns.if_index = if_index; 2370 rdns.rdomain = rdomain; 2371 2372 if ((iface = get_slaacd_iface_by_id(if_index)) != NULL) { 2373 LIST_FOREACH(rdns_proposal, &iface->rdns_proposals, entries) { 2374 if (rdns_proposal->state == PROPOSAL_WITHDRAWN || 2375 rdns_proposal->state == PROPOSAL_STALE) 2376 continue; 2377 rdns_proposal_state_transition(rdns_proposal, 2378 PROPOSAL_CONFIGURED); 2379 for (i = 0; i < rdns_proposal->rdns_count && 2380 rdns.rdns_count < MAX_RDNS_COUNT; i++) { 2381 rdns.rdns[rdns.rdns_count++] = 2382 rdns_proposal->rdns[i]; 2383 } 2384 } 2385 } 2386 2387 engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &rdns, sizeof(rdns)); 2388} 2389 2390void 2391free_rdns_proposal(struct rdns_proposal *rdns_proposal) 2392{ 2393 if (rdns_proposal == NULL) 2394 return; 2395 2396 LIST_REMOVE(rdns_proposal, entries); 2397 evtimer_del(&rdns_proposal->timer); 2398 switch (rdns_proposal->state) { 2399 case PROPOSAL_CONFIGURED: 2400 case PROPOSAL_NEARLY_EXPIRED: 2401 case PROPOSAL_STALE: 2402 withdraw_rdns(rdns_proposal); 2403 break; 2404 default: 2405 break; 2406 } 2407 free(rdns_proposal); 2408} 2409 2410void 2411withdraw_rdns(struct rdns_proposal *rdns_proposal) 2412{ 2413 log_debug("%s: %d", __func__, rdns_proposal->if_index); 2414 2415 rdns_proposal->state = PROPOSAL_WITHDRAWN; 2416 2417 /* we have to re-propose all rdns servers, minus one */ 2418 compose_rdns_proposal(rdns_proposal->if_index, rdns_proposal->rdomain); 2419} 2420 2421void 2422address_proposal_timeout(int fd, short events, void *arg) 2423{ 2424 struct address_proposal *addr_proposal; 2425 struct slaacd_iface *iface = NULL; 2426 struct radv *ra = NULL; 2427 struct radv_prefix *prefix = NULL; 2428 const char *hbuf; 2429 2430 addr_proposal = (struct address_proposal *)arg; 2431 2432 hbuf = sin6_to_str(&addr_proposal->addr); 2433 log_debug("%s: iface %d: %s [%s], priv: %s", __func__, 2434 addr_proposal->if_index, hbuf, 2435 proposal_state_name(addr_proposal->state), 2436 addr_proposal->temporary ? "y" : "n"); 2437 2438 switch (addr_proposal->state) { 2439 case PROPOSAL_IF_DOWN: 2440 addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE); 2441 break; 2442 case PROPOSAL_CONFIGURED: 2443 addr_proposal_state_transition(addr_proposal, 2444 PROPOSAL_NEARLY_EXPIRED); 2445 break; 2446 case PROPOSAL_NEARLY_EXPIRED: 2447 if (real_lifetime(&addr_proposal->uptime, 2448 addr_proposal->vltime) > 0) 2449 addr_proposal_state_transition(addr_proposal, 2450 PROPOSAL_NEARLY_EXPIRED); 2451 else 2452 addr_proposal_state_transition(addr_proposal, 2453 PROPOSAL_STALE); 2454 break; 2455 case PROPOSAL_DUPLICATED: 2456 iface = get_slaacd_iface_by_id(addr_proposal->if_index); 2457 if (iface != NULL) 2458 ra = find_ra(iface, &addr_proposal->from); 2459 if (ra != NULL) 2460 prefix = find_prefix(ra, &addr_proposal->prefix, 2461 addr_proposal->prefix_len); 2462 if (prefix != NULL) { 2463 if (!addr_proposal->temporary) { 2464 prefix->dad_counter++; 2465 gen_address_proposal(iface, ra, prefix, 0); 2466 } else 2467 gen_address_proposal(iface, ra, prefix, 1); 2468 } 2469 addr_proposal_state_transition(addr_proposal, PROPOSAL_STALE); 2470 break; 2471 case PROPOSAL_STALE: 2472 free_address_proposal(addr_proposal); 2473 addr_proposal = NULL; 2474 break; 2475 case PROPOSAL_WITHDRAWN: 2476 free_address_proposal(addr_proposal); 2477 addr_proposal = NULL; 2478 break; 2479 default: 2480 log_debug("%s: unhandled state: %s", __func__, 2481 proposal_state_name(addr_proposal->state)); 2482 } 2483} 2484 2485void 2486dfr_proposal_timeout(int fd, short events, void *arg) 2487{ 2488 struct dfr_proposal *dfr_proposal; 2489 const char *hbuf; 2490 2491 dfr_proposal = (struct dfr_proposal *)arg; 2492 2493 hbuf = sin6_to_str(&dfr_proposal->addr); 2494 log_debug("%s: iface %d: %s [%s]", __func__, dfr_proposal->if_index, 2495 hbuf, proposal_state_name(dfr_proposal->state)); 2496 2497 switch (dfr_proposal->state) { 2498 case PROPOSAL_IF_DOWN: 2499 dfr_proposal_state_transition(dfr_proposal, PROPOSAL_STALE); 2500 break; 2501 case PROPOSAL_CONFIGURED: 2502 dfr_proposal_state_transition(dfr_proposal, 2503 PROPOSAL_NEARLY_EXPIRED); 2504 break; 2505 case PROPOSAL_NEARLY_EXPIRED: 2506 if (real_lifetime(&dfr_proposal->uptime, 2507 dfr_proposal->router_lifetime) > 0) 2508 dfr_proposal_state_transition(dfr_proposal, 2509 PROPOSAL_NEARLY_EXPIRED); 2510 else 2511 dfr_proposal_state_transition(dfr_proposal, 2512 PROPOSAL_STALE); 2513 break; 2514 case PROPOSAL_STALE: 2515 free_dfr_proposal(dfr_proposal); 2516 dfr_proposal = NULL; 2517 break; 2518 case PROPOSAL_WITHDRAWN: 2519 free_dfr_proposal(dfr_proposal); 2520 dfr_proposal = NULL; 2521 break; 2522 2523 default: 2524 log_debug("%s: unhandled state: %s", __func__, 2525 proposal_state_name(dfr_proposal->state)); 2526 } 2527} 2528 2529void 2530rdns_proposal_timeout(int fd, short events, void *arg) 2531{ 2532 struct rdns_proposal *rdns_proposal; 2533 const char *hbuf; 2534 2535 rdns_proposal = (struct rdns_proposal *)arg; 2536 2537 hbuf = sin6_to_str(&rdns_proposal->from); 2538 log_debug("%s: iface %d: %s [%s]", __func__, rdns_proposal->if_index, 2539 hbuf, proposal_state_name(rdns_proposal->state)); 2540 2541 switch (rdns_proposal->state) { 2542 case PROPOSAL_IF_DOWN: 2543 rdns_proposal_state_transition(rdns_proposal, PROPOSAL_STALE); 2544 break; 2545 case PROPOSAL_CONFIGURED: 2546 rdns_proposal_state_transition(rdns_proposal, 2547 PROPOSAL_NEARLY_EXPIRED); 2548 break; 2549 case PROPOSAL_NEARLY_EXPIRED: 2550 if (real_lifetime(&rdns_proposal->uptime, 2551 rdns_proposal->rdns_lifetime) > 0) 2552 rdns_proposal_state_transition(rdns_proposal, 2553 PROPOSAL_NEARLY_EXPIRED); 2554 else 2555 rdns_proposal_state_transition(rdns_proposal, 2556 PROPOSAL_STALE); 2557 break; 2558 case PROPOSAL_STALE: 2559 free_rdns_proposal(rdns_proposal); 2560 rdns_proposal = NULL; 2561 break; 2562 case PROPOSAL_WITHDRAWN: 2563 free_rdns_proposal(rdns_proposal); 2564 rdns_proposal = NULL; 2565 break; 2566 2567 default: 2568 log_debug("%s: unhandled state: %s", __func__, 2569 proposal_state_name(rdns_proposal->state)); 2570 } 2571} 2572 2573void 2574iface_timeout(int fd, short events, void *arg) 2575{ 2576 struct slaacd_iface *iface = (struct slaacd_iface *)arg; 2577 2578 log_debug("%s[%d]: %s", __func__, iface->if_index, 2579 if_state_name(iface->state)); 2580 2581 switch (iface->state) { 2582 case IF_DOWN: 2583 fatalx("%s: timeout in wrong state IF_DOWN", __func__); 2584 break; 2585 case IF_INIT: 2586 iface_state_transition(iface, IF_INIT); 2587 break; 2588 default: 2589 break; 2590 } 2591} 2592 2593struct radv* 2594find_ra(struct slaacd_iface *iface, struct sockaddr_in6 *from) 2595{ 2596 struct radv *ra; 2597 2598 LIST_FOREACH (ra, &iface->radvs, entries) { 2599 if (memcmp(&ra->from.sin6_addr, &from->sin6_addr, 2600 sizeof(from->sin6_addr)) == 0) 2601 return (ra); 2602 } 2603 2604 return (NULL); 2605} 2606 2607struct address_proposal* 2608find_address_proposal_by_addr(struct slaacd_iface *iface, struct sockaddr_in6 2609 *addr) 2610{ 2611 struct address_proposal *addr_proposal; 2612 2613 LIST_FOREACH (addr_proposal, &iface->addr_proposals, entries) { 2614 if (memcmp(&addr_proposal->addr, addr, sizeof(*addr)) == 0) 2615 return (addr_proposal); 2616 } 2617 2618 return (NULL); 2619} 2620 2621struct dfr_proposal* 2622find_dfr_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6 2623 *addr) 2624{ 2625 struct dfr_proposal *dfr_proposal; 2626 2627 LIST_FOREACH (dfr_proposal, &iface->dfr_proposals, entries) { 2628 if (memcmp(&dfr_proposal->addr, addr, sizeof(*addr)) == 0) 2629 return (dfr_proposal); 2630 } 2631 2632 return (NULL); 2633} 2634 2635struct rdns_proposal* 2636find_rdns_proposal_by_gw(struct slaacd_iface *iface, struct sockaddr_in6 2637 *from) 2638{ 2639 struct rdns_proposal *rdns_proposal; 2640 2641 LIST_FOREACH (rdns_proposal, &iface->rdns_proposals, entries) { 2642 if (memcmp(&rdns_proposal->from, from, sizeof(*from)) == 0) 2643 return (rdns_proposal); 2644 } 2645 2646 return (NULL); 2647} 2648 2649struct radv_prefix * 2650find_prefix(struct radv *ra, struct in6_addr *prefix, uint8_t prefix_len) 2651{ 2652 struct radv_prefix *result; 2653 2654 2655 LIST_FOREACH(result, &ra->prefixes, entries) { 2656 if (memcmp(&result->prefix, prefix, 2657 sizeof(result->prefix)) == 0 && result->prefix_len == 2658 prefix_len) 2659 return (result); 2660 } 2661 return (NULL); 2662} 2663 2664uint32_t 2665real_lifetime(struct timespec *received_uptime, uint32_t ltime) 2666{ 2667 struct timespec now, diff; 2668 int64_t remaining; 2669 2670 if (clock_gettime(CLOCK_MONOTONIC, &now)) 2671 fatal("clock_gettime"); 2672 2673 timespecsub(&now, received_uptime, &diff); 2674 2675 remaining = ((int64_t)ltime) - diff.tv_sec; 2676 2677 if (remaining < 0) 2678 remaining = 0; 2679 2680 return (remaining); 2681} 2682 2683void 2684merge_dad_couters(struct radv *old_ra, struct radv *new_ra) 2685{ 2686 2687 struct radv_prefix *old_prefix, *new_prefix; 2688 2689 LIST_FOREACH(old_prefix, &old_ra->prefixes, entries) { 2690 if (!old_prefix->dad_counter) 2691 continue; 2692 if ((new_prefix = find_prefix(new_ra, &old_prefix->prefix, 2693 old_prefix->prefix_len)) != NULL) 2694 new_prefix->dad_counter = old_prefix->dad_counter; 2695 } 2696} 2697