From 204e3f1fabd133247df77c3b28bec76c6cfcc40a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 15 Dec 2018 15:48:48 +0100 Subject: [PATCH] BUG/MINOR: log: fix logging to both FD and IP PiBa-NL reported an issue affecting logs when stdout is enabled at the same time as an IP address. It does not affect FD and UNIX, but does still affect multiple FDs. What happens is that the condition to detect that the initialization was not made relies on the FD being -1, and in this case the FD points to the *unique* FD used for AF_INET sockets, so the configured socket used for outgoing logs over UDP gets overwritten by the last configured FD. This is not appropriate, so instead we rely on the sin_port part of the IPv4-mapped address to store the initialization state for each FD. This part deserves being significantly revamped, as IPv6 is still not possible due to the way the FDs are managed, and inherited FDs are a bit hackish. Note that this patch relies on "MINOR: tools: preset the port of fd-based "sockets" to zero" in order to operate properly. No backport is needed. --- src/log.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/log.c b/src/log.c index 37c2dbd072..e0c74bcd84 100644 --- a/src/log.c +++ b/src/log.c @@ -1355,8 +1355,7 @@ void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd nblogger = 0; list_for_each_entry(tmp, logsrvs, list) { const struct logsrv *logsrv = tmp; - int *plogfd = logsrv->addr.ss_family == AF_UNIX ? - &logfdunix : &logfdinet; + int *plogfd; char *pid_sep1 = "", *pid_sep2 = ""; char logheader_short[3]; int sent; @@ -1375,15 +1374,24 @@ void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd if (level > logsrv->level) continue; + if (logsrv->addr.ss_family == AF_UNSPEC) { + /* the socket's address is a file descriptor */ + plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr; + if (unlikely(!((struct sockaddr_in *)&logsrv->addr)->sin_port)) { + /* FD not yet initialized to non-blocking mode */ + fcntl(*plogfd, F_SETFL, O_NONBLOCK); + ((struct sockaddr_in *)&logsrv->addr)->sin_port = 1; + } + } + else if (logsrv->addr.ss_family == AF_UNIX) + plogfd = &logfdunix; + else + plogfd = &logfdinet; + if (unlikely(*plogfd < 0)) { /* socket not successfully initialized yet */ - if (logsrv->addr.ss_family == AF_UNSPEC) { - /* the socket's address is a file descriptor */ - *plogfd = ((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr; - fcntl(*plogfd, F_SETFL, O_NONBLOCK); - } - else if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, - (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) { + if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, + (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) { static char once; if (!once) {