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 */