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