1 /* $OpenBSD: slaacd.c,v 1.64 2021/08/24 14:56:06 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 struct imsg_addrinfo imsg_addrinfo; 385 int verbose; 386 #endif /* SMALL */ 387 388 ibuf = &iev->ibuf; 389 390 if (event & EV_READ) { 391 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 392 fatal("imsg_read error"); 393 if (n == 0) /* Connection closed. */ 394 shut = 1; 395 } 396 if (event & EV_WRITE) { 397 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 398 fatal("msgbuf_write"); 399 if (n == 0) /* Connection closed. */ 400 shut = 1; 401 } 402 403 for (;;) { 404 if ((n = imsg_get(ibuf, &imsg)) == -1) 405 fatal("imsg_get"); 406 if (n == 0) /* No more messages. */ 407 break; 408 409 switch (imsg.hdr.type) { 410 case IMSG_OPEN_ICMP6SOCK: 411 log_debug("IMSG_OPEN_ICMP6SOCK"); 412 if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) 413 fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: " 414 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 415 memcpy(&rdomain, imsg.data, sizeof(rdomain)); 416 open_icmp6sock(rdomain); 417 break; 418 #ifndef SMALL 419 case IMSG_CTL_LOG_VERBOSE: 420 if (IMSG_DATA_SIZE(imsg) != sizeof(verbose)) 421 fatalx("%s: IMSG_CTL_LOG_VERBOSE wrong length: " 422 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 423 memcpy(&verbose, imsg.data, sizeof(verbose)); 424 log_setverbose(verbose); 425 break; 426 case IMSG_UPDATE_ADDRESS: 427 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_addrinfo)) 428 fatalx("%s: IMSG_UPDATE_ADDRESS wrong length: " 429 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 430 memcpy(&imsg_addrinfo, imsg.data, 431 sizeof(imsg_addrinfo)); 432 main_imsg_compose_engine(IMSG_UPDATE_ADDRESS, 0, 433 &imsg_addrinfo, sizeof(imsg_addrinfo)); 434 break; 435 #endif /* SMALL */ 436 case IMSG_UPDATE_IF: 437 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo)) 438 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 439 __func__, IMSG_DATA_SIZE(imsg)); 440 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); 441 if (get_soiikey(imsg_ifinfo.soiikey) == -1) 442 log_warn("get_soiikey"); 443 else 444 main_imsg_compose_engine(IMSG_UPDATE_IF, 0, 445 &imsg_ifinfo, sizeof(imsg_ifinfo)); 446 break; 447 default: 448 log_debug("%s: error handling imsg %d", __func__, 449 imsg.hdr.type); 450 break; 451 } 452 imsg_free(&imsg); 453 } 454 if (!shut) 455 imsg_event_add(iev); 456 else { 457 /* This pipe is dead. Remove its event handler */ 458 event_del(&iev->ev); 459 event_loopexit(NULL); 460 } 461 } 462 463 void 464 main_dispatch_engine(int fd, short event, void *bula) 465 { 466 struct imsgev *iev = bula; 467 struct imsgbuf *ibuf; 468 struct imsg imsg; 469 struct imsg_configure_address address; 470 struct imsg_configure_dfr dfr; 471 struct imsg_propose_rdns rdns; 472 ssize_t n; 473 int shut = 0; 474 475 ibuf = &iev->ibuf; 476 477 if (event & EV_READ) { 478 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 479 fatal("imsg_read error"); 480 if (n == 0) /* Connection closed. */ 481 shut = 1; 482 } 483 if (event & EV_WRITE) { 484 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 485 fatal("msgbuf_write"); 486 if (n == 0) /* Connection closed. */ 487 shut = 1; 488 } 489 490 for (;;) { 491 if ((n = imsg_get(ibuf, &imsg)) == -1) 492 fatal("imsg_get"); 493 if (n == 0) /* No more messages. */ 494 break; 495 496 switch (imsg.hdr.type) { 497 case IMSG_CONFIGURE_ADDRESS: 498 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 499 fatalx("%s: IMSG_CONFIGURE_ADDRESS wrong " 500 "length: %lu", __func__, 501 IMSG_DATA_SIZE(imsg)); 502 memcpy(&address, imsg.data, sizeof(address)); 503 configure_interface(&address); 504 break; 505 case IMSG_WITHDRAW_ADDRESS: 506 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 507 fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong " 508 "length: %lu", __func__, 509 IMSG_DATA_SIZE(imsg)); 510 memcpy(&address, imsg.data, sizeof(address)); 511 delete_address(&address); 512 break; 513 case IMSG_CONFIGURE_DFR: 514 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 515 fatalx("%s: IMSG_CONFIGURE_DFR wrong " 516 "length: %lu", __func__, 517 IMSG_DATA_SIZE(imsg)); 518 memcpy(&dfr, imsg.data, sizeof(dfr)); 519 add_gateway(&dfr); 520 break; 521 case IMSG_WITHDRAW_DFR: 522 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 523 fatalx("%s: IMSG_WITHDRAW_DFR wrong " 524 "length: %lu", __func__, 525 IMSG_DATA_SIZE(imsg)); 526 memcpy(&dfr, imsg.data, sizeof(dfr)); 527 delete_gateway(&dfr); 528 break; 529 case IMSG_PROPOSE_RDNS: 530 if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) 531 fatalx("%s: IMSG_PROPOSE_RDNS wrong " 532 "length: %lu", __func__, 533 IMSG_DATA_SIZE(imsg)); 534 memcpy(&rdns, imsg.data, sizeof(rdns)); 535 if ((2 + rdns.rdns_count * sizeof(struct in6_addr)) > 536 sizeof(struct sockaddr_rtdns)) 537 fatalx("%s: rdns_count too big: %d", __func__, 538 rdns.rdns_count); 539 send_rdns_proposal(&rdns); 540 break; 541 default: 542 log_debug("%s: error handling imsg %d", __func__, 543 imsg.hdr.type); 544 break; 545 } 546 imsg_free(&imsg); 547 } 548 if (!shut) 549 imsg_event_add(iev); 550 else { 551 /* This pipe is dead. Remove its event handler. */ 552 event_del(&iev->ev); 553 event_loopexit(NULL); 554 } 555 } 556 557 int 558 main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) 559 { 560 if (iev_frontend) 561 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, 562 datalen)); 563 else 564 return (-1); 565 } 566 567 int 568 main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) 569 { 570 if (iev_engine) 571 return(imsg_compose_event(iev_engine, type, 0, pid, -1, data, 572 datalen)); 573 else 574 return (-1); 575 } 576 577 void 578 imsg_event_add(struct imsgev *iev) 579 { 580 iev->events = EV_READ; 581 if (iev->ibuf.w.queued) 582 iev->events |= EV_WRITE; 583 584 event_del(&iev->ev); 585 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 586 event_add(&iev->ev, NULL); 587 } 588 589 int 590 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 591 pid_t pid, int fd, void *data, uint16_t datalen) 592 { 593 int ret; 594 595 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 596 datalen)) != -1) 597 imsg_event_add(iev); 598 599 return (ret); 600 } 601 602 static int 603 main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 604 struct imsgbuf *engine_buf) 605 { 606 int pipe_frontend2engine[2]; 607 608 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 609 PF_UNSPEC, pipe_frontend2engine) == -1) 610 return (-1); 611 612 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 613 pipe_frontend2engine[0], NULL, 0) == -1) 614 return (-1); 615 imsg_flush(frontend_buf); 616 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 617 pipe_frontend2engine[1], NULL, 0) == -1) 618 return (-1); 619 imsg_flush(engine_buf); 620 return (0); 621 } 622 623 void 624 configure_interface(struct imsg_configure_address *address) 625 { 626 627 struct in6_aliasreq in6_addreq; 628 time_t t; 629 char *if_name; 630 631 memset(&in6_addreq, 0, sizeof(in6_addreq)); 632 633 if_name = if_indextoname(address->if_index, in6_addreq.ifra_name); 634 if (if_name == NULL) { 635 log_warnx("%s: cannot find interface %d", __func__, 636 address->if_index); 637 return; 638 } 639 640 memcpy(&in6_addreq.ifra_addr, &address->addr, 641 sizeof(in6_addreq.ifra_addr)); 642 memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask, 643 sizeof(in6_addreq.ifra_prefixmask.sin6_addr)); 644 in6_addreq.ifra_prefixmask.sin6_family = AF_INET6; 645 in6_addreq.ifra_prefixmask.sin6_len = 646 sizeof(in6_addreq.ifra_prefixmask); 647 648 t = time(NULL); 649 650 in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime; 651 in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime; 652 653 in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime; 654 in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime; 655 656 in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF; 657 658 if (address->temporary) 659 in6_addreq.ifra_flags |= IN6_IFF_TEMPORARY; 660 661 log_debug("%s: %s", __func__, if_name); 662 663 if (ioctl(ioctl_sock, SIOCAIFADDR_IN6, &in6_addreq) == -1) 664 log_warn("SIOCAIFADDR_IN6"); 665 666 if (address->mtu) { 667 struct ifreq ifr; 668 669 strlcpy(ifr.ifr_name, in6_addreq.ifra_name, 670 sizeof(ifr.ifr_name)); 671 ifr.ifr_mtu = address->mtu; 672 log_debug("Setting MTU to %d", ifr.ifr_mtu); 673 674 if (ioctl(ioctl_sock, SIOCSIFMTU, &ifr) == -1) 675 log_warn("failed to set MTU"); 676 } 677 } 678 679 void 680 delete_address(struct imsg_configure_address *address) 681 { 682 683 struct in6_ifreq in6_ridreq; 684 char *if_name; 685 686 memset(&in6_ridreq, 0, sizeof(in6_ridreq)); 687 688 if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name); 689 if (if_name == NULL) { 690 log_warnx("%s: cannot find interface %d", __func__, 691 address->if_index); 692 return; 693 } 694 695 memcpy(&in6_ridreq.ifr_addr, &address->addr, 696 sizeof(in6_ridreq.ifr_addr)); 697 698 log_debug("%s: %s", __func__, if_name); 699 700 if (ioctl(ioctl_sock, SIOCDIFADDR_IN6, &in6_ridreq) == -1) 701 log_warn("%s: cannot remove address", __func__); 702 703 } 704 705 #define ROUNDUP(a) \ 706 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 707 708 void 709 configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type) 710 { 711 struct rt_msghdr rtm; 712 struct sockaddr_rtlabel rl; 713 struct sockaddr_in6 dst, gw, mask; 714 struct iovec iov[10]; 715 long pad = 0; 716 int iovcnt = 0, padlen; 717 718 memset(&rtm, 0, sizeof(rtm)); 719 720 rtm.rtm_version = RTM_VERSION; 721 rtm.rtm_type = rtm_type; 722 rtm.rtm_msglen = sizeof(rtm); 723 rtm.rtm_tableid = dfr->rdomain; 724 rtm.rtm_index = dfr->if_index; 725 rtm.rtm_seq = ++rtm_seq; 726 rtm.rtm_priority = RTP_NONE; 727 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL; 728 rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC | RTF_MPATH; 729 730 iov[iovcnt].iov_base = &rtm; 731 iov[iovcnt++].iov_len = sizeof(rtm); 732 733 memset(&dst, 0, sizeof(mask)); 734 dst.sin6_family = AF_INET6; 735 dst.sin6_len = sizeof(struct sockaddr_in6); 736 737 iov[iovcnt].iov_base = &dst; 738 iov[iovcnt++].iov_len = sizeof(dst); 739 rtm.rtm_msglen += sizeof(dst); 740 padlen = ROUNDUP(sizeof(dst)) - sizeof(dst); 741 if (padlen > 0) { 742 iov[iovcnt].iov_base = &pad; 743 iov[iovcnt++].iov_len = padlen; 744 rtm.rtm_msglen += padlen; 745 } 746 747 memcpy(&gw, &dfr->addr, sizeof(gw)); 748 #ifdef __KAME__ 749 /* from route(8) getaddr()*/ 750 *(u_int16_t *)& gw.sin6_addr.s6_addr[2] = htons(gw.sin6_scope_id); 751 gw.sin6_scope_id = 0; 752 #endif 753 iov[iovcnt].iov_base = &gw; 754 iov[iovcnt++].iov_len = sizeof(gw); 755 rtm.rtm_msglen += sizeof(gw); 756 padlen = ROUNDUP(sizeof(gw)) - sizeof(gw); 757 if (padlen > 0) { 758 iov[iovcnt].iov_base = &pad; 759 iov[iovcnt++].iov_len = padlen; 760 rtm.rtm_msglen += padlen; 761 } 762 763 memset(&mask, 0, sizeof(mask)); 764 mask.sin6_family = AF_INET6; 765 mask.sin6_len = sizeof(struct sockaddr_in6); 766 iov[iovcnt].iov_base = &mask; 767 iov[iovcnt++].iov_len = sizeof(mask); 768 rtm.rtm_msglen += sizeof(mask); 769 padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 770 if (padlen > 0) { 771 iov[iovcnt].iov_base = &pad; 772 iov[iovcnt++].iov_len = padlen; 773 rtm.rtm_msglen += padlen; 774 } 775 776 memset(&rl, 0, sizeof(rl)); 777 rl.sr_len = sizeof(rl); 778 rl.sr_family = AF_UNSPEC; 779 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", 780 SLAACD_RTA_LABEL); 781 iov[iovcnt].iov_base = &rl; 782 iov[iovcnt++].iov_len = sizeof(rl); 783 rtm.rtm_msglen += sizeof(rl); 784 padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 785 if (padlen > 0) { 786 iov[iovcnt].iov_base = &pad; 787 iov[iovcnt++].iov_len = padlen; 788 rtm.rtm_msglen += padlen; 789 } 790 791 if (writev(routesock, iov, iovcnt) == -1) 792 log_warn("failed to send route message"); 793 } 794 795 void 796 add_gateway(struct imsg_configure_dfr *dfr) 797 { 798 configure_gateway(dfr, RTM_ADD); 799 } 800 801 void 802 delete_gateway(struct imsg_configure_dfr *dfr) 803 { 804 configure_gateway(dfr, RTM_DELETE); 805 } 806 807 void 808 send_rdns_proposal(struct imsg_propose_rdns *rdns) 809 { 810 struct rt_msghdr rtm; 811 struct sockaddr_rtdns rtdns; 812 struct iovec iov[3]; 813 long pad = 0; 814 int iovcnt = 0, padlen; 815 816 memset(&rtm, 0, sizeof(rtm)); 817 818 rtm.rtm_version = RTM_VERSION; 819 rtm.rtm_type = RTM_PROPOSAL; 820 rtm.rtm_msglen = sizeof(rtm); 821 rtm.rtm_tableid = rdns->rdomain; 822 rtm.rtm_index = rdns->if_index; 823 rtm.rtm_seq = ++rtm_seq; 824 rtm.rtm_priority = RTP_PROPOSAL_SLAAC; 825 rtm.rtm_addrs = RTA_DNS; 826 rtm.rtm_flags = RTF_UP; 827 828 iov[iovcnt].iov_base = &rtm; 829 iov[iovcnt++].iov_len = sizeof(rtm); 830 831 memset(&rtdns, 0, sizeof(rtdns)); 832 rtdns.sr_family = AF_INET6; 833 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr); 834 memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); 835 836 iov[iovcnt].iov_base = &rtdns; 837 iov[iovcnt++].iov_len = sizeof(rtdns); 838 rtm.rtm_msglen += sizeof(rtdns); 839 padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 840 if (padlen > 0) { 841 iov[iovcnt].iov_base = &pad; 842 iov[iovcnt++].iov_len = padlen; 843 rtm.rtm_msglen += padlen; 844 } 845 846 if (writev(routesock, iov, iovcnt) == -1) 847 log_warn("failed to send route message"); 848 } 849 850 #ifndef SMALL 851 const char* 852 sin6_to_str(struct sockaddr_in6 *sin6) 853 { 854 static char hbuf[NI_MAXHOST]; 855 int error; 856 857 error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf, 858 sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); 859 if (error) { 860 log_warnx("%s", gai_strerror(error)); 861 strlcpy(hbuf, "unknown", sizeof(hbuf)); 862 } 863 return hbuf; 864 } 865 #endif /* SMALL */ 866 867 int 868 get_soiikey(uint8_t *key) 869 { 870 int mib[4] = {CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_SOIIKEY}; 871 size_t size = SLAACD_SOIIKEY_LEN; 872 873 return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0); 874 } 875 876 void 877 open_icmp6sock(int rdomain) 878 { 879 int icmp6sock, on = 1; 880 881 log_debug("%s: %d", __func__, rdomain); 882 883 if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, 884 IPPROTO_ICMPV6)) == -1) 885 fatal("ICMPv6 socket"); 886 887 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 888 sizeof(on)) == -1) 889 fatal("IPV6_RECVPKTINFO"); 890 891 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 892 sizeof(on)) == -1) 893 fatal("IPV6_RECVHOPLIMIT"); 894 895 if (setsockopt(icmp6sock, SOL_SOCKET, SO_RTABLE, &rdomain, 896 sizeof(rdomain)) == -1) { 897 /* we might race against removal of the rdomain */ 898 log_warn("setsockopt SO_RTABLE"); 899 close(icmp6sock); 900 return; 901 } 902 903 main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, 904 sizeof(rdomain)); 905 } 906