1 /* $OpenBSD: slaacd.c,v 1.62 2021/07/22 15:32:51 kn 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 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 260 &rtfilter, sizeof(rtfilter)) == -1) 261 fatal("setsockopt(ROUTE_MSGFILTER)"); 262 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER, 263 &rtable_any, sizeof(rtable_any)) == -1) 264 fatal("setsockopt(ROUTE_TABLEFILTER)"); 265 266 #ifndef SMALL 267 if ((control_fd = control_init(csock)) == -1) 268 warnx("control socket setup failed"); 269 #endif /* SMALL */ 270 271 if (pledge("stdio inet sendfd wroute", NULL) == -1) 272 fatal("pledge"); 273 274 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0); 275 276 #ifndef SMALL 277 if (control_fd != -1) 278 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0); 279 #endif /* SMALL */ 280 281 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0); 282 283 /* we are taking over, clear all previos slaac proposals */ 284 memset(&rdns, 0, sizeof(rdns)); 285 rdns.if_index = 0; 286 rdns.rdns_count = 0; 287 send_rdns_proposal(&rdns); 288 289 event_dispatch(); 290 291 main_shutdown(); 292 return (0); 293 } 294 295 __dead void 296 main_shutdown(void) 297 { 298 pid_t pid; 299 int status; 300 301 /* Close pipes. */ 302 msgbuf_clear(&iev_frontend->ibuf.w); 303 close(iev_frontend->ibuf.fd); 304 msgbuf_clear(&iev_engine->ibuf.w); 305 close(iev_engine->ibuf.fd); 306 307 log_debug("waiting for children to terminate"); 308 do { 309 pid = wait(&status); 310 if (pid == -1) { 311 if (errno != EINTR && errno != ECHILD) 312 fatal("wait"); 313 } else if (WIFSIGNALED(status)) 314 log_warnx("%s terminated; signal %d", 315 (pid == engine_pid) ? "engine" : 316 "frontend", WTERMSIG(status)); 317 } while (pid != -1 || (pid == -1 && errno == EINTR)); 318 319 free(iev_frontend); 320 free(iev_engine); 321 322 log_info("terminating"); 323 exit(0); 324 } 325 326 static pid_t 327 start_child(enum slaacd_process p, char *argv0, int fd, int debug, int verbose) 328 { 329 char *argv[7]; 330 int argc = 0; 331 pid_t pid; 332 333 switch (pid = fork()) { 334 case -1: 335 fatal("cannot fork"); 336 case 0: 337 break; 338 default: 339 close(fd); 340 return (pid); 341 } 342 343 if (fd != 3) { 344 if (dup2(fd, 3) == -1) 345 fatal("cannot setup imsg fd"); 346 } else if (fcntl(fd, F_SETFD, 0) == -1) 347 fatal("cannot setup imsg fd"); 348 349 argv[argc++] = argv0; 350 switch (p) { 351 case PROC_MAIN: 352 fatalx("Can not start main process"); 353 case PROC_ENGINE: 354 argv[argc++] = "-E"; 355 break; 356 case PROC_FRONTEND: 357 argv[argc++] = "-F"; 358 break; 359 } 360 if (debug) 361 argv[argc++] = "-d"; 362 if (verbose) 363 argv[argc++] = "-v"; 364 if (verbose > 1) 365 argv[argc++] = "-v"; 366 argv[argc++] = NULL; 367 368 execvp(argv0, argv); 369 fatal("execvp"); 370 } 371 372 void 373 main_dispatch_frontend(int fd, short event, void *bula) 374 { 375 struct imsgev *iev = bula; 376 struct imsgbuf *ibuf; 377 struct imsg imsg; 378 struct imsg_ifinfo imsg_ifinfo; 379 ssize_t n; 380 int shut = 0; 381 int rdomain; 382 #ifndef SMALL 383 struct imsg_addrinfo imsg_addrinfo; 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 case IMSG_UPDATE_ADDRESS: 426 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_addrinfo)) 427 fatalx("%s: IMSG_UPDATE_ADDRESS wrong length: " 428 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 429 memcpy(&imsg_addrinfo, imsg.data, 430 sizeof(imsg_addrinfo)); 431 main_imsg_compose_engine(IMSG_UPDATE_ADDRESS, 0, 432 &imsg_addrinfo, sizeof(imsg_addrinfo)); 433 break; 434 #endif /* SMALL */ 435 case IMSG_UPDATE_IF: 436 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_ifinfo)) 437 fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", 438 __func__, IMSG_DATA_SIZE(imsg)); 439 memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); 440 if (get_soiikey(imsg_ifinfo.soiikey) == -1) 441 log_warn("get_soiikey"); 442 else 443 main_imsg_compose_engine(IMSG_UPDATE_IF, 0, 444 &imsg_ifinfo, sizeof(imsg_ifinfo)); 445 break; 446 default: 447 log_debug("%s: error handling imsg %d", __func__, 448 imsg.hdr.type); 449 break; 450 } 451 imsg_free(&imsg); 452 } 453 if (!shut) 454 imsg_event_add(iev); 455 else { 456 /* This pipe is dead. Remove its event handler */ 457 event_del(&iev->ev); 458 event_loopexit(NULL); 459 } 460 } 461 462 void 463 main_dispatch_engine(int fd, short event, void *bula) 464 { 465 struct imsgev *iev = bula; 466 struct imsgbuf *ibuf; 467 struct imsg imsg; 468 struct imsg_configure_address address; 469 struct imsg_configure_dfr dfr; 470 struct imsg_propose_rdns rdns; 471 ssize_t n; 472 int shut = 0; 473 474 ibuf = &iev->ibuf; 475 476 if (event & EV_READ) { 477 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 478 fatal("imsg_read error"); 479 if (n == 0) /* Connection closed. */ 480 shut = 1; 481 } 482 if (event & EV_WRITE) { 483 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 484 fatal("msgbuf_write"); 485 if (n == 0) /* Connection closed. */ 486 shut = 1; 487 } 488 489 for (;;) { 490 if ((n = imsg_get(ibuf, &imsg)) == -1) 491 fatal("imsg_get"); 492 if (n == 0) /* No more messages. */ 493 break; 494 495 switch (imsg.hdr.type) { 496 case IMSG_CONFIGURE_ADDRESS: 497 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 498 fatalx("%s: IMSG_CONFIGURE_ADDRESS wrong " 499 "length: %lu", __func__, 500 IMSG_DATA_SIZE(imsg)); 501 memcpy(&address, imsg.data, sizeof(address)); 502 configure_interface(&address); 503 break; 504 case IMSG_WITHDRAW_ADDRESS: 505 if (IMSG_DATA_SIZE(imsg) != sizeof(address)) 506 fatalx("%s: IMSG_WITHDRAW_ADDRESS wrong " 507 "length: %lu", __func__, 508 IMSG_DATA_SIZE(imsg)); 509 memcpy(&address, imsg.data, sizeof(address)); 510 delete_address(&address); 511 break; 512 case IMSG_CONFIGURE_DFR: 513 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 514 fatalx("%s: IMSG_CONFIGURE_DFR wrong " 515 "length: %lu", __func__, 516 IMSG_DATA_SIZE(imsg)); 517 memcpy(&dfr, imsg.data, sizeof(dfr)); 518 add_gateway(&dfr); 519 break; 520 case IMSG_WITHDRAW_DFR: 521 if (IMSG_DATA_SIZE(imsg) != sizeof(dfr)) 522 fatalx("%s: IMSG_WITHDRAW_DFR wrong " 523 "length: %lu", __func__, 524 IMSG_DATA_SIZE(imsg)); 525 memcpy(&dfr, imsg.data, sizeof(dfr)); 526 delete_gateway(&dfr); 527 break; 528 case IMSG_PROPOSE_RDNS: 529 if (IMSG_DATA_SIZE(imsg) != sizeof(rdns)) 530 fatalx("%s: IMSG_PROPOSE_RDNS wrong " 531 "length: %lu", __func__, 532 IMSG_DATA_SIZE(imsg)); 533 memcpy(&rdns, imsg.data, sizeof(rdns)); 534 if ((2 + rdns.rdns_count * sizeof(struct in6_addr)) > 535 sizeof(struct sockaddr_rtdns)) 536 fatalx("%s: rdns_count too big: %d", __func__, 537 rdns.rdns_count); 538 send_rdns_proposal(&rdns); 539 break; 540 default: 541 log_debug("%s: error handling imsg %d", __func__, 542 imsg.hdr.type); 543 break; 544 } 545 imsg_free(&imsg); 546 } 547 if (!shut) 548 imsg_event_add(iev); 549 else { 550 /* This pipe is dead. Remove its event handler. */ 551 event_del(&iev->ev); 552 event_loopexit(NULL); 553 } 554 } 555 556 int 557 main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) 558 { 559 if (iev_frontend) 560 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, 561 datalen)); 562 else 563 return (-1); 564 } 565 566 int 567 main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) 568 { 569 if (iev_engine) 570 return(imsg_compose_event(iev_engine, type, 0, pid, -1, data, 571 datalen)); 572 else 573 return (-1); 574 } 575 576 void 577 imsg_event_add(struct imsgev *iev) 578 { 579 iev->events = EV_READ; 580 if (iev->ibuf.w.queued) 581 iev->events |= EV_WRITE; 582 583 event_del(&iev->ev); 584 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 585 event_add(&iev->ev, NULL); 586 } 587 588 int 589 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 590 pid_t pid, int fd, void *data, uint16_t datalen) 591 { 592 int ret; 593 594 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 595 datalen)) != -1) 596 imsg_event_add(iev); 597 598 return (ret); 599 } 600 601 static int 602 main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 603 struct imsgbuf *engine_buf) 604 { 605 int pipe_frontend2engine[2]; 606 607 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 608 PF_UNSPEC, pipe_frontend2engine) == -1) 609 return (-1); 610 611 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 612 pipe_frontend2engine[0], NULL, 0) == -1) 613 return (-1); 614 imsg_flush(frontend_buf); 615 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 616 pipe_frontend2engine[1], NULL, 0) == -1) 617 return (-1); 618 imsg_flush(engine_buf); 619 return (0); 620 } 621 622 void 623 configure_interface(struct imsg_configure_address *address) 624 { 625 626 struct in6_aliasreq in6_addreq; 627 time_t t; 628 char *if_name; 629 630 memset(&in6_addreq, 0, sizeof(in6_addreq)); 631 632 if_name = if_indextoname(address->if_index, in6_addreq.ifra_name); 633 if (if_name == NULL) { 634 log_warnx("%s: cannot find interface %d", __func__, 635 address->if_index); 636 return; 637 } 638 639 memcpy(&in6_addreq.ifra_addr, &address->addr, 640 sizeof(in6_addreq.ifra_addr)); 641 memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask, 642 sizeof(in6_addreq.ifra_prefixmask.sin6_addr)); 643 in6_addreq.ifra_prefixmask.sin6_family = AF_INET6; 644 in6_addreq.ifra_prefixmask.sin6_len = 645 sizeof(in6_addreq.ifra_prefixmask); 646 647 t = time(NULL); 648 649 in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime; 650 in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime; 651 652 in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime; 653 in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime; 654 655 in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF; 656 657 if (address->temporary) 658 in6_addreq.ifra_flags |= IN6_IFF_TEMPORARY; 659 660 log_debug("%s: %s", __func__, if_name); 661 662 if (ioctl(ioctl_sock, SIOCAIFADDR_IN6, &in6_addreq) == -1) 663 fatal("SIOCAIFADDR_IN6"); 664 665 if (address->mtu) { 666 struct ifreq ifr; 667 668 strlcpy(ifr.ifr_name, in6_addreq.ifra_name, 669 sizeof(ifr.ifr_name)); 670 ifr.ifr_mtu = address->mtu; 671 log_debug("Setting MTU to %d", ifr.ifr_mtu); 672 673 if (ioctl(ioctl_sock, SIOCSIFMTU, &ifr) == -1) 674 log_warn("failed to set MTU"); 675 } 676 } 677 678 void 679 delete_address(struct imsg_configure_address *address) 680 { 681 682 struct in6_ifreq in6_ridreq; 683 char *if_name; 684 685 memset(&in6_ridreq, 0, sizeof(in6_ridreq)); 686 687 if_name = if_indextoname(address->if_index, in6_ridreq.ifr_name); 688 if (if_name == NULL) { 689 log_warnx("%s: cannot find interface %d", __func__, 690 address->if_index); 691 return; 692 } 693 694 memcpy(&in6_ridreq.ifr_addr, &address->addr, 695 sizeof(in6_ridreq.ifr_addr)); 696 697 log_debug("%s: %s", __func__, if_name); 698 699 if (ioctl(ioctl_sock, SIOCDIFADDR_IN6, &in6_ridreq) == -1) 700 log_warn("%s: cannot remove address", __func__); 701 702 } 703 704 #define ROUNDUP(a) \ 705 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 706 707 void 708 configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type) 709 { 710 struct rt_msghdr rtm; 711 struct sockaddr_rtlabel rl; 712 struct sockaddr_in6 dst, gw, mask; 713 struct iovec iov[10]; 714 long pad = 0; 715 int iovcnt = 0, padlen; 716 717 memset(&rtm, 0, sizeof(rtm)); 718 719 rtm.rtm_version = RTM_VERSION; 720 rtm.rtm_type = rtm_type; 721 rtm.rtm_msglen = sizeof(rtm); 722 rtm.rtm_tableid = dfr->rdomain; 723 rtm.rtm_index = dfr->if_index; 724 rtm.rtm_seq = ++rtm_seq; 725 rtm.rtm_priority = RTP_NONE; 726 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL; 727 rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC | RTF_MPATH; 728 729 iov[iovcnt].iov_base = &rtm; 730 iov[iovcnt++].iov_len = sizeof(rtm); 731 732 memset(&dst, 0, sizeof(mask)); 733 dst.sin6_family = AF_INET6; 734 dst.sin6_len = sizeof(struct sockaddr_in6); 735 736 iov[iovcnt].iov_base = &dst; 737 iov[iovcnt++].iov_len = sizeof(dst); 738 rtm.rtm_msglen += sizeof(dst); 739 padlen = ROUNDUP(sizeof(dst)) - sizeof(dst); 740 if (padlen > 0) { 741 iov[iovcnt].iov_base = &pad; 742 iov[iovcnt++].iov_len = padlen; 743 rtm.rtm_msglen += padlen; 744 } 745 746 memcpy(&gw, &dfr->addr, sizeof(gw)); 747 #ifdef __KAME__ 748 /* from route(8) getaddr()*/ 749 *(u_int16_t *)& gw.sin6_addr.s6_addr[2] = htons(gw.sin6_scope_id); 750 gw.sin6_scope_id = 0; 751 #endif 752 iov[iovcnt].iov_base = &gw; 753 iov[iovcnt++].iov_len = sizeof(gw); 754 rtm.rtm_msglen += sizeof(gw); 755 padlen = ROUNDUP(sizeof(gw)) - sizeof(gw); 756 if (padlen > 0) { 757 iov[iovcnt].iov_base = &pad; 758 iov[iovcnt++].iov_len = padlen; 759 rtm.rtm_msglen += padlen; 760 } 761 762 memset(&mask, 0, sizeof(mask)); 763 mask.sin6_family = AF_INET6; 764 mask.sin6_len = sizeof(struct sockaddr_in6); 765 iov[iovcnt].iov_base = &mask; 766 iov[iovcnt++].iov_len = sizeof(mask); 767 rtm.rtm_msglen += sizeof(mask); 768 padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 769 if (padlen > 0) { 770 iov[iovcnt].iov_base = &pad; 771 iov[iovcnt++].iov_len = padlen; 772 rtm.rtm_msglen += padlen; 773 } 774 775 memset(&rl, 0, sizeof(rl)); 776 rl.sr_len = sizeof(rl); 777 rl.sr_family = AF_UNSPEC; 778 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", 779 SLAACD_RTA_LABEL); 780 iov[iovcnt].iov_base = &rl; 781 iov[iovcnt++].iov_len = sizeof(rl); 782 rtm.rtm_msglen += sizeof(rl); 783 padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 784 if (padlen > 0) { 785 iov[iovcnt].iov_base = &pad; 786 iov[iovcnt++].iov_len = padlen; 787 rtm.rtm_msglen += padlen; 788 } 789 790 if (writev(routesock, iov, iovcnt) == -1) 791 log_warn("failed to send route message"); 792 } 793 794 void 795 add_gateway(struct imsg_configure_dfr *dfr) 796 { 797 configure_gateway(dfr, RTM_ADD); 798 } 799 800 void 801 delete_gateway(struct imsg_configure_dfr *dfr) 802 { 803 configure_gateway(dfr, RTM_DELETE); 804 } 805 806 void 807 send_rdns_proposal(struct imsg_propose_rdns *rdns) 808 { 809 struct rt_msghdr rtm; 810 struct sockaddr_rtdns rtdns; 811 struct iovec iov[3]; 812 long pad = 0; 813 int iovcnt = 0, padlen; 814 815 memset(&rtm, 0, sizeof(rtm)); 816 817 rtm.rtm_version = RTM_VERSION; 818 rtm.rtm_type = RTM_PROPOSAL; 819 rtm.rtm_msglen = sizeof(rtm); 820 rtm.rtm_tableid = rdns->rdomain; 821 rtm.rtm_index = rdns->if_index; 822 rtm.rtm_seq = ++rtm_seq; 823 rtm.rtm_priority = RTP_PROPOSAL_SLAAC; 824 rtm.rtm_addrs = RTA_DNS; 825 rtm.rtm_flags = RTF_UP; 826 827 iov[iovcnt].iov_base = &rtm; 828 iov[iovcnt++].iov_len = sizeof(rtm); 829 830 memset(&rtdns, 0, sizeof(rtdns)); 831 rtdns.sr_family = AF_INET6; 832 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in6_addr); 833 memcpy(rtdns.sr_dns, rdns->rdns, sizeof(rtdns.sr_dns)); 834 835 iov[iovcnt].iov_base = &rtdns; 836 iov[iovcnt++].iov_len = sizeof(rtdns); 837 rtm.rtm_msglen += sizeof(rtdns); 838 padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 839 if (padlen > 0) { 840 iov[iovcnt].iov_base = &pad; 841 iov[iovcnt++].iov_len = padlen; 842 rtm.rtm_msglen += padlen; 843 } 844 845 if (writev(routesock, iov, iovcnt) == -1) 846 log_warn("failed to send route message"); 847 } 848 849 #ifndef SMALL 850 const char* 851 sin6_to_str(struct sockaddr_in6 *sin6) 852 { 853 static char hbuf[NI_MAXHOST]; 854 int error; 855 856 error = getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, hbuf, 857 sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); 858 if (error) { 859 log_warnx("%s", gai_strerror(error)); 860 strlcpy(hbuf, "unknown", sizeof(hbuf)); 861 } 862 return hbuf; 863 } 864 #endif /* SMALL */ 865 866 int 867 get_soiikey(uint8_t *key) 868 { 869 int mib[4] = {CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_SOIIKEY}; 870 size_t size = SLAACD_SOIIKEY_LEN; 871 872 return sysctl(mib, sizeof(mib) / sizeof(mib[0]), key, &size, NULL, 0); 873 } 874 875 void 876 open_icmp6sock(int rdomain) 877 { 878 int icmp6sock, on = 1; 879 880 log_debug("%s: %d", __func__, rdomain); 881 882 if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, 883 IPPROTO_ICMPV6)) == -1) 884 fatal("ICMPv6 socket"); 885 886 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 887 sizeof(on)) == -1) 888 fatal("IPV6_RECVPKTINFO"); 889 890 if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 891 sizeof(on)) == -1) 892 fatal("IPV6_RECVHOPLIMIT"); 893 894 if (setsockopt(icmp6sock, SOL_SOCKET, SO_RTABLE, &rdomain, 895 sizeof(rdomain)) == -1) { 896 /* we might race against removal of the rdomain */ 897 log_warn("setsockopt SO_RTABLE"); 898 close(icmp6sock); 899 return; 900 } 901 902 main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, 903 sizeof(rdomain)); 904 } 905