1122679Sume/* $KAME: faithd.c,v 1.67 2003/10/16 05:26:21 itojun Exp $ */ 262655Skris 356668Sshin/* 456668Sshin * Copyright (C) 1997 and 1998 WIDE Project. 556668Sshin * All rights reserved. 662655Skris * 756668Sshin * Redistribution and use in source and binary forms, with or without 856668Sshin * modification, are permitted provided that the following conditions 956668Sshin * are met: 1056668Sshin * 1. Redistributions of source code must retain the above copyright 1156668Sshin * notice, this list of conditions and the following disclaimer. 1256668Sshin * 2. Redistributions in binary form must reproduce the above copyright 1356668Sshin * notice, this list of conditions and the following disclaimer in the 1456668Sshin * documentation and/or other materials provided with the distribution. 1556668Sshin * 3. Neither the name of the project nor the names of its contributors 1656668Sshin * may be used to endorse or promote products derived from this software 1756668Sshin * without specific prior written permission. 1862655Skris * 1956668Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2056668Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2156668Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2256668Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2356668Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2456668Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2556668Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2656668Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2756668Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2856668Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2956668Sshin * SUCH DAMAGE. 3056668Sshin */ 3156668Sshin 3256668Sshin/* 3356668Sshin * User level translator from IPv6 to IPv4. 3456668Sshin * 3556668Sshin * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...] 3695023Ssuz * e.g. faithd telnet /usr/libexec/telnetd telnetd 3756668Sshin */ 3856668Sshin 39173298Scharnier#include <sys/cdefs.h> 40173298Scharnier__FBSDID("$FreeBSD: releng/10.3/usr.sbin/faithd/faithd.c 219158 2011-03-02 00:29:14Z delphij $"); 41173298Scharnier 4256668Sshin#include <sys/param.h> 4356668Sshin#include <sys/types.h> 4456668Sshin#include <sys/sysctl.h> 4556668Sshin#include <sys/socket.h> 4656668Sshin#include <sys/wait.h> 4756668Sshin#include <sys/stat.h> 4856668Sshin#include <sys/time.h> 4956668Sshin#include <sys/ioctl.h> 5078064Sume#include <libutil.h> 51122679Sume 52122679Sume#ifdef HAVE_POLL_H 53122679Sume#include <poll.h> 5478064Sume#endif 5556668Sshin#include <stdio.h> 5656668Sshin#include <stdlib.h> 5756668Sshin#include <stdarg.h> 5856668Sshin#include <string.h> 5956668Sshin#include <syslog.h> 6056668Sshin#include <unistd.h> 6156668Sshin#include <errno.h> 6256668Sshin#include <signal.h> 6356668Sshin#include <fcntl.h> 6456668Sshin#include <termios.h> 6556668Sshin 6656668Sshin#include <net/if_types.h> 6756668Sshin#ifdef IFT_FAITH 6856668Sshin# define USE_ROUTE 6956668Sshin# include <net/if.h> 7056668Sshin# include <net/route.h> 7156668Sshin# include <net/if_dl.h> 7256668Sshin#endif 7356668Sshin 7456668Sshin#include <netinet/in.h> 7556668Sshin#include <arpa/inet.h> 7656668Sshin#include <netdb.h> 7762655Skris#include <ifaddrs.h> 7856668Sshin 7956668Sshin#include "faithd.h" 8078064Sume#include "prefix.h" 8156668Sshin 8256668Sshinchar *serverpath = NULL; 8356668Sshinchar *serverarg[MAXARGV + 1]; 8456668Sshinstatic char *faithdname = NULL; 8556668Sshinchar logname[BUFSIZ]; 8656668Sshinchar procname[BUFSIZ]; 87122679Sume 8856668Sshinstruct myaddrs { 8956668Sshin struct myaddrs *next; 9056668Sshin struct sockaddr *addr; 9156668Sshin}; 9256668Sshinstruct myaddrs *myaddrs = NULL; 93122679Sume 9495023Ssuzstatic const char *service; 9556668Sshin#ifdef USE_ROUTE 9656668Sshinstatic int sockfd = 0; 9756668Sshin#endif 9856668Sshinint dflag = 0; 9956668Sshinstatic int pflag = 0; 10062655Skrisstatic int inetd = 0; 10178064Sumestatic char *configfile = NULL; 10256668Sshin 103173412Skevloint main(int, char **); 104173412Skevlostatic int inetd_main(int, char **); 105173412Skevlostatic int daemon_main(int, char **); 106173412Skevlostatic void play_service(int); 107173412Skevlostatic void play_child(int, struct sockaddr *); 108173412Skevlostatic int faith_prefix(struct sockaddr *); 109173412Skevlostatic int map6to4(struct sockaddr_in6 *, struct sockaddr_in *); 110173412Skevlostatic void sig_child(int); 111173412Skevlostatic void sig_terminate(int); 112173412Skevlostatic void start_daemon(void); 113173412Skevlostatic void exit_stderr(const char *, ...) 11478064Sume __attribute__((__format__(__printf__, 1, 2))); 115173412Skevlostatic void grab_myaddrs(void); 116173412Skevlostatic void free_myaddrs(void); 117173412Skevlostatic void update_myaddrs(void); 118173412Skevlostatic void usage(void); 11956668Sshin 12056668Sshinint 12162655Skrismain(int argc, char **argv) 12256668Sshin{ 12356668Sshin 12456668Sshin /* 12556668Sshin * Initializing stuff 12656668Sshin */ 12756668Sshin 12856668Sshin faithdname = strrchr(argv[0], '/'); 12956668Sshin if (faithdname) 13056668Sshin faithdname++; 13156668Sshin else 13256668Sshin faithdname = argv[0]; 13356668Sshin 13462655Skris if (strcmp(faithdname, "faithd") != 0) { 13562655Skris inetd = 1; 13662655Skris return inetd_main(argc, argv); 13762655Skris } else 13862655Skris return daemon_main(argc, argv); 13962655Skris} 14062655Skris 14162655Skrisstatic int 14262655Skrisinetd_main(int argc, char **argv) 14362655Skris{ 14462655Skris char path[MAXPATHLEN]; 14562655Skris struct sockaddr_storage me; 14662655Skris struct sockaddr_storage from; 147122679Sume socklen_t melen, fromlen; 14862655Skris int i; 14962655Skris int error; 15062655Skris const int on = 1; 15162655Skris char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; 15262655Skris 15378064Sume if (config_load(configfile) < 0 && configfile) { 15478064Sume exit_failure("could not load config file"); 15578064Sume /*NOTREACHED*/ 15678064Sume } 15778064Sume 15862655Skris if (strrchr(argv[0], '/') == NULL) 15962655Skris snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); 16062655Skris else 16162655Skris snprintf(path, sizeof(path), "%s", argv[0]); 16262655Skris 16362655Skris#ifdef USE_ROUTE 16462655Skris grab_myaddrs(); 16562655Skris 16662655Skris sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 16762655Skris if (sockfd < 0) { 16895023Ssuz exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 16962655Skris /*NOTREACHED*/ 17062655Skris } 17162655Skris#endif 17262655Skris 17362655Skris melen = sizeof(me); 17478064Sume if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { 17595023Ssuz exit_failure("getsockname: %s", strerror(errno)); 17678064Sume /*NOTREACHED*/ 17778064Sume } 17862655Skris fromlen = sizeof(from); 17978064Sume if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { 18095023Ssuz exit_failure("getpeername: %s", strerror(errno)); 18178064Sume /*NOTREACHED*/ 18278064Sume } 18362655Skris if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 18462655Skris sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) 18562655Skris service = sbuf; 18662655Skris else 18762655Skris service = DEFAULT_PORT_NAME; 18862655Skris if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, 18962655Skris snum, sizeof(snum), NI_NUMERICHOST) != 0) 19062655Skris snprintf(snum, sizeof(snum), "?"); 19162655Skris 19262655Skris snprintf(logname, sizeof(logname), "faithd %s", snum); 19362655Skris snprintf(procname, sizeof(procname), "accepting port %s", snum); 19462655Skris openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 19562655Skris 19678064Sume if (argc >= MAXARGV) { 19769312Scharnier exit_failure("too many arguments"); 19878064Sume /*NOTREACHED*/ 19978064Sume } 20062655Skris serverarg[0] = serverpath = path; 20162655Skris for (i = 1; i < argc; i++) 20262655Skris serverarg[i] = argv[i]; 20362655Skris serverarg[i] = NULL; 20462655Skris 20562655Skris error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, 20662655Skris sizeof(on)); 20778064Sume if (error < 0) { 20895023Ssuz exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 20978064Sume /*NOTREACHED*/ 21078064Sume } 21162655Skris 21262655Skris play_child(STDIN_FILENO, (struct sockaddr *)&from); 21362655Skris exit_failure("should not reach here"); 21462655Skris return 0; /*dummy!*/ 21562655Skris} 21662655Skris 21762655Skrisstatic int 21862655Skrisdaemon_main(int argc, char **argv) 21962655Skris{ 22062655Skris struct addrinfo hints, *res; 22162655Skris int s_wld, error, i, serverargc, on = 1; 22262655Skris int family = AF_INET6; 22362655Skris int c; 22462655Skris 225122679Sume while ((c = getopt(argc, argv, "df:p")) != -1) { 22656668Sshin switch (c) { 22756668Sshin case 'd': 22856668Sshin dflag++; 22956668Sshin break; 23078064Sume case 'f': 23178064Sume configfile = optarg; 23278064Sume break; 23356668Sshin case 'p': 23456668Sshin pflag++; 23556668Sshin break; 23656668Sshin default: 23756668Sshin usage(); 23878064Sume /*NOTREACHED*/ 23956668Sshin } 24056668Sshin } 24156668Sshin argc -= optind; 24256668Sshin argv += optind; 24356668Sshin 24478064Sume if (config_load(configfile) < 0 && configfile) { 24578064Sume exit_failure("could not load config file"); 24678064Sume /*NOTREACHED*/ 24778064Sume } 24878064Sume 24956668Sshin 25056668Sshin#ifdef USE_ROUTE 25156668Sshin grab_myaddrs(); 25256668Sshin#endif 25356668Sshin 25456668Sshin switch (argc) { 25556668Sshin case 0: 25678064Sume usage(); 25778064Sume /*NOTREACHED*/ 25856668Sshin default: 25956668Sshin serverargc = argc - NUMARG; 26062655Skris if (serverargc >= MAXARGV) 26178064Sume exit_stderr("too many arguments"); 26256668Sshin 263122679Sume serverpath = strdup(argv[NUMPRG]); 264122679Sume if (!serverpath) 265122679Sume exit_stderr("not enough core"); 26656668Sshin for (i = 0; i < serverargc; i++) { 267122679Sume serverarg[i] = strdup(argv[i + NUMARG]); 268122679Sume if (!serverarg[i]) 269122679Sume exit_stderr("not enough core"); 27056668Sshin } 27156668Sshin serverarg[i] = NULL; 27262655Skris /* fall throuth */ 27356668Sshin case 1: /* no local service */ 27456668Sshin service = argv[NUMPRT]; 27556668Sshin break; 27656668Sshin } 27756668Sshin 278122679Sume start_daemon(); 279122679Sume 28056668Sshin /* 28156668Sshin * Opening wild card socket for this service. 28256668Sshin */ 28356668Sshin 28456668Sshin memset(&hints, 0, sizeof(hints)); 28556668Sshin hints.ai_flags = AI_PASSIVE; 28656668Sshin hints.ai_family = family; 28756668Sshin hints.ai_socktype = SOCK_STREAM; 288122679Sume hints.ai_protocol = IPPROTO_TCP; /* SCTP? */ 28956668Sshin error = getaddrinfo(NULL, service, &hints, &res); 29062655Skris if (error) 29195023Ssuz exit_failure("getaddrinfo: %s", gai_strerror(error)); 29256668Sshin 29356668Sshin s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 29456668Sshin if (s_wld == -1) 29595023Ssuz exit_failure("socket: %s", strerror(errno)); 29656668Sshin 29756668Sshin#ifdef IPV6_FAITH 29856668Sshin if (res->ai_family == AF_INET6) { 29956668Sshin error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); 30056668Sshin if (error == -1) 30195023Ssuz exit_failure("setsockopt(IPV6_FAITH): %s", 30295023Ssuz strerror(errno)); 30356668Sshin } 30456668Sshin#endif 30556668Sshin 30656668Sshin error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 30756668Sshin if (error == -1) 30895023Ssuz exit_failure("setsockopt(SO_REUSEADDR): %s", strerror(errno)); 30956668Sshin 31056668Sshin error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 31156668Sshin if (error == -1) 31295023Ssuz exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 31356668Sshin 314122679Sume#ifdef IPV6_V6ONLY 315122679Sume error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); 316122679Sume if (error == -1) 317122679Sume exit_failure("setsockopt(IPV6_V6ONLY): %s", strerror(errno)); 318122679Sume#endif 319122679Sume 32056668Sshin error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); 32156668Sshin if (error == -1) 32295023Ssuz exit_failure("bind: %s", strerror(errno)); 32356668Sshin 32456668Sshin error = listen(s_wld, 5); 32556668Sshin if (error == -1) 32695023Ssuz exit_failure("listen: %s", strerror(errno)); 32756668Sshin 32856668Sshin#ifdef USE_ROUTE 32956668Sshin sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); 33056668Sshin if (sockfd < 0) { 33195023Ssuz exit_failure("socket(PF_ROUTE): %s", strerror(errno)); 33256668Sshin /*NOTREACHED*/ 33356668Sshin } 33456668Sshin#endif 33556668Sshin 33656668Sshin /* 33756668Sshin * Everything is OK. 33856668Sshin */ 33956668Sshin 34056668Sshin snprintf(logname, sizeof(logname), "faithd %s", service); 34156668Sshin snprintf(procname, sizeof(procname), "accepting port %s", service); 34256668Sshin openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 343219158Sdelphij syslog(LOG_INFO, "Starting faith daemon for %s port", service); 34456668Sshin 34556668Sshin play_service(s_wld); 34678064Sume /* NOTREACHED */ 34756668Sshin exit(1); /*pacify gcc*/ 34856668Sshin} 34956668Sshin 35056668Sshinstatic void 35156668Sshinplay_service(int s_wld) 35256668Sshin{ 35356668Sshin struct sockaddr_storage srcaddr; 354122679Sume socklen_t len; 35556668Sshin int s_src; 35656668Sshin pid_t child_pid; 357122679Sume#ifdef HAVE_POLL_H 358122679Sume struct pollfd pfd[2]; 359122679Sume#else 36056668Sshin fd_set rfds; 361122679Sume int maxfd; 362122679Sume#endif 36356668Sshin int error; 36456668Sshin 36556668Sshin /* 36656668Sshin * Wait, accept, fork, faith.... 36756668Sshin */ 36856668Sshinagain: 36962683Sbrian setproctitle("%s", procname); 37056668Sshin 371122679Sume#ifdef HAVE_POLL_H 372122679Sume pfd[0].fd = s_wld; 373122679Sume pfd[0].events = POLLIN; 374122679Sume pfd[1].fd = -1; 375122679Sume pfd[1].revents = 0; 376122679Sume#else 37756668Sshin FD_ZERO(&rfds); 378122679Sume if (s_wld >= FD_SETSIZE) 379122679Sume exit_failure("descriptor too big"); 38056668Sshin FD_SET(s_wld, &rfds); 38156668Sshin maxfd = s_wld; 382122679Sume#endif 38356668Sshin#ifdef USE_ROUTE 38456668Sshin if (sockfd) { 385122679Sume#ifdef HAVE_POLL_H 386122679Sume pfd[1].fd = sockfd; 387122679Sume pfd[1].events = POLLIN; 388122679Sume#else 389122679Sume if (sockfd >= FD_SETSIZE) 390122679Sume exit_failure("descriptor too big"); 39156668Sshin FD_SET(sockfd, &rfds); 39256668Sshin maxfd = (maxfd < sockfd) ? sockfd : maxfd; 393122679Sume#endif 39456668Sshin } 39556668Sshin#endif 39656668Sshin 397122679Sume#ifdef HAVE_POLL_H 398122679Sume error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), INFTIM); 399122679Sume#else 40056668Sshin error = select(maxfd + 1, &rfds, NULL, NULL, NULL); 401122679Sume#endif 40256668Sshin if (error < 0) { 40356668Sshin if (errno == EINTR) 40456668Sshin goto again; 40595023Ssuz exit_failure("select: %s", strerror(errno)); 40656668Sshin /*NOTREACHED*/ 40756668Sshin } 40856668Sshin 40956668Sshin#ifdef USE_ROUTE 410122679Sume#ifdef HAVE_POLL_H 411122679Sume if (pfd[1].revents & POLLIN) 412122679Sume#else 413122679Sume if (FD_ISSET(sockfd, &rfds)) 414122679Sume#endif 415122679Sume { 41656668Sshin update_myaddrs(); 41756668Sshin } 41856668Sshin#endif 419122679Sume#ifdef HAVE_POLL_H 420122679Sume if (pfd[0].revents & POLLIN) 421122679Sume#else 422122679Sume if (FD_ISSET(s_wld, &rfds)) 423122679Sume#endif 424122679Sume { 42556668Sshin len = sizeof(srcaddr); 426122679Sume s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); 42795359Sume if (s_src < 0) { 42895359Sume if (errno == ECONNABORTED) 42995359Sume goto again; 43095023Ssuz exit_failure("socket: %s", strerror(errno)); 43178064Sume /*NOTREACHED*/ 43278064Sume } 433122679Sume if (srcaddr.ss_family == AF_INET6 && 434122679Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&srcaddr)->sin6_addr)) { 435122679Sume close(s_src); 436122679Sume syslog(LOG_ERR, "connection from IPv4 mapped address?"); 437122679Sume goto again; 438122679Sume } 43956668Sshin 44056668Sshin child_pid = fork(); 441122679Sume 44256668Sshin if (child_pid == 0) { 44356668Sshin /* child process */ 44456668Sshin close(s_wld); 44556668Sshin closelog(); 44656668Sshin openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); 44756668Sshin play_child(s_src, (struct sockaddr *)&srcaddr); 44856668Sshin exit_failure("should never reach here"); 44978064Sume /*NOTREACHED*/ 45056668Sshin } else { 45156668Sshin /* parent process */ 45256668Sshin close(s_src); 45356668Sshin if (child_pid == -1) 45456668Sshin syslog(LOG_ERR, "can't fork"); 45556668Sshin } 45656668Sshin } 45756668Sshin goto again; 45856668Sshin} 45956668Sshin 46056668Sshinstatic void 46156668Sshinplay_child(int s_src, struct sockaddr *srcaddr) 46256668Sshin{ 46362655Skris struct sockaddr_storage dstaddr6; 46456668Sshin struct sockaddr_storage dstaddr4; 46595023Ssuz char src[NI_MAXHOST]; 46695023Ssuz char dst6[NI_MAXHOST]; 46795023Ssuz char dst4[NI_MAXHOST]; 468122679Sume socklen_t len = sizeof(dstaddr6); 46956668Sshin int s_dst, error, hport, nresvport, on = 1; 47056668Sshin struct timeval tv; 47156668Sshin struct sockaddr *sa4; 47278064Sume const struct config *conf; 47356668Sshin 47456668Sshin tv.tv_sec = 1; 47556668Sshin tv.tv_usec = 0; 47656668Sshin 47756668Sshin getnameinfo(srcaddr, srcaddr->sa_len, 478122679Sume src, sizeof(src), NULL, 0, NI_NUMERICHOST); 47956668Sshin syslog(LOG_INFO, "accepted a client from %s", src); 48056668Sshin 48156668Sshin error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); 48278064Sume if (error == -1) { 48395023Ssuz exit_failure("getsockname: %s", strerror(errno)); 48478064Sume /*NOTREACHED*/ 48578064Sume } 48656668Sshin 48756668Sshin getnameinfo((struct sockaddr *)&dstaddr6, len, 488122679Sume dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); 48956668Sshin syslog(LOG_INFO, "the client is connecting to %s", dst6); 49056668Sshin 49156668Sshin if (!faith_prefix((struct sockaddr *)&dstaddr6)) { 49256668Sshin if (serverpath) { 49356668Sshin /* 49456668Sshin * Local service 49556668Sshin */ 49656668Sshin syslog(LOG_INFO, "executing local %s", serverpath); 49762655Skris if (!inetd) { 49862655Skris dup2(s_src, 0); 49962655Skris close(s_src); 50062655Skris dup2(0, 1); 50162655Skris dup2(0, 2); 50262655Skris } 50356668Sshin execv(serverpath, serverarg); 50495023Ssuz syslog(LOG_ERR, "execv %s: %s", serverpath, 50595023Ssuz strerror(errno)); 50656668Sshin _exit(EXIT_FAILURE); 50756668Sshin } else { 50856668Sshin close(s_src); 50956668Sshin exit_success("no local service for %s", service); 51056668Sshin } 51156668Sshin } 51256668Sshin 51356668Sshin /* 51456668Sshin * Act as a translator 51556668Sshin */ 51656668Sshin 51756668Sshin switch (((struct sockaddr *)&dstaddr6)->sa_family) { 51856668Sshin case AF_INET6: 51956668Sshin if (!map6to4((struct sockaddr_in6 *)&dstaddr6, 52056668Sshin (struct sockaddr_in *)&dstaddr4)) { 52156668Sshin close(s_src); 52278064Sume exit_failure("map6to4 failed"); 52378064Sume /*NOTREACHED*/ 52456668Sshin } 52556668Sshin syslog(LOG_INFO, "translating from v6 to v4"); 52656668Sshin break; 52756668Sshin default: 52856668Sshin close(s_src); 52978064Sume exit_failure("family not supported"); 53056668Sshin /*NOTREACHED*/ 53156668Sshin } 53256668Sshin 53356668Sshin sa4 = (struct sockaddr *)&dstaddr4; 53456668Sshin getnameinfo(sa4, sa4->sa_len, 535122679Sume dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); 53678064Sume 53778064Sume conf = config_match(srcaddr, sa4); 53878064Sume if (!conf || !conf->permit) { 53978064Sume close(s_src); 54078064Sume if (conf) { 54178064Sume exit_failure("translation to %s not permitted for %s", 54278064Sume dst4, prefix_string(&conf->match)); 54378064Sume /*NOTREACHED*/ 54478064Sume } else { 54578064Sume exit_failure("translation to %s not permitted", dst4); 54678064Sume /*NOTREACHED*/ 54778064Sume } 54878064Sume } 54978064Sume 55056668Sshin syslog(LOG_INFO, "the translator is connecting to %s", dst4); 55156668Sshin 55256668Sshin setproctitle("port %s, %s -> %s", service, src, dst4); 55356668Sshin 55456668Sshin if (sa4->sa_family == AF_INET6) 55556668Sshin hport = ntohs(((struct sockaddr_in6 *)&dstaddr4)->sin6_port); 55656668Sshin else /* AF_INET */ 55756668Sshin hport = ntohs(((struct sockaddr_in *)&dstaddr4)->sin_port); 55856668Sshin 559122679Sume if (pflag) 56056668Sshin s_dst = rresvport_af(&nresvport, sa4->sa_family); 561122679Sume else 562122679Sume s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); 56378064Sume if (s_dst < 0) { 56495023Ssuz exit_failure("socket: %s", strerror(errno)); 56578064Sume /*NOTREACHED*/ 56678064Sume } 56756668Sshin 56878064Sume if (conf->src.a.ss_family) { 56995023Ssuz if (bind(s_dst, (const struct sockaddr *)&conf->src.a, 57078064Sume conf->src.a.ss_len) < 0) { 57195023Ssuz exit_failure("bind: %s", strerror(errno)); 57278064Sume /*NOTREACHED*/ 57378064Sume } 57478064Sume } 57578064Sume 57656668Sshin error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); 57778064Sume if (error < 0) { 57895023Ssuz exit_failure("setsockopt(SO_OOBINLINE): %s", strerror(errno)); 57978064Sume /*NOTREACHED*/ 58078064Sume } 58156668Sshin 58256668Sshin error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 58378064Sume if (error < 0) { 58495023Ssuz exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); 58578064Sume /*NOTREACHED*/ 58678064Sume } 58756668Sshin error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 58878064Sume if (error < 0) { 58995023Ssuz exit_failure("setsockopt(SO_SNDTIMEO): %s", strerror(errno)); 59078064Sume /*NOTREACHED*/ 59178064Sume } 59256668Sshin 59356668Sshin error = connect(s_dst, sa4, sa4->sa_len); 59478064Sume if (error < 0) { 59595023Ssuz exit_failure("connect: %s", strerror(errno)); 59678064Sume /*NOTREACHED*/ 59778064Sume } 59856668Sshin 59956668Sshin switch (hport) { 60056668Sshin case FTP_PORT: 60156668Sshin ftp_relay(s_src, s_dst); 60256668Sshin break; 60356668Sshin default: 60456668Sshin tcp_relay(s_src, s_dst, service); 60556668Sshin break; 60656668Sshin } 60756668Sshin 60856668Sshin /* NOTREACHED */ 60956668Sshin} 61056668Sshin 61156668Sshin/* 0: non faith, 1: faith */ 61256668Sshinstatic int 61356668Sshinfaith_prefix(struct sockaddr *dst) 61456668Sshin{ 61556668Sshin#ifndef USE_ROUTE 61656668Sshin int mib[4], size; 61756668Sshin struct in6_addr faith_prefix; 61856668Sshin struct sockaddr_in6 *dst6 = (struct sockaddr_in *)dst; 61956668Sshin 62056668Sshin if (dst->sa_family != AF_INET6) 62156668Sshin return 0; 62256668Sshin 62356668Sshin mib[0] = CTL_NET; 62456668Sshin mib[1] = PF_INET6; 62556668Sshin mib[2] = IPPROTO_IPV6; 62656668Sshin mib[3] = IPV6CTL_FAITH_PREFIX; 62756668Sshin size = sizeof(struct in6_addr); 62878064Sume if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { 62995023Ssuz exit_failure("sysctl: %s", strerror(errno)); 63078064Sume /*NOTREACHED*/ 63178064Sume } 63256668Sshin 63356668Sshin if (memcmp(dst, &faith_prefix, 634122679Sume sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { 63556668Sshin return 1; 63656668Sshin } 63756668Sshin return 0; 63856668Sshin#else 63956668Sshin struct myaddrs *p; 64056668Sshin struct sockaddr_in6 *sin6; 64156668Sshin struct sockaddr_in *sin4; 64256668Sshin struct sockaddr_in6 *dst6; 64356668Sshin struct sockaddr_in *dst4; 64456668Sshin struct sockaddr_in dstmap; 64556668Sshin 64656668Sshin dst6 = (struct sockaddr_in6 *)dst; 64756668Sshin if (dst->sa_family == AF_INET6 64856668Sshin && IN6_IS_ADDR_V4MAPPED(&dst6->sin6_addr)) { 64956668Sshin /* ugly... */ 65056668Sshin memset(&dstmap, 0, sizeof(dstmap)); 65156668Sshin dstmap.sin_family = AF_INET; 65256668Sshin dstmap.sin_len = sizeof(dstmap); 65356668Sshin memcpy(&dstmap.sin_addr, &dst6->sin6_addr.s6_addr[12], 65456668Sshin sizeof(dstmap.sin_addr)); 65556668Sshin dst = (struct sockaddr *)&dstmap; 65656668Sshin } 65756668Sshin 65856668Sshin dst6 = (struct sockaddr_in6 *)dst; 65956668Sshin dst4 = (struct sockaddr_in *)dst; 66056668Sshin 66156668Sshin for (p = myaddrs; p; p = p->next) { 66256668Sshin sin6 = (struct sockaddr_in6 *)p->addr; 66356668Sshin sin4 = (struct sockaddr_in *)p->addr; 66456668Sshin 66556668Sshin if (p->addr->sa_len != dst->sa_len 66656668Sshin || p->addr->sa_family != dst->sa_family) 66756668Sshin continue; 66856668Sshin 66956668Sshin switch (dst->sa_family) { 67056668Sshin case AF_INET6: 67156668Sshin if (sin6->sin6_scope_id == dst6->sin6_scope_id 67256668Sshin && IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &dst6->sin6_addr)) 67356668Sshin return 0; 67456668Sshin break; 67556668Sshin case AF_INET: 67656668Sshin if (sin4->sin_addr.s_addr == dst4->sin_addr.s_addr) 67756668Sshin return 0; 67856668Sshin break; 67956668Sshin } 68056668Sshin } 68156668Sshin return 1; 68256668Sshin#endif 68356668Sshin} 68456668Sshin 68556668Sshin/* 0: non faith, 1: faith */ 68656668Sshinstatic int 68756668Sshinmap6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) 68856668Sshin{ 68956668Sshin memset(dst4, 0, sizeof(*dst4)); 69056668Sshin dst4->sin_len = sizeof(*dst4); 69156668Sshin dst4->sin_family = AF_INET; 69256668Sshin dst4->sin_port = dst6->sin6_port; 69356668Sshin memcpy(&dst4->sin_addr, &dst6->sin6_addr.s6_addr[12], 69456668Sshin sizeof(dst4->sin_addr)); 69556668Sshin 69656668Sshin if (dst4->sin_addr.s_addr == INADDR_ANY 69756668Sshin || dst4->sin_addr.s_addr == INADDR_BROADCAST 69878064Sume || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) 69956668Sshin return 0; 70056668Sshin 70156668Sshin return 1; 70256668Sshin} 70356668Sshin 70456668Sshin 70556668Sshinstatic void 706173298Scharniersig_child(int sig __unused) 70756668Sshin{ 70856668Sshin int status; 70956668Sshin pid_t pid; 71056668Sshin 711122679Sume while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) 712122679Sume if (WEXITSTATUS(status)) 713122679Sume syslog(LOG_WARNING, "child %ld exit status 0x%x", 714122679Sume (long)pid, status); 71556668Sshin} 71656668Sshin 71756668Sshinvoid 718173298Scharniersig_terminate(int sig __unused) 71956668Sshin{ 72062655Skris syslog(LOG_INFO, "Terminating faith daemon"); 72156668Sshin exit(EXIT_SUCCESS); 72256668Sshin} 72356668Sshin 72456668Sshinstatic void 72556668Sshinstart_daemon(void) 72656668Sshin{ 72778064Sume#ifdef SA_NOCLDWAIT 72878064Sume struct sigaction sa; 72978064Sume#endif 73078064Sume 73156668Sshin if (daemon(0, 0) == -1) 73295023Ssuz exit_stderr("daemon: %s", strerror(errno)); 73356668Sshin 73478064Sume#ifdef SA_NOCLDWAIT 73578064Sume memset(&sa, 0, sizeof(sa)); 73678064Sume sa.sa_handler = sig_child; 73778064Sume sa.sa_flags = SA_NOCLDWAIT; 73878064Sume sigemptyset(&sa.sa_mask); 73978064Sume sigaction(SIGCHLD, &sa, (struct sigaction *)0); 74078064Sume#else 74178064Sume if (signal(SIGCHLD, sig_child) == SIG_ERR) { 74295023Ssuz exit_failure("signal CHLD: %s", strerror(errno)); 74378064Sume /*NOTREACHED*/ 74478064Sume } 74578064Sume#endif 74656668Sshin 74778064Sume if (signal(SIGTERM, sig_terminate) == SIG_ERR) { 74895023Ssuz exit_failure("signal TERM: %s", strerror(errno)); 74978064Sume /*NOTREACHED*/ 75078064Sume } 75156668Sshin} 75256668Sshin 75378064Sumestatic void 75478064Sumeexit_stderr(const char *fmt, ...) 75556668Sshin{ 75656668Sshin va_list ap; 75756668Sshin char buf[BUFSIZ]; 75856668Sshin 75956668Sshin va_start(ap, fmt); 76056668Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 76156668Sshin va_end(ap); 76256668Sshin fprintf(stderr, "%s\n", buf); 76356668Sshin exit(EXIT_FAILURE); 76456668Sshin} 76556668Sshin 76656668Sshinvoid 76756668Sshinexit_failure(const char *fmt, ...) 76856668Sshin{ 76956668Sshin va_list ap; 77056668Sshin char buf[BUFSIZ]; 77156668Sshin 77256668Sshin va_start(ap, fmt); 77356668Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 77456668Sshin va_end(ap); 77562655Skris syslog(LOG_ERR, "%s", buf); 77656668Sshin exit(EXIT_FAILURE); 77756668Sshin} 77856668Sshin 77956668Sshinvoid 78056668Sshinexit_success(const char *fmt, ...) 78156668Sshin{ 78256668Sshin va_list ap; 78356668Sshin char buf[BUFSIZ]; 78456668Sshin 78556668Sshin va_start(ap, fmt); 78656668Sshin vsnprintf(buf, sizeof(buf), fmt, ap); 78756668Sshin va_end(ap); 78862655Skris syslog(LOG_INFO, "%s", buf); 78956668Sshin exit(EXIT_SUCCESS); 79056668Sshin} 79156668Sshin 79256668Sshin#ifdef USE_ROUTE 79356668Sshinstatic void 794201387Sedgrab_myaddrs(void) 79556668Sshin{ 79662655Skris struct ifaddrs *ifap, *ifa; 79762655Skris struct myaddrs *p; 79862655Skris struct sockaddr_in6 *sin6; 79962655Skris 80062655Skris if (getifaddrs(&ifap) != 0) { 80162655Skris exit_failure("getifaddrs"); 80262655Skris /*NOTREACHED*/ 80362655Skris } 80462655Skris 80562655Skris for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 80662655Skris switch (ifa->ifa_addr->sa_family) { 80762655Skris case AF_INET: 80862655Skris case AF_INET6: 80962655Skris break; 81062655Skris default: 81162655Skris continue; 81262655Skris } 81362655Skris 81462655Skris p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + 81562655Skris ifa->ifa_addr->sa_len); 81662655Skris if (!p) { 81762655Skris exit_failure("not enough core"); 81862655Skris /*NOTREACHED*/ 81962655Skris } 82062655Skris memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); 82162655Skris p->next = myaddrs; 82262655Skris p->addr = (struct sockaddr *)(p + 1); 82362655Skris#ifdef __KAME__ 82462655Skris if (ifa->ifa_addr->sa_family == AF_INET6) { 82562655Skris sin6 = (struct sockaddr_in6 *)p->addr; 82662655Skris if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) 82762655Skris || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { 82862655Skris sin6->sin6_scope_id = 82962655Skris ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 83062655Skris sin6->sin6_addr.s6_addr[2] = 0; 83162655Skris sin6->sin6_addr.s6_addr[3] = 0; 83262655Skris } 83362655Skris } 83462655Skris#endif 83562655Skris myaddrs = p; 83662655Skris if (dflag) { 83762655Skris char hbuf[NI_MAXHOST]; 83862655Skris getnameinfo(p->addr, p->addr->sa_len, 839122679Sume hbuf, sizeof(hbuf), NULL, 0, 840122679Sume NI_NUMERICHOST); 84162655Skris syslog(LOG_INFO, "my interface: %s %s", hbuf, 84262655Skris ifa->ifa_name); 84362655Skris } 84462655Skris } 84562655Skris 84662655Skris freeifaddrs(ifap); 84756668Sshin} 84856668Sshin 84956668Sshinstatic void 850201387Sedfree_myaddrs(void) 85156668Sshin{ 85256668Sshin struct myaddrs *p, *q; 85356668Sshin 85456668Sshin p = myaddrs; 85556668Sshin while (p) { 85656668Sshin q = p->next; 85756668Sshin free(p); 85856668Sshin p = q; 85956668Sshin } 86056668Sshin myaddrs = NULL; 86156668Sshin} 86256668Sshin 86356668Sshinstatic void 864201387Sedupdate_myaddrs(void) 86556668Sshin{ 86656668Sshin char msg[BUFSIZ]; 86756668Sshin int len; 86856668Sshin struct rt_msghdr *rtm; 86956668Sshin 87056668Sshin len = read(sockfd, msg, sizeof(msg)); 87156668Sshin if (len < 0) { 87256668Sshin syslog(LOG_ERR, "read(PF_ROUTE) failed"); 87356668Sshin return; 87456668Sshin } 87556668Sshin rtm = (struct rt_msghdr *)msg; 87656668Sshin if (len < 4 || len < rtm->rtm_msglen) { 87756668Sshin syslog(LOG_ERR, "read(PF_ROUTE) short read"); 87856668Sshin return; 87956668Sshin } 88056668Sshin if (rtm->rtm_version != RTM_VERSION) { 88156668Sshin syslog(LOG_ERR, "routing socket version mismatch"); 88256668Sshin close(sockfd); 88356668Sshin sockfd = 0; 88456668Sshin return; 88556668Sshin } 88656668Sshin switch (rtm->rtm_type) { 88756668Sshin case RTM_NEWADDR: 88856668Sshin case RTM_DELADDR: 88956668Sshin case RTM_IFINFO: 89056668Sshin break; 89156668Sshin default: 89256668Sshin return; 89356668Sshin } 89456668Sshin /* XXX more filters here? */ 89556668Sshin 89656668Sshin syslog(LOG_INFO, "update interface address list"); 89756668Sshin free_myaddrs(); 89856668Sshin grab_myaddrs(); 89956668Sshin} 90056668Sshin#endif /*USE_ROUTE*/ 90156668Sshin 90256668Sshinstatic void 903201387Sedusage(void) 90456668Sshin{ 90578064Sume fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", 90656668Sshin faithdname); 90756668Sshin exit(0); 90856668Sshin} 909