1 /* $NetBSD: faithd.c,v 1.32 2007/12/15 16:32:07 perry 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 static char *faithdname = NULL; 81 char logname[BUFSIZ]; 82 char procname[BUFSIZ]; 83 struct myaddrs { 84 struct myaddrs *next; 85 struct sockaddr *addr; 86 }; 87 struct myaddrs *myaddrs = NULL; 88 static const char *service; 89 #ifdef USE_ROUTE 90 static int sockfd = 0; 91 #endif 92 int dflag = 0; 93 static int pflag = 0; 94 static int inetd = 0; 95 static char *configfile = NULL; 96 97 int main __P((int, char **)); 98 static int inetd_main __P((int, char **)); 99 static int daemon_main __P((int, char **)); 100 static void play_service __P((int)); 101 static void play_child __P((int, struct sockaddr *)); 102 static int faith_prefix __P((struct sockaddr *)); 103 static int map6to4 __P((struct sockaddr_in6 *, struct sockaddr_in *)); 104 static void sig_child __P((int)); 105 static void sig_terminate __P((int)); 106 static void start_daemon __P((void)); 107 static void exit_stderr __P((const char *, ...)) 108 __attribute__((__format__(__printf__, 1, 2))); 109 static void grab_myaddrs __P((void)); 110 static void free_myaddrs __P((void)); 111 static void update_myaddrs __P((void)); 112 static void usage __P((void)); 113 114 int 115 main(int argc, char **argv) 116 { 117 118 /* 119 * Initializing stuff 120 */ 121 122 faithdname = strrchr(argv[0], '/'); 123 if (faithdname) 124 faithdname++; 125 else 126 faithdname = argv[0]; 127 128 if (strcmp(faithdname, "faithd") != 0) { 129 inetd = 1; 130 return inetd_main(argc, argv); 131 } else 132 return daemon_main(argc, argv); 133 } 134 135 static int 136 inetd_main(int argc, char **argv) 137 { 138 char path[MAXPATHLEN]; 139 struct sockaddr_storage me; 140 struct sockaddr_storage from; 141 socklen_t melen, fromlen; 142 int i; 143 int error; 144 const int on = 1; 145 char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; 146 147 if (config_load(configfile) < 0 && configfile) { 148 exit_failure("could not load config file"); 149 /*NOTREACHED*/ 150 } 151 152 if (strrchr(argv[0], '/') == NULL) 153 snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); 154 else 155 snprintf(path, sizeof(path), "%s", argv[0]); 156 157 #ifdef USE_ROUTE 158 grab_myaddrs(); 159 160 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 161 if (sockfd < 0) { 162 exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 163 /*NOTREACHED*/ 164 } 165 #endif 166 167 melen = sizeof(me); 168 if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { 169 exit_failure("getsockname: %s", strerror(errno)); 170 /*NOTREACHED*/ 171 } 172 fromlen = sizeof(from); 173 if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { 174 exit_failure("getpeername: %s", strerror(errno)); 175 /*NOTREACHED*/ 176 } 177 if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 178 sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) 179 service = sbuf; 180 else 181 service = DEFAULT_PORT_NAME; 182 if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 183 snum, sizeof(snum), NI_NUMERICHOST) != 0) 184 snprintf(snum, sizeof(snum), "?"); 185 186 snprintf(logname, sizeof(logname), "faithd %s", snum); 187 snprintf(procname, sizeof(procname), "accepting port %s", snum); 188 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 189 190 if (argc >= MAXARGV) { 191 exit_failure("too many arguments"); 192 /*NOTREACHED*/ 193 } 194 serverarg[0] = serverpath = path; 195 for (i = 1; i < argc; i++) 196 serverarg[i] = argv[i]; 197 serverarg[i] = NULL; 198 199 error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, 200 sizeof(on)); 201 if (error < 0) { 202 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 203 /*NOTREACHED*/ 204 } 205 206 play_child(STDIN_FILENO, (struct sockaddr *)&from); 207 exit_failure("should not reach here"); 208 return 0; /*dummy!*/ 209 } 210 211 static int 212 daemon_main(int argc, char **argv) 213 { 214 struct addrinfo hints, *res; 215 int s_wld, error, i, serverargc, on = 1; 216 int family = AF_INET6; 217 int c; 218 219 while ((c = getopt(argc, argv, "df:p")) != -1) { 220 switch (c) { 221 case 'd': 222 dflag++; 223 break; 224 case 'f': 225 configfile = optarg; 226 break; 227 case 'p': 228 pflag++; 229 break; 230 default: 231 usage(); 232 /*NOTREACHED*/ 233 } 234 } 235 argc -= optind; 236 argv += optind; 237 238 if (config_load(configfile) < 0 && configfile) { 239 exit_failure("could not load config file"); 240 /*NOTREACHED*/ 241 } 242 243 244 #ifdef USE_ROUTE 245 grab_myaddrs(); 246 #endif 247 248 switch (argc) { 249 case 0: 250 usage(); 251 /*NOTREACHED*/ 252 default: 253 serverargc = argc - NUMARG; 254 if (serverargc >= MAXARGV) 255 exit_stderr("too many arguments"); 256 257 serverpath = strdup(argv[NUMPRG]); 258 if (!serverpath) 259 exit_stderr("not enough core"); 260 for (i = 0; i < serverargc; i++) { 261 serverarg[i] = strdup(argv[i + NUMARG]); 262 if (!serverarg[i]) 263 exit_stderr("not enough core"); 264 } 265 serverarg[i] = NULL; 266 /* fall throuth */ 267 case 1: /* no local service */ 268 service = argv[NUMPRT]; 269 break; 270 } 271 272 start_daemon(); 273 274 /* 275 * Opening wild card socket for this service. 276 */ 277 278 memset(&hints, 0, sizeof(hints)); 279 hints.ai_flags = AI_PASSIVE; 280 hints.ai_family = family; 281 hints.ai_socktype = SOCK_STREAM; 282 hints.ai_protocol = IPPROTO_TCP; /* SCTP? */ 283 error = getaddrinfo(NULL, service, &hints, &res); 284 if (error) 285 exit_failure("getaddrinfo: %s", gai_strerror(error)); 286 287 s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 288 if (s_wld == -1) 289 exit_failure("socket: %s", strerror(errno)); 290 291 #ifdef IPV6_FAITH 292 if (res->ai_family == AF_INET6) { 293 error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); 294 if (error == -1) 295 exit_failure("setsockopt(IPV6_FAITH): %s", 296 strerror(errno)); 297 } 298 #endif 299 300 error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 301 if (error == -1) 302 exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno)); 303 304 error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 305 if (error == -1) 306 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 307 308 #ifdef IPV6_V6ONLY 309 error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); 310 if (error == -1) 311 exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno)); 312 #endif 313 314 error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); 315 if (error == -1) 316 exit_failure("bind: %s", strerror(errno)); 317 318 error = listen(s_wld, 5); 319 if (error == -1) 320 exit_failure("listen: %s", strerror(errno)); 321 322 #ifdef USE_ROUTE 323 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 324 if (sockfd < 0) { 325 exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 326 /*NOTREACHED*/ 327 } 328 #endif 329 330 /* 331 * Everything is OK. 332 */ 333 334 snprintf(logname, sizeof(logname), "faithd %s", service); 335 snprintf(procname, sizeof(procname), "accepting port %s", service); 336 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 337 syslog(LOG_INFO, "Staring faith daemon for %s port", service); 338 339 play_service(s_wld); 340 /* NOTREACHED */ 341 exit(1); /*pacify gcc*/ 342 } 343 344 static void 345 play_service(int s_wld) 346 { 347 struct sockaddr_storage srcaddr; 348 socklen_t len; 349 int s_src; 350 pid_t child_pid; 351 struct pollfd pfd[2]; 352 int error; 353 354 /* 355 * Wait, accept, fork, faith.... 356 */ 357 again: 358 setproctitle("%s", procname); 359 360 pfd[0].fd = s_wld; 361 pfd[0].events = POLLIN; 362 pfd[1].fd = -1; 363 pfd[1].revents = 0; 364 #ifdef USE_ROUTE 365 if (sockfd) { 366 pfd[1].fd = sockfd; 367 pfd[1].events = POLLIN; 368 } 369 #endif 370 371 error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), INFTIM); 372 if (error < 0) { 373 if (errno == EINTR) 374 goto again; 375 exit_failure("select: %s", strerror(errno)); 376 /*NOTREACHED*/ 377 } 378 379 #ifdef USE_ROUTE 380 if (pfd[1].revents & POLLIN) 381 { 382 update_myaddrs(); 383 } 384 #endif 385 if (pfd[0].revents & POLLIN) 386 { 387 len = sizeof(srcaddr); 388 s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); 389 if (s_src < 0) { 390 if (errno == ECONNABORTED) 391 goto again; 392 exit_failure("socket: %s", strerror(errno)); 393 /*NOTREACHED*/ 394 } 395 if (srcaddr.ss_family == AF_INET6 && 396 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&srcaddr)->sin6_addr)) { 397 close(s_src); 398 syslog(LOG_ERR, "connection from IPv4 mapped address?"); 399 goto again; 400 } 401 402 child_pid = fork(); 403 404 if (child_pid == 0) { 405 /* child process */ 406 close(s_wld); 407 closelog(); 408 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 409 play_child(s_src, (struct sockaddr *)&srcaddr); 410 exit_failure("should never reach here"); 411 /*NOTREACHED*/ 412 } else { 413 /* parent process */ 414 close(s_src); 415 if (child_pid == -1) 416 syslog(LOG_ERR, "can't fork"); 417 } 418 } 419 goto again; 420 } 421 422 static void 423 play_child(int s_src, struct sockaddr *srcaddr) 424 { 425 struct sockaddr_storage dstaddr6; 426 struct sockaddr_storage dstaddr4; 427 char src[NI_MAXHOST]; 428 char dst6[NI_MAXHOST]; 429 char dst4[NI_MAXHOST]; 430 socklen_t len = sizeof(dstaddr6); 431 int s_dst, error, hport, nresvport, on = 1; 432 struct timeval tv; 433 struct sockaddr *sa4; 434 const struct config *conf; 435 436 tv.tv_sec = 1; 437 tv.tv_usec = 0; 438 439 getnameinfo(srcaddr, srcaddr->sa_len, 440 src, sizeof(src), NULL, 0, NI_NUMERICHOST); 441 syslog(LOG_INFO, "accepted a client from %s", src); 442 443 error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); 444 if (error == -1) { 445 exit_failure("getsockname: %s", strerror(errno)); 446 /*NOTREACHED*/ 447 } 448 449 getnameinfo((struct sockaddr *)&dstaddr6, len, 450 dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); 451 syslog(LOG_INFO, "the client is connecting to %s", dst6); 452 453 if (!faith_prefix((struct sockaddr *)&dstaddr6)) { 454 if (serverpath) { 455 /* 456 * Local service 457 */ 458 syslog(LOG_INFO, "executing local %s", serverpath); 459 if (!inetd) { 460 dup2(s_src, 0); 461 close(s_src); 462 dup2(0, 1); 463 dup2(0, 2); 464 } 465 execv(serverpath, serverarg); 466 syslog(LOG_ERR, "execv %s: %s", serverpath, 467 strerror(errno)); 468 _exit(EXIT_FAILURE); 469 } else { 470 close(s_src); 471 exit_success("no local service for %s", service); 472 } 473 } 474 475 /* 476 * Act as a translator 477 */ 478 479 switch (((struct sockaddr *)&dstaddr6)->sa_family) { 480 case AF_INET6: 481 if (!map6to4((struct sockaddr_in6 *)&dstaddr6, 482 (struct sockaddr_in *)&dstaddr4)) { 483 close(s_src); 484 exit_failure("map6to4 failed"); 485 /*NOTREACHED*/ 486 } 487 syslog(LOG_INFO, "translating from v6 to v4"); 488 break; 489 default: 490 close(s_src); 491 exit_failure("family not supported"); 492 /*NOTREACHED*/ 493 } 494 495 sa4 = (struct sockaddr *)&dstaddr4; 496 getnameinfo(sa4, sa4->sa_len, 497 dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); 498 499 conf = config_match(srcaddr, sa4); 500 if (!conf || !conf->permit) { 501 close(s_src); 502 if (conf) { 503 exit_failure("translation to %s not permitted for %s", 504 dst4, prefix_string(&conf->match)); 505 /*NOTREACHED*/ 506 } else { 507 exit_failure("translation to %s not permitted", dst4); 508 /*NOTREACHED*/ 509 } 510 } 511 512 syslog(LOG_INFO, "the translator is connecting to %s", dst4); 513 514 setproctitle("port %s, %s -> %s", service, src, dst4); 515 516 if (sa4->sa_family == AF_INET6) 517 hport = ntohs(((struct sockaddr_in6 *)&dstaddr4)->sin6_port); 518 else /* AF_INET */ 519 hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port); 520 521 if (pflag) 522 s_dst = rresvport_af(&nresvport, sa4->sa_family); 523 else 524 s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); 525 if (s_dst < 0) { 526 exit_failure("socket: %s", strerror(errno)); 527 /*NOTREACHED*/ 528 } 529 530 if (conf->src.a.ss_family) { 531 if (bind(s_dst, (const struct sockaddr *)&conf->src.a, 532 conf->src.a.ss_len) < 0) { 533 exit_failure("bind: %s", strerror(errno)); 534 /*NOTREACHED*/ 535 } 536 } 537 538 error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 539 if (error < 0) { 540 exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 541 /*NOTREACHED*/ 542 } 543 544 error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, 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, sizeof(tv)); 550 if (error < 0) { 551 exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); 552 /*NOTREACHED*/ 553 } 554 555 error = connect(s_dst, sa4, sa4->sa_len); 556 if (error < 0) { 557 exit_failure("connect: %s", strerror(errno)); 558 /*NOTREACHED*/ 559 } 560 561 switch (hport) { 562 case FTP_PORT: 563 ftp_relay(s_src, s_dst); 564 break; 565 default: 566 tcp_relay(s_src, s_dst, service); 567 break; 568 } 569 570 /* NOTREACHED */ 571 } 572 573 /* 0: non faith, 1: faith */ 574 static int 575 faith_prefix(struct sockaddr *dst) 576 { 577 #ifndef USE_ROUTE 578 int mib[4], size; 579 struct in6_addr faith_prefix; 580 struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst; 581 582 if (dst->sa_family != AF_INET6) 583 return 0; 584 585 mib[0] = CTL_NET; 586 mib[1] = PF_INET6; 587 mib[2] = IPPROTO_IPV6; 588 mib[3] = IPV6CTL_FAITH_PREFIX; 589 size = sizeof(struct in6_addr); 590 if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { 591 exit_failure("sysctl: %s", strerror(errno)); 592 /*NOTREACHED*/ 593 } 594 595 if (memcmp(dst, &faith_prefix, 596 sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { 597 return 1; 598 } 599 return 0; 600 #else 601 struct myaddrs *p; 602 struct sockaddr_in6 *sin6; 603 struct sockaddr_in *sin4; 604 struct sockaddr_in6 *dst6; 605 struct sockaddr_in *dst4; 606 struct sockaddr_in dstmap; 607 608 dst6 = (struct sockaddr_in6 *)dst; 609 if (dst->sa_family == AF_INET6 610 && IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) { 611 /* ugly... */ 612 memset(&dstmap, 0, sizeof(dstmap)); 613 dstmap.sin_family = AF_INET; 614 dstmap.sin_len = sizeof(dstmap); 615 memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12], 616 sizeof(dstmap.sin_addr)); 617 dst = (struct sockaddr *)&dstmap; 618 } 619 620 dst6 = (struct sockaddr_in6 *)dst; 621 dst4 = (struct sockaddr_in *)dst; 622 623 for (p = myaddrs; p; p = p->next) { 624 sin6 = (struct sockaddr_in6 *)p->addr; 625 sin4 = (struct sockaddr_in *)p->addr; 626 627 if (p->addr->sa_len != dst->sa_len 628 || p->addr->sa_family != dst->sa_family) 629 continue; 630 631 switch (dst->sa_family) { 632 case AF_INET6: 633 if (sin6->sin6_scope_id == dst6->sin6_scope_id 634 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr)) 635 return 0; 636 break; 637 case AF_INET: 638 if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr) 639 return 0; 640 break; 641 } 642 } 643 return 1; 644 #endif 645 } 646 647 /* 0: non faith, 1: faith */ 648 static int 649 map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) 650 { 651 memset(dst4, 0, sizeof(*dst4)); 652 dst4->sin_len = sizeof(*dst4); 653 dst4->sin_family = AF_INET; 654 dst4->sin_port = dst6->sin6_port; 655 memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12], 656 sizeof(dst4->sin_addr)); 657 658 if (dst4->sin_addr.s_addr == INADDR_ANY 659 || dst4->sin_addr.s_addr == INADDR_BROADCAST 660 || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) 661 return 0; 662 663 return 1; 664 } 665 666 667 static void 668 sig_child(int sig) 669 { 670 int status; 671 pid_t pid; 672 673 while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) 674 if (WEXITSTATUS(status)) 675 syslog(LOG_WARNING, "child %ld exit status 0x%x", 676 (long)pid, status); 677 } 678 679 void 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 memset(&sa, 0, sizeof(sa)); 698 sa.sa_handler = sig_child; 699 sa.sa_flags = SA_NOCLDWAIT; 700 sigemptyset(&sa.sa_mask); 701 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 char buf[BUFSIZ]; 720 721 va_start(ap, fmt); 722 vsnprintf(buf, sizeof(buf), fmt, ap); 723 va_end(ap); 724 fprintf(stderr, "%s\n", buf); 725 exit(EXIT_FAILURE); 726 } 727 728 void 729 exit_failure(const char *fmt, ...) 730 { 731 va_list ap; 732 char buf[BUFSIZ]; 733 734 va_start(ap, fmt); 735 vsnprintf(buf, sizeof(buf), fmt, ap); 736 va_end(ap); 737 syslog(LOG_ERR, "%s", buf); 738 exit(EXIT_FAILURE); 739 } 740 741 void 742 exit_success(const char *fmt, ...) 743 { 744 va_list ap; 745 char buf[BUFSIZ]; 746 747 va_start(ap, fmt); 748 vsnprintf(buf, sizeof(buf), fmt, ap); 749 va_end(ap); 750 syslog(LOG_INFO, "%s", buf); 751 exit(EXIT_SUCCESS); 752 } 753 754 #ifdef USE_ROUTE 755 static void 756 grab_myaddrs() 757 { 758 struct ifaddrs *ifap, *ifa; 759 struct myaddrs *p; 760 struct sockaddr_in6 *sin6; 761 762 if (getifaddrs(&ifap) != 0) { 763 exit_failure("getifaddrs"); 764 /*NOTREACHED*/ 765 } 766 767 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 768 switch (ifa->ifa_addr->sa_family) { 769 case AF_INET: 770 case AF_INET6: 771 break; 772 default: 773 continue; 774 } 775 776 p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + 777 ifa->ifa_addr->sa_len); 778 if (!p) { 779 exit_failure("not enough core"); 780 /*NOTREACHED*/ 781 } 782 memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); 783 p->next = myaddrs; 784 p->addr = (struct sockaddr *)(p + 1); 785 #ifdef __KAME__ 786 if (ifa->ifa_addr->sa_family == AF_INET6) { 787 sin6 = (struct sockaddr_in6 *)p->addr; 788 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) 789 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { 790 sin6->sin6_scope_id = 791 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 792 sin6->sin6_addr.s6_addr[2] = 0; 793 sin6->sin6_addr.s6_addr[3] = 0; 794 } 795 } 796 #endif 797 myaddrs = p; 798 if (dflag) { 799 char hbuf[NI_MAXHOST]; 800 getnameinfo(p->addr, p->addr->sa_len, 801 hbuf, sizeof(hbuf), NULL, 0, 802 NI_NUMERICHOST); 803 syslog(LOG_INFO, "my interface: %s %s", hbuf, 804 ifa->ifa_name); 805 } 806 } 807 808 freeifaddrs(ifap); 809 } 810 811 static void 812 free_myaddrs() 813 { 814 struct myaddrs *p, *q; 815 816 p = myaddrs; 817 while (p) { 818 q = p->next; 819 free(p); 820 p = q; 821 } 822 myaddrs = NULL; 823 } 824 825 static void 826 update_myaddrs() 827 { 828 char msg[BUFSIZ]; 829 int len; 830 struct rt_msghdr *rtm; 831 832 len = read(sockfd, msg, sizeof(msg)); 833 if (len < 0) { 834 syslog(LOG_ERR, "read(PF_ROUTE) failed"); 835 return; 836 } 837 rtm = (struct rt_msghdr *)msg; 838 if (len < 4 || len < rtm->rtm_msglen) { 839 syslog(LOG_ERR, "read(PF_ROUTE) short read"); 840 return; 841 } 842 if (rtm->rtm_version != RTM_VERSION) { 843 syslog(LOG_ERR, "routing socket version mismatch"); 844 close(sockfd); 845 sockfd = 0; 846 return; 847 } 848 switch (rtm->rtm_type) { 849 case RTM_NEWADDR: 850 case RTM_DELADDR: 851 case RTM_IFINFO: 852 break; 853 default: 854 return; 855 } 856 /* XXX more filters here? */ 857 858 syslog(LOG_INFO, "update interface address list"); 859 free_myaddrs(); 860 grab_myaddrs(); 861 } 862 #endif /*USE_ROUTE*/ 863 864 static void 865 usage() 866 { 867 fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", 868 faithdname); 869 exit(0); 870 } 871