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