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