1 /* $NetBSD: faithd.c,v 1.16 2001/01/11 03:34:12 lukem Exp $ */ 2 /* $KAME: faithd.c,v 1.31 2000/10/05 22:20:37 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 #define HAVE_GETIFADDRS 40 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 #ifdef __FreeBSD__ 50 #include <libutil.h> 51 #endif 52 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <stdarg.h> 56 #include <string.h> 57 #include <syslog.h> 58 #include <unistd.h> 59 #include <errno.h> 60 #include <signal.h> 61 #include <fcntl.h> 62 #include <termios.h> 63 64 #include <net/if_types.h> 65 #ifdef IFT_FAITH 66 # define USE_ROUTE 67 # include <net/if.h> 68 # include <net/route.h> 69 # include <net/if_dl.h> 70 #endif 71 72 #include <netinet/in.h> 73 #include <arpa/inet.h> 74 #include <netdb.h> 75 #ifdef HAVE_GETIFADDRS 76 #include <ifaddrs.h> 77 #endif 78 79 #ifdef FAITH4 80 #include <resolv.h> 81 #include <arpa/nameser.h> 82 #ifndef FAITH_NS 83 #define FAITH_NS "FAITH_NS" 84 #endif 85 #endif 86 87 #include "faithd.h" 88 89 char *serverpath = NULL; 90 char *serverarg[MAXARGV + 1]; 91 static char *faithdname = NULL; 92 char logname[BUFSIZ]; 93 char procname[BUFSIZ]; 94 struct myaddrs { 95 struct myaddrs *next; 96 struct sockaddr *addr; 97 }; 98 struct myaddrs *myaddrs = NULL; 99 static char *service; 100 #ifdef USE_ROUTE 101 static int sockfd = 0; 102 #endif 103 int dflag = 0; 104 static int pflag = 0; 105 static int inetd = 0; 106 107 int main __P((int, char **)); 108 static int inetd_main __P((int, char **)); 109 static int daemon_main __P((int, char **)); 110 static void play_service __P((int)); 111 static void play_child __P((int, struct sockaddr *)); 112 static int faith_prefix __P((struct sockaddr *)); 113 static int map6to4 __P((struct sockaddr_in6 *, struct sockaddr_in *)); 114 #ifdef FAITH4 115 static int map4to6 __P((struct sockaddr_in *, struct sockaddr_in6 *)); 116 #endif 117 static void sig_child __P((int)); 118 static void sig_terminate __P((int)); 119 static void start_daemon __P((void)); 120 static void exit_stderr __P((const char *, ...)) 121 __attribute__((__format__(__printf__, 1, 2))); 122 #ifndef HAVE_GETIFADDRS 123 static unsigned int if_maxindex __P((void)); 124 #endif 125 static void grab_myaddrs __P((void)); 126 static void free_myaddrs __P((void)); 127 static void update_myaddrs __P((void)); 128 static void usage __P((void)); 129 130 int 131 main(int argc, char **argv) 132 { 133 134 /* 135 * Initializing stuff 136 */ 137 138 faithdname = strrchr(argv[0], '/'); 139 if (faithdname) 140 faithdname++; 141 else 142 faithdname = argv[0]; 143 144 if (strcmp(faithdname, "faithd") != 0) { 145 inetd = 1; 146 return inetd_main(argc, argv); 147 } else 148 return daemon_main(argc, argv); 149 } 150 151 static int 152 inetd_main(int argc, char **argv) 153 { 154 char path[MAXPATHLEN]; 155 struct sockaddr_storage me; 156 struct sockaddr_storage from; 157 int melen, fromlen; 158 int i; 159 int error; 160 const int on = 1; 161 char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; 162 163 if (strrchr(argv[0], '/') == NULL) 164 snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); 165 else 166 snprintf(path, sizeof(path), "%s", argv[0]); 167 168 #ifdef USE_ROUTE 169 grab_myaddrs(); 170 171 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 172 if (sockfd < 0) { 173 exit_failure("socket(PF_ROUTE): %s", ERRSTR); 174 /*NOTREACHED*/ 175 } 176 #endif 177 178 melen = sizeof(me); 179 if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) 180 exit_failure("getsockname"); 181 fromlen = sizeof(from); 182 if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) 183 exit_failure("getpeername"); 184 if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 185 sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) 186 service = sbuf; 187 else 188 service = DEFAULT_PORT_NAME; 189 if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 190 snum, sizeof(snum), NI_NUMERICHOST) != 0) 191 snprintf(snum, sizeof(snum), "?"); 192 193 snprintf(logname, sizeof(logname), "faithd %s", snum); 194 snprintf(procname, sizeof(procname), "accepting port %s", snum); 195 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 196 197 if (argc >= MAXARGV) 198 exit_failure("too many arguments"); 199 serverarg[0] = serverpath = path; 200 for (i = 1; i < argc; i++) 201 serverarg[i] = argv[i]; 202 serverarg[i] = NULL; 203 204 error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, 205 sizeof(on)); 206 if (error < 0) 207 exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); 208 209 play_child(STDIN_FILENO, (struct sockaddr *)&from); 210 exit_failure("should not reach here"); 211 return 0; /*dummy!*/ 212 } 213 214 static int 215 daemon_main(int argc, char **argv) 216 { 217 struct addrinfo hints, *res; 218 int s_wld, error, i, serverargc, on = 1; 219 int family = AF_INET6; 220 int c; 221 #ifdef FAITH_NS 222 char *ns; 223 #endif /* FAITH_NS */ 224 225 while ((c = getopt(argc, argv, "dp46")) != -1) { 226 switch (c) { 227 case 'd': 228 dflag++; 229 break; 230 case 'p': 231 pflag++; 232 break; 233 #ifdef FAITH4 234 case '4': 235 family = AF_INET; 236 break; 237 case '6': 238 family = AF_INET6; 239 break; 240 #endif 241 default: 242 usage(); 243 /*NOTREACHED*/ 244 } 245 } 246 argc -= optind; 247 argv += optind; 248 249 #ifdef FAITH_NS 250 if ((ns = getenv(FAITH_NS)) != NULL) { 251 struct sockaddr_storage ss; 252 struct addrinfo hints, *res; 253 char serv[NI_MAXSERV]; 254 255 memset(&ss, 0, sizeof(ss)); 256 memset(&hints, 0, sizeof(hints)); 257 snprintf(serv, sizeof(serv), "%u", NAMESERVER_PORT); 258 hints.ai_flags = AI_NUMERICHOST; 259 if (getaddrinfo(ns, serv, &hints, &res) == 0) { 260 res_init(); 261 memcpy(&_res_ext.nsaddr, res->ai_addr, res->ai_addrlen); 262 _res.nscount = 1; 263 } 264 } 265 #endif /* FAITH_NS */ 266 267 #ifdef USE_ROUTE 268 grab_myaddrs(); 269 #endif 270 271 switch (argc) { 272 case 0: 273 usage(); 274 /*NOTREACHED*/ 275 default: 276 serverargc = argc - NUMARG; 277 if (serverargc >= MAXARGV) 278 exit_stderr("too many arguments"); 279 280 serverpath = malloc(strlen(argv[NUMPRG]) + 1); 281 strcpy(serverpath, argv[NUMPRG]); 282 for (i = 0; i < serverargc; i++) { 283 serverarg[i] = malloc(strlen(argv[i + NUMARG]) + 1); 284 strcpy(serverarg[i], argv[i + NUMARG]); 285 } 286 serverarg[i] = NULL; 287 /* fall throuth */ 288 case 1: /* no local service */ 289 service = argv[NUMPRT]; 290 break; 291 } 292 293 /* 294 * Opening wild card socket for this service. 295 */ 296 297 memset(&hints, 0, sizeof(hints)); 298 hints.ai_flags = AI_PASSIVE; 299 hints.ai_family = family; 300 hints.ai_socktype = SOCK_STREAM; 301 hints.ai_protocol = 0; 302 error = getaddrinfo(NULL, service, &hints, &res); 303 if (error) 304 exit_stderr("getaddrinfo: %s", gai_strerror(error)); 305 306 s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 307 if (s_wld == -1) 308 exit_stderr("socket: %s", ERRSTR); 309 310 #ifdef IPV6_FAITH 311 if (res->ai_family == AF_INET6) { 312 error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); 313 if (error == -1) 314 exit_stderr("setsockopt(IPV6_FAITH): %s", ERRSTR); 315 } 316 #endif 317 #ifdef FAITH4 318 #ifdef IP_FAITH 319 if (res->ai_family == AF_INET) { 320 error = setsockopt(s_wld, IPPROTO_IP, IP_FAITH, &on, sizeof(on)); 321 if (error == -1) 322 exit_stderr("setsockopt(IP_FAITH): %s", ERRSTR); 323 } 324 #endif 325 #endif /* FAITH4 */ 326 327 error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 328 if (error == -1) 329 exit_stderr("setsockopt(SO_REUSEADDR): %s", ERRSTR); 330 331 error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 332 if (error == -1) 333 exit_stderr("setsockopt(SO_OOBINLINE): %s", ERRSTR); 334 335 error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); 336 if (error == -1) 337 exit_stderr("bind: %s", ERRSTR); 338 339 error = listen(s_wld, 5); 340 if (error == -1) 341 exit_stderr("listen: %s", ERRSTR); 342 343 #ifdef USE_ROUTE 344 sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 345 if (sockfd < 0) { 346 exit_stderr("socket(PF_ROUTE): %s", ERRSTR); 347 /*NOTREACHED*/ 348 } 349 #endif 350 351 /* 352 * Everything is OK. 353 */ 354 355 start_daemon(); 356 357 snprintf(logname, sizeof(logname), "faithd %s", service); 358 snprintf(procname, sizeof(procname), "accepting port %s", service); 359 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 360 syslog(LOG_INFO, "Starting faith daemon for %s port", service); 361 362 play_service(s_wld); 363 /* NOTREACHED */ 364 exit(1); /*pacify gcc*/ 365 } 366 367 static void 368 play_service(int s_wld) 369 { 370 struct sockaddr_storage srcaddr; 371 int len; 372 int s_src; 373 pid_t child_pid; 374 fd_set rfds; 375 int error; 376 int maxfd; 377 378 /* 379 * Wait, accept, fork, faith.... 380 */ 381 again: 382 setproctitle("%s", procname); 383 384 FD_ZERO(&rfds); 385 FD_SET(s_wld, &rfds); 386 maxfd = s_wld; 387 #ifdef USE_ROUTE 388 if (sockfd) { 389 FD_SET(sockfd, &rfds); 390 maxfd = (maxfd < sockfd) ? sockfd : maxfd; 391 } 392 #endif 393 394 error = select(maxfd + 1, &rfds, NULL, NULL, NULL); 395 if (error < 0) { 396 if (errno == EINTR) 397 goto again; 398 exit_failure("select: %s", ERRSTR); 399 /*NOTREACHED*/ 400 } 401 402 #ifdef USE_ROUTE 403 if (FD_ISSET(sockfd, &rfds)) { 404 update_myaddrs(); 405 } 406 #endif 407 if (FD_ISSET(s_wld, &rfds)) { 408 len = sizeof(srcaddr); 409 s_src = accept(s_wld, (struct sockaddr *)&srcaddr, 410 &len); 411 if (s_src == -1) 412 exit_failure("socket: %s", ERRSTR); 413 414 child_pid = fork(); 415 416 if (child_pid == 0) { 417 /* child process */ 418 close(s_wld); 419 closelog(); 420 openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 421 play_child(s_src, (struct sockaddr *)&srcaddr); 422 exit_failure("should never reach here"); 423 } else { 424 /* parent process */ 425 close(s_src); 426 if (child_pid == -1) 427 syslog(LOG_ERR, "can't fork"); 428 } 429 } 430 goto again; 431 } 432 433 static void 434 play_child(int s_src, struct sockaddr *srcaddr) 435 { 436 struct sockaddr_storage dstaddr6; 437 struct sockaddr_storage dstaddr4; 438 char src[MAXHOSTNAMELEN]; 439 char dst6[MAXHOSTNAMELEN]; 440 char dst4[MAXHOSTNAMELEN]; 441 int len = sizeof(dstaddr6); 442 int s_dst, error, hport, nresvport, on = 1; 443 struct timeval tv; 444 struct sockaddr *sa4; 445 446 tv.tv_sec = 1; 447 tv.tv_usec = 0; 448 449 getnameinfo(srcaddr, srcaddr->sa_len, 450 src, sizeof(src), NULL, 0, NI_NUMERICHOST); 451 syslog(LOG_INFO, "accepted a client from %s", src); 452 453 error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); 454 if (error == -1) 455 exit_failure("getsockname: %s", ERRSTR); 456 457 getnameinfo((struct sockaddr *)&dstaddr6, len, 458 dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); 459 syslog(LOG_INFO, "the client is connecting to %s", dst6); 460 461 if (!faith_prefix((struct sockaddr *)&dstaddr6)) { 462 if (serverpath) { 463 /* 464 * Local service 465 */ 466 syslog(LOG_INFO, "executing local %s", serverpath); 467 if (!inetd) { 468 dup2(s_src, 0); 469 close(s_src); 470 dup2(0, 1); 471 dup2(0, 2); 472 } 473 execv(serverpath, serverarg); 474 syslog(LOG_ERR, "execv %s: %s", serverpath, ERRSTR); 475 _exit(EXIT_FAILURE); 476 } else { 477 close(s_src); 478 exit_success("no local service for %s", service); 479 } 480 } 481 482 /* 483 * Act as a translator 484 */ 485 486 switch (((struct sockaddr *)&dstaddr6)->sa_family) { 487 case AF_INET6: 488 if (!map6to4((struct sockaddr_in6 *)&dstaddr6, 489 (struct sockaddr_in *)&dstaddr4)) { 490 close(s_src); 491 exit_failure("map6to4 failed"); 492 } 493 syslog(LOG_INFO, "translating from v6 to v4"); 494 break; 495 #ifdef FAITH4 496 case AF_INET: 497 if (!map4to6((struct sockaddr_in *)&dstaddr6, 498 (struct sockaddr_in6 *)&dstaddr4)) { 499 close(s_src); 500 exit_failure("map4to6 failed"); 501 } 502 syslog(LOG_INFO, "translating from v4 to v6"); 503 break; 504 #endif 505 default: 506 close(s_src); 507 exit_failure("family not supported"); 508 /*NOTREACHED*/ 509 } 510 511 sa4 = (struct sockaddr *)&dstaddr4; 512 getnameinfo(sa4, sa4->sa_len, 513 dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); 514 syslog(LOG_INFO, "the translator is connecting to %s", dst4); 515 516 setproctitle("port %s, %s -> %s", service, src, dst4); 517 518 if (sa4->sa_family == AF_INET6) 519 hport = ntohs(((struct sockaddr_in6 *)&dstaddr4)->sin6_port); 520 else /* AF_INET */ 521 hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port); 522 523 switch (hport) { 524 case RLOGIN_PORT: 525 case RSH_PORT: 526 s_dst = rresvport_af(&nresvport, sa4->sa_family); 527 break; 528 default: 529 if (pflag) 530 s_dst = rresvport_af(&nresvport, sa4->sa_family); 531 else 532 s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); 533 break; 534 } 535 if (s_dst == -1) 536 exit_failure("socket: %s", ERRSTR); 537 538 error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 539 if (error == -1) 540 exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); 541 542 error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 543 if (error == -1) 544 exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); 545 error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 546 if (error == -1) 547 exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); 548 549 error = connect(s_dst, sa4, sa4->sa_len); 550 if (error == -1) 551 exit_failure("connect: %s", ERRSTR); 552 553 switch (hport) { 554 case FTP_PORT: 555 ftp_relay(s_src, s_dst); 556 break; 557 case RSH_PORT: 558 rsh_relay(s_src, s_dst); 559 break; 560 default: 561 tcp_relay(s_src, s_dst, service); 562 break; 563 } 564 565 /* NOTREACHED */ 566 } 567 568 /* 0: non faith, 1: faith */ 569 static int 570 faith_prefix(struct sockaddr *dst) 571 { 572 #ifndef USE_ROUTE 573 int mib[4], size; 574 struct in6_addr faith_prefix; 575 struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst; 576 577 if (dst->sa_family != AF_INET6) 578 return 0; 579 580 mib[0] = CTL_NET; 581 mib[1] = PF_INET6; 582 mib[2] = IPPROTO_IPV6; 583 mib[3] = IPV6CTL_FAITH_PREFIX; 584 size = sizeof(struct in6_addr); 585 if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) 586 exit_failure("sysctl: %s", ERRSTR); 587 588 if (memcmp(dst, &faith_prefix, 589 sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { 590 return 1; 591 } 592 return 0; 593 #else 594 struct myaddrs *p; 595 struct sockaddr_in6 *sin6; 596 struct sockaddr_in *sin4; 597 struct sockaddr_in6 *dst6; 598 struct sockaddr_in *dst4; 599 struct sockaddr_in dstmap; 600 601 dst6 = (struct sockaddr_in6 *)dst; 602 if (dst->sa_family == AF_INET6 603 && IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) { 604 /* ugly... */ 605 memset(&dstmap, 0, sizeof(dstmap)); 606 dstmap.sin_family = AF_INET; 607 dstmap.sin_len = sizeof(dstmap); 608 memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12], 609 sizeof(dstmap.sin_addr)); 610 dst = (struct sockaddr *)&dstmap; 611 } 612 613 dst6 = (struct sockaddr_in6 *)dst; 614 dst4 = (struct sockaddr_in *)dst; 615 616 for (p = myaddrs; p; p = p->next) { 617 sin6 = (struct sockaddr_in6 *)p->addr; 618 sin4 = (struct sockaddr_in *)p->addr; 619 620 if (p->addr->sa_len != dst->sa_len 621 || p->addr->sa_family != dst->sa_family) 622 continue; 623 624 switch (dst->sa_family) { 625 case AF_INET6: 626 if (sin6->sin6_scope_id == dst6->sin6_scope_id 627 && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr)) 628 return 0; 629 break; 630 case AF_INET: 631 if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr) 632 return 0; 633 break; 634 } 635 } 636 return 1; 637 #endif 638 } 639 640 /* 0: non faith, 1: faith */ 641 static int 642 map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) 643 { 644 memset(dst4, 0, sizeof(*dst4)); 645 dst4->sin_len = sizeof(*dst4); 646 dst4->sin_family = AF_INET; 647 dst4->sin_port = dst6->sin6_port; 648 memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12], 649 sizeof(dst4->sin_addr)); 650 651 if (dst4->sin_addr.s_addr == INADDR_ANY 652 || dst4->sin_addr.s_addr == INADDR_BROADCAST 653 || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) 654 return 0; 655 656 return 1; 657 } 658 659 #ifdef FAITH4 660 /* 0: non faith, 1: faith */ 661 static int 662 map4to6(struct sockaddr_in *dst4, struct sockaddr_in6 *dst6) 663 { 664 char host[NI_MAXHOST]; 665 char serv[NI_MAXSERV]; 666 struct addrinfo hints, *res; 667 int ai_errno; 668 669 if (getnameinfo((struct sockaddr *)dst4, dst4->sin_len, host, sizeof(host), 670 serv, sizeof(serv), NI_NAMEREQD|NI_NUMERICSERV) != 0) 671 return 0; 672 673 memset(&hints, 0, sizeof(hints)); 674 hints.ai_flags = 0; 675 hints.ai_family = AF_INET6; 676 hints.ai_socktype = SOCK_STREAM; 677 hints.ai_protocol = 0; 678 679 if ((ai_errno = getaddrinfo(host, serv, &hints, &res)) != 0) { 680 syslog(LOG_INFO, "%s %s: %s", host, serv, gai_strerror(ai_errno)); 681 return 0; 682 } 683 684 memcpy(dst6, res->ai_addr, res->ai_addrlen); 685 686 freeaddrinfo(res); 687 688 return 1; 689 } 690 #endif /* FAITH4 */ 691 692 static void 693 sig_child(int sig) 694 { 695 int status; 696 pid_t pid; 697 698 pid = wait3(&status, WNOHANG, (struct rusage *)0); 699 if (pid && WEXITSTATUS(status)) 700 syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); 701 } 702 703 void 704 sig_terminate(int sig) 705 { 706 syslog(LOG_INFO, "Terminating faith daemon"); 707 exit(EXIT_SUCCESS); 708 } 709 710 static void 711 start_daemon(void) 712 { 713 if (daemon(0, 0) == -1) 714 exit_stderr("daemon: %s", ERRSTR); 715 716 if (signal(SIGCHLD, sig_child) == SIG_ERR) 717 exit_failure("signal CHLD: %s", ERRSTR); 718 719 if (signal(SIGTERM, sig_terminate) == SIG_ERR) 720 exit_failure("signal TERM: %s", ERRSTR); 721 } 722 723 static void 724 exit_stderr(const char *fmt, ...) 725 { 726 va_list ap; 727 char buf[BUFSIZ]; 728 729 va_start(ap, fmt); 730 vsnprintf(buf, sizeof(buf), fmt, ap); 731 va_end(ap); 732 fprintf(stderr, "%s", buf); 733 exit(EXIT_FAILURE); 734 } 735 736 void 737 exit_failure(const char *fmt, ...) 738 { 739 va_list ap; 740 char buf[BUFSIZ]; 741 742 va_start(ap, fmt); 743 vsnprintf(buf, sizeof(buf), fmt, ap); 744 va_end(ap); 745 syslog(LOG_ERR, "%s", buf); 746 exit(EXIT_FAILURE); 747 } 748 749 void 750 exit_success(const char *fmt, ...) 751 { 752 va_list ap; 753 char buf[BUFSIZ]; 754 755 va_start(ap, fmt); 756 vsnprintf(buf, sizeof(buf), fmt, ap); 757 va_end(ap); 758 syslog(LOG_INFO, "%s", buf); 759 exit(EXIT_SUCCESS); 760 } 761 762 #ifdef USE_ROUTE 763 #ifndef HAVE_GETIFADDRS 764 static unsigned int 765 if_maxindex() 766 { 767 struct if_nameindex *p, *p0; 768 unsigned int max = 0; 769 770 p0 = if_nameindex(); 771 for (p = p0; p && p->if_index && p->if_name; p++) { 772 if (max < p->if_index) 773 max = p->if_index; 774 } 775 if_freenameindex(p0); 776 return max; 777 } 778 #endif 779 780 static void 781 grab_myaddrs() 782 { 783 #ifdef HAVE_GETIFADDRS 784 struct ifaddrs *ifap, *ifa; 785 struct myaddrs *p; 786 struct sockaddr_in6 *sin6; 787 788 if (getifaddrs(&ifap) != 0) { 789 exit_failure("getifaddrs"); 790 /*NOTREACHED*/ 791 } 792 793 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 794 switch (ifa->ifa_addr->sa_family) { 795 case AF_INET: 796 case AF_INET6: 797 break; 798 default: 799 continue; 800 } 801 802 p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + 803 ifa->ifa_addr->sa_len); 804 if (!p) { 805 exit_failure("not enough core"); 806 /*NOTREACHED*/ 807 } 808 memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); 809 p->next = myaddrs; 810 p->addr = (struct sockaddr *)(p + 1); 811 #ifdef __KAME__ 812 if (ifa->ifa_addr->sa_family == AF_INET6) { 813 sin6 = (struct sockaddr_in6 *)p->addr; 814 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) 815 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { 816 sin6->sin6_scope_id = 817 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 818 sin6->sin6_addr.s6_addr[2] = 0; 819 sin6->sin6_addr.s6_addr[3] = 0; 820 } 821 } 822 #endif 823 myaddrs = p; 824 if (dflag) { 825 char hbuf[NI_MAXHOST]; 826 getnameinfo(p->addr, p->addr->sa_len, 827 hbuf, sizeof(hbuf), NULL, 0, 828 NI_NUMERICHOST); 829 syslog(LOG_INFO, "my interface: %s %s", hbuf, 830 ifa->ifa_name); 831 } 832 } 833 834 freeifaddrs(ifap); 835 #else 836 int s; 837 unsigned int maxif; 838 struct ifreq *iflist; 839 struct ifconf ifconf; 840 struct ifreq *ifr, *ifrp, *ifr_end; 841 struct myaddrs *p; 842 struct sockaddr_in6 *sin6; 843 size_t siz; 844 char ifrbuf[sizeof(struct ifreq) + 1024]; 845 846 maxif = if_maxindex() + 1; 847 iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */ 848 if (!iflist) { 849 exit_failure("not enough core"); 850 /*NOTREACHED*/ 851 } 852 853 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 854 exit_failure("socket(SOCK_DGRAM)"); 855 /*NOTREACHED*/ 856 } 857 memset(&ifconf, 0, sizeof(ifconf)); 858 ifconf.ifc_req = iflist; 859 ifconf.ifc_len = maxif * BUFSIZ; /* XXX */ 860 if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { 861 exit_failure("ioctl(SIOCGIFCONF)"); 862 /*NOTREACHED*/ 863 } 864 close(s); 865 866 /* Look for this interface in the list */ 867 ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); 868 for (ifrp = ifconf.ifc_req; 869 ifrp < ifr_end; 870 ifrp = (struct ifreq *)((char *)ifrp + siz)) { 871 memcpy(ifrbuf, ifrp, sizeof(*ifrp)); 872 ifr = (struct ifreq *)ifrbuf; 873 siz = ifr->ifr_addr.sa_len; 874 if (siz < sizeof(ifr->ifr_addr)) 875 siz = sizeof(ifr->ifr_addr); 876 siz += (sizeof(*ifrp) - sizeof(ifr->ifr_addr)); 877 if (siz > sizeof(ifrbuf)) { 878 /* ifr too big */ 879 break; 880 } 881 memcpy(ifrbuf, ifrp, siz); 882 883 switch (ifr->ifr_addr.sa_family) { 884 case AF_INET: 885 case AF_INET6: 886 p = (struct myaddrs *)malloc(sizeof(struct myaddrs) 887 + ifr->ifr_addr.sa_len); 888 if (!p) { 889 exit_failure("not enough core"); 890 /*NOTREACHED*/ 891 } 892 memcpy(p + 1, &ifr->ifr_addr, ifr->ifr_addr.sa_len); 893 p->next = myaddrs; 894 p->addr = (struct sockaddr *)(p + 1); 895 #ifdef __KAME__ 896 if (ifr->ifr_addr.sa_family == AF_INET6) { 897 sin6 = (struct sockaddr_in6 *)p->addr; 898 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) 899 || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { 900 sin6->sin6_scope_id = 901 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 902 sin6->sin6_addr.s6_addr[2] = 0; 903 sin6->sin6_addr.s6_addr[3] = 0; 904 } 905 } 906 #endif 907 myaddrs = p; 908 if (dflag) { 909 char hbuf[NI_MAXHOST]; 910 getnameinfo(p->addr, p->addr->sa_len, 911 hbuf, sizeof(hbuf), NULL, 0, 912 NI_NUMERICHOST); 913 syslog(LOG_INFO, "my interface: %s %s", hbuf, ifr->ifr_name); 914 } 915 break; 916 default: 917 break; 918 } 919 } 920 921 free(iflist); 922 #endif 923 } 924 925 static void 926 free_myaddrs() 927 { 928 struct myaddrs *p, *q; 929 930 p = myaddrs; 931 while (p) { 932 q = p->next; 933 free(p); 934 p = q; 935 } 936 myaddrs = NULL; 937 } 938 939 static void 940 update_myaddrs() 941 { 942 char msg[BUFSIZ]; 943 int len; 944 struct rt_msghdr *rtm; 945 946 len = read(sockfd, msg, sizeof(msg)); 947 if (len < 0) { 948 syslog(LOG_ERR, "read(PF_ROUTE) failed"); 949 return; 950 } 951 rtm = (struct rt_msghdr *)msg; 952 if (len < 4 || len < rtm->rtm_msglen) { 953 syslog(LOG_ERR, "read(PF_ROUTE) short read"); 954 return; 955 } 956 if (rtm->rtm_version != RTM_VERSION) { 957 syslog(LOG_ERR, "routing socket version mismatch"); 958 close(sockfd); 959 sockfd = 0; 960 return; 961 } 962 switch (rtm->rtm_type) { 963 case RTM_NEWADDR: 964 case RTM_DELADDR: 965 case RTM_IFINFO: 966 break; 967 default: 968 return; 969 } 970 /* XXX more filters here? */ 971 972 syslog(LOG_INFO, "update interface address list"); 973 free_myaddrs(); 974 grab_myaddrs(); 975 } 976 #endif /*USE_ROUTE*/ 977 978 static void 979 usage() 980 { 981 fprintf(stderr, "usage: %s [-dp] service [serverpath [serverargs]]\n", 982 faithdname); 983 exit(0); 984 } 985