1 /* $OpenBSD: slaacd.c,v 1.4 2017/07/06 15:02:53 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/uio.h> 27 #include <sys/wait.h> 28 29 #include <net/if.h> 30 #include <net/route.h> 31 #include <netinet/in.h> 32 #include <netinet/if_ether.h> 33 #include <netinet6/in6_var.h> 34 35 #include <err.h> 36 #include <errno.h> 37 #include <event.h> 38 #include <imsg.h> 39 #include <pwd.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <signal.h> 45 #include <unistd.h> 46 47 #include "log.h" 48 #include "slaacd.h" 49 #include "frontend.h" 50 #include "engine.h" 51 #include "control.h" 52 53 #ifndef SMALL 54 const char* imsg_type_name[] = { 55 "IMSG_NONE", 56 "IMSG_CTL_LOG_VERBOSE", 57 "IMSG_CTL_SHOW_INTERFACE_INFO", 58 "IMSG_CTL_SHOW_INTERFACE_INFO_RA", 59 "IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX", 60 "IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS", 61 "IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL", 62 "IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS", 63 "IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL", 64 "IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS", 65 "IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL", 66 "IMSG_CTL_END", 67 "IMSG_CTL_SEND_SOLICITATION", 68 "IMSG_SOCKET_IPC", 69 "IMSG_STARTUP", 70 "IMSG_UPDATE_IF", 71 "IMSG_REMOVE_IF", 72 "IMSG_RA", 73 "IMSG_PROPOSAL", 74 "IMSG_PROPOSAL_ACK", 75 "IMSG_CONFIGURE_ADDRESS", 76 "IMSG_DEL_ADDRESS", 77 "IMSG_FAKE_ACK", 78 "IMSG_CONFIGURE_DFR", 79 "IMSG_WITHDRAW_DFR", 80 }; 81 #endif /* SMALL */ 82 83 __dead void usage(void); 84 __dead void main_shutdown(void); 85 86 void main_sig_handler(int, short, void *); 87 88 static pid_t start_child(int, char *, int, int, int, char *); 89 90 void main_dispatch_frontend(int, short, void *); 91 void main_dispatch_engine(int, short, void *); 92 void handle_proposal(struct imsg_proposal *); 93 void configure_interface(struct imsg_configure_address *); 94 void configure_gateway(struct imsg_configure_dfr *, uint8_t); 95 void add_gateway(struct imsg_configure_dfr *); 96 void delete_gateway(struct imsg_configure_dfr *); 97 98 static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 99 100 struct imsgev *iev_frontend; 101 struct imsgev *iev_engine; 102 103 pid_t frontend_pid; 104 pid_t engine_pid; 105 106 uint32_t cmd_opts; 107 108 int routesock, ioctl_sock; 109 110 char *csock; 111 112 int rtm_seq = 0; 113 114 void 115 main_sig_handler(int sig, short event, void *arg) 116 { 117 /* 118 * Normal signal handler rules don't apply because libevent 119 * decouples for us. 120 */ 121 122 switch (sig) { 123 case SIGTERM: 124 case SIGINT: 125 main_shutdown(); 126 case SIGHUP: 127 log_debug("sighub received"); 128 break; 129 default: 130 fatalx("unexpected signal"); 131 } 132 } 133 134 __dead void 135 usage(void) 136 { 137 extern char *__progname; 138 139 fprintf(stderr, "usage: %s [-dv] [-s socket]\n", 140 __progname); 141 exit(1); 142 } 143 144 int 145 main(int argc, char *argv[]) 146 { 147 struct event ev_sigint, ev_sigterm, ev_sighup; 148 int ch; 149 int debug = 0, engine_flag = 0, frontend_flag = 0; 150 char *saved_argv0; 151 int pipe_main2frontend[2]; 152 int pipe_main2engine[2]; 153 154 csock = SLAACD_SOCKET; 155 156 log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 157 log_setverbose(1); 158 159 saved_argv0 = argv[0]; 160 if (saved_argv0 == NULL) 161 saved_argv0 = "slaacd"; 162 163 while ((ch = getopt(argc, argv, "dEFs:v")) != -1) { 164 switch (ch) { 165 case 'd': 166 debug = 1; 167 break; 168 case 'E': 169 engine_flag = 1; 170 break; 171 case 'F': 172 frontend_flag = 1; 173 break; 174 case 's': 175 csock = optarg; 176 break; 177 case 'v': 178 if (cmd_opts & OPT_VERBOSE) 179 cmd_opts |= OPT_VERBOSE2; 180 cmd_opts |= OPT_VERBOSE; 181 break; 182 default: 183 usage(); 184 } 185 } 186 187 argc -= optind; 188 argv += optind; 189 if (argc > 0 || (engine_flag && frontend_flag)) 190 usage(); 191 192 if (engine_flag) 193 engine(debug, cmd_opts & OPT_VERBOSE); 194 else if (frontend_flag) 195 frontend(debug, cmd_opts & OPT_VERBOSE, csock); 196 197 /* Check for root privileges. */ 198 if (geteuid()) 199 errx(1, "need root privileges"); 200 201 /* Check for assigned daemon user */ 202 if (getpwnam(SLAACD_USER) == NULL) 203 errx(1, "unknown user %s", SLAACD_USER); 204 205 log_init(debug, LOG_DAEMON); 206 log_setverbose(cmd_opts & OPT_VERBOSE); 207 208 if (!debug) 209 daemon(1, 0); 210 211 log_info("startup"); 212 213 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 214 PF_UNSPEC, pipe_main2frontend) == -1) 215 fatal("main2frontend socketpair"); 216 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 217 PF_UNSPEC, pipe_main2engine) == -1) 218 fatal("main2engine socketpair"); 219 220 /* Start children. */ 221 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], 222 debug, cmd_opts & OPT_VERBOSE, NULL); 223 frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 224 pipe_main2frontend[1], debug, cmd_opts & OPT_VERBOSE, csock); 225 226 slaacd_process = PROC_MAIN; 227 228 log_procinit(log_procnames[slaacd_process]); 229 230 if ((routesock = socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 231 SOCK_NONBLOCK, 0)) < 0) 232 fatal("route socket"); 233 234 event_init(); 235 236 /* Setup signal handler. */ 237 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 238 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 239 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 240 signal_add(&ev_sigint, NULL); 241 signal_add(&ev_sigterm, NULL); 242 signal_add(&ev_sighup, NULL); 243 signal(SIGPIPE, SIG_IGN); 244 245 /* Setup pipes to children. */ 246 247 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 248 (iev_engine = malloc(sizeof(struct imsgev))) == NULL) 249 fatal(NULL); 250 imsg_init(&iev_frontend->ibuf, pipe_main2frontend[0]); 251 iev_frontend->handler = main_dispatch_frontend; 252 imsg_init(&iev_engine->ibuf, pipe_main2engine[0]); 253 iev_engine->handler = main_dispatch_engine; 254 255 /* Setup event handlers for pipes to engine & frontend. */ 256 iev_frontend->events = EV_READ; 257 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 258 iev_frontend->events, iev_frontend->handler, iev_frontend); 259 event_add(&iev_frontend->ev, NULL); 260 261 iev_engine->events = EV_READ; 262 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, 263 iev_engine->handler, iev_engine); 264 event_add(&iev_engine->ev, NULL); 265 266 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) 267 fatal("could not establish imsg links"); 268 269 if ((ioctl_sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0) 270 fatal("socket"); 271 272 #if 0 273 /* XXX ioctl SIOCAIFADDR_IN6 */ 274 if (pledge("rpath stdio sendfd cpath", NULL) == -1) 275 fatal("pledge"); 276 #endif 277 278 main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); 279 280 event_dispatch(); 281 282 main_shutdown(); 283 return (0); 284 } 285 286 __dead void 287 main_shutdown(void) 288 { 289 pid_t pid; 290 int status; 291 292 /* Close pipes. */ 293 msgbuf_clear(&iev_frontend->ibuf.w); 294 close(iev_frontend->ibuf.fd); 295 msgbuf_clear(&iev_engine->ibuf.w); 296 close(iev_engine->ibuf.fd); 297 298 log_debug("waiting for children to terminate"); 299 do { 300 pid = wait(&status); 301 if (pid == -1) { 302 if (errno != EINTR && errno != ECHILD) 303 fatal("wait"); 304 } else if (WIFSIGNALED(status)) 305 log_warnx("%s terminated; signal %d", 306 (pid == engine_pid) ? "engine" : 307 "frontend", WTERMSIG(status)); 308 } while (pid != -1 || (pid == -1 && errno == EINTR)); 309 310 free(iev_frontend); 311 free(iev_engine); 312 313 #ifndef SMALL 314 control_cleanup(csock); 315 #endif /* SMALL */ 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, char *sockname) 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 (dup2(fd, 3) == -1) 339 fatal("cannot setup imsg fd"); 340 341 argv[argc++] = argv0; 342 switch (p) { 343 case PROC_MAIN: 344 fatalx("Can not start main process"); 345 case PROC_ENGINE: 346 argv[argc++] = "-E"; 347 break; 348 case PROC_FRONTEND: 349 argv[argc++] = "-F"; 350 break; 351 } 352 if (debug) 353 argv[argc++] = "-d"; 354 if (verbose) 355 argv[argc++] = "-v"; 356 if (sockname) { 357 argv[argc++] = "-s"; 358 argv[argc++] = sockname; 359 } 360 argv[argc++] = NULL; 361 362 execvp(argv0, argv); 363 fatal("execvp"); 364 } 365 366 void 367 main_dispatch_frontend(int fd, short event, void *bula) 368 { 369 struct imsgev *iev = bula; 370 struct imsgbuf *ibuf; 371 struct imsg imsg; 372 ssize_t n; 373 int shut = 0; 374 #ifndef SMALL 375 int verbose; 376 #endif /* SMALL */ 377 378 ibuf = &iev->ibuf; 379 380 if (event & EV_READ) { 381 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 382 fatal("imsg_read error"); 383 if (n == 0) /* Connection closed. */ 384 shut = 1; 385 } 386 if (event & EV_WRITE) { 387 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 388 fatal("msgbuf_write"); 389 if (n == 0) /* Connection closed. */ 390 shut = 1; 391 } 392 393 for (;;) { 394 if ((n = imsg_get(ibuf, &imsg)) == -1) 395 fatal("imsg_get"); 396 if (n == 0) /* No more messages. */ 397 break; 398 399 switch (imsg.hdr.type) { 400 #ifndef SMALL 401 case IMSG_CTL_LOG_VERBOSE: 402 /* Already checked by frontend. */ 403 memcpy(&verbose, imsg.data, sizeof(verbose)); 404 log_setverbose(verbose); 405 break; 406 #endif /* SMALL */ 407 default: 408 log_debug("%s: error handling imsg %d", __func__, 409 imsg.hdr.type); 410 break; 411 } 412 imsg_free(&imsg); 413 } 414 if (!shut) 415 imsg_event_add(iev); 416 else { 417 /* This pipe is dead. Remove its event handler */ 418 event_del(&iev->ev); 419 event_loopexit(NULL); 420 } 421 } 422 423 void 424 main_dispatch_engine(int fd, short event, void *bula) 425 { 426 struct imsgev *iev = bula; 427 struct imsgbuf *ibuf; 428 struct imsg imsg; 429 struct imsg_proposal proposal; 430 struct imsg_configure_address address; 431 struct imsg_configure_dfr dfr; 432 ssize_t n; 433 int shut = 0; 434 435 ibuf = &iev->ibuf; 436 437 if (event & EV_READ) { 438 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 439 fatal("imsg_read error"); 440 if (n == 0) /* Connection closed. */ 441 shut = 1; 442 } 443 if (event & EV_WRITE) { 444 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 445 fatal("msgbuf_write"); 446 if (n == 0) /* Connection closed. */ 447 shut = 1; 448 } 449 450 for (;;) { 451 if ((n = imsg_get(ibuf, &imsg)) == -1) 452 fatal("imsg_get"); 453 if (n == 0) /* No more messages. */ 454 break; 455 456 switch (imsg.hdr.type) { 457 case IMSG_PROPOSAL: 458 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(proposal)) 459 fatal("%s: IMSG_PROPOSAL wrong " 460 "length: %d", __func__, imsg.hdr.len); 461 memcpy(&proposal, imsg.data, sizeof(proposal)); 462 handle_proposal(&proposal); 463 break; 464 case IMSG_CONFIGURE_ADDRESS: 465 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(address)) 466 fatal("%s: IMSG_CONFIGURE_ADDRESS wrong " 467 "length: %d", __func__, imsg.hdr.len); 468 memcpy(&address, imsg.data, sizeof(address)); 469 configure_interface(&address); 470 break; 471 case IMSG_CONFIGURE_DFR: 472 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(dfr)) 473 fatal("%s: IMSG_CONFIGURE_DFR wrong " 474 "length: %d", __func__, imsg.hdr.len); 475 memcpy(&dfr, imsg.data, sizeof(dfr)); 476 add_gateway(&dfr); 477 break; 478 case IMSG_WITHDRAW_DFR: 479 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(dfr)) 480 fatal("%s: IMSG_CONFIGURE_DFR wrong " 481 "length: %d", __func__, imsg.hdr.len); 482 memcpy(&dfr, imsg.data, sizeof(dfr)); 483 delete_gateway(&dfr); 484 break; 485 default: 486 log_debug("%s: error handling imsg %d", __func__, 487 imsg.hdr.type); 488 break; 489 } 490 imsg_free(&imsg); 491 } 492 if (!shut) 493 imsg_event_add(iev); 494 else { 495 /* This pipe is dead. Remove its event handler. */ 496 event_del(&iev->ev); 497 event_loopexit(NULL); 498 } 499 } 500 501 int 502 main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 503 { 504 if (iev_frontend) 505 return (imsg_compose_event(iev_frontend, type, 0, pid, -1, data, 506 datalen)); 507 else 508 return (-1); 509 } 510 511 int 512 main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) 513 { 514 if (iev_engine) 515 return(imsg_compose_event(iev_engine, type, 0, pid, -1, data, 516 datalen)); 517 else 518 return (-1); 519 } 520 521 void 522 imsg_event_add(struct imsgev *iev) 523 { 524 iev->events = EV_READ; 525 if (iev->ibuf.w.queued) 526 iev->events |= EV_WRITE; 527 528 event_del(&iev->ev); 529 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 530 event_add(&iev->ev, NULL); 531 } 532 533 int 534 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 535 pid_t pid, int fd, void *data, uint16_t datalen) 536 { 537 int ret; 538 539 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 540 datalen)) != -1) 541 imsg_event_add(iev); 542 543 return (ret); 544 } 545 546 static int 547 main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 548 struct imsgbuf *engine_buf) 549 { 550 int pipe_frontend2engine[2]; 551 552 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 553 PF_UNSPEC, pipe_frontend2engine) == -1) 554 return (-1); 555 556 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 557 pipe_frontend2engine[0], NULL, 0) == -1) 558 return (-1); 559 imsg_flush(frontend_buf); 560 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 561 pipe_frontend2engine[1], NULL, 0) == -1) 562 return (-1); 563 imsg_flush(engine_buf); 564 return (0); 565 } 566 567 #define ROUNDUP(a) \ 568 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 569 570 void 571 handle_proposal(struct imsg_proposal *proposal) 572 { 573 struct rt_msghdr rtm; 574 struct sockaddr_in6 ifa, mask; 575 struct sockaddr_rtlabel rl; 576 struct iovec iov[13]; 577 long pad = 0; 578 int iovcnt = 0, padlen; 579 580 memset(&rtm, 0, sizeof(rtm)); 581 582 rtm.rtm_version = RTM_VERSION; 583 rtm.rtm_type = RTM_PROPOSAL; 584 rtm.rtm_msglen = sizeof(rtm); 585 rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */ 586 rtm.rtm_index = proposal->if_index; 587 rtm.rtm_seq = ++rtm_seq; 588 rtm.rtm_priority = RTP_PROPOSAL_SLAAC; 589 rtm.rtm_addrs = (proposal->rtm_addrs & (RTA_NETMASK | RTA_IFA)) | 590 RTA_LABEL; 591 rtm.rtm_flags = RTF_UP; 592 593 iov[iovcnt].iov_base = &rtm; 594 iov[iovcnt++].iov_len = sizeof(rtm); 595 596 if (rtm.rtm_addrs & RTA_NETMASK) { 597 memset(&mask, 0, sizeof(mask)); 598 mask.sin6_family = AF_INET6; 599 mask.sin6_len = sizeof(struct sockaddr_in6); 600 mask.sin6_addr = proposal->mask; 601 602 iov[iovcnt].iov_base = &mask; 603 iov[iovcnt++].iov_len = sizeof(mask); 604 rtm.rtm_msglen += sizeof(mask); 605 padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 606 if (padlen > 0) { 607 iov[iovcnt].iov_base = &pad; 608 iov[iovcnt++].iov_len = padlen; 609 rtm.rtm_msglen += padlen; 610 } 611 } 612 613 if (rtm.rtm_addrs & RTA_IFA) { 614 memcpy(&ifa, &proposal->addr, sizeof(ifa)); 615 616 if (ifa.sin6_family != AF_INET6 || ifa.sin6_len != 617 sizeof(struct sockaddr_in6)) { 618 log_warnx("%s: invalid address", __func__); 619 return; 620 } 621 622 iov[iovcnt].iov_base = &ifa; 623 iov[iovcnt++].iov_len = sizeof(ifa); 624 rtm.rtm_msglen += sizeof(ifa); 625 padlen = ROUNDUP(sizeof(ifa)) - sizeof(ifa); 626 if (padlen > 0) { 627 iov[iovcnt].iov_base = &pad; 628 iov[iovcnt++].iov_len = padlen; 629 rtm.rtm_msglen += padlen; 630 } 631 } 632 633 rl.sr_len = sizeof(rl); 634 rl.sr_family = AF_UNSPEC; 635 if (snprintf(rl.sr_label, sizeof(rl.sr_label), "%s: %lld %d", "slaacd", 636 proposal->id, (int32_t)proposal->pid) >= 637 (ssize_t)sizeof(rl.sr_label)) 638 log_warnx("route label truncated"); 639 640 iov[iovcnt].iov_base = &rl; 641 iov[iovcnt++].iov_len = sizeof(rl); 642 rtm.rtm_msglen += sizeof(rl); 643 padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 644 if (padlen > 0) { 645 iov[iovcnt].iov_base = &pad; 646 iov[iovcnt++].iov_len = padlen; 647 rtm.rtm_msglen += padlen; 648 } 649 650 if (writev(routesock, iov, iovcnt) == -1) 651 log_warn("failed to send proposal"); 652 } 653 654 void 655 configure_interface(struct imsg_configure_address *address) 656 { 657 658 struct in6_aliasreq in6_addreq; 659 time_t t; 660 char *if_name; 661 662 memset(&in6_addreq, 0, sizeof(in6_addreq)); 663 664 if_name = if_indextoname(address->if_index, in6_addreq.ifra_name); 665 if (if_name == NULL) { 666 log_warnx("%s: cannot find interface %d", __func__, 667 address->if_index); 668 return; 669 } 670 671 memcpy(&in6_addreq.ifra_addr, &address->addr, 672 sizeof(in6_addreq.ifra_addr)); 673 memcpy(&in6_addreq.ifra_prefixmask.sin6_addr, &address->mask, 674 sizeof(in6_addreq.ifra_prefixmask.sin6_addr)); 675 in6_addreq.ifra_prefixmask.sin6_family = AF_INET6; 676 in6_addreq.ifra_prefixmask.sin6_len = 677 sizeof(in6_addreq.ifra_prefixmask); 678 679 t = time(NULL); 680 681 in6_addreq.ifra_lifetime.ia6t_expire = t + address->vltime; 682 in6_addreq.ifra_lifetime.ia6t_vltime = address->vltime; 683 684 in6_addreq.ifra_lifetime.ia6t_preferred = t + address->pltime; 685 in6_addreq.ifra_lifetime.ia6t_pltime = address->pltime; 686 687 in6_addreq.ifra_flags |= IN6_IFF_AUTOCONF; 688 689 if (address->privacy) 690 in6_addreq.ifra_flags |= IN6_IFF_PRIVACY; 691 692 log_debug("%s: %s", __func__, if_name); 693 694 if (ioctl(ioctl_sock, SIOCAIFADDR_IN6, &in6_addreq) < 0) 695 fatal("SIOCAIFADDR_IN6"); 696 } 697 698 void 699 configure_gateway(struct imsg_configure_dfr *dfr, uint8_t rtm_type) 700 { 701 struct rt_msghdr rtm; 702 struct sockaddr_in6 dst, gw, mask; 703 struct iovec iov[8]; 704 long pad = 0; 705 int iovcnt = 0, padlen; 706 707 memset(&rtm, 0, sizeof(rtm)); 708 709 rtm.rtm_version = RTM_VERSION; 710 rtm.rtm_type = rtm_type; 711 rtm.rtm_msglen = sizeof(rtm); 712 rtm.rtm_tableid = 0; /* XXX imsg->rdomain; */ 713 rtm.rtm_index = dfr->if_index; 714 rtm.rtm_seq = ++rtm_seq; 715 rtm.rtm_priority = RTP_DEFAULT; 716 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 717 rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 718 719 iov[iovcnt].iov_base = &rtm; 720 iov[iovcnt++].iov_len = sizeof(rtm); 721 722 memset(&dst, 0, sizeof(mask)); 723 dst.sin6_family = AF_INET6; 724 dst.sin6_len = sizeof(struct sockaddr_in6); 725 726 iov[iovcnt].iov_base = &dst; 727 iov[iovcnt++].iov_len = sizeof(dst); 728 rtm.rtm_msglen += sizeof(dst); 729 padlen = ROUNDUP(sizeof(dst)) - sizeof(dst); 730 if (padlen > 0) { 731 iov[iovcnt].iov_base = &pad; 732 iov[iovcnt++].iov_len = padlen; 733 rtm.rtm_msglen += padlen; 734 } 735 736 memcpy(&gw, &dfr->addr, sizeof(gw)); 737 *(u_int16_t *)& gw.sin6_addr.s6_addr[2] = htons(gw.sin6_scope_id); 738 /* gw.sin6_scope_id = 0; XXX route(8) does this*/ 739 iov[iovcnt].iov_base = &gw; 740 iov[iovcnt++].iov_len = sizeof(gw); 741 rtm.rtm_msglen += sizeof(gw); 742 padlen = ROUNDUP(sizeof(gw)) - sizeof(gw); 743 if (padlen > 0) { 744 iov[iovcnt].iov_base = &pad; 745 iov[iovcnt++].iov_len = padlen; 746 rtm.rtm_msglen += padlen; 747 } 748 749 memset(&mask, 0, sizeof(mask)); 750 mask.sin6_family = AF_INET6; 751 mask.sin6_len = 0;//sizeof(struct sockaddr_in6); 752 iov[iovcnt].iov_base = &mask; 753 iov[iovcnt++].iov_len = sizeof(mask); 754 rtm.rtm_msglen += sizeof(mask); 755 padlen = ROUNDUP(sizeof(mask)) - sizeof(mask); 756 if (padlen > 0) { 757 iov[iovcnt].iov_base = &pad; 758 iov[iovcnt++].iov_len = padlen; 759 rtm.rtm_msglen += padlen; 760 } 761 762 if (writev(routesock, iov, iovcnt) == -1) 763 log_warn("failed to send route message"); 764 } 765 766 void 767 add_gateway(struct imsg_configure_dfr *dfr) 768 { 769 configure_gateway(dfr, RTM_ADD); 770 } 771 772 void 773 delete_gateway(struct imsg_configure_dfr *dfr) 774 { 775 configure_gateway(dfr, RTM_DELETE); 776 } 777