1 /* $OpenBSD: slaacd.c,v 1.65 2022/07/12 16:54:59 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 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 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/syslog.h> 26 #include <sys/sysctl.h> 27 #include <sys/uio.h> 28 #include <sys/wait.h> 29 30 #include <net/if.h> 31 #include <net/route.h> 32 #include <netinet/in.h> 33 #include <netinet/if_ether.h> 34 #include <netinet6/in6_var.h> 35 #include <netinet/icmp6.h> 36 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <event.h> 41 #include <imsg.h> 42 #include <netdb.h> 43 #include <pwd.h> 44 #include <stddef.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <signal.h> 49 #include <unistd.h> 50 51 #include "log.h" 52 #include "slaacd.h" 53 #include "frontend.h" 54 #include "engine.h" 55 #include "control.h" 56 57 enum slaacd_process { 58 PROC_MAIN, 59 PROC_ENGINE, 60 PROC_FRONTEND 61 }; 62 63 __dead void usage(void); 64 __dead void main_shutdown(void); 65 66 void main_sig_handler(int, short, void *); 67 68 static pid_t start_child(enum slaacd_process, char *, int, int, int); 69 70 void main_dispatch_frontend(int, short, void *); 71 void main_dispatch_engine(int, short, void *); 72 void open_icmp6sock(int); 73 void configure_interface(struct imsg_configure_address *); 74 void delete_address(struct imsg_configure_address *); 75 void configure_gateway(struct imsg_configure_dfr *, uint8_t); 76 void add_gateway(struct imsg_configure_dfr *); 77 void delete_gateway(struct imsg_configure_dfr *); 78 void send_rdns_proposal(struct imsg_propose_rdns *); 79 int get_soiikey(uint8_t *); 80 81 static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 82 int main_imsg_compose_frontend(int, int, void *, uint16_t); 83 int main_imsg_compose_engine(int, pid_t, void *, uint16_t); 84 85 static struct imsgev *iev_frontend; 86 static struct imsgev *iev_engine; 87 88 pid_t frontend_pid; 89 pid_t engine_pid; 90 91 int routesock, ioctl_sock, rtm_seq = 0; 92 93 void 94 main_sig_handler(int sig, short event, void *arg) 95 { 96 /* 97 * Normal signal handler rules don't apply because libevent 98 * decouples for us. 99 */ 100 101 switch (sig) { 102 case SIGTERM: 103 case SIGINT: 104 main_shutdown(); 105 default: 106 fatalx("unexpected signal"); 107 } 108 } 109 110 __dead void 111 usage(void) 112 { 113 extern char *__progname; 114 115 fprintf(stderr, "usage: %s [-dv] [-s socket]\n", 116 __progname); 117 exit(1); 118 } 119 120 int 121 main(int argc, char *argv[]) 122 { 123 struct event ev_sigint, ev_sigterm; 124 int ch; 125 int debug = 0, engine_flag = 0, frontend_flag = 0; 126 int verbose = 0; 127 char *saved_argv0; 128 int pipe_main2frontend[2]; 129 int pipe_main2engine[2]; 130 int frontend_routesock, rtfilter, lockfd; 131 int rtable_any = RTABLE_ANY; 132 char *csock = _PATH_SLAACD_SOCKET; 133 struct imsg_propose_rdns rdns; 134 #ifndef SMALL 135 int control_fd; 136 #endif /* SMALL */ 137 138 log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 139 log_setverbose(1); 140 141 saved_argv0 = argv[0]; 142 if (saved_argv0 == NULL) 143 saved_argv0 = "slaacd"; 144 145 while ((ch = getopt(argc, argv, "dEFs:v")) != -1) { 146 switch (ch) { 147 case 'd': 148 debug = 1; 149 break; 150 case 'E': 151 engine_flag = 1; 152 break; 153 case 'F': 154 frontend_flag = 1; 155 break; 156 case 's': 157 csock = optarg; 158 break; 159 case 'v': 160 verbose++; 161 break; 162 default: 163 usage(); 164 } 165 } 166 167 argc -= optind; 168 argv += optind; 169 if (argc > 0 || (engine_flag && frontend_flag)) 170 usage(); 171 172 if (engine_flag) 173 engine(debug, verbose); 174 else if (frontend_flag) 175 frontend(debug, verbose); 176 177 /* Check for root privileges. */ 178 if (geteuid()) 179 errx(1, "need root privileges"); 180 181 lockfd = open(_PATH_LOCKFILE, O_CREAT|O_RDWR|O_EXLOCK|O_NONBLOCK, 0600); 182 if (lockfd == -1) 183 errx(1, "already running"); 184 185 /* Check for assigned daemon user */ 186 if (getpwnam(SLAACD_USER) == NULL) 187 errx(1, "unknown user %s", SLAACD_USER); 188 189 log_init(debug, LOG_DAEMON); 190 log_setverbose(verbose); 191 192 if (!debug) 193 daemon(0, 0); 194 195 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 196 PF_UNSPEC, pipe_main2frontend) == -1) 197 fatal("main2frontend socketpair"); 198 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 199 PF_UNSPEC, pipe_main2engine) == -1) 200 fatal("main2engine socketpair"); 201 202 /* Start children. */ 203 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], 204 debug, verbose); 205 frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 206 pipe_main2frontend[1], debug, verbose); 207 208 log_procinit("main"); 209 210 if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 211 SOCK_NONBLOCK, AF_INET6)) == -1) 212 fatal("route socket"); 213 shutdown(SHUT_RD, routesock); 214 215 event_init(); 216 217 /* Setup signal handler. */ 218 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 219 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 220 signal_add(&ev_sigint, NULL); 221 signal_add(&ev_sigterm, NULL); 222 signal(SIGPIPE, SIG_IGN); 223 signal(SIGHUP, SIG_IGN); 224 225 /* Setup pipes to children. */ 226 227 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 228 (iev_engine = malloc(sizeof(struct imsgev))) == NULL) 229 fatal(NULL); 230 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 231 iev_frontend->handler = main_dispatch_frontend; 232 imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); 233 iev_engine->handler = main_dispatch_engine; 234 235 /* Setup event handlers for pipes to engine & frontend. */ 236 iev_frontend->events = EV_READ; 237 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 238 iev_frontend->events, iev_frontend->handler, iev_frontend); 239 event_add(&iev_frontend->ev, NULL); 240 241 iev_engine->events = EV_READ; 242 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, 243 iev_engine->handler, iev_engine); 244 event_add(&iev_engine->ev, NULL); 245 246 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) 247 fatal("could not establish imsg links"); 248 249 if ((ioctl_sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 250 fatal("socket"); 251 252 if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 253 AF_INET6)) == -1) 254 fatal("route socket"); 255 256 rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | 257 ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_DELETE) | 258 ROUTE_FILTER(RTM_CHGADDRATTR) | ROUTE_FILTER(RTM_PROPOSAL) | 259 ROUTE_FILTER(RTM_IFANNOUNCE); 260 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 261 &rtfilter, sizeof(rtfilter)) == -1) 262 fatal("setsockopt(ROUTE_MSGFILTER)"); 263 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER, 264 &rtable_any, sizeof(rtable_any)) == -1) 265 fatal("setsockopt(ROUTE_TABLEFILTER)"); 266 267 #ifndef SMALL 268 if ((control_fd = control_init(csock)) == -1) 269 warnx("control socket setup failed"); 270 #endif /* SMALL */ 271 272 if (pledge("stdio inet sendfd wroute", NULL) == -1) 273 fatal("pledge"); 274 275 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0); 276 277 #ifndef SMALL 278 if (control_fd != -1) 279 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0); 280 #endif /* SMALL */ 281 282 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0); 283 284 /* we are taking over, clear all previos slaac proposals */ 285 memset(&rdns, 0, sizeof(rdns)); 286 rdns.if_index = 0; 287 rdns.rdns_count = 0; 288 send_rdns_proposal(&rdns); 289 290 event_dispatch(); 291 292 main_shutdown(); 293 return (0); 294 } 295 296 __dead void 297 main_shutdown(void) 298 { 299 pid_t pid; 300 int status; 301 302 /* Close pipes. */ 303 msgbuf_clear(&iev_frontend->ibuf.w); 304 close(iev_frontend->ibuf.fd); 305 msgbuf_clear(&iev_engine->ibuf.w); 306 close(iev_engine->ibuf.fd); 307 308 log_debug("waiting for children to terminate"); 309 do { 310 pid = wait(&status); 311 if (pid == -1) { 312 if (errno != EINTR && errno != ECHILD) 313 fatal("wait"); 314 } else if (WIFSIGNALED(status)) 315 log_warnx("%s terminated; signal %d", 316 (pid == engine_pid) ? "engine" : 317 "frontend", WTERMSIG(status)); 318 } while (pid != -1 || (pid == -1 && errno == EINTR)); 319 320 free(iev_frontend); 321 free(iev_engine); 322 323 log_info("terminating"); 324 exit(0); 325 } 326 327 static pid_t 328 start_child(enum slaacd_process p, char *argv0, int fd, int debug, int verbose) 329 { 330 char *argv[7]; 331 int argc = 0; 332 pid_t pid; 333 334 switch (pid = fork()) { 335 case -1: 336 fatal("cannot fork"); 337 case 0: 338 break; 339 default: 340 close(fd); 341 return (pid); 342 } 343 344 if (fd != 3) { 345 if (dup2(fd, 3) == -1) 346 fatal("cannot setup imsg fd"); 347 } else if (fcntl(fd, F_SETFD, 0) == -1) 348 fatal("cannot setup imsg fd"); 349 350 argv[argc++] = argv0; 351 switch (p) { 352 case PROC_MAIN: 353 fatalx("Can not start main process"); 354 case PROC_ENGINE: 355 argv[argc++] = "-E"; 356 break; 357 case PROC_FRONTEND: 358 argv[argc++] = "-F"; 359 break; 360 } 361 if (debug) 362 argv[argc++] = "-d"; 363 if (verbose) 364 argv[argc++] = "-v"; 365 if (verbose > 1) 366 argv[argc++] = "-v"; 367 argv[argc++] = NULL; 368 369 execvp(argv0, argv); 370 fatal("execvp"); 371 } 372 373 void 374 main_dispatch_frontend(int fd, short event, void *bula) 375 { 376 struct imsgev *iev = bula; 377 struct imsgbuf *ibuf; 378 struct imsg imsg; 379 struct imsg_ifinfo imsg_ifinfo; 380 ssize_t n; 381 int shut = 0; 382 int rdomain; 383 #ifndef SMALL 384 int verbose; 385 #endif /* SMALL */ 386 387 ibuf = &iev->ibuf; 388 389 if (event & EV_READ) { 390 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 391 fatal("imsg_read error"); 392 if (n == 0) /* Connection closed. */ 393 shut = 1; 394 } 395 if (event & EV_WRITE) { 396 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 397 fatal("msgbuf_write"); 398 if (n == 0) /* Connection closed. */ 399 shut = 1; 400 } 401 402 for (;;) { 403 if ((n = imsg_get(ibuf, &imsg)) == -1) 404 fatal("imsg_get"); 405 if (n == 0) /* No more messages. */ 406 break; 407 408 switch (imsg.hdr.type) { 409 case IMSG_OPEN_ICMP6SOCK: 410 log_debug("IMSG_OPEN_ICMP6SOCK"); 411 if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) 412 fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: " 413 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 414 memcpy(&rdomain, imsg.data, sizeof(rdomain)); 415 open_icmp6sock(rdomain); 416 break; 417 #ifndef SMALL 418 case IMSG_CTL_LOG_VERBOSE: 419 if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 420 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 421 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 422 memcpy(&verbose, imsg.data, sizeof(verbose)); 423 log_setverbose(verbose); 424 break; 425 #endif /* SMALL */ 426 case IMSG_UPDATE_IF: 427 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo)) 428 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 429 __func__, IMSG_DATA_SIZE(imsg)); 430 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); 431 if (get_soiikey(imsg_ifinfo.soiikey) == -1) 432 log_warn("get_soiikey"); 433 else 434 main_imsg_compose_engine(IMSG_UPDATE_IF, 0, 435 &imsg_ifinfo, sizeof(imsg_ifinfo)); 436 break; 437 default: 438 log_debug("%s: error handling imsg %d", __func__, 439 imsg.hdr.type); 440 break; 441 } 442 imsg_free(&imsg); 443 } 444 if (!shut) 445 imsg_event_add(iev); 446 else { 447 /* This pipe is dead. Remove its event handler */ 448 event_del(&iev->ev); 449 event_loopexit(NULL); 450 } 451 } 452 453 void 454 main_dispatch_engine(int fd, short event, void *bula) 455 { 456 struct imsgev *iev = bula; 457 struct imsgbuf *ibuf; 458 struct imsg imsg; 459 struct imsg_configure_address address; 460 struct imsg_configure_dfr dfr; 461 struct imsg_propose_rdns rdns; 462 ssize_t n; 463 int shut = 0; 464 465 ibuf = &iev->ibuf; 466 467 if (event & EV_READ) { 468 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 469 fatal("imsg_read error"); 470 if (n == 0) /* Connection closed. */ 471 shut = 1; 472 } 473 if (event & EV_WRITE) { 474 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 475 fatal("msgbuf_write"); 476 if (n == 0) /* Connection closed. */ 477 shut = 1; 478 } 479 480 for (;;) { 481 if ((n = imsg_get(ibuf, &imsg)) == -1) 482 fatal("imsg_get"); 483 if (n == 0) /* No more messages. */ 484 break; 485 486 switch (imsg.hdr.type) { 487 case IMSG_CONFIGURE_ADDRESS: 488 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 489 fatalx("%s: IMSG_CONFIGURE_ADDRESS wrong " 490 "length: %lu", __func__, 491 IMSG_DATA_SIZE(imsg)); 492 memcpy(&address, imsg.data, sizeof(address)); 493 configure_interface(&address); 494 break; 495 case IMSG_WITHDRAW_ADDRESS: 496 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 497 fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong " 498 "length: %lu", __func__, 499 IMSG_DATA_SIZE(imsg)); 500 memcpy(&address, imsg.data, sizeof(address)); 501 delete_address(&address); 502 break; 503 case IMSG_CONFIGURE_DFR: 504 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 505 fatalx("%s: IMSG_CONFIGURE_DFR wrong " 506 "length: %lu", __func__, 507 IMSG_DATA_SIZE(imsg)); 508 memcpy(&dfr, imsg.data, sizeof(dfr)); 509 add_gateway(&dfr); 510 break; 511 case IMSG_WITHDRAW_DFR: 512 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 513 fatalx("%s: IMSG_WITHDRAW_DFR wrong " 514 "length: %lu", __func__, 515 IMSG_DATA_SIZE(imsg)); 516 memcpy(&dfr, imsg.data, sizeof(dfr)); 517 delete_gateway(&dfr); 518 break; 519 case IMSG_PROPOSE_RDNS: 520 if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) 521 fatalx("%s: IMSG_PROPOSE_RDNS wrong " 522 "length: %lu", __func__, 523 IMSG_DATA_SIZE(imsg)); 524 memcpy(&rdns, imsg.data, sizeof(rdns)); 525 if ((2 + rdns.rdns_count * sizeof(struct in6_addr)) > 526 sizeof(struct sockaddr_rtdns)) 527 fatalx("%s: rdns_count too big: %d", __func__, 528 rdns.rdns_count); 529 send_rdns_proposal(&rdns); 530 break; 531 default: 532 log_debug("%s: error handling imsg %d", __func__, 533 imsg.hdr.type); 534 break; 535 } 536 imsg_free(&imsg); 537 } 538 if (!shut) 539 imsg_event_add(iev); 540 else { 541 /* This pipe is dead. Remove its event handler. */ 542 event_del(&iev->ev); 543 event_loopexit(NULL); 544 } 545 } 546 547 int 548 main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) 549 { 550 if (iev_frontend) 551 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, 552 datalen)); 553 else 554 return (-1); 555 } 556 557 int 558 main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) 559 { 560 if (iev_engine) 561 return(imsg_compose_event(iev_engine, type, 0, pid, -1, data, 562 datalen)); 563 else 564 return (-1); 565 } 566 567 void 568 imsg_event_add(struct imsgev *iev) 569 { 570 iev->events = EV_READ; 571 if (iev->ibuf.w.queued) 572 iev->events |= EV_WRITE; 573 574 event_del(&iev->ev); 575 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 576 event_add(&iev->ev, NULL); 577 } 578 579 int 580 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 581 pid_t pid, int fd, void *data, uint16_t datalen) 582 { 583 int ret; 584 585 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 586 datalen)) != -1) 587 imsg_event_add(iev); 588 589 return (ret); 590 } 591 592 static int 593 main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 594 struct imsgbuf *engine_buf) 595 { 596 int pipe_frontend2engine[2]; 597 598 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 599 PF_UNSPEC, pipe_frontend2engine) == -1) 600 return (-1); 601 602 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 603 pipe_frontend2engine[0], NULL, 0) == -1) 604 return (-1); 605 imsg_flush(frontend_buf); 606 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 607 pipe_frontend2engine[1], NULL, 0) == -1) 608 return (-1); 609 imsg_flush(engine_buf); 610 return (0); 611 } 612 613 void 614 configure_interface(struct imsg_configure_address *address) 615 { 616 617 struct in6_aliasreq in6_addreq; 618 time_t t; 619 char *if_name; 620 621 memset(&in6_addreq, 0, sizeof(in6_addreq)); 622 623 if_name = if_indextoname(address->if_index, in6_addreq.ifra_name); 624 if (if_name == NULL) { 625 log_warnx("%s: cannot find interface %d", __func__, 626 address->if_index); 627 return; 628 } 629 630 memcpy(&in6_addreq.ifra_addr, &address->addr, 631 sizeof(in6_addreq.ifra_addr)); 632 memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask, 633 sizeof(in6_addreq.ifra_prefixmask.sin6_addr)); 634 in6_addreq.ifra_prefixmask.sin6_family = AF_INET6; 635 in6_addreq.ifra_prefixmask.sin6_len = 636 sizeof(in6_addreq.ifra_prefixmask); 637 638 t = time(NULL); 639 640 in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime; 641 in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime; 642 643 in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime; 644 in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime; 645 646 in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF; 647 648 if (address->temporary) 649 in6_addreq.ifra_flags |= IN6_IFF_TEMPORARY; 650 651 log_debug("%s: %s", __func__, if_name); 652 653 if (ioctl(ioctl_sock, SIOCAIFADDR_IN6, &in6_addreq) == -1) 654 log_warn("SIOCAIFADDR_IN6"); 655 656 if (address->mtu) { 657 struct ifreq ifr; 658 659 strlcpy(ifr.ifr_name, in6_addreq.ifra_name, 660 sizeof(ifr.ifr_name)); 661 ifr.ifr_mtu = address->mtu; 662 log_debug("Setting MTU to %d", ifr.ifr_mtu); 663 664 if (ioctl(ioctl_sock, SIOCSIFMTU, &ifr) == -1) 665 log_warn("failed to set MTU"); 666 } 667 } 668 669 void 670 delete_address(struct imsg_configure_address *address) 671 { 672 673 struct in6_ifreq in6_ridreq; 674 char *if_name; 675 676 memset(&in6_ridreq, 0, sizeof(in6_ridreq)); 677 678 if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name); 679 if (if_name == NULL) { 680 log_warnx("%s: cannot find interface %d", __func__, 681 address->if_index); 682 return; 683 } 684 685 memcpy(&in6_ridreq.ifr_addr, &address->addr, 686 sizeof(in6_ridreq.ifr_addr)); 687 688 log_debug("%s: %s", __func__, if_name); 689 690 if (ioctl(ioctl_sock, SIOCDIFADDR_IN6, &in6_ridreq) == -1) 691 log_warn("%s: cannot remove address", __func__); 692 693 } 694 695 #define ROUNDUP(a) \ 696 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 697 698 void 699 configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type) 700 { 701 struct rt_msghdr rtm; 702 struct sockaddr_rtlabel rl; 703 struct sockaddr_in6 dst, gw, mask; 704 struct iovec iov[10]; 705 long pad = 0; 706 int iovcnt = 0, padlen; 707 708 memset(&rtm, 0, sizeof(rtm)); 709 710 rtm.rtm_version = RTM_VERSION; 711 rtm.rtm_type = rtm_type; 712 rtm.rtm_msglen = sizeof(rtm); 713 rtm.rtm_tableid = dfr->rdomain; 714 rtm.rtm_index = dfr->if_index; 715 rtm.rtm_seq = ++rtm_seq; 716 rtm.rtm_priority = RTP_NONE; 717 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL; 718 rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC | RTF_MPATH; 719 720 iov[iovcnt].iov_base = &rtm; 721 iov[iovcnt++].iov_len = sizeof(rtm); 722 723 memset(&dst, 0, sizeof(mask)); 724 dst.sin6_family = AF_INET6; 725 dst.sin6_len = sizeof(struct sockaddr_in6); 726 727 iov[iovcnt].iov_base = &dst; 728 iov[iovcnt++].iov_len = sizeof(dst); 729 rtm.rtm_msglen += sizeof(dst); 730 padlen = ROUNDUP(sizeof(dst)) - sizeof(dst); 731 if (padlen > 0) { 732 iov[iovcnt].iov_base = &pad; 733 iov[iovcnt++].iov_len = padlen; 734 rtm.rtm_msglen += padlen; 735 } 736 737 memcpy(&gw, &dfr->addr, sizeof(gw)); 738 #ifdef __KAME__ 739 /* from route(8) getaddr()*/ 740 *(u_int16_t *)& gw.sin6_addr.s6_addr[2] = htons(gw.sin6_scope_id); 741 gw.sin6_scope_id = 0; 742 #endif 743 iov[iovcnt].iov_base = &gw; 744 iov[iovcnt++].iov_len = sizeof(gw); 745 rtm.rtm_msglen += sizeof(gw); 746 padlen = ROUNDUP(sizeof(gw)) - sizeof(gw); 747 if (padlen > 0) { 748 iov[iovcnt].iov_base = &pad; 749 iov[iovcnt++].iov_len = padlen; 750 rtm.rtm_msglen += padlen; 751 } 752 753 memset(&mask, 0, sizeof(mask)); 754 mask.sin6_family = AF_INET6; 755 mask.sin6_len = sizeof(struct sockaddr_in6); 756 iov[iovcnt].iov_base = &mask; 757 iov[iovcnt++].iov_len = sizeof(mask); 758 rtm.rtm_msglen += sizeof(mask); 759 padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 760 if (padlen > 0) { 761 iov[iovcnt].iov_base = &pad; 762 iov[iovcnt++].iov_len = padlen; 763 rtm.rtm_msglen += padlen; 764 } 765 766 memset(&rl, 0, sizeof(rl)); 767 rl.sr_len = sizeof(rl); 768 rl.sr_family = AF_UNSPEC; 769 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", 770 SLAACD_RTA_LABEL); 771 iov[iovcnt].iov_base = &rl; 772 iov[iovcnt++].iov_len = sizeof(rl); 773 rtm.rtm_msglen += sizeof(rl); 774 padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 775 if (padlen > 0) { 776 iov[iovcnt].iov_base = &pad; 777 iov[iovcnt++].iov_len = padlen; 778 rtm.rtm_msglen += padlen; 779 } 780 781 if (writev(routesock, iov, iovcnt) == -1) 782 log_warn("failed to send route message"); 783 } 784 785 void 786 add_gateway(struct imsg_configure_dfr *dfr) 787 { 788 configure_gateway(dfr, RTM_ADD); 789 } 790 791 void 792 delete_gateway(struct imsg_configure_dfr *dfr) 793 { 794 configure_gateway(dfr, RTM_DELETE); 795 } 796 797 void 798 send_rdns_proposal(struct imsg_propose_rdns *rdns) 799 { 800 struct rt_msghdr rtm; 801 struct sockaddr_rtdns rtdns; 802 struct iovec iov[3]; 803 long pad = 0; 804 int iovcnt = 0, padlen; 805 806 memset(&rtm, 0, sizeof(rtm)); 807 808 rtm.rtm_version = RTM_VERSION; 809 rtm.rtm_type = RTM_PROPOSAL; 810 rtm.rtm_msglen = sizeof(rtm); 811 rtm.rtm_tableid = rdns->rdomain; 812 rtm.rtm_index = rdns->if_index; 813 rtm.rtm_seq = ++rtm_seq; 814 rtm.rtm_priority = RTP_PROPOSAL_SLAAC; 815 rtm.rtm_addrs = RTA_DNS; 816 rtm.rtm_flags = RTF_UP; 817 818 iov[iovcnt].iov_base = &rtm; 819 iov[iovcnt++].iov_len = sizeof(rtm); 820 821 memset(&rtdns, 0, sizeof(rtdns)); 822 rtdns.sr_family = AF_INET6; 823 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr); 824 memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); 825 826 iov[iovcnt].iov_base = &rtdns; 827 iov[iovcnt++].iov_len = sizeof(rtdns); 828 rtm.rtm_msglen += sizeof(rtdns); 829 padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 830 if (padlen > 0) { 831 iov[iovcnt].iov_base = &pad; 832 iov[iovcnt++].iov_len = padlen; 833 rtm.rtm_msglen += padlen; 834 } 835 836 if (writev(routesock, iov, iovcnt) == -1) 837 log_warn("failed to send route message"); 838 } 839 840 #ifndef SMALL 841 const char* 842 sin6_to_str(struct sockaddr_in6 *sin6) 843 { 844 static char hbuf[NI_MAXHOST]; 845 int error; 846 847 error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf, 848 sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); 849 if (error) { 850 log_warnx("%s", gai_strerror(error)); 851 strlcpy(hbuf, "unknown", sizeof(hbuf)); 852 } 853 return hbuf; 854 } 855 #endif /* SMALL */ 856 857 int 858 get_soiikey(uint8_t *key) 859 { 860 int mib[4] = {CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_SOIIKEY}; 861 size_t size = SLAACD_SOIIKEY_LEN; 862 863 return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0); 864 } 865 866 void 867 open_icmp6sock(int rdomain) 868 { 869 int icmp6sock, on = 1; 870 871 log_debug("%s: %d", __func__, rdomain); 872 873 if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, 874 IPPROTO_ICMPV6)) == -1) 875 fatal("ICMPv6 socket"); 876 877 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 878 sizeof(on)) == -1) 879 fatal("IPV6_RECVPKTINFO"); 880 881 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 882 sizeof(on)) == -1) 883 fatal("IPV6_RECVHOPLIMIT"); 884 885 if (setsockopt(icmp6sock, SOL_SOCKET, SO_RTABLE, &rdomain, 886 sizeof(rdomain)) == -1) { 887 /* we might race against removal of the rdomain */ 888 log_warn("setsockopt SO_RTABLE"); 889 close(icmp6sock); 890 return; 891 } 892 893 main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, 894 sizeof(rdomain)); 895 } 896