From 832f8d224926758a9ae0b23a6b45353e44fbc87a Mon Sep 17 00:00:00 2001 From: ume Date: Mon, 11 Jun 2001 12:39:29 +0000 Subject: Sync with recent KAME. This work was based on kame-20010528-freebsd43-snap.tgz and some critical problem after the snap was out were fixed. There are many many changes since last KAME merge. TODO: - The definitions of SADB_* in sys/net/pfkeyv2.h are still different from RFC2407/IANA assignment because of binary compatibility issue. It should be fixed under 5-CURRENT. - ip6po_m member of struct ip6_pktopts is no longer used. But, it is still there because of binary compatibility issue. It should be removed under 5-CURRENT. Reviewed by: itojun Obtained from: KAME MFC after: 3 weeks --- usr.sbin/faithd/faithd.c | 191 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 140 insertions(+), 51 deletions(-) (limited to 'usr.sbin/faithd/faithd.c') diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c index fddf402..2f02da1 100644 --- a/usr.sbin/faithd/faithd.c +++ b/usr.sbin/faithd/faithd.c @@ -1,4 +1,4 @@ -/* $KAME: faithd.c,v 1.20 2000/07/01 11:40:45 itojun Exp $ */ +/* $KAME: faithd.c,v 1.39 2001/04/25 11:20:42 itojun Exp $ */ /* * Copyright (C) 1997 and 1998 WIDE Project. @@ -47,6 +47,9 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#endif #include #include @@ -83,6 +86,7 @@ #endif #include "faithd.h" +#include "prefix.h" char *serverpath = NULL; char *serverarg[MAXARGV + 1]; @@ -101,6 +105,7 @@ static int sockfd = 0; int dflag = 0; static int pflag = 0; static int inetd = 0; +static char *configfile = NULL; int main __P((int, char **)); static int inetd_main __P((int, char **)); @@ -115,6 +120,8 @@ static int map4to6 __P((struct sockaddr_in *, struct sockaddr_in6 *)); static void sig_child __P((int)); static void sig_terminate __P((int)); static void start_daemon __P((void)); +static void exit_stderr __P((const char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); #ifndef HAVE_GETIFADDRS static unsigned int if_maxindex __P((void)); #endif @@ -156,6 +163,11 @@ inetd_main(int argc, char **argv) const int on = 1; char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + if (strrchr(argv[0], '/') == NULL) snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); else @@ -166,17 +178,21 @@ inetd_main(int argc, char **argv) sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); if (sockfd < 0) { - exit_error("socket(PF_ROUTE): %s", ERRSTR); + exit_failure("socket(PF_ROUTE): %s", ERRSTR); /*NOTREACHED*/ } #endif melen = sizeof(me); - if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) - exit_error("getsockname"); + if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) { + exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } fromlen = sizeof(from); - if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) - exit_error("getpeername"); + if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) { + exit_failure("getpeername: %s", ERRSTR); + /*NOTREACHED*/ + } if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) service = sbuf; @@ -190,8 +206,10 @@ inetd_main(int argc, char **argv) snprintf(procname, sizeof(procname), "accepting port %s", snum); openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - if (argc >= MAXARGV) + if (argc >= MAXARGV) { exit_failure("too many arguments"); + /*NOTREACHED*/ + } serverarg[0] = serverpath = path; for (i = 1; i < argc; i++) serverarg[i] = argv[i]; @@ -199,8 +217,10 @@ inetd_main(int argc, char **argv) error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error < 0) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } play_child(STDIN_FILENO, (struct sockaddr *)&from); exit_failure("should not reach here"); @@ -218,11 +238,14 @@ daemon_main(int argc, char **argv) char *ns; #endif /* FAITH_NS */ - while ((c = getopt(argc, argv, "dp46")) != -1) { + while ((c = getopt(argc, argv, "df:p46")) != -1) { switch (c) { case 'd': dflag++; break; + case 'f': + configfile = optarg; + break; case 'p': pflag++; break; @@ -236,12 +259,17 @@ daemon_main(int argc, char **argv) #endif default: usage(); - break; + /*NOTREACHED*/ } } argc -= optind; argv += optind; + if (config_load(configfile) < 0 && configfile) { + exit_failure("could not load config file"); + /*NOTREACHED*/ + } + #ifdef FAITH_NS if ((ns = getenv(FAITH_NS)) != NULL) { struct sockaddr_storage ss; @@ -266,15 +294,12 @@ daemon_main(int argc, char **argv) switch (argc) { case 0: - serverpath = DEFAULT_PATH; - serverarg[0] = DEFAULT_NAME; - serverarg[1] = NULL; - service = DEFAULT_PORT_NAME; - break; + usage(); + /*NOTREACHED*/ default: serverargc = argc - NUMARG; if (serverargc >= MAXARGV) - exit_error("too many augments"); + exit_stderr("too many arguments"); serverpath = malloc(strlen(argv[NUMPRG]) + 1); strcpy(serverpath, argv[NUMPRG]); @@ -300,17 +325,17 @@ daemon_main(int argc, char **argv) hints.ai_protocol = 0; error = getaddrinfo(NULL, service, &hints, &res); if (error) - exit_error("getaddrinfo: %s", gai_strerror(error)); + exit_stderr("getaddrinfo: %s", gai_strerror(error)); s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s_wld == -1) - exit_error("socket: %s", ERRSTR); + exit_stderr("socket: %s", ERRSTR); #ifdef IPV6_FAITH if (res->ai_family == AF_INET6) { error = setsockopt(s_wld, IPPROTO_IPV6, IPV6_FAITH, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(IPV6_FAITH): %s", ERRSTR); + exit_stderr("setsockopt(IPV6_FAITH): %s", ERRSTR); } #endif #ifdef FAITH4 @@ -318,31 +343,31 @@ daemon_main(int argc, char **argv) if (res->ai_family == AF_INET) { error = setsockopt(s_wld, IPPROTO_IP, IP_FAITH, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(IP_FAITH): %s", ERRSTR); + exit_stderr("setsockopt(IP_FAITH): %s", ERRSTR); } #endif #endif /* FAITH4 */ error = setsockopt(s_wld, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(SO_REUSEADDR): %s", ERRSTR); + exit_stderr("setsockopt(SO_REUSEADDR): %s", ERRSTR); error = setsockopt(s_wld, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); if (error == -1) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + exit_stderr("setsockopt(SO_OOBINLINE): %s", ERRSTR); error = bind(s_wld, (struct sockaddr *)res->ai_addr, res->ai_addrlen); if (error == -1) - exit_error("bind: %s", ERRSTR); + exit_stderr("bind: %s", ERRSTR); error = listen(s_wld, 5); if (error == -1) - exit_error("listen: %s", ERRSTR); + exit_stderr("listen: %s", ERRSTR); #ifdef USE_ROUTE sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); if (sockfd < 0) { - exit_error("socket(PF_ROUTE): %s", ERRSTR); + exit_stderr("socket(PF_ROUTE): %s", ERRSTR); /*NOTREACHED*/ } #endif @@ -359,7 +384,7 @@ daemon_main(int argc, char **argv) syslog(LOG_INFO, "Staring faith daemon for %s port", service); play_service(s_wld); - /*NOTREACHED*/ + /* NOTREACHED */ exit(1); /*pacify gcc*/ } @@ -407,8 +432,10 @@ again: len = sizeof(srcaddr); s_src = accept(s_wld, (struct sockaddr *)&srcaddr, &len); - if (s_src == -1) + if (s_src == -1) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } child_pid = fork(); @@ -419,6 +446,7 @@ again: openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); play_child(s_src, (struct sockaddr *)&srcaddr); exit_failure("should never reach here"); + /*NOTREACHED*/ } else { /* parent process */ close(s_src); @@ -441,6 +469,7 @@ play_child(int s_src, struct sockaddr *srcaddr) int s_dst, error, hport, nresvport, on = 1; struct timeval tv; struct sockaddr *sa4; + const struct config *conf; tv.tv_sec = 1; tv.tv_usec = 0; @@ -450,8 +479,10 @@ play_child(int s_src, struct sockaddr *srcaddr) syslog(LOG_INFO, "accepted a client from %s", src); error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len); - if (error == -1) + if (error == -1) { exit_failure("getsockname: %s", ERRSTR); + /*NOTREACHED*/ + } getnameinfo((struct sockaddr *)&dstaddr6, len, dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST); @@ -487,7 +518,8 @@ play_child(int s_src, struct sockaddr *srcaddr) if (!map6to4((struct sockaddr_in6 *)&dstaddr6, (struct sockaddr_in *)&dstaddr4)) { close(s_src); - exit_error("map6to4 failed"); + exit_failure("map6to4 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v6 to v4"); break; @@ -496,20 +528,35 @@ play_child(int s_src, struct sockaddr *srcaddr) if (!map4to6((struct sockaddr_in *)&dstaddr6, (struct sockaddr_in6 *)&dstaddr4)) { close(s_src); - exit_error("map4to6 failed"); + exit_failure("map4to6 failed"); + /*NOTREACHED*/ } syslog(LOG_INFO, "translating from v4 to v6"); break; #endif default: close(s_src); - exit_error("family not supported"); + exit_failure("family not supported"); /*NOTREACHED*/ } sa4 = (struct sockaddr *)&dstaddr4; getnameinfo(sa4, sa4->sa_len, dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST); + + conf = config_match(srcaddr, sa4); + if (!conf || !conf->permit) { + close(s_src); + if (conf) { + exit_failure("translation to %s not permitted for %s", + dst4, prefix_string(&conf->match)); + /*NOTREACHED*/ + } else { + exit_failure("translation to %s not permitted", dst4); + /*NOTREACHED*/ + } + } + syslog(LOG_INFO, "the translator is connecting to %s", dst4); setproctitle("port %s, %s -> %s", service, src, dst4); @@ -531,31 +578,55 @@ play_child(int s_src, struct sockaddr *srcaddr) s_dst = socket(sa4->sa_family, SOCK_STREAM, 0); break; } - if (s_dst == -1) + if (s_dst < 0) { exit_failure("socket: %s", ERRSTR); + /*NOTREACHED*/ + } + + if (conf->src.a.ss_family) { + if (bind(s_dst, (struct sockaddr *)&conf->src.a, + conf->src.a.ss_len) < 0) { + exit_failure("bind: %s", ERRSTR); + /*NOTREACHED*/ + } + } error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)); - if (error == -1) - exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) - exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - if (error == -1) - exit_error("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + if (error < 0) { + exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR); + /*NOTREACHED*/ + } error = connect(s_dst, sa4, sa4->sa_len); - if (error == -1) + if (error < 0) { exit_failure("connect: %s", ERRSTR); + /*NOTREACHED*/ + } switch (hport) { case FTP_PORT: ftp_relay(s_src, s_dst); break; case RSH_PORT: + syslog(LOG_WARNING, + "WARINNG: it is insecure to relay rsh port"); rsh_relay(s_src, s_dst); break; + case RLOGIN_PORT: + syslog(LOG_WARNING, + "WARINNG: it is insecure to relay rlogin port"); + /*FALLTHROUGH*/ default: tcp_relay(s_src, s_dst, service); break; @@ -581,8 +652,10 @@ faith_prefix(struct sockaddr *dst) mib[2] = IPPROTO_IPV6; mib[3] = IPV6CTL_FAITH_PREFIX; size = sizeof(struct in6_addr); - if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) - exit_error("sysctl: %s", ERRSTR); + if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) { + exit_failure("sysctl: %s", ERRSTR); + /*NOTREACHED*/ + } if (memcmp(dst, &faith_prefix, sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) { @@ -649,7 +722,7 @@ map6to4(struct sockaddr_in6 *dst6, struct sockaddr_in *dst4) if (dst4->sin_addr.s_addr == INADDR_ANY || dst4->sin_addr.s_addr == INADDR_BROADCAST - || IN_MULTICAST(dst4->sin_addr.s_addr)) + || IN_MULTICAST(ntohl(dst4->sin_addr.s_addr))) return 0; return 1; @@ -695,7 +768,7 @@ sig_child(int sig) pid_t pid; pid = wait3(&status, WNOHANG, (struct rusage *)0); - if (pid && status) + if (pid && WEXITSTATUS(status)) syslog(LOG_WARNING, "child %d exit status 0x%x", pid, status); } @@ -709,18 +782,34 @@ sig_terminate(int sig) static void start_daemon(void) { - if (daemon(0, 0) == -1) - exit_error("daemon: %s", ERRSTR); +#ifdef SA_NOCLDWAIT + struct sigaction sa; +#endif - if (signal(SIGCHLD, sig_child) == SIG_ERR) + if (daemon(0, 0) == -1) + exit_stderr("daemon: %s", ERRSTR); + +#ifdef SA_NOCLDWAIT + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sig_child; + sa.sa_flags = SA_NOCLDWAIT; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, (struct sigaction *)0); +#else + if (signal(SIGCHLD, sig_child) == SIG_ERR) { exit_failure("signal CHLD: %s", ERRSTR); + /*NOTREACHED*/ + } +#endif - if (signal(SIGTERM, sig_terminate) == SIG_ERR) + if (signal(SIGTERM, sig_terminate) == SIG_ERR) { exit_failure("signal TERM: %s", ERRSTR); + /*NOTREACHED*/ + } } -void -exit_error(const char *fmt, ...) +static void +exit_stderr(const char *fmt, ...) { va_list ap; char buf[BUFSIZ]; @@ -977,7 +1066,7 @@ update_myaddrs() static void usage() { - fprintf(stderr, "usage: %s [-dp] [service [serverpath [serverargs]]]\n", + fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n", faithdname); exit(0); } -- cgit v1.1