diff options
Diffstat (limited to 'usr.sbin/faithd/faithd.c')
-rw-r--r-- | usr.sbin/faithd/faithd.c | 231 |
1 files changed, 190 insertions, 41 deletions
diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c index 6c4a6a4..4d4f19e 100644 --- a/usr.sbin/faithd/faithd.c +++ b/usr.sbin/faithd/faithd.c @@ -1,7 +1,9 @@ +/* $KAME: faithd.c,v 1.20 2000/07/01 11:40:45 itojun Exp $ */ + /* * Copyright (C) 1997 and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,6 +37,7 @@ * Usage: faithd [<port> <progpath> <arg1(progname)> <arg2> ...] * e.g. faithd telnet /usr/local/v6/sbin/telnetd telnetd */ +#define HAVE_GETIFADDRS #include <sys/param.h> #include <sys/types.h> @@ -44,7 +47,9 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/ioctl.h> +#ifdef __FreeBSD__ #include <libutil.h> +#endif #include <stdio.h> #include <stdlib.h> @@ -68,6 +73,9 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> +#ifdef HAVE_GETIFADDRS +#include <ifaddrs.h> +#endif #ifdef FAITH4 #include <resolv.h> @@ -95,8 +103,11 @@ static int sockfd = 0; #endif int dflag = 0; static int pflag = 0; +static int inetd = 0; int main __P((int, char **)); +static int inetd_main __P((int, char **)); +static int daemon_main __P((int, char **)); static void play_service __P((int)); static void play_child __P((int, struct sockaddr *)); static int faith_prefix __P((struct sockaddr *)); @@ -107,24 +118,17 @@ 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)); +#ifndef HAVE_GETIFADDRS static unsigned int if_maxindex __P((void)); +#endif static void grab_myaddrs __P((void)); static void free_myaddrs __P((void)); static void update_myaddrs __P((void)); static void usage __P((void)); int -main(int argc, char *argv[]) +main(int argc, char **argv) { - struct addrinfo hints, *res; - int s_wld, error, i, serverargc, on = 1; - int family = AF_INET6; - int c; -#ifdef FAITH_NS - char *ns; -#endif /* FAITH_NS */ - extern int optind; - extern char *optarg; /* * Initializing stuff @@ -136,6 +140,87 @@ main(int argc, char *argv[]) else faithdname = argv[0]; + if (strcmp(faithdname, "faithd") != 0) { + inetd = 1; + return inetd_main(argc, argv); + } else + return daemon_main(argc, argv); +} + +static int +inetd_main(int argc, char **argv) +{ + char path[MAXPATHLEN]; + struct sockaddr_storage me; + struct sockaddr_storage from; + int melen, fromlen; + int i; + int error; + const int on = 1; + char sbuf[NI_MAXSERV], snum[NI_MAXSERV]; + + if (strrchr(argv[0], '/') == NULL) + snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]); + else + snprintf(path, sizeof(path), "%s", argv[0]); + +#ifdef USE_ROUTE + grab_myaddrs(); + + sockfd = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); + if (sockfd < 0) { + exit_error("socket(PF_ROUTE): %s", ERRSTR); + /*NOTREACHED*/ + } +#endif + + melen = sizeof(me); + if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) + exit_error("getsockname"); + fromlen = sizeof(from); + if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) + exit_error("getpeername"); + if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, + sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0) + service = sbuf; + else + service = DEFAULT_PORT_NAME; + if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0, + snum, sizeof(snum), NI_NUMERICHOST) != 0) + snprintf(snum, sizeof(snum), "?"); + + snprintf(logname, sizeof(logname), "faithd %s", snum); + snprintf(procname, sizeof(procname), "accepting port %s", snum); + openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); + + if (argc >= MAXARGV) + exit_failure("too many augments"); + serverarg[0] = serverpath = path; + for (i = 1; i < argc; i++) + serverarg[i] = argv[i]; + serverarg[i] = NULL; + + error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on, + sizeof(on)); + if (error < 0) + exit_error("setsockopt(SO_OOBINLINE): %s", ERRSTR); + + play_child(STDIN_FILENO, (struct sockaddr *)&from); + exit_failure("should not reach here"); + return 0; /*dummy!*/ +} + +static int +daemon_main(int argc, char **argv) +{ + struct addrinfo hints, *res; + int s_wld, error, i, serverargc, on = 1; + int family = AF_INET6; + int c; +#ifdef FAITH_NS + char *ns; +#endif /* FAITH_NS */ + while ((c = getopt(argc, argv, "dp46")) != -1) { switch (c) { case 'd': @@ -191,17 +276,17 @@ main(int argc, char *argv[]) break; default: serverargc = argc - NUMARG; - if (serverargc > MAXARGV) - exit_error("too many arguments"); + if (serverargc >= MAXARGV) + exit_error("too many augments"); - serverpath = malloc(strlen(argv[NUMPRG])); + serverpath = malloc(strlen(argv[NUMPRG]) + 1); strcpy(serverpath, argv[NUMPRG]); for (i = 0; i < serverargc; i++) { - serverarg[i] = malloc(strlen(argv[i + NUMARG])); + serverarg[i] = malloc(strlen(argv[i + NUMARG]) + 1); strcpy(serverarg[i], argv[i + NUMARG]); } serverarg[i] = NULL; - /* FALLTHROUGH */ + /* fall throuth */ case 1: /* no local service */ service = argv[NUMPRT]; break; @@ -217,12 +302,8 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; error = getaddrinfo(NULL, service, &hints, &res); - if (error) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error)); - if (error == EAI_SYSTEM) - exit_error("getaddrinfo: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } + if (error) + exit_error("getaddrinfo: %s", gai_strerror(error)); s_wld = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s_wld == -1) @@ -278,10 +359,10 @@ main(int argc, char *argv[]) snprintf(logname, sizeof(logname), "faithd %s", service); snprintf(procname, sizeof(procname), "accepting port %s", service); openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); - syslog(LOG_INFO, "starting faith daemon for %s port", service); + syslog(LOG_INFO, "Staring faith daemon for %s port", service); play_service(s_wld); - /*NOTREACHED*/ + /*NOTRECHED*/ exit(1); /*pacify gcc*/ } @@ -354,7 +435,7 @@ again: static void play_child(int s_src, struct sockaddr *srcaddr) { - struct sockaddr_storage dstaddr6; + struct sockaddr_storage dstaddr6; struct sockaddr_storage dstaddr4; char src[MAXHOSTNAMELEN]; char dst6[MAXHOSTNAMELEN]; @@ -385,10 +466,12 @@ play_child(int s_src, struct sockaddr *srcaddr) * Local service */ syslog(LOG_INFO, "executing local %s", serverpath); - dup2(s_src, 0); - close(s_src); - dup2(0, 1); - dup2(0, 2); + if (!inetd) { + dup2(s_src, 0); + close(s_src); + dup2(0, 1); + dup2(0, 2); + } execv(serverpath, serverarg); syslog(LOG_ERR, "execv %s: %s", serverpath, ERRSTR); _exit(EXIT_FAILURE); @@ -597,9 +680,6 @@ map4to6(struct sockaddr_in *dst4, struct sockaddr_in6 *dst6) if ((ai_errno = getaddrinfo(host, serv, &hints, &res)) != 0) { syslog(LOG_INFO, "%s %s: %s", host, serv, gai_strerror(ai_errno)); - if (ai_errno == EAI_SYSTEM) - syslog(LOG_INFO, "%s %s: %s", host, serv, - strerror(errno)); return 0; } @@ -625,7 +705,7 @@ sig_child(int sig) void sig_terminate(int sig) { - syslog(LOG_INFO, "terminating faith daemon"); + syslog(LOG_INFO, "Terminating faith daemon"); exit(EXIT_SUCCESS); } @@ -664,7 +744,7 @@ exit_failure(const char *fmt, ...) va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - syslog(LOG_ERR, buf); + syslog(LOG_ERR, "%s", buf); exit(EXIT_FAILURE); } @@ -677,11 +757,12 @@ exit_success(const char *fmt, ...) va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - syslog(LOG_INFO, buf); + syslog(LOG_INFO, "%s", buf); exit(EXIT_SUCCESS); } #ifdef USE_ROUTE +#ifndef HAVE_GETIFADDRS static unsigned int if_maxindex() { @@ -696,17 +777,73 @@ if_maxindex() if_freenameindex(p0); return max; } +#endif static void grab_myaddrs() { +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifap, *ifa; + struct myaddrs *p; + struct sockaddr_in6 *sin6; + + if (getifaddrs(&ifap) != 0) { + exit_failure("getifaddrs"); + /*NOTREACHED*/ + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + switch (ifa->ifa_addr->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + continue; + } + + p = (struct myaddrs *)malloc(sizeof(struct myaddrs) + + ifa->ifa_addr->sa_len); + if (!p) { + exit_failure("not enough core"); + /*NOTREACHED*/ + } + memcpy(p + 1, ifa->ifa_addr, ifa->ifa_addr->sa_len); + p->next = myaddrs; + p->addr = (struct sockaddr *)(p + 1); +#ifdef __KAME__ + if (ifa->ifa_addr->sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)p->addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) + || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + } + } +#endif + myaddrs = p; + if (dflag) { + char hbuf[NI_MAXHOST]; + getnameinfo(p->addr, p->addr->sa_len, + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + syslog(LOG_INFO, "my interface: %s %s", hbuf, + ifa->ifa_name); + } + } + + freeifaddrs(ifap); +#else int s; unsigned int maxif; struct ifreq *iflist; struct ifconf ifconf; - struct ifreq *ifr, *ifr_end; + struct ifreq *ifr, *ifrp, *ifr_end; struct myaddrs *p; struct sockaddr_in6 *sin6; + size_t siz; + char ifrbuf[sizeof(struct ifreq) + 1024]; maxif = if_maxindex() + 1; iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */ @@ -730,10 +867,21 @@ grab_myaddrs() /* Look for this interface in the list */ ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); - for (ifr = ifconf.ifc_req; - ifr < ifr_end; - ifr = (struct ifreq *) ((char *) &ifr->ifr_addr - + ifr->ifr_addr.sa_len)) { + for (ifrp = ifconf.ifc_req; + ifrp < ifr_end; + ifrp = (struct ifreq *)((char *)ifrp + siz)) { + memcpy(ifrbuf, ifrp, sizeof(*ifrp)); + ifr = (struct ifreq *)ifrbuf; + siz = ifr->ifr_addr.sa_len; + if (siz < sizeof(ifr->ifr_addr)) + siz = sizeof(ifr->ifr_addr); + siz += (sizeof(*ifrp) - sizeof(ifr->ifr_addr)); + if (siz > sizeof(ifrbuf)) { + /* ifr too big */ + break; + } + memcpy(ifrbuf, ifrp, siz); + switch (ifr->ifr_addr.sa_family) { case AF_INET: case AF_INET6: @@ -773,6 +921,7 @@ grab_myaddrs() } free(iflist); +#endif } static void |