On Sun, Sep 03, 2023 at 02:00:46AM +0200, Alexander Bluhm wrote:
> When DNS lookup for remote loghost in @ line in syslog.conf does
> not work at startup, retry in intervals.

Thanks Paul de Weerd for testing my diff.  Together we improved the
debug output to make clear what is going on.  I also added generic
loghost_resolve() and loghost_retry() functions for UDP and TCP.

I am looking for ok now.

bluhm

Index: usr.sbin/syslogd/privsep.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/privsep.c,v
retrieving revision 1.76
diff -u -p -r1.76 privsep.c
--- usr.sbin/syslogd/privsep.c  11 Aug 2023 04:45:06 -0000      1.76
+++ usr.sbin/syslogd/privsep.c  2 Oct 2023 16:48:55 -0000
@@ -742,8 +742,8 @@ priv_config_parse_done(void)
 /* Name/service to address translation.  Response is placed into addr.
  * Return 0 for success or < 0 for error like getaddrinfo(3) */
 int
-priv_getaddrinfo(char *proto, char *host, char *serv, struct sockaddr *addr,
-    size_t addr_len)
+priv_getaddrinfo(const char *proto, const char *host, const char *serv,
+    struct sockaddr *addr, size_t addr_len)
 {
        char protocpy[5], hostcpy[NI_MAXHOST], servcpy[NI_MAXSERV];
        int cmd, ret_len;
Index: usr.sbin/syslogd/syslogd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.277
diff -u -p -r1.277 syslogd.c
--- usr.sbin/syslogd/syslogd.c  16 Mar 2023 18:22:08 -0000      1.277
+++ usr.sbin/syslogd/syslogd.c  2 Oct 2023 18:46:27 -0000
@@ -156,9 +156,12 @@ struct filed {
                        struct sockaddr_storage  f_addr;
                        struct buffertls         f_buftls;
                        struct bufferevent      *f_bufev;
+                       struct event             f_ev;
                        struct tls              *f_ctx;
+                       char                    *f_ipproto;
                        char                    *f_host;
-                       int                      f_reconnectwait;
+                       char                    *f_port;
+                       int                      f_retrywait;
                } f_forw;               /* forwarding address */
                char    f_fname[PATH_MAX];
                struct {
@@ -319,7 +322,9 @@ void         tcp_dropcb(struct bufferevent *, v
 void    tcp_writecb(struct bufferevent *, void *);
 void    tcp_errorcb(struct bufferevent *, short, void *);
 void    tcp_connectcb(int, short, void *);
-void    tcp_connect_retry(struct bufferevent *, struct filed *);
+int     loghost_resolve(struct filed *);
+void    loghost_retry(struct filed *);
+void    udp_resolvecb(int, short, void *);
 int     tcpbuf_countmsg(struct bufferevent *bufev);
 void    die_signalcb(int, short, void *);
 void    mark_timercb(int, short, void *);
@@ -962,12 +967,15 @@ socket_bind(const char *proto, const cha
                    res->ai_socktype | SOCK_NONBLOCK, res->ai_protocol)) == -1)
                        continue;
 
-               if (getnameinfo(res->ai_addr, res->ai_addrlen, hostname,
+               error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname,
                    sizeof(hostname), servname, sizeof(servname),
                    NI_NUMERICHOST | NI_NUMERICSERV |
-                   (res->ai_socktype == SOCK_DGRAM ? NI_DGRAM : 0)) != 0) {
-                       log_debug("Malformed bind address");
-                       hostname[0] = servname[0] = '\0';
+                   (res->ai_socktype == SOCK_DGRAM ? NI_DGRAM : 0));
+               if (error) {
+                       log_warnx("malformed bind address host \"%s\": %s",
+                           host, gai_strerror(error));
+                       strlcpy(hostname, hostname_unknown, sizeof(hostname));
+                       strlcpy(servname, hostname_unknown, sizeof(servname));
                }
                if (shutread && shutdown(*fdp, SHUT_RD) == -1) {
                        log_warn("shutdown SHUT_RD "
@@ -1130,7 +1138,7 @@ acceptcb(int lfd, short event, void *arg
        socklen_t                sslen;
        char                     hostname[NI_MAXHOST], servname[NI_MAXSERV];
        char                    *peername;
-       int                      fd;
+       int                      fd, error;
 
        sslen = sizeof(ss);
        if ((fd = reserve_accept4(lfd, event, ev, tcp_acceptcb,
@@ -1143,17 +1151,21 @@ acceptcb(int lfd, short event, void *arg
        }
        log_debug("Accepting tcp connection");
 
-       if (getnameinfo((struct sockaddr *)&ss, sslen, hostname,
+       error = getnameinfo((struct sockaddr *)&ss, sslen, hostname,
            sizeof(hostname), servname, sizeof(servname),
-           NI_NUMERICHOST | NI_NUMERICSERV) != 0 ||
-           asprintf(&peername, ss.ss_family == AF_INET6 ?
+           NI_NUMERICHOST | NI_NUMERICSERV);
+       if (error) {
+               log_warnx("malformed TCP accept address: %s",
+                   gai_strerror(error));
+               peername = hostname_unknown;
+       } else if (asprintf(&peername, ss.ss_family == AF_INET6 ?
            "[%s]:%s" : "%s:%s", hostname, servname) == -1) {
-               log_debug("Malformed accept address");
+               log_warn("allocate hostname \"%s\"", hostname);
                peername = hostname_unknown;
        }
        log_debug("Peer address and port %s", peername);
        if ((p = malloc(sizeof(*p))) == NULL) {
-               log_warn("allocate \"%s\"", peername);
+               log_warn("allocate peername \"%s\"", peername);
                close(fd);
                return;
        }
@@ -1380,7 +1392,7 @@ tcp_writecb(struct bufferevent *bufev, v
         * Successful write, connection to server is good, reset wait time.
         */
        log_debug("loghost \"%s\" successful write", f->f_un.f_forw.f_loghost);
-       f->f_un.f_forw.f_reconnectwait = 0;
+       f->f_un.f_forw.f_retrywait = 0;
 
        if (f->f_dropped > 0 &&
            EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output) < MAX_TCPBUF) {
@@ -1440,7 +1452,7 @@ tcp_errorcb(struct bufferevent *bufev, s
                f->f_dropped++;
        }
 
-       tcp_connect_retry(bufev, f);
+       loghost_retry(f);
 
        /* Log the connection error to the fresh buffer after reconnecting. */
        log_info(LOG_WARNING, "%s", ebuf);
@@ -1453,8 +1465,15 @@ tcp_connectcb(int fd, short event, void 
        struct bufferevent      *bufev = f->f_un.f_forw.f_bufev;
        int                      s;
 
+       if (f->f_un.f_forw.f_addr.ss_family == AF_UNSPEC) {
+               if (loghost_resolve(f) != 0) {
+                       loghost_retry(f);
+                       return;
+               }
+       }
+
        if ((s = tcp_socket(f)) == -1) {
-               tcp_connect_retry(bufev, f);
+               loghost_retry(f);
                return;
        }
        log_debug("tcp connect callback: socket success, event %#x", event);
@@ -1503,29 +1522,87 @@ tcp_connectcb(int fd, short event, void 
        }
        close(f->f_file);
        f->f_file = -1;
-       tcp_connect_retry(bufev, f);
+       loghost_retry(f);
+}
+
+int
+loghost_resolve(struct filed *f)
+{
+       char    hostname[NI_MAXHOST];
+       int     error;
+
+       error = priv_getaddrinfo(f->f_un.f_forw.f_ipproto,
+           f->f_un.f_forw.f_host, f->f_un.f_forw.f_port,
+           (struct sockaddr *)&f->f_un.f_forw.f_addr,
+           sizeof(f->f_un.f_forw.f_addr));
+       if (error) {
+               log_warnx("bad hostname \"%s\"", f->f_un.f_forw.f_loghost);
+               f->f_un.f_forw.f_addr.ss_family = AF_UNSPEC;
+               return (error);
+       }
+
+       error = getnameinfo((struct sockaddr *)&f->f_un.f_forw.f_addr,
+           f->f_un.f_forw.f_addr.ss_len, hostname, sizeof(hostname), NULL, 0,
+           NI_NUMERICHOST | NI_NUMERICSERV |
+           (strncmp(f->f_un.f_forw.f_ipproto, "udp", 3) == 0 ? NI_DGRAM : 0));
+       if (error) {
+               log_warnx("malformed UDP address loghost \"%s\": %s",
+                   f->f_un.f_forw.f_loghost, gai_strerror(error));
+               strlcpy(hostname, hostname_unknown, sizeof(hostname));
+       }
+
+       log_debug("resolved loghost \"%s\" address %s",
+           f->f_un.f_forw.f_loghost, hostname);
+       return (0);
 }
 
 void
-tcp_connect_retry(struct bufferevent *bufev, struct filed *f)
+loghost_retry(struct filed *f)
 {
        struct timeval           to;
 
-       if (f->f_un.f_forw.f_reconnectwait == 0)
-               f->f_un.f_forw.f_reconnectwait = 1;
+       if (f->f_un.f_forw.f_retrywait == 0)
+               f->f_un.f_forw.f_retrywait = 1;
        else
-               f->f_un.f_forw.f_reconnectwait <<= 1;
-       if (f->f_un.f_forw.f_reconnectwait > 600)
-               f->f_un.f_forw.f_reconnectwait = 600;
-       to.tv_sec = f->f_un.f_forw.f_reconnectwait;
+               f->f_un.f_forw.f_retrywait <<= 1;
+       if (f->f_un.f_forw.f_retrywait > 600)
+               f->f_un.f_forw.f_retrywait = 600;
+       to.tv_sec = f->f_un.f_forw.f_retrywait;
        to.tv_usec = 0;
+       evtimer_add(&f->f_un.f_forw.f_ev, &to);
 
-       log_debug("tcp connect retry: wait %d",
-           f->f_un.f_forw.f_reconnectwait);
-       bufferevent_setfd(bufev, -1);
-       /* We can reuse the write event as bufferevent is disabled. */
-       evtimer_set(&bufev->ev_write, tcp_connectcb, f);
-       evtimer_add(&bufev->ev_write, &to);
+       log_debug("retry loghost \"%s\" wait %d",
+           f->f_un.f_forw.f_loghost, f->f_un.f_forw.f_retrywait);
+}
+
+void
+udp_resolvecb(int fd, short event, void *arg)
+{
+       struct filed            *f = arg;
+       struct timeval           to;
+
+       if (loghost_resolve(f) != 0) {
+               loghost_retry(f);
+               return;
+       }
+
+       switch (f->f_un.f_forw.f_addr.ss_family) {
+       case AF_INET:
+               f->f_file = fd_udp;
+               break;
+       case AF_INET6:
+               f->f_file = fd_udp6;
+               break;
+       }
+       f->f_un.f_forw.f_retrywait = 0;
+
+       if (f->f_dropped > 0) {
+               char ebuf[ERRBUFSIZE];
+
+               snprintf(ebuf, sizeof(ebuf), "to udp loghost \"%s\"",
+                   f->f_un.f_forw.f_loghost);
+               dropped_warn(&f->f_dropped, ebuf);
+       }
 }
 
 int
@@ -1933,6 +2010,11 @@ fprintlog(struct filed *f, int flags, ch
 
        case F_FORWUDP:
                log_debug(" %s", f->f_un.f_forw.f_loghost);
+               if (f->f_un.f_forw.f_addr.ss_family == AF_UNSPEC) {
+                       log_warnx("not resolved \"%s\"",
+                           f->f_un.f_forw.f_loghost);
+                       break;
+               }
                l = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len +
                    iov[3].iov_len + iov[4].iov_len + iov[5].iov_len +
                    iov[6].iov_len;
@@ -2168,9 +2250,13 @@ wallmsg(struct filed *f, struct iovec *i
 void
 cvthname(struct sockaddr *f, char *result, size_t res_len)
 {
-       if (getnameinfo(f, f->sa_len, result, res_len, NULL, 0,
-           NI_NUMERICHOST|NI_NUMERICSERV|NI_DGRAM) != 0) {
-               log_debug("Malformed from address");
+       int error;
+
+       error = getnameinfo(f, f->sa_len, result, res_len, NULL, 0,
+           NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
+       if (error) {
+               log_warnx("malformed UDP from address: %s",
+                   gai_strerror(error));
                strlcpy(result, hostname_unknown, res_len);
                return;
        }
@@ -2295,23 +2381,33 @@ init(void)
                        fprintlog(f, 0, (char *)NULL);
 
                switch (f->f_type) {
+               case F_FORWUDP:
+                       evtimer_del(&f->f_un.f_forw.f_ev);
+                       free(f->f_un.f_forw.f_ipproto);
+                       free(f->f_un.f_forw.f_host);
+                       free(f->f_un.f_forw.f_port);
+                       break;
                case F_FORWTLS:
                        if (f->f_un.f_forw.f_ctx) {
                                tls_close(f->f_un.f_forw.f_ctx);
                                tls_free(f->f_un.f_forw.f_ctx);
                        }
-                       free(f->f_un.f_forw.f_host);
                        /* FALLTHROUGH */
                case F_FORWTCP:
+                       evtimer_del(&f->f_un.f_forw.f_ev);
                        tcpbuf_dropped += f->f_dropped +
                             tcpbuf_countmsg(f->f_un.f_forw.f_bufev);
                        bufferevent_free(f->f_un.f_forw.f_bufev);
+                       free(f->f_un.f_forw.f_ipproto);
+                       free(f->f_un.f_forw.f_host);
+                       free(f->f_un.f_forw.f_port);
                        /* FALLTHROUGH */
                case F_FILE:
                        if (f->f_type == F_FILE) {
                                file_dropped += f->f_dropped;
                                f->f_dropped = 0;
                        }
+                       /* FALLTHROUGH */
                case F_TTY:
                case F_CONSOLE:
                case F_PIPE:
@@ -2704,16 +2800,31 @@ cfline(char *line, char *progblock, char
                            f->f_un.f_forw.f_loghost);
                        break;
                }
-               if (priv_getaddrinfo(ipproto, host, port,
-                   (struct sockaddr*)&f->f_un.f_forw.f_addr,
-                   sizeof(f->f_un.f_forw.f_addr)) != 0) {
-                       log_warnx("bad hostname \"%s\"",
+               f->f_un.f_forw.f_ipproto = strdup(ipproto);
+               f->f_un.f_forw.f_host = strdup(host);
+               f->f_un.f_forw.f_port = strdup(port);
+               if (f->f_un.f_forw.f_ipproto == NULL ||
+                   f->f_un.f_forw.f_host == NULL ||
+                   f->f_un.f_forw.f_port == NULL) {
+                       log_warnx("strdup ipproto host port \"%s\"",
                            f->f_un.f_forw.f_loghost);
+                       free(f->f_un.f_forw.f_ipproto);
+                       free(f->f_un.f_forw.f_host);
+                       free(f->f_un.f_forw.f_port);
                        break;
                }
                f->f_file = -1;
+               loghost_resolve(f);
                if (strncmp(proto, "udp", 3) == 0) {
+                       evtimer_set(&f->f_un.f_forw.f_ev, udp_resolvecb, f);
                        switch (f->f_un.f_forw.f_addr.ss_family) {
+                       case AF_UNSPEC:
+                               log_debug("resolve \"%s\" delayed",
+                                   f->f_un.f_forw.f_loghost);
+                               to.tv_sec = 0;
+                               to.tv_usec = 1;
+                               evtimer_add(&f->f_un.f_forw.f_ev, &to);
+                               break;
                        case AF_INET:
                                f->f_file = fd_udp;
                                break;
@@ -2727,26 +2838,23 @@ cfline(char *line, char *progblock, char
                            tcp_dropcb, tcp_writecb, tcp_errorcb, f)) == NULL) {
                                log_warn("bufferevent \"%s\"",
                                    f->f_un.f_forw.f_loghost);
+                               free(f->f_un.f_forw.f_ipproto);
+                               free(f->f_un.f_forw.f_host);
+                               free(f->f_un.f_forw.f_port);
                                break;
                        }
-                       if (strncmp(proto, "tls", 3) == 0) {
-                               f->f_un.f_forw.f_host = strdup(host);
-                               f->f_type = F_FORWTLS;
-                       } else {
-                               f->f_type = F_FORWTCP;
-                       }
                        /*
                         * If we try to connect to a TLS server immediately
                         * syslogd gets an SIGPIPE as the signal handlers have
                         * not been set up.  Delay the connection until the
-                        * event loop is started.  We can reuse the write event
-                        * for that as bufferevent is still disabled.
+                        * event loop is started.
                         */
+                       evtimer_set(&f->f_un.f_forw.f_ev, tcp_connectcb, f);
                        to.tv_sec = 0;
                        to.tv_usec = 1;
-                       evtimer_set(&f->f_un.f_forw.f_bufev->ev_write,
-                           tcp_connectcb, f);
-                       evtimer_add(&f->f_un.f_forw.f_bufev->ev_write, &to);
+                       evtimer_add(&f->f_un.f_forw.f_ev, &to);
+                       f->f_type = (strncmp(proto, "tls", 3) == 0) ?
+                           F_FORWTLS : F_FORWTCP;
                }
                break;
 
Index: usr.sbin/syslogd/syslogd.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.h,v
retrieving revision 1.36
diff -u -p -r1.36 syslogd.h
--- usr.sbin/syslogd/syslogd.h  13 Jan 2022 10:34:07 -0000      1.36
+++ usr.sbin/syslogd/syslogd.h  2 Oct 2023 16:49:31 -0000
@@ -34,7 +34,8 @@ FILE *priv_open_utmp(void);
 FILE *priv_open_config(void);
 void  priv_config_parse_done(void);
 int   priv_config_modified(void);
-int   priv_getaddrinfo(char *, char *, char *, struct sockaddr *, size_t);
+int   priv_getaddrinfo(const char *, const char *, const char *,
+    struct sockaddr *, size_t);
 int   priv_getnameinfo(struct sockaddr *, socklen_t, char *, size_t);
 
 #define IOVCNT         7

Reply via email to