--- CHANGES | 3 Makefile | 2 syslogd.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 210 insertions(+), 23 deletions(-) --- CHANGES +++ CHANGES 2022-10-13 08:13:35.285747318 +0000 @@ -72,6 +72,9 @@ Version 1.5 . Matthew Fischer - Remove special treatment of the percent sign in klogd +Version 1.4.1-usagi (2001/03/21) + - syslogd IPv6 support + (based on patch from Hiroyuki YAMAMORI ) Version 1.4.1 --- Makefile +++ Makefile 2022-10-13 08:30:44.607385067 +0000 @@ -20,7 +20,7 @@ CC= gcc #SKFLAGS= -g -DSYSV -Wall #LDFLAGS= -g -SKFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce +SKFLAGS= $(RPM_OPT_FLAGS) -DINET6 -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce # -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE # -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE # $(shell getconf LFS_SKFLAGS) --- syslogd.c +++ syslogd.c 2022-10-13 08:30:05.088090073 +0000 @@ -654,6 +654,7 @@ int funix[MAXFUNIX] = { -1, }; * This table contains plain text for h_errno errors used by the * net subsystem. */ +#ifndef INET6 /* not */ const char *sys_h_errlist[] = { "No problem", /* NETDB_SUCCESS */ "Authoritative answer: host not found", /* HOST_NOT_FOUND */ @@ -662,6 +663,7 @@ const char *sys_h_errlist[] = { "Valid name, no data record of requested type", /* NO_DATA */ "no address, look for MX record" /* NO_ADDRESS */ }; +#endif /* * This structure represents the files that will have log @@ -680,7 +682,18 @@ struct filed { char f_uname[MAXUNAMES][UNAMESZ+1]; 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 +#else struct sockaddr_in f_addr; +#endif } f_forw; /* forwarding address */ char f_fname[MAXFNAME]; } f_un; @@ -788,7 +801,11 @@ char *LocalDomain; /* our local domain char *emptystring = ""; int InetInuse = 0; /* non-zero if INET sockets are being used */ int finet = -1; /* Internet datagram socket */ +#ifdef INET6 +sa_family_t family; /* socket address family */ +#else int LogPort; /* port number for INET connections */ +#endif int Initialized = 0; /* set when we have initialized ourselves */ int MarkInterval = 20 * 60; /* interval between marks in seconds */ int MarkSeq = 0; /* mark sequence number */ @@ -815,10 +832,10 @@ void fprintlog(register struct filed *f, void endtty(); void wallmsg(register struct filed *f, struct iovec *iov); void reapchild(); -const char *cvthname(struct sockaddr_in *f); +const char *cvthname(struct sockaddr *f); void domark(); void debug_switch(); -void logerror(char *type); +void logerror(const char *type); void die(int sig); #ifndef TESTING void doexit(int sig); @@ -838,6 +855,10 @@ static int create_unix_socket(const char #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 #endif int main(argc, argv) @@ -875,7 +896,12 @@ int main(argc, argv) #ifndef TESTING int fd; #ifdef SYSLOG_INET +#ifdef INET6 + struct sockaddr_storage frominet; + char hbuf[INET6_ADDRSTRLEN]; +#else struct sockaddr_in frominet; +#endif char *from; #endif pid_t ppid = getpid(); @@ -1204,10 +1230,21 @@ int main(argc, argv) memset(line, 0, sizeof(line)); msglen = recvfrom(finet, line, MAXLINE - 2, 0, \ (struct sockaddr *) &frominet, &len); +#ifdef INET6 + if (getnameinfo((struct sockaddr *)&frominet, len, + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) { + strcpy(hbuf, "???"); + } + dprintf("Message from inetd socket: #%d, host: %s\n", + inetm, hbuf); +#else + dprintf("Message from inetd socket: #%d, host: %s\n", inetm, inet_ntoa(frominet.sin_addr)); +#endif if (msglen > 0) { - from = (char *)cvthname(&frominet); + from = (char *)cvthname((struct sockaddr*)&frominet); /* * Here we could check if the host is permitted * to send us syslog messages. We just have to @@ -1293,18 +1330,51 @@ static int create_unix_socket(const char static int create_inet_socket() { int fd, on = 1; +#ifdef INET6 + struct addrinfo hints, *res; + int error; +#else struct sockaddr_in sin; +#endif int sockflags; +#ifdef INET6 + fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (fd >= 0) { + family = AF_INET6; + } else { + family = AF_INET; + dprintf("cannot create INET6 socket.\n"); + fd = socket(AF_INET, SOCK_DGRAM, 0); + } +#else fd = socket(AF_INET, SOCK_DGRAM, 0); +#endif if (fd < 0) { logerror("syslog: Unknown protocol, suspending inet service."); return fd; } +#ifdef NO_BIND_AT_FORWARD_ONLY + if (AcceptRemote == 0) + return fd; +#endif +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(NULL, "syslog", &hints, &res); + if (error) { + logerror(gai_strerror(error)); + close(fd); + return -1; + } +#else memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = LogPort; +#endif if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, \ (char *) &on, sizeof(on)) < 0 ) { logerror("setsockopt(REUSEADDR), suspending inet"); @@ -1329,13 +1399,77 @@ static int create_inet_socket() close(fd); return -1; } +#ifdef INET6 + error = bind(fd, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + if (error < 0) { +#else if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { +#endif logerror("bind, suspending inet"); close(fd); return -1; } 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 ** @@ -1778,8 +1912,12 @@ void fprintlog(f, from, flags, msg) register int l; char line[MAXLINE + 1]; time_t fwd_suspend; +#ifdef INET6 + const char *errmsg; +#else struct hostent *hp; #endif +#endif dprintf("Called fprintlog, "); @@ -1833,22 +1971,27 @@ void fprintlog(f, from, flags, msg) fwd_suspend); } break; - + /* * The trick is to wait some time, then retry to get the * address. If that fails retry x times and then give up. * * You'll run into this problem mostly if the name server you * need for resolving the address is on the same machine, but - * is started after syslogd. + * is started after syslogd. */ 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"); @@ -1859,7 +2002,9 @@ void fprintlog(f, from, flags, msg) } 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; @@ -1901,7 +2046,11 @@ void fprintlog(f, from, flags, msg) l = MAXLINE; if (sendto(finet, line, l, 0, \ (struct sockaddr *) &f->f_un.f_forw.f_addr, - sizeof(f->f_un.f_forw.f_addr)) != l) { +#ifdef INET6 + family == AF_INET6 ? + sizeof(struct sockaddr_in6) : +#endif + sizeof(f->f_un.f_forw.f_addr)) != l) { int e = errno; dprintf("INET sendto error: %d = %s.\n", e, strerror(e)); @@ -2132,28 +2281,53 @@ void reapchild() /* * Return a printable representation of a host address. */ -const char *cvthname(f) - struct sockaddr_in *f; +const char *cvthname(struct sockaddr *f) { +#ifdef INET6 + static char hname[NI_MAXHOST]; + int error; +#else struct hostent *hp; + char *hname; +#endif register char *p; int count; - if (f->sin_family != AF_INET) { +#ifdef INET6 + if (((struct sockaddr *)f)->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)f)->sin6_addr)) { + ((struct sockaddr *)f)->sa_family = AF_INET; + ((struct sockaddr_in *)f)->sin_addr.s_addr = + ((struct sockaddr_in6 *)f)->sin6_addr.s6_addr32[3]; + } + error = getnameinfo((struct sockaddr *)f, + ((struct sockaddr *)f)->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) + : sizeof(struct sockaddr_in), + hname, sizeof(hname), NULL, 0, 0); + if (error) { + dprintf("Malformed from address %s\n", gai_strerror(error)); + return ("???"); + } +#else + if (((struct sockaddr_in *)f)->sin_family != AF_INET) { dprintf("Malformed from address.\n"); return ("???"); } - hp = gethostbyaddr((char *) &f->sin_addr, sizeof(struct in_addr), \ - f->sin_family); + hp = gethostbyaddr((char *) &(((struct sockaddr_in *)&f)->sin_addr), + sizeof(struct in_addr), + ((struct sockaddr_in *)f)->sin_family); if (hp == 0) { dprintf("Host name for your address (%s) unknown.\n", - inet_ntoa(f->sin_addr)); - return (inet_ntoa(f->sin_addr)); + inet_ntoa(((struct sockaddr_in *)f)->sin_addr)); + return (inet_ntoa(((struct sockaddr_in *)f)->sin_addr)); } + hname = hp->h_name; +#endif /* * Convert to lower case, just like LocalDomain above */ - for (p = (char *)hp->h_name; *p ; p++) + for (p = hname; *p ; p++) if (isupper(*p)) *p = tolower(*p); @@ -2161,17 +2335,17 @@ const char *cvthname(f) * Notice that the string still contains the fqdn, but your * hostname and domain are separated by a '\0'. */ - if ((p = strchr(hp->h_name, '.'))) { + if ((p = strchr(hname, '.'))) { if (strcmp(p + 1, LocalDomain) == 0) { *p = '\0'; - return (hp->h_name); + return (hname); } else { if (StripDomains) { count=0; while (StripDomains[count]) { if (strcmp(p + 1, StripDomains[count]) == 0) { *p = '\0'; - return (hp->h_name); + return (hname); } count++; } @@ -2179,9 +2353,9 @@ const char *cvthname(f) if (LocalHosts) { count=0; while (LocalHosts[count]) { - if (!strcmp(hp->h_name, LocalHosts[count])) { + if (!strcmp(hname, LocalHosts[count])) { *p = '\0'; - return (hp->h_name); + return (hname); } count++; } @@ -2189,7 +2363,7 @@ const char *cvthname(f) } } - return (hp->h_name); + return (hname); } void domark() @@ -2239,7 +2413,7 @@ void debug_switch() * Print syslogd errors some place. */ void logerror(type) - char *type; + const char *type; { char buf[100]; @@ -2333,6 +2507,7 @@ void init() #else char cline[BUFSIZ]; #endif +#ifndef INET6 /* not */ struct servent *sp; sp = getservbyname("syslog", "udp"); @@ -2347,6 +2522,7 @@ void init() LogPort = 0; } else LogPort = sp->s_port; +#endif /* * Close all open log files and free log descriptor array. @@ -2495,6 +2671,10 @@ void init() InetInuse = 0; } inetm = finet; +#ifdef INET6 + if (finet >= 0) + setup_inetaddr_all(); +#endif #endif Initialized = 1; @@ -2582,7 +2762,7 @@ void cfline(line, f) int singlpri = 0; int ignorepri = 0; int syncfile; -#ifdef SYSLOG_INET +#if defined(SYSLOG_INET) && !defined(INET6) struct hostent *hp; #endif char buf[MAXLINE]; @@ -2747,6 +2927,9 @@ void cfline(line, f) (void) strcpy(f->f_un.f_forw.f_hname, ++p); dprintf("forwarding host: %s\n", p); /*ASP*/ +#ifdef INET6 + f->f_type = F_FORW_UNKN; +#else if ( (hp = gethostbyname(p)) == NULL ) { f->f_type = F_FORW_UNKN; f->f_prevcount = INET_RETRY_MAX; @@ -2761,6 +2944,7 @@ void cfline(line, f) f->f_un.f_forw.f_addr.sin_port = LogPort; if ( f->f_type == F_FORW ) memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); +#endif /* * Otherwise the host might be unknown due to an * inaccessible nameserver (perhaps on the same