1 /* $NetBSD: faithd.c,v 1.33 2010/11/26 18:58:43 christos Exp $ */ 2 /* $KAME: faithd.c,v 1.62 2003/08/19 21:20:33 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1997 and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * User level translator from IPv6 to IPv4. 35 * 36 * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...] 37 * e.g. faithd telnet /usr/local/v6/sbin/telnetd telnetd 38 */ 39 40 #include <sys/cdefs.h> 41 #include <sys/param.h> 42 #include <sys/types.h> 43 #include <sys/sysctl.h> 44 #include <sys/socket.h> 45 #include <sys/wait.h> 46 #include <sys/stat.h> 47 #include <sys/time.h> 48 #include <sys/ioctl.h> 49 50 #include <poll.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <stdarg.h> 54 #include <string.h> 55 #include <syslog.h> 56 #include <unistd.h> 57 #include <errno.h> 58 #include <signal.h> 59 #include <fcntl.h> 60 #include <termios.h> 61 62 #include <net/if_types.h> 63 #ifdef IFT_FAITH 64 # define USE_ROUTE 65 # include <net/if.h> 66 # include <net/route.h> 67 # include <net/if_dl.h> 68 #endif 69 70 #include <netinet/in.h> 71 #include <arpa/inet.h> 72 #include <netdb.h> 73 #include <ifaddrs.h> 74 75 #include "faithd.h" 76 #include "prefix.h" 77 78 char *serverpath = NULL; 79 char *serverarg[MAXARGV + 1]; 80 char logname[BUFSIZ]; 81 char procname[BUFSIZ]; 82 struct myaddrs { 83 struct myaddrs *next; 84 struct sockaddr *addr; 85 }; 86 struct myaddrs *myaddrs = NULL; 87 static const char *service; 88 #ifdef USE_ROUTE 89 static int sockfd = 0; 90 #endif 91 int dflag = 0; 92 static int pflag = 0; 93 static int inetd = 0; 94 static char *configfile = NULL; 95 96 static int inetd_main(int, char **); 97 static int daemon_main(int, char **); 98 static void play_service(int); 99 static void play_child(int, struct sockaddr *); 100 static int faith_prefix(struct sockaddr *); 101 static int map6to4(struct sockaddr_in6 *, struct sockaddr_in *); 102 static void sig_child(int); 103 static void sig_terminate(int); 104 static void start_daemon(void); 105 static void exit_stderr(const char *, ...) 106 __attribute__((__format__(__printf__, 1, 2))); 107 static void grab_myaddrs(void); 108 static void free_myaddrs(void); 109 static void update_myaddrs(void); 110 static void usage(void) __attribute__((__noreturn__)); 111 112 int 113 main(int argc, char **argv) 114 { 115 116 /* 117 * Initializing stuff 118 */ 119 120 setprogname(argv[0]); 121 122 if (strcmp(getprogname(), "faithd") != 0) { 123 inetd = 1; 124 return inetd_main(argc, argv); 125 } else 126 return daemon_main(argc, argv); 127 } 128 129 static int 130 inetd_main(int argc, char **argv) 131 { 132 char path[MAXPATHLEN]; 133 struct sockaddr_storage me; 134 struct sockaddr_storage from; 135 socklen_t melen, fromlen; 136 int i; 137 int error; 138 const int on = 1; 139 char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; 140 141 if (config_load(configfile) < 0 && configfile) { 142 exit_failure("could not load config file"); 143 /*NOTREACHED*/ 144 } 145 146 if (strrchr(argv[0], '/') == NULL) 147 (void)snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, 148 argv[0]); 149 else 150 (void)snprintf(path, sizeof(path), "%s", argv[0]); 151 152 #ifdef USE_ROUTE 153 grab_myaddrs(); 154 155 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 156 if (sockfd < 0) { 157 exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 158 /*NOTREACHED*/ 159 } 160 #endif 161 162 melen = sizeof(me); 163 if (getsockname(STDIN_FILENO, (void *)&me, &melen) == -1) { 164 exit_failure("getsockname: %s", strerror(errno)); 165 /*NOTREACHED*/ 166 } 167 fromlen = sizeof(from); 168 if (getpeername(STDIN_FILENO, (void *)&from, &fromlen) == -1) { 169 exit_failure("getpeername: %s", strerror(errno)); 170 /*NOTREACHED*/ 171 } 172 if (getnameinfo((void *)&me, melen, NULL, 0, 173 sbuf, (socklen_t)sizeof(sbuf), NI_NUMERICHOST) == 0) 174 service = sbuf; 175 else 176 service = DEFAULT_PORT_NAME; 177 if (getnameinfo((void *)&me, melen, NULL, 0, 178 snum, (socklen_t)sizeof(snum), NI_NUMERICHOST) != 0) 179 (void)snprintf(snum, sizeof(snum), "?"); 180 181 (void)snprintf(logname, sizeof(logname), "faithd %s", snum); 182 (void)snprintf(procname, sizeof(procname), "accepting port %s", snum); 183 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 184 185 if (argc >= MAXARGV) { 186 exit_failure("too many arguments"); 187 /*NOTREACHED*/ 188 } 189 serverarg[0] = serverpath = path; 190 for (i = 1; i < argc; i++) 191 serverarg[i] = argv[i]; 192 serverarg[i] = NULL; 193 194 error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, 195 (socklen_t)sizeof(on)); 196 if (error < 0) { 197 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 198 /*NOTREACHED*/ 199 } 200 201 play_child(STDIN_FILENO, (void *)&from); 202 exit_failure("should not reach here"); 203 return 0; /*dummy!*/ 204 } 205 206 static int 207 daemon_main(int argc, char **argv) 208 { 209 struct addrinfo hints, *res; 210 int s_wld, error, i, serverargc, on = 1; 211 int family = AF_INET6; 212 int c; 213 214 while ((c = getopt(argc, argv, "df:p")) != -1) { 215 switch (c) { 216 case 'd': 217 dflag++; 218 break; 219 case 'f': 220 configfile = optarg; 221 break; 222 case 'p': 223 pflag++; 224 break; 225 default: 226 usage(); 227 /*NOTREACHED*/ 228 } 229 } 230 argc -= optind; 231 argv += optind; 232 233 if (config_load(configfile) < 0 && configfile) { 234 exit_failure("could not load config file"); 235 /*NOTREACHED*/ 236 } 237 238 239 #ifdef USE_ROUTE 240 grab_myaddrs(); 241 #endif 242 243 switch (argc) { 244 case 0: 245 usage(); 246 /*NOTREACHED*/ 247 default: 248 serverargc = argc - NUMARG; 249 if (serverargc >= MAXARGV) 250 exit_stderr("too many arguments"); 251 252 serverpath = strdup(argv[NUMPRG]); 253 if (!serverpath) 254 exit_stderr("not enough core"); 255 for (i = 0; i < serverargc; i++) { 256 serverarg[i] = strdup(argv[i + NUMARG]); 257 if (!serverarg[i]) 258 exit_stderr("not enough core"); 259 } 260 serverarg[i] = NULL; 261 /*FALLTHROUGH*/ 262 case 1: /* no local service */ 263 service = argv[NUMPRT]; 264 break; 265 } 266 267 start_daemon(); 268 269 /* 270 * Opening wild card socket for this service. 271 */ 272 273 memset(&hints, 0, sizeof(hints)); 274 hints.ai_flags = AI_PASSIVE; 275 hints.ai_family = family; 276 hints.ai_socktype = SOCK_STREAM; 277 hints.ai_protocol = IPPROTO_TCP; /* SCTP? */ 278 error = getaddrinfo(NULL, service, &hints, &res); 279 if (error) 280 exit_failure("getaddrinfo: %s", gai_strerror(error)); 281 282 s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 283 if (s_wld == -1) 284 exit_failure("socket: %s", strerror(errno)); 285 286 #ifdef IPV6_FAITH 287 if (res->ai_family == AF_INET6) { 288 error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, 289 (socklen_t)sizeof(on)); 290 if (error == -1) 291 exit_failure("setsockopt(IPV6_FAITH): %s", 292 strerror(errno)); 293 } 294 #endif 295 296 error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, 297 (socklen_t)sizeof(on)); 298 if (error == -1) 299 exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno)); 300 301 error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, 302 (socklen_t)sizeof(on)); 303 if (error == -1) 304 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 305 306 #ifdef IPV6_V6ONLY 307 error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on, 308 (socklen_t)sizeof(on)); 309 if (error == -1) 310 exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno)); 311 #endif 312 313 error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); 314 if (error == -1) 315 exit_failure("bind: %s", strerror(errno)); 316 317 error = listen(s_wld, 5); 318 if (error == -1) 319 exit_failure("listen: %s", strerror(errno)); 320 321 #ifdef USE_ROUTE 322 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 323 if (sockfd < 0) { 324 exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 325 /*NOTREACHED*/ 326 } 327 #endif 328 329 /* 330 * Everything is OK. 331 */ 332 333 (void)snprintf(logname, sizeof(logname), "faithd %s", service); 334 (void)snprintf(procname, sizeof(procname), "accepting port %s", service); 335 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 336 syslog(LOG_INFO, "Staring faith daemon for %s port", service); 337 338 play_service(s_wld); 339 return 1; 340 } 341 342 static void 343 play_service(int s_wld) 344 { 345 struct sockaddr_storage srcaddr; 346 socklen_t len; 347 int s_src; 348 pid_t child_pid; 349 struct pollfd pfd[2]; 350 int error; 351 352 /* 353 * Wait, accept, fork, faith.... 354 */ 355 again: 356 setproctitle("%s", procname); 357 358 pfd[0].fd = s_wld; 359 pfd[0].events = POLLIN; 360 pfd[1].fd = -1; 361 pfd[1].revents = 0; 362 #ifdef USE_ROUTE 363 if (sockfd) { 364 pfd[1].fd = sockfd; 365 pfd[1].events = POLLIN; 366 } 367 #endif 368 369 error = poll(pfd, (unsigned int)(sizeof(pfd) / sizeof(pfd[0])), INFTIM); 370 if (error < 0) { 371 if (errno == EINTR) 372 goto again; 373 exit_failure("select: %s", strerror(errno)); 374 /*NOTREACHED*/ 375 } 376 377 #ifdef USE_ROUTE 378 if (pfd[1].revents & POLLIN) 379 { 380 update_myaddrs(); 381 } 382 #endif 383 if (pfd[0].revents & POLLIN) 384 { 385 len = sizeof(srcaddr); 386 s_src = accept(s_wld, (void *)&srcaddr, &len); 387 if (s_src < 0) { 388 if (errno == ECONNABORTED) 389 goto again; 390 exit_failure("socket: %s", strerror(errno)); 391 /*NOTREACHED*/ 392 } 393 if (srcaddr.ss_family == AF_INET6 && 394 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)&srcaddr)->sin6_addr)) { 395 (void)close(s_src); 396 syslog(LOG_ERR, "connection from IPv4 mapped address?"); 397 goto again; 398 } 399 400 child_pid = fork(); 401 402 if (child_pid == 0) { 403 /* child process */ 404 (void)close(s_wld); 405 closelog(); 406 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 407 play_child(s_src, (void *)&srcaddr); 408 exit_failure("should never reach here"); 409 /*NOTREACHED*/ 410 } else { 411 /* parent process */ 412 (void)close(s_src); 413 if (child_pid == -1) 414 syslog(LOG_ERR, "can't fork"); 415 } 416 } 417 goto again; 418 } 419 420 static void 421 play_child(int s_src, struct sockaddr *srcaddr) 422 { 423 struct sockaddr_storage dstaddr6; 424 struct sockaddr_storage dstaddr4; 425 char src[NI_MAXHOST]; 426 char dst6[NI_MAXHOST]; 427 char dst4[NI_MAXHOST]; 428 socklen_t len = sizeof(dstaddr6); 429 int s_dst, error, hport, nresvport, on = 1; 430 struct timeval tv; 431 struct sockaddr *sa4; 432 const struct config *conf; 433 434 tv.tv_sec = 1; 435 tv.tv_usec = 0; 436 437 (void)getnameinfo(srcaddr, (socklen_t)srcaddr->sa_len, 438 src, (socklen_t)sizeof(src), NULL, 0, NI_NUMERICHOST); 439 syslog(LOG_INFO, "accepted a client from %s", src); 440 441 error = getsockname(s_src, (void *)&dstaddr6, &len); 442 if (error == -1) { 443 exit_failure("getsockname: %s", strerror(errno)); 444 /*NOTREACHED*/ 445 } 446 447 (void)getnameinfo((void *)&dstaddr6, len, 448 dst6, (socklen_t)sizeof(dst6), NULL, 0, NI_NUMERICHOST); 449 syslog(LOG_INFO, "the client is connecting to %s", dst6); 450 451 if (!faith_prefix((void *)&dstaddr6)) { 452 if (serverpath) { 453 /* 454 * Local service 455 */ 456 syslog(LOG_INFO, "executing local %s", serverpath); 457 if (!inetd) { 458 (void)dup2(s_src, 0); 459 (void)close(s_src); 460 (void)dup2(0, 1); 461 (void)dup2(0, 2); 462 } 463 (void)execv(serverpath, serverarg); 464 syslog(LOG_ERR, "execv %s: %s", serverpath, 465 strerror(errno)); 466 _exit(EXIT_FAILURE); 467 } else { 468 (void)close(s_src); 469 exit_success("no local service for %s", service); 470 } 471 } 472 473 /* 474 * Act as a translator 475 */ 476 477 switch (((struct sockaddr *)(void *)&dstaddr6)->sa_family) { 478 case AF_INET6: 479 if (!map6to4((struct sockaddr_in6 *)(void *)&dstaddr6, 480 (struct sockaddr_in *)(void *)&dstaddr4)) { 481 (void)close(s_src); 482 exit_failure("map6to4 failed"); 483 /*NOTREACHED*/ 484 } 485 syslog(LOG_INFO, "translating from v6 to v4"); 486 break; 487 default: 488 (void)close(s_src); 489 exit_failure("family not supported"); 490 /*NOTREACHED*/ 491 } 492 493 sa4 = (void *)&dstaddr4; 494 (void)getnameinfo(sa4, (socklen_t)sa4->sa_len, 495 dst4, (socklen_t)sizeof(dst4), NULL, 0, NI_NUMERICHOST); 496 497 conf = config_match(srcaddr, sa4); 498 if (!conf || !conf->permit) { 499 (void)close(s_src); 500 if (conf) { 501 exit_failure("translation to %s not permitted for %s", 502 dst4, prefix_string(&conf->match)); 503 /*NOTREACHED*/ 504 } else { 505 exit_failure("translation to %s not permitted", dst4); 506 /*NOTREACHED*/ 507 } 508 } 509 510 syslog(LOG_INFO, "the translator is connecting to %s", dst4); 511 512 setproctitle("port %s, %s -> %s", service, src, dst4); 513 514 if (sa4->sa_family == AF_INET6) 515 hport = ntohs(((struct sockaddr_in6 *)(void *)&dstaddr4)->sin6_port); 516 else /* AF_INET */ 517 hport = ntohs(((struct sockaddr_in *)(void *)&dstaddr4)->sin_port); 518 519 if (pflag) 520 s_dst = rresvport_af(&nresvport, sa4->sa_family); 521 else 522 s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); 523 if (s_dst < 0) { 524 exit_failure("socket: %s", strerror(errno)); 525 /*NOTREACHED*/ 526 } 527 528 if (conf->src.a.ss_family) { 529 if (bind(s_dst, (const void*)&conf->src.a, 530 (socklen_t)conf->src.a.ss_len) < 0) { 531 exit_failure("bind: %s", strerror(errno)); 532 /*NOTREACHED*/ 533 } 534 } 535 536 error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, 537 (socklen_t)sizeof(on)); 538 if (error < 0) { 539 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 540 /*NOTREACHED*/ 541 } 542 543 error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, 544 (socklen_t)sizeof(tv)); 545 if (error < 0) { 546 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); 547 /*NOTREACHED*/ 548 } 549 error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, 550 (socklen_t)sizeof(tv)); 551 if (error < 0) { 552 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); 553 /*NOTREACHED*/ 554 } 555 556 error = connect(s_dst, sa4, (socklen_t)sa4->sa_len); 557 if (error < 0) { 558 exit_failure("connect: %s", strerror(errno)); 559 /*NOTREACHED*/ 560 } 561 562 switch (hport) { 563 case FTP_PORT: 564 ftp_relay(s_src, s_dst); 565 break; 566 default: 567 tcp_relay(s_src, s_dst, service); 568 break; 569 } 570 571 /* NOTREACHED */ 572 } 573 574 /* 0: non faith, 1: faith */ 575 static int 576 faith_prefix(struct sockaddr *dst) 577 { 578 #ifndef USE_ROUTE 579 int mib[4], size; 580 struct in6_addr faith_prefix; 581 struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst; 582 583 if (dst->sa_family != AF_INET6) 584 return 0; 585 586 mib[0] = CTL_NET; 587 mib[1] = PF_INET6; 588 mib[2] = IPPROTO_IPV6; 589 mib[3] = IPV6CTL_FAITH_PREFIX; 590 size = sizeof(struct in6_addr); 591 if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { 592 exit_failure("sysctl: %s", strerror(errno)); 593 /*NOTREACHED*/ 594 } 595 596 return memcmp(dst, &faith_prefix, 597 sizeof(struct in6_addr) - sizeof(struct in_addr)) == 0; 598 #else 599 struct myaddrs *p; 600 struct sockaddr_in6 *sin6; 601 struct sockaddr_in *sin4; 602 struct sockaddr_in6 *dst6; 603 struct sockaddr_in *dst4; 604 struct sockaddr_in dstmap; 605 606 dst6 = (void *)dst; 607 if (dst->sa_family == AF_INET6 608 && IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) { 609 /* ugly... */ 610 memset(&dstmap, 0, sizeof(dstmap)); 611 dstmap.sin_family = AF_INET; 612 dstmap.sin_len = sizeof(dstmap); 613 memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12], 614 sizeof(dstmap.sin_addr)); 615 dst = (void *)&dstmap; 616 } 617 618 dst6 = (void *)dst; 619 dst4 = (void *)dst; 620 621 for (p = myaddrs; p; p = p->next) { 622 sin6 = (void *)p->addr; 623 sin4 = (void *)p->addr; 624 625 if (p->addr->sa_len != dst->sa_len 626 || p->addr->sa_family != dst->sa_family) 627 continue; 628 629 switch (dst->sa_family) { 630 case AF_INET6: 631 if (sin6->sin6_scope_id == dst6->sin6_scope_id 632 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr)) 633 return 0; 634 break; 635 case AF_INET: 636 if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr) 637 return 0; 638 break; 639 } 640 } 641 return 1; 642 #endif 643 } 644 645 /* 0: non faith, 1: faith */ 646 static int 647 map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) 648 { 649 memset(dst4, 0, sizeof(*dst4)); 650 dst4->sin_len = sizeof(*dst4); 651 dst4->sin_family = AF_INET; 652 dst4->sin_port = dst6->sin6_port; 653 memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12], 654 sizeof(dst4->sin_addr)); 655 656 if (dst4->sin_addr.s_addr == INADDR_ANY 657 || dst4->sin_addr.s_addr == INADDR_BROADCAST 658 || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) 659 return 0; 660 661 return 1; 662 } 663 664 665 static void 666 /*ARGSUSED*/ 667 sig_child(int sig) 668 { 669 int status; 670 pid_t pid; 671 672 while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) 673 if (WEXITSTATUS(status)) 674 syslog(LOG_WARNING, "child %ld exit status 0x%x", 675 (long)pid, status); 676 } 677 678 void 679 /*ARGSUSED*/ 680 sig_terminate(int sig) 681 { 682 syslog(LOG_INFO, "Terminating faith daemon"); 683 exit(EXIT_SUCCESS); 684 } 685 686 static void 687 start_daemon(void) 688 { 689 #ifdef SA_NOCLDWAIT 690 struct sigaction sa; 691 #endif 692 693 if (daemon(0, 0) == -1) 694 exit_stderr("daemon: %s", strerror(errno)); 695 696 #ifdef SA_NOCLDWAIT 697 (void)memset(&sa, 0, sizeof(sa)); 698 sa.sa_handler = sig_child; 699 sa.sa_flags = SA_NOCLDWAIT; 700 (void)sigemptyset(&sa.sa_mask); 701 (void)sigaction(SIGCHLD, &sa, (struct sigaction *)0); 702 #else 703 if (signal(SIGCHLD, sig_child) == SIG_ERR) { 704 exit_failure("signal CHLD: %s", strerror(errno)); 705 /*NOTREACHED*/ 706 } 707 #endif 708 709 if (signal(SIGTERM, sig_terminate) == SIG_ERR) { 710 exit_failure("signal TERM: %s", strerror(errno)); 711 /*NOTREACHED*/ 712 } 713 } 714 715 static void 716 exit_stderr(const char *fmt, ...) 717 { 718 va_list ap; 719 720 va_start(ap, fmt); 721 (void)fprintf(stderr, "%s: ", getprogname()); 722 (void)vfprintf(stderr, fmt, ap); 723 va_end(ap); 724 exit(EXIT_FAILURE); 725 } 726 727 void 728 exit_failure(const char *fmt, ...) 729 { 730 va_list ap; 731 732 va_start(ap, fmt); 733 vsyslog(LOG_ERR, fmt, ap); 734 va_end(ap); 735 exit(EXIT_FAILURE); 736 } 737 738 void 739 exit_success(const char *fmt, ...) 740 { 741 va_list ap; 742 743 va_start(ap, fmt); 744 vsyslog(LOG_INFO, fmt, ap); 745 va_end(ap); 746 exit(EXIT_SUCCESS); 747 } 748 749 #ifdef USE_ROUTE 750 static void 751 grab_myaddrs(void) 752 { 753 struct ifaddrs *ifap, *ifa; 754 struct myaddrs *p; 755 struct sockaddr_in6 *sin6; 756 757 if (getifaddrs(&ifap) != 0) { 758 exit_failure("getifaddrs"); 759 /*NOTREACHED*/ 760 } 761 762 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 763 switch (ifa->ifa_addr->sa_family) { 764 case AF_INET: 765 case AF_INET6: 766 break; 767 default: 768 continue; 769 } 770 771 p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + 772 ifa->ifa_addr->sa_len); 773 if (!p) { 774 exit_failure("not enough core"); 775 /*NOTREACHED*/ 776 } 777 memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); 778 p->next = myaddrs; 779 p->addr = (void *)(p + 1); 780 #ifdef __KAME__ 781 if (ifa->ifa_addr->sa_family == AF_INET6) { 782 sin6 = (void *)p->addr; 783 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) 784 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { 785 sin6->sin6_scope_id = 786 ntohs(*(uint16_t *)(void *) 787 &sin6->sin6_addr.s6_addr[3]); 788 sin6->sin6_addr.s6_addr[2] = 0; 789 sin6->sin6_addr.s6_addr[3] = 0; 790 } 791 } 792 #endif 793 myaddrs = p; 794 if (dflag) { 795 char hbuf[NI_MAXHOST]; 796 (void)getnameinfo(p->addr, (socklen_t)p->addr->sa_len, 797 hbuf, (socklen_t)sizeof(hbuf), NULL, 0, 798 NI_NUMERICHOST); 799 syslog(LOG_INFO, "my interface: %s %s", hbuf, 800 ifa->ifa_name); 801 } 802 } 803 804 freeifaddrs(ifap); 805 } 806 807 static void 808 free_myaddrs(void) 809 { 810 struct myaddrs *p, *q; 811 812 p = myaddrs; 813 while (p) { 814 q = p->next; 815 free(p); 816 p = q; 817 } 818 myaddrs = NULL; 819 } 820 821 static void 822 update_myaddrs(void) 823 { 824 char msg[BUFSIZ]; 825 ssize_t len; 826 struct rt_msghdr *rtm; 827 828 len = read(sockfd, msg, sizeof(msg)); 829 if (len < 0) { 830 syslog(LOG_ERR, "read(PF_ROUTE) failed"); 831 return; 832 } 833 rtm = (void *)msg; 834 if (len < 4 || len < rtm->rtm_msglen) { 835 syslog(LOG_ERR, "read(PF_ROUTE) short read"); 836 return; 837 } 838 if (rtm->rtm_version != RTM_VERSION) { 839 syslog(LOG_ERR, "routing socket version mismatch"); 840 (void)close(sockfd); 841 sockfd = 0; 842 return; 843 } 844 switch (rtm->rtm_type) { 845 case RTM_NEWADDR: 846 case RTM_DELADDR: 847 case RTM_IFINFO: 848 break; 849 default: 850 return; 851 } 852 /* XXX more filters here? */ 853 854 syslog(LOG_INFO, "update interface address list"); 855 free_myaddrs(); 856 grab_myaddrs(); 857 } 858 #endif /*USE_ROUTE*/ 859 860 static void 861 usage(void) 862 { 863 (void)fprintf(stderr, 864 "Usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", 865 getprogname()); 866 exit(0); 867 } 868