--- Makefile | 4 resolve.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ syslogd.c | 139 +++++----------------------------- 3 files changed, 275 insertions(+), 117 deletions(-) --- Makefile +++ Makefile 2022-10-18 06:11:16.691008894 +0000 @@ -79,8 +79,8 @@ test: syslog_tst ksym oops.ko tsyslogd install: install_man install_exec -syslogd: syslogd.o pidfile.o - ${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o ${LIBS} +syslogd: syslogd.o pidfile.o resolve.o + ${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o resolve.o ${LIBS} klogd: klogd.o syslog.o pidfile.o ksym.o ksym_mod.o ${CC} ${LDFLAGS} -o klogd klogd.o syslog.o pidfile.o ksym.o \ --- resolve.c +++ resolve.c 2022-10-18 06:11:16.691008894 +0000 @@ -0,0 +1,249 @@ +/* + * Resolve a hostname + * + * Copyright (C) 2003, SuSE Linux AG + * Written by okir@suse.de + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__GLIBC__) +#define dprintf mydprintf +#endif /* __GLIBC__ */ + +/* Number of times we retry resolving a name */ +#define RESOLVER_RETRIES 10 +/* Timeout between retries to resolve a name */ +#define RESOLVER_RETRY_TIME (3 * 60) +/* Time to wait for the sub-process comes up with an + * answer, before we suspend the entry */ +#define RESOLVER_WAIT_TIME 5 + +struct res_name { + struct res_name * next; + char * name; + unsigned int retries; + time_t retry_time; + time_t wait_time; + pid_t process; + int pipe; + struct sockaddr_storage address; +}; + +extern void dprintf(char *fmt, ...); +static int do_result(struct res_name *res); +static void do_query(int, int, const char *); + +static struct res_name *resolve; + +int +resolve_name(const char *name, int family, struct sockaddr_storage *addr) +{ + struct res_name *res; + int fd[2]; + pid_t pid; + time_t now; + + time(&now); + for (res = resolve; res; res = res->next) { + if (!strcmp(res->name, name)) { + /* If there's still a sub-process + * attached, see if it came up with an + * answer in the meantime */ + if (res->pipe >= 0) + do_result(res); + goto check_result; + } + } + + res = (struct res_name *) calloc(1, sizeof(*res)); + res->name = strdup(name); + res->retries = RESOLVER_RETRIES; + res->retry_time = now + RESOLVER_RETRY_TIME; + res->pipe = -1; + res->next = resolve; + resolve = res; + +retry: res->retries -= 1; + + dprintf("Trying to resolve \"%s\", attempt #%u\n", + res->name, RESOLVER_RETRIES - res->retries); + + if (res->pipe >= 0) { + /* Make sure resolver subprocess is dead */ + kill(res->process, SIGKILL); + close(res->pipe); + res->pipe = -1; + } + + signal(SIGCHLD, SIG_IGN); + if (pipe(fd) < 0) { + /* log error? */ + return -1; + } + if ((pid = fork()) < 0) { + /* log error? */ + close(fd[0]); + close(fd[1]); + return -1; + } + + if (pid == 0) { + close(fd[0]); + do_query(fd[1], family, res->name); + /* shouldn't return */ + exit(1); + } + + res->wait_time = now + RESOLVER_WAIT_TIME; + res->process = pid; + res->pipe = fd[0]; + close(fd[1]); + + /* Try to collect result within the next couple + * of seconds */ + do_result(res); + +check_result: + if (res->pipe >= 0) { + dprintf("%s: name resolution not complete, " + "waiting for resolver sub-process\n", + res->name); + return 0; + } + + if (res->address.ss_family != AF_UNSPEC) { + *addr = res->address; + return 1; + } + if (res->retries == 0) { + dprintf("%s: too many failed attempts to resolve hostname, " + "given up.\n", res->name); + return -1; + } + if (res->retry_time > now) { + dprintf("%s: name resolution failed, " + "will retry in %d seconds\n", + res->name, res->retry_time - now); + return 0; + } + goto retry; +} + +/* + * This function clears the resolver's internal state + * when syslogd received a SIGHUP + */ +void +init_resolver(void) +{ + struct res_name *res; + + for (res = resolve; res; res = res->next) { + res->address.ss_family = AF_UNSPEC; + res->retries = RESOLVER_RETRIES; + res->retry_time = 0; + } +} + + +/* + * Collect result from sub-process + */ +int +do_result(struct res_name *res) +{ + struct sockaddr_storage addr; + struct pollfd _poll; + long wait; + int n; + + if (res->pipe < 0) + return 0; + + /* See if we should wait for the subprocess to come + * up with an answer (the initial call to do_result + * after starting the sub-process will always wait for + * a few seconds to avoid losing messages) */ + if ((wait = res->wait_time - time(NULL)) < 0) + wait = 0; + + /* See if we get the resolver's result within the + * next "wait" seconds. If not, let it continue in the + * background */ + _poll.fd = res->pipe; + _poll.events = POLLIN; + if (poll(&_poll, 1, wait * 1000) < 1) + return 0; + + n = read(res->pipe, &addr, sizeof(addr)); + + /* child process has done its duty. */ + kill(res->process, SIGKILL); + close(res->pipe); + res->process = 0; + res->pipe = -1; + + if (n != sizeof(addr)) + return -1; + + res->address = addr; + if (addr.ss_family != AF_UNSPEC) + return 1; + return -1; +} + +/* + * Sub-process performing lookup + */ +void +do_query(int fd, int family, const char *name) +{ + struct sockaddr_storage ss; + struct addrinfo hints, *res; + int r; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; +#ifdef notyet + /* XXX - specify AI_whatever for automatic v4-v6 mapping */ +#else + hints.ai_family = (family == AF_INET)? family : AF_UNSPEC; +#endif + + r = getaddrinfo(name, "syslog", &hints, &res); + if (r != 0) { + dprintf("failed to resolve \"%s\": %s\n", + name, gai_strerror(r)); + exit(1); + } + + memset(&ss, 0, sizeof(ss)); + + /* Do v4mapped v6 address (supported by recent glibcs + * only) */ + if (family == AF_INET6 && res->ai_family == AF_INET) { + struct sockaddr_in6 *six = (struct sockaddr_in6 *) &ss; + struct sockaddr_in *sin = (struct sockaddr_in *) res->ai_addr; + + six->sin6_family = AF_INET6; + six->sin6_port = sin->sin_port; + six->sin6_addr.s6_addr16[5] = 0xffff; + six->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; + } else if (res->ai_addrlen > sizeof(ss)) { + dprintf("failed to resolve \"%s\": address too large\n", + name); + exit(1); + } else { + memcpy(&ss, res->ai_addr, res->ai_addrlen); + } + write(fd, &ss, sizeof(ss)); + exit(0); +} --- syslogd.c +++ syslogd.c 2022-10-18 06:17:39.648170295 +0000 @@ -683,14 +683,7 @@ struct filed { struct { char f_hname[MAXHOSTNAMELEN+1]; #ifdef INET6 - union { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } f_sa; -#define f_addr f_sa.sa -#define f_addr4 f_sa.sin -#define f_addr6 f_sa.sin6 + struct sockaddr_storage f_addr; #else struct sockaddr_in f_addr; #endif @@ -846,19 +839,17 @@ int decode(char *name, struct code *code #if defined(__GLIBC__) #define dprintf mydprintf #endif /* __GLIBC__ */ -static void dprintf(char *, ...); +void dprintf(char *, ...); static void allocate_log(void); -void sighup_handler(); +void sighup_handler(int sig); #ifdef SYSLOG_UNIXAF static int create_unix_socket(const char *path); #endif #ifdef SYSLOG_INET static int create_inet_socket(); -#ifdef INET6 -static void setup_inetaddr_all(); -static const char *setup_inetaddr(struct filed *f); -#endif +extern int resolve_name(const char *, int, struct sockaddr_storage *); +extern void init_resolver(void); #endif int main(argc, argv) @@ -1413,63 +1404,6 @@ static int create_inet_socket() return fd; } -#ifdef INET6 - -static void setup_inetaddr_all() -{ - struct filed *f; -#ifdef SYSV - int lognum; - - for (lognum = 0; lognum <= nlogs; lognum++) { - f = &Files[lognum]; -#else - for (f = Files; f; f = f->f_next) { -#endif - if (f->f_type == F_FORW_UNKN) { - if (setup_inetaddr(f)) { - f->f_prevcount = INET_RETRY_MAX; - f->f_time = time( (time_t *)0 ); - } else { - f->f_type = F_FORW; - } - } - } -} - -static const char *setup_inetaddr(struct filed *f) -{ - struct addrinfo hints, *res; - int error; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family == AF_INET6 ? AF_UNSPEC : AF_INET; - hints.ai_socktype = SOCK_DGRAM; - error = getaddrinfo(f->f_un.f_forw.f_hname, "syslog", &hints, &res); - if (error) { - return gai_strerror(error); - } - if (res->ai_addrlen > sizeof(f->f_un.f_forw.f_sa)) { - freeaddrinfo(res); - return "addrlen too large"; - } - if (family == AF_INET6 && res->ai_family == AF_INET) { - /* v4mapped addr */ - f->f_un.f_forw.f_addr.sa_family = AF_INET6; - f->f_un.f_forw.f_addr6.sin6_port = - ((struct sockaddr_in *)res->ai_addr)->sin_port; - f->f_un.f_forw.f_addr6.sin6_addr.s6_addr16[5] = 0xffff; - memcpy(&f->f_un.f_forw.f_addr6.sin6_addr.s6_addr32[3], - &((struct sockaddr_in *)res->ai_addr)->sin_addr, - sizeof(struct in_addr)); - } else { - memcpy(&f->f_un.f_forw.f_addr, res->ai_addr, res->ai_addrlen); - } - freeaddrinfo(res); - - return NULL; -} -#endif /* end of INET6 */ #endif char ** @@ -1913,7 +1847,7 @@ void fprintlog(f, from, flags, msg) char line[MAXLINE + 1]; time_t fwd_suspend; #ifdef INET6 - const char *errmsg; + int reserr; #else struct hostent *hp; #endif @@ -1982,38 +1916,21 @@ void fprintlog(f, from, flags, msg) */ case F_FORW_UNKN: dprintf(" %s\n", f->f_un.f_forw.f_hname); - fwd_suspend = time((time_t *) 0) - f->f_time; - if ( fwd_suspend >= INET_SUSPEND_TIME ) { - dprintf("Forwarding suspension to unknown over, retrying\n"); -#ifdef INET6 - if ((errmsg = setup_inetaddr(f))) { - dprintf("Failure: %s\n", errmsg); -#else - if ( (hp = gethostbyname(f->f_un.f_forw.f_hname)) == NULL ) { - dprintf("Failure: %s\n", sys_h_errlist[h_errno]); -#endif - dprintf("Retries: %d\n", f->f_prevcount); - if ( --f->f_prevcount < 0 ) { - dprintf("Giving up.\n"); - f->f_type = F_UNUSED; - } - else - dprintf("Left retries: %d\n", f->f_prevcount); - } - else { - dprintf("%s found, resuming.\n", f->f_un.f_forw.f_hname); -#ifndef INET6 /* not */ - memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); -#endif - f->f_prevcount = 0; - f->f_type = F_FORW; - goto f_forw; - } + reserr = resolve_name(f->f_un.f_forw.f_hname, + family, + &f->f_un.f_forw.f_addr); + if (reserr > 0) { + dprintf("Successfully resolved hostname \"%s\"\n", f->f_un.f_forw.f_hname); + f->f_type = F_FORW; + } else if (reserr < 0) { + dprintf("Giving up on hostname \"%s\"\n", f->f_un.f_forw.f_hname); + f->f_type = F_UNUSED; + break; + } else { + /* Not yet - query in progress, or suspended */ + break; } - else - dprintf("Forwarding suspension not over, time " \ - "left: %d\n", INET_SUSPEND_TIME - fwd_suspend); - break; + /* fallthrough */ case F_FORW: /* @@ -2429,9 +2346,7 @@ void logerror(type) } void die(sig) - int sig; - { register struct filed *f; char buf[100]; @@ -2655,6 +2570,7 @@ void init() #endif #ifdef SYSLOG_INET + init_resolver(); if (Forwarding || AcceptRemote) { if (finet < 0) { finet = create_inet_socket(); @@ -2671,10 +2587,6 @@ void init() InetInuse = 0; } inetm = finet; -#ifdef INET6 - if (finet >= 0) - setup_inetaddr_all(); -#endif #endif Initialized = 1; @@ -3040,8 +2952,7 @@ int decode(name, codetab) return (-1); } -static void dprintf(char *fmt, ...) - +void dprintf(char *fmt, ...) { va_list ap; @@ -3061,8 +2972,7 @@ static void dprintf(char *fmt, ...) * The following function is responsible for allocating/reallocating the * array which holds the structures which define the logging outputs. */ -static void allocate_log() - +static void allocate_log(void) { dprintf("Called allocate_log, nlogs = %d.\n", nlogs); @@ -3109,8 +3019,7 @@ static void allocate_log() * doing this during a signal handler. Instead this function simply sets * a flag variable which will tell the main loop to go through a restart. */ -void sighup_handler() - +void sighup_handler(int sig) { restart = 1; signal(SIGHUP, sighup_handler);