On Fri, 28 Apr 2006, Brian wrote:

> I am in the process of making syslogd more protocol independent (IPv4
> & IPv6). I am just about ready to add a priviledged fuction for
> getnameinfo, but what I do not understand is why the the DNS lookups
> are priviledged separated. I do understand the security piece talked
> about in the getnameinfo(3) man page. And I have read through the CVS
> comments.

Unless you are doing it for education or fun, then don't bother making
syslogd IPv6 capable - there is already a patch (see below).

The DNS lookups are privilege separated because the unprivileged
child will not have access to /etc/resolv.conf, /etc/hosts, etc. 
If it passes them back up to the monitor, then the monitor will have
access to these files and will be able to make the lookups normally.

-d

----------------------------

IPv6 syslogd patch from Mischa Diehm <[EMAIL PROTECTED]>. It might be a little
stale, as it is around a year old now.

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- Makefile    4 Jan 2004 08:28:49 -0000       1.5
+++ Makefile    6 Aug 2005 19:02:57 -0000
@@ -4,4 +4,13 @@ PROG=  syslogd
 SRCS=  syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c
 MAN=   syslogd.8 syslog.conf.5
 
+CDIAGFLAGS=    -Wall
+CDIAGFLAGS+=   -Wpointer-arith
+CDIAGFLAGS+=   -Wno-uninitialized
+CDIAGFLAGS+=   -Wstrict-prototypes
+CDIAGFLAGS+=   -Wmissing-prototypes
+CDIAGFLAGS+=   -Wunused
+CDIAGFLAGS+=   -Wbounded
+CDIAGFLAGS+=   -Wshadow
+
 .include <bsd.prog.mk>
Index: privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/privsep.c,v
retrieving revision 1.26
diff -u -p -r1.26 privsep.c
--- privsep.c   6 Jun 2005 23:20:44 -0000       1.26
+++ privsep.c   6 Aug 2005 19:02:57 -0000
@@ -66,8 +66,8 @@ enum cmd_types {
        PRIV_OPEN_UTMP,         /* open utmp for reading only */
        PRIV_OPEN_CONFIG,       /* open config file for reading only */
        PRIV_CONFIG_MODIFIED,   /* check if config file has been modified */
-       PRIV_GETHOSTSERV,       /* resolve host/service names */
-       PRIV_GETHOSTBYADDR,     /* resolve numeric address into hostname */
+       PRIV_GETADDRINFO,       /* resolve hostname into numerical address */
+       PRIV_GETNAMEINFO,       /* resolve numeric address into hostname */
        PRIV_DONE_CONFIG_PARSE  /* signal that the initial config parse is done 
*/
 };
 
@@ -75,7 +75,7 @@ static int priv_fd = -1;
 static volatile pid_t child_pid = -1;
 static char config_file[MAXPATHLEN];
 static struct stat cf_info;
-static int allow_gethostbyaddr = 0;
+static int allow_getnameinfo = 0;
 static volatile sig_atomic_t cur_state = STATE_INIT;
 
 /* Queue for the allowed logfiles */
@@ -97,14 +97,14 @@ static int  may_read(int, void *, size_t
 int
 priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[])
 {
-       int i, fd, socks[2], cmd, addr_len, addr_af, result, restart;
+       int i, fd, socks[2], cmd, addr_len, result, restart, error;
        size_t path_len, hostname_len, servname_len;
-       char path[MAXPATHLEN], hostname[MAXHOSTNAMELEN];
-       char servname[MAXHOSTNAMELEN];
+       char path[MAXPATHLEN], host[NI_MAXHOST];
+       char hostname[NI_MAXHOST], servname[NI_MAXSERV];
        struct stat cf_stat;
-       struct hostent *hp;
        struct passwd *pw;
-       struct addrinfo hints, *res0;
+       struct addrinfo hints, *res, *r;
+       struct sockaddr_storage s_addr;
 
        for (i = 1; i < _NSIG; i++)
                signal(i, SIG_DFL);
@@ -164,8 +164,9 @@ priv_init(char *conf, int numeric, int l
        for (i = 0; i < nfunix; i++)
                if (pfd[PFD_UNIX_0 + i].fd != -1)
                        close(pfd[PFD_UNIX_0 + i].fd);
-       if (pfd[PFD_INET].fd != -1)
-               close(pfd[PFD_INET].fd);
+       for (i = 0; i < nfinet; i++)
+               if (pfd[start_inetfds + i].fd != -1)
+                       close(pfd[start_inetfds + i].fd);
        if (pfd[PFD_CTLSOCK].fd != -1)
                close(pfd[PFD_CTLSOCK].fd);
        if (pfd[PFD_CTLCONN].fd != -1)
@@ -180,11 +181,11 @@ priv_init(char *conf, int numeric, int l
        if (stat(config_file, &cf_info) < 0)
                err(1, "stat config file failed");
 
-       /* Save whether or not the child can have access to gethostbyaddr(3) */
+       /* Save whether or not the child can have access to getnameinfo(3) */
        if (numeric > 0)
-               allow_gethostbyaddr = 0;
+               allow_getnameinfo = 0;
        else
-               allow_gethostbyaddr = 1;
+               allow_getnameinfo = 1;
 
        TAILQ_INIT(&lognames);
        increase_state(STATE_CONFIG);
@@ -269,57 +270,91 @@ priv_init(char *conf, int numeric, int l
                        increase_state(STATE_RUNNING);
                        break;
 
-               case PRIV_GETHOSTSERV:
-                       dprintf("[priv]: msg PRIV_GETHOSTSERV received\n");
-                       /* Expecting: len, hostname, len, servname */
+               case PRIV_GETADDRINFO:
+                       dprintf("[priv]: msg PRIV_GETADDRINFO received\n");
+
+                       /* Expecting: length, hostname, length, servname */
                        must_read(socks[0], &hostname_len, sizeof(size_t));
-                       if (hostname_len == 0 || hostname_len > 
sizeof(hostname))
+                       if (hostname_len == 0 ||
+                           hostname_len > sizeof(hostname)) {
+                               dprintf("[priv]: PRIV_GETADDRINFO bad len %d\n",
+                                   hostname_len);
                                _exit(0);
+                       }
                        must_read(socks[0], &hostname, hostname_len);
                        hostname[hostname_len - 1] = '\0';
-
                        must_read(socks[0], &servname_len, sizeof(size_t));
-                       if (servname_len == 0 || servname_len > 
sizeof(servname))
+                       if (servname_len == 0 ||
+                           servname_len > sizeof(servname))
                                _exit(0);
                        must_read(socks[0], &servname, servname_len);
                        servname[servname_len - 1] = '\0';
 
-                       memset(&hints, '\0', sizeof(hints));
-                       hints.ai_family = AF_INET;
+                       memset(&hints, 0, sizeof(hints));
+                       hints.ai_family = af;
                        hints.ai_socktype = SOCK_DGRAM;
-                       i = getaddrinfo(hostname, servname, &hints, &res0);
-                       if (i != 0 || res0 == NULL) {
+                       error = getaddrinfo(hostname, servname, &hints, &res);
+                       if (error) {
+                               warnx("getaddrinfo failed: %s",
+                                   gai_strerror(error));
                                addr_len = 0;
                                must_write(socks[0], &addr_len, sizeof(int));
                        } else {
-                               /* Just send the first address */
-                               i = res0->ai_addrlen;
-                               must_write(socks[0], &i, sizeof(int));
-                               must_write(socks[0], res0->ai_addr, i);
-                               freeaddrinfo(res0);
+                               int num = 0;
+
+                               for (r = res; r != NULL; r = r->ai_next)
+                                       num++;
+
+                               /* limit the number of returned addresses */
+                               if (num > MAX_GETADDR) {
+                                       dprintf("[priv]: Getaddrinfo returned "
+                                           "%d addresses. Limiting to %d.\n",
+                                           num, MAX_GETADDR);
+                                       num = MAX_GETADDR;
+                               }
+                               must_write(socks[0], &num, sizeof(int));
+                               for (r = res; num > 0; r = r->ai_next) {
+                                       must_write(socks[0], &r->ai_addrlen,
+                                           sizeof(socklen_t));
+                                       must_write(socks[0], r->ai_addr,
+                                           r->ai_addrlen);
+                                       num--;
+                               }
+                               freeaddrinfo(res);
                        }
                        break;
 
-               case PRIV_GETHOSTBYADDR:
-                       dprintf("[priv]: msg PRIV_GETHOSTBYADDR received\n");
-                       if (!allow_gethostbyaddr)
-                               errx(1, "rejected attempt to gethostbyaddr");
-                       /* Expecting: length, address, address family */
+               case PRIV_GETNAMEINFO:
+                       dprintf("[priv]: msg PRIV_GETNAMEINFO received\n");
+                       if (!allow_getnameinfo)
+                               errx(1, "rejected attempt to getnameinfo");
+
+                       /* Expecting: length, sockaddr */
                        must_read(socks[0], &addr_len, sizeof(int));
-                       if (addr_len <= 0 || addr_len > sizeof(hostname))
+                       if (addr_len <= 0 ||
+                           addr_len > sizeof(struct sockaddr_storage)) {
+                               dprintf("[priv]: PRIV_GETNAMEINFO bad len %d\n",
+                                   addr_len);
                                _exit(0);
-                       must_read(socks[0], hostname, addr_len);
-                       must_read(socks[0], &addr_af, sizeof(int));
-                       hp = gethostbyaddr(hostname, addr_len, addr_af);
-                       if (hp == NULL) {
+                       }
+                       must_read(socks[0], &s_addr, addr_len);
+
+                       error = getnameinfo((struct sockaddr*)&s_addr,
+                           ((struct sockaddr*)&s_addr)->sa_len,
+                           host, sizeof(host), NULL, 0, NI_DGRAM);
+
+                       if (error) {
+                               warnx("getnameinfo failed: %s",
+                                   gai_strerror(error));
                                addr_len = 0;
                                must_write(socks[0], &addr_len, sizeof(int));
                        } else {
-                               addr_len = strlen(hp->h_name) + 1;
+                               addr_len = strlen(host) + 1;
                                must_write(socks[0], &addr_len, sizeof(int));
-                               must_write(socks[0], hp->h_name, addr_len);
+                               must_write(socks[0], host, addr_len);
                        }
                        break;
+                       
                default:
                        errx(1, "unknown command %d", cmd);
                        break;
@@ -336,9 +371,9 @@ priv_init(char *conf, int numeric, int l
                (void)unlink(ctlsock_path);
 
        if (restart) {
-               int r;
+               int status;
 
-               wait(&r);
+               wait(&status);
                execvp(argv[0], argv);
        }
        _exit(1);
@@ -555,63 +590,67 @@ priv_config_parse_done(void)
 /* Name/service to address translation.  Response is placed into addr, and
  * the length is returned (zero on error) */
 int
-priv_gethostserv(char *host, char *serv, struct sockaddr *addr,
-    size_t addr_len)
+priv_getaddrinfo(char *host, char *servname, struct sockaddr **s_addr)
 {
-       char hostcpy[MAXHOSTNAMELEN], servcpy[MAXHOSTNAMELEN];
-       int cmd, ret_len;
+       int cmd, i, num = 0;
+       char hostcpy[NI_MAXHOST];
+       char servnamecpy[NI_MAXSERV];
        size_t hostname_len, servname_len;
+       socklen_t addr_len;
+       struct sockaddr_storage *tmp_ss;
 
        if (priv_fd < 0)
-               errx(1, "%s: called from privileged portion", 
"priv_gethostserv");
+               errx(1, "priv_getaddrinfo: called from privileged portion");
 
        if (strlcpy(hostcpy, host, sizeof hostcpy) >= sizeof(hostcpy))
-               errx(1, "%s: overflow attempt in hostname", "priv_gethostserv");
+               errx(1, "priv_getaddrinfo: overflow attempt in hostname");
        hostname_len = strlen(hostcpy) + 1;
-       if (strlcpy(servcpy, serv, sizeof servcpy) >= sizeof(servcpy))
-               errx(1, "%s: overflow attempt in servname", "priv_gethostserv");
-       servname_len = strlen(servcpy) + 1;
+       if (strlcpy(servnamecpy, servname, sizeof servnamecpy) >=
+           sizeof(servnamecpy))
+               errx(1, "priv_getaddrinfo: overflow attempt in servname");
+       servname_len = strlen(servnamecpy) + 1;
 
-       cmd = PRIV_GETHOSTSERV;
+       cmd = PRIV_GETADDRINFO;
        must_write(priv_fd, &cmd, sizeof(int));
        must_write(priv_fd, &hostname_len, sizeof(size_t));
        must_write(priv_fd, hostcpy, hostname_len);
        must_write(priv_fd, &servname_len, sizeof(size_t));
-       must_write(priv_fd, servcpy, servname_len);
+       must_write(priv_fd, servnamecpy, servname_len);
 
-       /* Expect back an integer size, and then a string of that length */
-       must_read(priv_fd, &ret_len, sizeof(int));
+       /* Expect back an integer with the number of sockaddr(s) */
+       must_read(priv_fd, &num, sizeof(int));
 
-       /* Check there was no error (indicated by a return of 0) */
-       if (!ret_len)
-               return 0;
+       if (num <= 0)
+               return (0);
 
-       /* Make sure we aren't overflowing the passed in buffer */
-       if (addr_len < ret_len)
-               errx(1, "%s: overflow attempt in return", "priv_gethostserv");
-
-       /* Read the resolved address and make sure we got all of it */
-       memset(addr, '\0', addr_len);
-       must_read(priv_fd, addr, ret_len);
-
-       return ret_len;
+       if ((*s_addr = malloc(num * sizeof(struct sockaddr_storage))) == NULL)
+               err(1, "priv_getaddrinfo() malloc");
+
+       /* Read the returned address structure(s) */
+       tmp_ss = (struct sockaddr_storage *)*s_addr;
+       for (i = 0; i < num; i++) {
+               must_read(priv_fd, &addr_len, sizeof(socklen_t));
+               must_read(priv_fd, &(tmp_ss[i]), addr_len);
+       }
+       return num;
 }
 
 /* Reverse address resolution; response is placed into res, and length of
  * response is returned (zero on error) */
 int
-priv_gethostbyaddr(char *addr, int addr_len, int af, char *res, size_t res_len)
+priv_getnameinfo(struct sockaddr *s_addr, char *res, size_t res_len)
 {
-       int cmd, ret_len;
+       int cmd, ret_len, addr_len;
+
+       addr_len = s_addr->sa_len;
 
        if (priv_fd < 0)
-               errx(1, "%s called from privileged portion", 
"priv_gethostbyaddr");
+               errx(1, "%s called from privileged portion", 
"priv_getnameinfo");
 
-       cmd = PRIV_GETHOSTBYADDR;
+       cmd = PRIV_GETNAMEINFO;
        must_write(priv_fd, &cmd, sizeof(int));
        must_write(priv_fd, &addr_len, sizeof(int));
-       must_write(priv_fd, addr, addr_len);
-       must_write(priv_fd, &af, sizeof(int));
+       must_write(priv_fd, s_addr, addr_len);
 
        /* Expect back an integer size, and then a string of that length */
        must_read(priv_fd, &ret_len, sizeof(int));
@@ -622,7 +661,7 @@ priv_gethostbyaddr(char *addr, int addr_
 
        /* Check we don't overflow the passed in buffer */
        if (res_len < ret_len)
-               errx(1, "%s: overflow attempt in return", "priv_gethostbyaddr");
+               errx(1, "%s: overflow attempt in return", "priv_getnameinfo");
 
        /* Read the resolved hostname */
        must_read(priv_fd, res, ret_len);
@@ -677,7 +716,8 @@ static void
 must_read(int fd, void *buf, size_t n)
 {
        char *s = buf;
-       ssize_t res, pos = 0;
+       ssize_t res;
+       size_t pos = 0;
 
        while (n > pos) {
                res = read(fd, s + pos, n - pos);
@@ -699,7 +739,8 @@ static void
 must_write(int fd, void *buf, size_t n)
 {
        char *s = buf;
-       ssize_t res, pos = 0;
+       ssize_t res;
+       size_t pos = 0;
 
        while (n > pos) {
                res = write(fd, s + pos, n - pos);
Index: syslogd.8
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.8,v
retrieving revision 1.21
diff -u -p -r1.21 syslogd.8
--- syslogd.8   2 Dec 2004 21:58:57 -0000       1.21
+++ syslogd.8   6 Aug 2005 19:02:57 -0000
@@ -39,7 +39,7 @@
 .Sh SYNOPSIS
 .Nm syslogd
 .Bk -words
-.Op Fl dnu
+.Op Fl 46dnu
 .Op Fl a Ar path
 .Op Fl f Ar config_file
 .Op Fl m Ar mark_interval
@@ -53,6 +53,14 @@ machines and/or users as specified by it
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
+.It Fl 4
+Force
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Force
+.Nm
+to use IPv6 addresses only.
 .It Fl a Pa path
 Specify a location where
 .Nm
@@ -73,7 +81,7 @@ Select the number of minutes between
 .Dq mark
 messages; the default is 20 minutes.
 .It Fl n
-Print source addresses numerically rather than symbolically.
+Print values for loghosts as defined in the configuration file.
 This saves an address-to-name lookup for each incoming message,
 which can be useful when combined with the
 .Fl u
Index: syslogd.c
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.92
diff -u -p -r1.92 syslogd.c
--- syslogd.c   10 Jun 2005 01:41:43 -0000      1.92
+++ syslogd.c   6 Aug 2005 19:02:58 -0000
@@ -141,8 +141,11 @@ struct filed {
        union {
                char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
                struct {
-                       char    f_hname[MAXHOSTNAMELEN];
-                       struct sockaddr_storage f_addr;
+                       char    f_host[NI_MAXHOST];
+                       char    f_serv[NI_MAXSERV];
+                       int     f_num_addrs;
+                       struct sockaddr_storage *f_addrs;
+                       int     f_good_addr;
                } f_forw;               /* forwarding address */
                char    f_fname[MAXPATHLEN];
                struct {
@@ -153,7 +156,7 @@ struct filed {
        } f_un;
        char    f_prevline[MAXSVLINE];          /* last message logged */
        char    f_lasttime[16];                 /* time of last occurrence */
-       char    f_prevhost[MAXHOSTNAMELEN];     /* host from which recd. */
+       char    f_prevhost[NI_MAXHOST];         /* host from which recd. */
        int     f_prevpri;                      /* pri of f_prevline */
        int     f_prevlen;                      /* length of f_prevline */
        int     f_prevcount;                    /* repetition cnt of prevline */
@@ -192,10 +195,12 @@ struct    filed *Files;
 struct filed consfile;
 
 int    nfunix = 1;             /* Number of Unix domain sockets requested */
+int    nfinet = 0;             /* Number of Inet domain sockets requested */
+int    start_inetfds = 0;      /* Offset for Internet datagram sockets */
 char   *funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */
 int    Debug;                  /* debug flag */
 int    Startup = 1;            /* startup flag */
-char   LocalHostName[MAXHOSTNAMELEN];  /* our hostname */
+char   LocalHostName[NI_MAXHOST]; /* our hostname */
 char   *LocalDomain;           /* our local domain name */
 int    InetInuse = 0;          /* non-zero if INET sockets are being used */
 int    LogPort;                /* port number for INET connections */
@@ -206,6 +211,8 @@ int MarkSeq = 0;            /* mark sequence numbe
 int    SecureMode = 1;         /* when true, speak only unix domain socks */
 int    NoDNS = 0;              /* when true, will refrain from doing DNS 
lookups */
 
+int    af = AF_UNSPEC;         /* address family for inet-socket */
+
 char   *ctlsock_path = NULL;   /* Path to control socket */
 
 #define CTL_READING_CMD                1
@@ -247,13 +254,14 @@ size_t    ctl_reply_size = 0;     /* Number of 
 size_t ctl_reply_offset = 0;   /* Number of bytes of reply written so far */
 
 struct pollfd pfd[N_PFD];
+int pollfd_ai_fam[MAX_AI_PASSIVE];
 
 volatile sig_atomic_t MarkSet;
 volatile sig_atomic_t WantDie;
 volatile sig_atomic_t DoInit;
 
 struct filed *cfline(char *, char *);
-void    cvthname(struct sockaddr_in *, char *, size_t);
+void   cvthname(struct sockaddr *, char *, size_t);
 int    decode(const char *, const CODE *);
 void   dodie(int);
 void   doinit(int);
@@ -281,17 +289,25 @@ void      ctlconn_write_handler(void);
 int
 main(int argc, char *argv[])
 {
-       int ch, i, linesize, fd;
+       int ch, error, fd, i, linesize, maxs, nfds;
+       const int on = 1;
+       FILE *fp;
        struct sockaddr_un fromunix;
-       struct sockaddr_in s_in, frominet;
+       struct addrinfo hints, *res, *r;
+       struct sockaddr_storage frominet;
        socklen_t len;
        char *p, *line;
-       char resolve[MAXHOSTNAMELEN];
+       char resolve[NI_MAXHOST];
        int lockpipe[2], nullfd;
-       FILE *fp;
 
-       while ((ch = getopt(argc, argv, "dnuf:m:p:a:s:")) != -1)
+       while ((ch = getopt(argc, argv, "46dnuf:m:p:a:s:")) != -1)
                switch (ch) {
+               case '4':               /* IPv4 only */
+                       af = AF_INET;
+                       break;
+               case '6':               /* IPv6 only */
+                       af = AF_INET6;
+                       break;
                case 'd':               /* debug */
                        Debug++;
                        break;
@@ -359,41 +375,69 @@ main(int argc, char *argv[])
        }
 
        /* Clear poll array, set all fds to ignore */
-       for (i = 0; i < N_PFD; i++) {
+       for (i = 0; i < MAX_AI_PASSIVE; i++) {
                pfd[i].fd = -1;
                pfd[i].events = 0;
        }
 
-       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) != -1) {
-               struct servent *sp;
+       /* setup listening sockets */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_PASSIVE;
+       hints.ai_family = af;
+       hints.ai_socktype = SOCK_DGRAM;
+       error = getaddrinfo(NULL, "syslog", &hints, &res);
+       if (error) {
+               logerror(gai_strerror(error));
+               errno = 0;
+               die(0);
+       }
 
-               /* XXX use getaddrinfo */
-               sp = getservbyname("syslog", "udp");
-               if (sp == NULL) {
-                       errno = 0;
-                       logerror("syslog/udp: unknown service");
-                       die(0);
+       /* Count max number of sockets we may open */
+       for (maxs = 0, r = res; r; r = r->ai_next, maxs++) {
+               if (maxs >= MAX_AI_PASSIVE) {
+                       dprintf("Too may listening sockets returned!\
+                           Using maximum of (%d) sockets\n", MAX_AI_PASSIVE);
                }
-               memset(&s_in, 0, sizeof(s_in));
-               s_in.sin_len = sizeof(s_in);
-               s_in.sin_family = AF_INET;
-               s_in.sin_port = LogPort = sp->s_port;
-               if (bind(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) {
-                       logerror("bind");
-                       if (!Debug)
-                               die(0);
+       }
+       
+       start_inetfds = PFD_UNIX_0 + nfunix;
+       i = 0;
+       for (r = res; r && i < MAX_AI_PASSIVE; r = r->ai_next, i++) {
+               fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+               if (fd < 0) {
+                       logerror("socket() failed");
+                       continue;
+               }
+               if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,  &on,
+                   sizeof(on)) < 0) {
+                       logerror("setsockopt(REUSEADDR) failed");
+                       close(fd);
+                       continue;
+               }
+               if (bind(fd, r->ai_addr, r->ai_addrlen) < 0) {
+                       logerror("bind() failed");
+                       close(fd);
+                       continue;
                } else {
-                       InetInuse = 1;
-                       pfd[PFD_INET].fd = fd;
+                       pfd[start_inetfds + i].fd = fd;
+                       nfinet++;
                        if (SecureMode) {
-                               shutdown(fd, SHUT_RD);
+                               if (shutdown(fd, SHUT_RD) == -1) {
+                                       logerror("shutdown() failed");
+                                       die(0);
+                               }
                        } else {
                                double_rbuf(fd);
-                               pfd[PFD_INET].events = POLLIN;
+                               pfd[start_inetfds + i].events = POLLIN;
+                               pollfd_ai_fam[i] = r->ai_family;
                        }
                }
+               InetInuse = 1;
        }
 
+       if (res)
+               freeaddrinfo(res);
+
 #ifndef SUN_LEN
 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
 #endif
@@ -513,7 +557,8 @@ main(int argc, char *argv[])
                        DoInit = 0;
                }
 
-               switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) {
+               nfds = PFD_UNIX_0 + nfunix + nfinet;
+               switch (poll(pfd, nfds, -1)) {
                case 0:
                        continue;
                case -1:
@@ -533,19 +578,6 @@ main(int argc, char *argv[])
                                pfd[PFD_KLOG].events = 0;
                        }
                }
-               if ((pfd[PFD_INET].revents & POLLIN) != 0) {
-                       len = sizeof(frominet);
-                       i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0,
-                           (struct sockaddr *)&frominet, &len);
-                       if (i > 0) {
-                               line[i] = '\0';
-                               cvthname(&frominet, resolve,
-                                   sizeof resolve);
-                               dprintf("cvthname res: %s\n", resolve);
-                               printline(resolve, line);
-                       } else if (i < 0 && errno != EINTR)
-                               logerror("recvfrom inet");
-               }
                if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0)
                        ctlsock_accept_handler();
                if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0)
@@ -568,6 +600,23 @@ main(int argc, char *argv[])
                                        logerror("recvfrom unix");
                        }
                }
+
+               for (i = 0; SecureMode && i < nfinet; i++) {
+                       if ((pfd[start_inetfds + i].revents & POLLIN) != 0) {
+                               len = sizeof(frominet);
+                               i = recvfrom(pfd[start_inetfds + i].fd, line,
+                                   MAXLINE, 0, (struct sockaddr *)&frominet,
+                                   &len);
+                               if (i > 0) {
+                                       line[i] = '\0';
+                                       cvthname((struct sockaddr *)&frominet,
+                                           resolve, sizeof(resolve));
+                                       dprintf("cvthname res: %s\n", resolve);
+                                       printline(resolve, line);
+                               } else if (i < 0 && errno != EINTR)
+                                       logerror("recvfrom inet");
+                       }
+               }
        }
        /* NOTREACHED */
        free(pfd);
@@ -579,8 +628,9 @@ usage(void)
 {
 
        (void)fprintf(stderr,
-           "usage: syslogd [-dnu] [-a path] [-f config_file] [-m 
mark_interval]\n"
-           "               [-p log_socket] [-s reporting_socket]\n");
+           "usage: syslogd [-dnu46] [-a path] [-f config_file]\n"
+           "               [-m mark_interval] [-p log_socket]\n"
+           "               [-s reporting_socket]\n");
        exit(1);
 }
 
@@ -799,8 +849,9 @@ fprintlog(struct filed *f, int flags, ch
 {
        struct iovec iov[6];
        struct iovec *v;
-       int l, retryonce;
+       int i, j, l, len, n, ok, retryonce;
        char line[MAXLINE + 1], repbuf[80], greetings[500];
+       struct sockaddr_storage *addr;
 
        v = iov;
        if (f->f_type == F_WALL) {
@@ -855,26 +906,50 @@ fprintlog(struct filed *f, int flags, ch
                break;
 
        case F_FORW:
-               dprintf(" %s\n", f->f_un.f_forw.f_hname);
+               dprintf(" %s:%s\n", f->f_un.f_forw.f_host,
+                   f->f_un.f_forw.f_serv);
                if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s",
                    f->f_prevpri, (char *)iov[0].iov_base,
                    (char *)iov[4].iov_base)) >= sizeof(line) || l == -1)
                        l = strlen(line);
-               if (sendto(pfd[PFD_INET].fd, line, l, 0,
-                   (struct sockaddr *)&f->f_un.f_forw.f_addr,
-                   f->f_un.f_forw.f_addr.ss_len) != l) {
-                       switch (errno) {
-                       case EHOSTDOWN:
-                       case EHOSTUNREACH:
-                       case ENETDOWN:
-                       case ENOBUFS:
-                               /* silently dropped */
-                               break;
-                       default:
-                               f->f_type = F_UNUSED;
-                               logerror("sendto");
-                               break;
+               ok = 0;
+               for (i = 0; i < f->f_un.f_forw.f_num_addrs; i++) {
+                       /*
+                        * Try all addresses, starting with the
+                        * last known good one.
+                        */
+                       n = (f->f_un.f_forw.f_good_addr + i) %
+                           f->f_un.f_forw.f_num_addrs;
+                       addr = &(f->f_un.f_forw.f_addrs[n]);
+
+                       for (j = 0; j < nfinet; j++) {
+                               if (addr->ss_family != pollfd_ai_fam[j])
+                                       continue;
+                               len = f->f_un.f_forw.f_addrs[n].ss_len;
+                               if (sendto(pfd[start_inetfds + j].fd, line, l,
+                                   0, (struct sockaddr *)addr, len) == l) {
+                                       f->f_un.f_forw.f_good_addr += i;
+                                       ok = 1;
+                                       break;
+                               } else {
+                                       switch (errno) {
+                                       case EHOSTDOWN:
+                                       case EHOSTUNREACH:
+                                       case ENETDOWN:
+                                       case ENOBUFS:
+                                               /* silently dropped */
+                                               continue;
+                                       default:
+                                               f->f_type = F_UNUSED;
+                                               f->f_un.f_forw.f_num_addrs = 0;
+                                               free(f->f_un.f_forw.f_addrs);
+                                               f->f_un.f_forw.f_addrs = NULL;
+                                               logerror("sendto() failed");
+                                       }
+                               }
                        }
+                       if (ok)
+                               break;
                }
                break;
 
@@ -939,7 +1014,7 @@ fprintlog(struct filed *f, int flags, ch
        case F_MEMBUF:
                dprintf("\n");
                snprintf(line, sizeof(line), "%.15s %s %s",
-                   (char *)iov[0].iov_base, (char *)iov[2].iov_base, 
+                   (char *)iov[0].iov_base, (char *)iov[2].iov_base,
                    (char *)iov[4].iov_base);
                if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
                        f->f_un.f_mb.f_overflow = 1;
@@ -1019,19 +1094,27 @@ reapchild(int signo)
  * Return a printable representation of a host address.
  */
 void
-cvthname(struct sockaddr_in *f, char *result, size_t res_len)
+cvthname(struct sockaddr *f, char *result, size_t res_len)
 {
        sigset_t omask, nmask;
-       char *p, *ip;
        int ret_len;
+       char *p;
+       int error;
+       char ip[NI_MAXHOST];
 
-       if (f->sin_family != AF_INET) {
-               dprintf("Malformed from address\n");
+       if (f->sa_family != AF_INET && f->sa_family != AF_INET6) {
+               dprintf("Unsupport from address family\n");
+               strlcpy(result, "???", res_len);
+               return;
+       }
+
+       if ((error = getnameinfo(f, f->sa_len, ip, sizeof(ip), NULL, 0,
+           NI_NUMERICHOST|NI_DGRAM)) != 0) {
+               dprintf("Malformed from address: %s\n", gai_strerror(error));
                strlcpy(result, "???", res_len);
                return;
        }
 
-       ip = inet_ntoa(f->sin_addr);
        dprintf("cvthname(%s)\n", ip);
        if (NoDNS) {
                strlcpy(result, ip, res_len);
@@ -1042,8 +1125,7 @@ cvthname(struct sockaddr_in *f, char *re
        sigaddset(&nmask, SIGHUP);
        sigprocmask(SIG_BLOCK, &nmask, &omask);
 
-       ret_len = priv_gethostbyaddr((char *)&f->sin_addr,
-               sizeof(struct in_addr), f->sin_family, result, res_len);
+       ret_len = priv_getnameinfo(f, result, res_len);
 
        sigprocmask(SIG_SETMASK, &omask, NULL);
        if (ret_len == 0) {
@@ -1154,6 +1236,9 @@ init(void)
                        (void)close(f->f_file);
                        break;
                case F_FORW:
+                       f->f_un.f_forw.f_num_addrs = 0;
+                       free(f->f_un.f_forw.f_addrs);
+                       f->f_un.f_forw.f_addrs = NULL;
                        break;
                case F_MEMBUF:
                        ringbuf_free(f->f_un.f_mb.f_rb);
@@ -1242,7 +1327,8 @@ init(void)
                                break;
 
                        case F_FORW:
-                               printf("%s", f->f_un.f_forw.f_hname);
+                               printf("%s:%s", f->f_un.f_forw.f_host,
+                                   f->f_un.f_forw.f_serv);
                                break;
 
                        case F_USERS:
@@ -1305,7 +1391,7 @@ find_dup(struct filed *f)
 struct filed *
 cfline(char *line, char *prog)
 {
-       int i, pri, addr_len;
+       int i, pri;
        size_t rb_len;
        char *bp, *p, *q, *cp;
        char buf[MAXLINE], ebuf[100];
@@ -1399,32 +1485,77 @@ cfline(char *line, char *prog)
        }
 
        /* skip to action part */
-       while (*p == '\t')
+       while (*p == '\t' || *p == ' ')
                p++;
 
        switch (*p) {
        case '@':
-               if (!InetInuse)
-                       break;
-               if ((cp = strrchr(++p, ':')) != NULL)
+               if (!InetInuse) {
+                       free(f);
+                       return (NULL);
+               }
+               p++;
+               if (*p == '[') {
+                       p++;
+                       if ((cp = strchr(p, ']')) == NULL) {
+ bad_forward_addr:
+                               snprintf(ebuf, sizeof(ebuf), "invalid "
+                                   "host/port specification \"%s\"", p);
+                               logerror(ebuf);
+                               free(f);
+                               return (NULL);
+                       }
                        *cp++ = '\0';
-               if ((strlcpy(f->f_un.f_forw.f_hname, p,
-                   sizeof(f->f_un.f_forw.f_hname)) >=
-                   sizeof(f->f_un.f_forw.f_hname))) {
-                       snprintf(ebuf, sizeof(ebuf), "hostname too long \"%s\"",
-                           p);
+                       if (*cp == ':')
+                               cp++;
+                       else if (*cp == '\0')
+                               cp = NULL;
+                       else
+                               goto bad_forward_addr;
+               } else {
+                       /* Don't allow IPv6 host:port without square braces */
+                       if ((cp = strchr(p, ':')) != strrchr(p, ':'))
+                               goto bad_forward_addr;
+                       if (cp != NULL)
+                                *cp++ = '\0';
+               }
+               /* Now 'p' points to hostname and 'cp' points to port or NULL */
+               if (cp == NULL)
+                       cp = "syslog";
+
+               if (strlcpy(f->f_un.f_forw.f_host, p,
+                   sizeof(f->f_un.f_forw.f_host)) >=
+                   sizeof(f->f_un.f_forw.f_host)) {
+                       snprintf(ebuf, sizeof(ebuf), "hostname name too "
+                           "long \"%s\"", p);
+                       logerror(ebuf);
+                       break;
+               }
+               if (strlcpy(f->f_un.f_forw.f_serv, cp,
+                   sizeof(f->f_un.f_forw.f_serv)) >=
+                   sizeof(f->f_un.f_forw.f_serv)) {
+                       snprintf(ebuf, sizeof(ebuf), "service name too "
+                           "long \"%s\"", p);
                        logerror(ebuf);
                        break;
                }
-               addr_len = priv_gethostserv(f->f_un.f_forw.f_hname, 
-                   cp == NULL ? "syslog" : cp, 
-                   (struct sockaddr*)&f->f_un.f_forw.f_addr, 
-                   sizeof(f->f_un.f_forw.f_addr));
-               if (addr_len < 1) {
-                       snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"", p);
+
+               f->f_un.f_forw.f_num_addrs = priv_getaddrinfo(
+                   f->f_un.f_forw.f_host, f->f_un.f_forw.f_serv,
+                   (struct sockaddr **)&f->f_un.f_forw.f_addrs);
+               f->f_un.f_forw.f_good_addr = 0;
+
+               if (f->f_un.f_forw.f_num_addrs <= 0) {
+                       f->f_type = F_UNUSED;
+                       f->f_un.f_forw.f_num_addrs = 0;
+                       f->f_un.f_forw.f_addrs = NULL;
+                       snprintf(ebuf, sizeof(ebuf), "bad host/service "
+                           "name \"%s:%s\"", f->f_un.f_forw.f_host,
+                           f->f_un.f_forw.f_serv);
                        logerror(ebuf);
                        break;
                }
+
                f->f_type = F_FORW;
                break;
 
Index: syslogd.h
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.h,v
retrieving revision 1.5
diff -u -p -r1.5 syslogd.h
--- syslogd.h   6 Jun 2005 23:22:04 -0000       1.5
+++ syslogd.h   6 Aug 2005 19:02:58 -0000
@@ -25,8 +25,8 @@ FILE *priv_open_utmp(void);
 FILE *priv_open_config(void);
 void  priv_config_parse_done(void);
 int   priv_config_modified(void);
-int   priv_gethostserv(char *, char *, struct sockaddr *, size_t);
-int   priv_gethostbyaddr(char *, int, int, char *, size_t);
+int   priv_getaddrinfo(char *, char *, struct sockaddr **);
+int   priv_getnameinfo(struct sockaddr *, char *, size_t);
 
 /* Terminal message */
 char *ttymsg(struct iovec *, int, char *, int);
@@ -37,7 +37,14 @@ int  receive_fd(int);
 
 /* The list of domain sockets */
 #define MAXFUNIX       21
+/* Maximum # of udp listening sockets */
+#define MAX_AI_PASSIVE 8
+/* Maximum # of addresses for loghost */
+#define MAX_GETADDR    128
+
 extern int nfunix;
+extern int nfinet;
+extern int start_inetfds;
 extern char *funixn[MAXFUNIX];
 extern char *ctlsock_path;
 
@@ -45,13 +52,16 @@ extern char *ctlsock_path;
 extern int Debug;
 extern int Startup;
 
+/* inet-socket address family */
+extern int af;
+
 /* fds to poll */
 #define PFD_KLOG       0               /* Offset of /dev/klog entry */
-#define PFD_INET       1               /* Offset of inet socket entry */
-#define PFD_CTLSOCK    2               /* Offset of control socket entry */
-#define PFD_CTLCONN    3               /* Offset of control connection entry */
-#define PFD_UNIX_0     4               /* Start of Unix socket entries */
-#define N_PFD          (PFD_UNIX_0 + MAXFUNIX) /* # of pollfd entries */
+#define PFD_CTLSOCK    1               /* Offset of control socket entry */
+#define PFD_CTLCONN    2               /* Offset of control connection entry */
+#define PFD_UNIX_0     3               /* Start of Unix socket entries */
+#define N_PFD          (PFD_UNIX_0 + MAXFUNIX + MAX_AI_PASSIVE) /* # of pollfd
+                                                                   entries */
 extern struct pollfd pfd[N_PFD];
 
 struct ringbuf {

----- End forwarded message -----

Reply via email to