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