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