On Fri, Aug 22, 2014 at 06:43:47PM +0200, Alexander Bluhm wrote:
> At the moment syslogd opens both IPv4 and IPv6 sockets unconditionally.
> I can restrict it to a protocol family with -4 and -6 command line
> switches.  If the log server is a FQDN, DNS chosses wether to take
> the IPv4 or IPv6 route.  For that I have invented a udp4:// or
> udp6:// prefix to choose a protocol.  This syntax was chosen as I
> want to extend it to tcp:// and tls:// later.

Before -46 and -64 disabled both protocols.  halex@ suggested to
use the latter one like other programs do.

updated diff changed in the getopt switch, ok?

bluhm

Index: usr.sbin/syslogd/privsep.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/privsep.c,v
retrieving revision 1.40
diff -u -p -r1.40 privsep.c
--- usr.sbin/syslogd/privsep.c  21 Aug 2014 17:00:34 -0000      1.40
+++ usr.sbin/syslogd/privsep.c  23 Aug 2014 11:01:38 -0000
@@ -101,8 +101,8 @@ int
 priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[])
 {
        int i, fd, socks[2], cmd, addr_len, result, restart;
-       size_t path_len, hostname_len, servname_len;
-       char path[MAXPATHLEN], hostname[MAXHOSTNAMELEN];
+       size_t path_len, protoname_len, hostname_len, servname_len;
+       char path[MAXPATHLEN], protoname[5], hostname[MAXHOSTNAMELEN];
        char servname[NI_MAXSERV];
        struct sockaddr_storage addr;
        struct stat cf_stat;
@@ -293,7 +293,14 @@ priv_init(char *conf, int numeric, int l
 
                case PRIV_GETADDRINFO:
                        dprintf("[priv]: msg PRIV_GETADDRINFO received\n");
-                       /* Expecting: len, hostname, len, servname */
+                       /* Expecting: len, proto, len, host, len, serv */
+                       must_read(socks[0], &protoname_len, sizeof(size_t));
+                       if (protoname_len == 0 ||
+                           protoname_len > sizeof(protoname))
+                               _exit(1);
+                       must_read(socks[0], &protoname, protoname_len);
+                       protoname[protoname_len - 1] = '\0';
+
                        must_read(socks[0], &hostname_len, sizeof(size_t));
                        if (hostname_len == 0 ||
                            hostname_len > sizeof(hostname))
@@ -309,8 +316,17 @@ priv_init(char *conf, int numeric, int l
                        servname[servname_len - 1] = '\0';
 
                        memset(&hints, 0, sizeof(hints));
-                       hints.ai_family = AF_UNSPEC;
+                       if (strcmp(protoname, "udp") == 0) {
+                               hints.ai_family = AF_UNSPEC;
+                       } else if (strcmp(protoname, "udp4") == 0) {
+                               hints.ai_family = AF_INET;
+                       } else if (strcmp(protoname, "udp6") == 0) {
+                               hints.ai_family = AF_INET6;
+                       } else {
+                               errx(1, "unknown protocol %s", protoname);
+                       }
                        hints.ai_socktype = SOCK_DGRAM;
+                       hints.ai_protocol = IPPROTO_UDP;
                        i = getaddrinfo(hostname, servname, &hints, &res0);
                        if (i != 0 || res0 == NULL) {
                                addr_len = 0;
@@ -661,25 +677,30 @@ 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 *host, char *serv, struct sockaddr *addr,
+priv_getaddrinfo(char *proto, char *host, char *serv, struct sockaddr *addr,
     size_t addr_len)
 {
-       char hostcpy[MAXHOSTNAMELEN], servcpy[NI_MAXSERV];
+       char protocpy[5], hostcpy[MAXHOSTNAMELEN], servcpy[NI_MAXSERV];
        int cmd, ret_len;
-       size_t hostname_len, servname_len;
+       size_t protoname_len, hostname_len, servname_len;
 
        if (priv_fd < 0)
                errx(1, "%s: called from privileged portion", __func__);
 
-       if (strlcpy(hostcpy, host, sizeof hostcpy) >= sizeof(hostcpy))
+       if (strlcpy(protocpy, proto, sizeof(protocpy)) >= sizeof(protocpy))
+               errx(1, "%s: overflow attempt in protoname", __func__);
+       protoname_len = strlen(protocpy) + 1;
+       if (strlcpy(hostcpy, host, sizeof(hostcpy)) >= sizeof(hostcpy))
                errx(1, "%s: overflow attempt in hostname", __func__);
        hostname_len = strlen(hostcpy) + 1;
-       if (strlcpy(servcpy, serv, sizeof servcpy) >= sizeof(servcpy))
+       if (strlcpy(servcpy, serv, sizeof(servcpy)) >= sizeof(servcpy))
                errx(1, "%s: overflow attempt in servname", __func__);
        servname_len = strlen(servcpy) + 1;
 
        cmd = PRIV_GETADDRINFO;
        must_write(priv_fd, &cmd, sizeof(int));
+       must_write(priv_fd, &protoname_len, sizeof(size_t));
+       must_write(priv_fd, protocpy, protoname_len);
        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));
Index: usr.sbin/syslogd/syslogd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.117
diff -u -p -r1.117 syslogd.c
--- usr.sbin/syslogd/syslogd.c  22 Aug 2014 16:14:11 -0000      1.117
+++ usr.sbin/syslogd/syslogd.c  23 Aug 2014 11:04:06 -0000
@@ -127,8 +127,8 @@ struct filed {
        union {
                char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
                struct {
-                       char    f_loghost[1+1+MAXHOSTNAMELEN+1+NI_MAXSERV];
-                               /* @[hostname]:servname\0 */
+                       char    f_loghost[1+4+3+1+MAXHOSTNAMELEN+1+NI_MAXSERV];
+                               /* @proto46://[hostname]:servname\0 */
                        struct sockaddr_storage f_addr;
                } f_forw;               /* forwarding address */
                char    f_fname[MAXPATHLEN];
@@ -195,6 +195,8 @@ int MarkInterval = 20 * 60; /* interval 
 int    MarkSeq = 0;            /* mark sequence number */
 int    SecureMode = 1;         /* when true, speak only unix domain socks */
 int    NoDNS = 0;              /* when true, will refrain from doing DNS 
lookups */
+int    IPv4Only = 0;           /* when true, disable IPv6 */
+int    IPv6Only = 0;           /* when true, disable IPv4 */
 int    IncludeHostname = 0;    /* include RFC 3164 style hostnames when 
forwarding */
 
 char   *ctlsock_path = NULL;   /* Path to control socket */
@@ -268,7 +270,7 @@ void        reapchild(int);
 char   *ttymsg(struct iovec *, int, char *, int);
 void   usage(void);
 void   wallmsg(struct filed *, struct iovec *);
-int    loghost(char *, char **, char **);
+int    loghost(char *, char **, char **, char **);
 int    getmsgbufsize(void);
 int    unix_socket(char *, int, mode_t);
 void   double_rbuf(int);
@@ -291,8 +293,16 @@ main(int argc, char *argv[])
        struct addrinfo hints, *res, *res0;
        FILE *fp;
 
-       while ((ch = getopt(argc, argv, "dhnuf:m:p:a:s:")) != -1)
+       while ((ch = getopt(argc, argv, "46dhnuf:m:p:a:s:")) != -1)
                switch (ch) {
+               case '4':               /* disable IPv6 */
+                       IPv4Only = 1;
+                       IPv6Only = 0;
+                       break;
+               case '6':               /* disable IPv4 */
+                       IPv6Only = 1;
+                       IPv4Only = 0;
+                       break;
                case 'd':               /* debug */
                        Debug++;
                        break;
@@ -387,9 +397,13 @@ main(int argc, char *argv[])
 
                switch (res->ai_family) {
                case AF_INET:
+                       if (IPv6Only)
+                               continue;
                        pfdp = &pfd[PFD_INET];
                        break;
                case AF_INET6:
+                       if (IPv4Only)
+                               continue;
                        pfdp = &pfd[PFD_INET6];
                        break;
                default:
@@ -641,7 +655,7 @@ usage(void)
 {
 
        (void)fprintf(stderr,
-           "usage: syslogd [-dhnu] [-a path] [-f config_file] [-m 
mark_interval]\n"
+           "usage: syslogd [-46dhnu] [-a path] [-f config_file] [-m 
mark_interval]\n"
            "               [-p log_socket] [-s reporting_socket]\n");
        exit(1);
 }
@@ -1436,7 +1450,7 @@ cfline(char *line, char *prog)
 {
        int i, pri;
        size_t rb_len;
-       char *bp, *p, *q, *host, *port;
+       char *bp, *p, *q, *proto, *host, *port;
        char buf[MAXLINE], ebuf[100];
        struct filed *xf, *f, *d;
 
@@ -1541,12 +1555,39 @@ cfline(char *line, char *prog)
                        logerror(ebuf);
                        break;
                }
-               if (loghost(++p, &host, &port) == -1) {
+               if (loghost(++p, &proto, &host, &port) == -1) {
                        snprintf(ebuf, sizeof(ebuf), "bad loghost \"%s\"",
                            f->f_un.f_forw.f_loghost);
                        logerror(ebuf);
                        break;
                }
+               if (proto == NULL)
+                       proto = "udp";
+               if (strcmp(proto, "udp") == 0) {
+                       if (pfd[PFD_INET].fd == -1)
+                               proto = "udp6";
+                       if (pfd[PFD_INET6].fd == -1)
+                               proto = "udp4";
+               } else if (strcmp(proto, "udp4") == 0) {
+                       if (pfd[PFD_INET].fd == -1) {
+                               snprintf(ebuf, sizeof(ebuf), "no udp4 \"%s\"",
+                                   f->f_un.f_forw.f_loghost);
+                               logerror(ebuf);
+                               break;
+                       }
+               } else if (strcmp(proto, "udp6") == 0) {
+                       if (pfd[PFD_INET6].fd == -1) {
+                               snprintf(ebuf, sizeof(ebuf), "no udp6 \"%s\"",
+                                   f->f_un.f_forw.f_loghost);
+                               logerror(ebuf);
+                               break;
+                       }
+               } else {
+                       snprintf(ebuf, sizeof(ebuf), "bad protocol \"%s\"",
+                           f->f_un.f_forw.f_loghost);
+                       logerror(ebuf);
+                       break;
+               }
                if (strlen(host) >= MAXHOSTNAMELEN) {
                        snprintf(ebuf, sizeof(ebuf), "host too long \"%s\"",
                            f->f_un.f_forw.f_loghost);
@@ -1561,7 +1602,7 @@ cfline(char *line, char *prog)
                        logerror(ebuf);
                        break;
                }
-               if (priv_getaddrinfo(host, port,
+               if (priv_getaddrinfo(proto, host, port,
                    (struct sockaddr*)&f->f_un.f_forw.f_addr,
                    sizeof(f->f_un.f_forw.f_addr)) != 0) {
                        snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"",
@@ -1678,8 +1719,15 @@ cfline(char *line, char *prog)
  * Parse the host and port parts from a loghost string.
  */
 int
-loghost(char *str, char **host, char **port)
+loghost(char *str, char **proto, char **host, char **port)
 {
+       *proto = NULL;
+       if ((*host = strchr(str, ':')) &&
+           (*host)[1] == '/' && (*host)[2] == '/') {
+               *proto = str;
+               **host = '\0';
+               str = *host + 3;
+       }
        *host = str;
        if (**host == '[') {
                (*host)++;
Index: usr.sbin/syslogd/syslogd.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.h,v
retrieving revision 1.11
diff -u -p -r1.11 syslogd.h
--- usr.sbin/syslogd/syslogd.h  20 Aug 2014 20:10:17 -0000      1.11
+++ usr.sbin/syslogd/syslogd.h  23 Aug 2014 11:01:38 -0000
@@ -28,7 +28,7 @@ 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 *, struct sockaddr *, size_t);
+int   priv_getaddrinfo(char *, char *, char *, struct sockaddr *, size_t);
 int   priv_getnameinfo(struct sockaddr *, socklen_t, char *, size_t);
 
 /* Terminal message */

Reply via email to