NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/54527: syslogd hangs when forwarding logs to a IPv6 host that is down



The following reply was made to PR lib/54527; it has been noted by GNATS.

From: Anthony Mallet <anthony.mallet%useless-ficus.net@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: lib/54527: syslogd hangs when forwarding logs to a IPv6 host that is down
Date: Sat, 14 Sep 2019 15:26:49 +0200

 --izN8ETk60E
 Content-Type: text/plain; charset=us-ascii
 Content-Description: message body text
 Content-Transfer-Encoding: 7bit
 
 I could finally debug this further. The problem is the following:
 
 When syslog sends a udp datagram to the remote, unreachable IPv6 host,
 the socket is marked readable and a recv on it will return
 EHOSTDOWN. So far so good.
 
 However, there is a call to libwrap "fromhost" (syslogd.c:795) that
 eats the error and prevents the further "recvfrom" (syslog.c:802) from
 getting it (that's why recvfrom then block forever).
 I attach a sample program that shows the issue more clearly.
 
 For UDP sockets, libwrap does "recvfrom( ... MSG_PEEK ...)" to
 determine the remote address. This is the call that gets the
 EHOSTDOWN. However, the hostfrom() function does not return errors, so
 syslogd cannot use this information to avoid the blocking recvfrom().
 
 Not sure what to do ...
 
 
 --izN8ETk60E
 Content-Type: text/plain;
 	 name="sock.c"
 Content-Disposition: inline;
 	 filename="sock.c"
 Content-Transfer-Encoding: 7bit
 
 #include <sys/socket.h>
 #include <netinet/in.h>
 
 #include <err.h>
 #include <event.h>
 #include <netdb.h>
 #include <poll.h>
 
 int
 main()
 {
   struct addrinfo hints = { 0 }, *res, *r;
   struct sockaddr_storage frominet;
   struct pollfd fds;
   socklen_t len;
   char buf[16];
   ssize_t s;
   int error;
   int fd;
 
   /* setup sending socket */
   hints.ai_flags = AI_PASSIVE;
   hints.ai_family = AF_INET6;
   hints.ai_socktype = SOCK_DGRAM;
   error = getaddrinfo(NULL, "12345", &hints, &res);
   if (error) err(2, "getaddrinfo bind");
 
   for (r = res; r; r = r->ai_next) {
     fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
     if (fd < 0) err(2, "socket");
 
     if (bind(fd, r->ai_addr, r->ai_addrlen) < 0)
       err(2, "bind");
 
     break;
   }
   freeaddrinfo(res);
 
   /* non-existent host */
   hints.ai_flags = AI_NUMERICHOST;
   hints.ai_family = AF_INET6;
   hints.ai_socktype = SOCK_DGRAM;
   error = getaddrinfo("fc00::", "12345", &hints, &res);
   if (error) err(2, "getaddrinfo sendto");
 
   /* send empty datagram */
   for (r = res; r; r = r->ai_next) {
     s = sendto(fd, "", 1, 0, r->ai_addr, r->ai_addrlen);
     if (s == -1)
       err(2, "sendto");
     warnx("sent %zd bytes", s);
     break;
   }
   freeaddrinfo(res);
 
   /* wait for events: sock will be readable and return EHOSTDOWN */
   while (1) {
     fds.fd = fd;
     fds.events = POLLIN;
     if (poll(&fds, 1, -1) == 1) {
       warnx("events %d %d", fds.events, fds.revents);
 
       /* do the equivalent of a libwarp "hostfrom" */
       len = sizeof(frominet);
       if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
                    (struct sockaddr *)&frominet, &len) < 0) {
         warn("can't get client address");
       }
 
       /* this blocks because the EHOSTDOWN was eaten above */
       s = recv(fd, buf, sizeof(buf), 0);
       warn("recv %zd", s);
     }
 
     warnx("not reached :/");
   }
 
   return 0;
 }
 
 --izN8ETk60E--
 



Home | Main Index | Thread Index | Old Index