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