On Sat, Aug 23, 2014 at 01:10:52PM +0200, Alexander Bluhm wrote:
> 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?
I still need an ok for this. The -4 switch has been made especially
for our ipv6 haters^W^Wipv4 lovers. I can live without it.
When implementing tcp, I will need the tcp:// logic anyway.
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 */