On Fri, Jan 16, 2015 at 09:11:47AM +0000, Nicholas Marriott wrote:
> Hi
> 
> WRT libevent - we have already added some ASR functions to libevent for
> smtpd, I'd say libevent 1.4 is pretty much closed for new development
> upstream - there won't be much to sync - and we have a port of 2.x for
> ports to use. So I don't think there are strong reasons not to change
> our libevent as we like
> 

I didn't say that we cannot change libevent - this was different when
I first started using the evbuffer API for SSL in relayd.

I just don't think that adding a specific dependency for
libtls/libssl/libcrypto to libevent is the right direction.  We could
change the evbuffer API _in libevent_ to make it easier using it with
TCP, libssl, libssl or anything else instead of just TCP.  But without
adding any TLS code to libevent.

Reyk

> 
> On Fri, Jan 16, 2015 at 10:00:46AM +0100, Reyk Floeter wrote:
> > On Fri, Jan 16, 2015 at 01:46:09AM +0100, Alexander Bluhm wrote:
> > > Hi,
> > > 
> > > This diff enables sending syslog messages over TLS.
> > > 
> > > To implement the buffer layer, I have copied evbuffer.c from libevent
> > > and changed TCP to TLS where necessary.  This way I made a buffertls
> > > wrapper around bufferevent.  This might be integrated into libevent
> > > later.
> > > 
> > > It still has some limitations:
> > > - No certificate validation.  This will get a bit tricky because
> > >   of privsep.
> > 
> > Not that tricky - it has already been done and I intended to port it
> > to libtls/libssl.  Let me see if I can create a diff quickly.
> > 
> > > - Wrong format.  The TLS RFC requires length-message encoding, I
> > >   use message-newline inherited from TCP.
> > > - Not all lost messages are logged.
> > > - At SIGHUP messages may get lost.
> > > - Man page is missing.  You can active it with @tls://ip-address.
> > > 
> > > comment, test, ok?
> > > 
> > > bluhm
> > > 
> > 
> > The implementation looks somewhat similar to the code in httpd/relayd
> > that didn't copy the evbuffer code.  But instead of calling
> > tls_read/tls_write directly, you implemented evtls_read/evtls_write.
> > I wonder if this solves/improves anything in the daemon but I haven't
> > seen any related issue.
> > 
> > I'm fine with adding it to syslogd locally and the diff looks sane.
> > 
> > But I'm not convinced that libevent is the right place to add a
> > dependency on libtls.  I never pushed the SSL evbuffer wrappers back
> > into libevent to keep portability and to avoid such a dependency; but
> > I also saw that the implementation outside of libevent is a bit
> > hackish because the evbuffers were never intended for anything except
> > TCP.
> > 
> > relayd could also benefit from it, but I want to continue to use bare
> > libssl instead of libtls there.
> > 
> > So it would be desirable to change the libevent code in a way that
> > that allows a more flexible approach - instead of duplicating
> > everything all over again, libevent should allow to provide custom
> > read/write callbacks in a smarter way.
> > 
> > For example, there is be no reason to have bufferevent_add() static
> > and to duplicate the function everywhere (server_bufferevent_add()).
> > evbuffer_read/write() could use an optional callback instead of
> > read/write directly to allow plugging in tls_read/SSL_read etc.
> > Problematic is the handling of things like TLS_READ_AGAIN instead of
> > EAGAIN, but there should be a way to abstract it further.
> > 
> > Reyk
> > 
> > > Index: usr.sbin/syslogd/Makefile
> > > ===================================================================
> > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/Makefile,v
> > > retrieving revision 1.6
> > > diff -u -p -r1.6 Makefile
> > > --- usr.sbin/syslogd/Makefile     5 Oct 2014 18:14:01 -0000       1.6
> > > +++ usr.sbin/syslogd/Makefile     15 Jan 2015 13:26:09 -0000
> > > @@ -1,9 +1,9 @@
> > >  #        $OpenBSD: Makefile,v 1.6 2014/10/05 18:14:01 bluhm Exp $
> > >  
> > >  PROG=    syslogd
> > > -SRCS=    syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c
> > > +SRCS=    syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c 
> > > evbuffer_tls.c
> > >  MAN=     syslogd.8 syslog.conf.5
> > > -LDADD=   -levent
> > > -DPADD=   ${LIBEVENT}
> > > +LDADD=   -levent -ltls -lssl -lcrypto
> > > +DPADD=   ${LIBEVENT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
> > >  
> > >  .include <bsd.prog.mk>
> > > Index: usr.sbin/syslogd/evbuffer_tls.c
> > > ===================================================================
> > > RCS file: usr.sbin/syslogd/evbuffer_tls.c
> > > diff -N usr.sbin/syslogd/evbuffer_tls.c
> > > --- /dev/null     1 Jan 1970 00:00:00 -0000
> > > +++ usr.sbin/syslogd/evbuffer_tls.c       15 Jan 2015 15:18:01 -0000
> > > @@ -0,0 +1,357 @@
> > > +/*       $OpenBSD$ */
> > > +
> > > +/*
> > > + * Copyright (c) 2002-2004 Niels Provos <pro...@citi.umich.edu>
> > > + * Copyright (c) 2014-2015 Alexander Bluhm <bl...@openbsd.org>
> > > + * All rights reserved.
> > > + *
> > > + * Redistribution and use in source and binary forms, with or without
> > > + * modification, are permitted provided that the following conditions
> > > + * are met:
> > > + * 1. Redistributions of source code must retain the above copyright
> > > + *    notice, this list of conditions and the following disclaimer.
> > > + * 2. Redistributions in binary form must reproduce the above copyright
> > > + *    notice, this list of conditions and the following disclaimer in the
> > > + *    documentation and/or other materials provided with the 
> > > distribution.
> > > + * 3. The name of the author may not be used to endorse or promote 
> > > products
> > > + *    derived from this software without specific prior written 
> > > permission.
> > > + *
> > > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
> > > + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
> > > WARRANTIES
> > > + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
> > > DISCLAIMED.
> > > + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> > > + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
> > > BUT
> > > + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
> > > USE,
> > > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> > > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> > > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
> > > OF
> > > + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> > > + */
> > > +
> > > +#include <sys/types.h>
> > > +#include <sys/time.h>
> > > +#include <sys/ioctl.h>
> > > +
> > > +#include <errno.h>
> > > +#include <event.h>
> > > +#include <stdio.h>
> > > +#include <stdlib.h>
> > > +#include <string.h>
> > > +#include <stdarg.h>
> > > +#include <tls.h>
> > > +
> > > +#include "evbuffer_tls.h"
> > > +
> > > +/* prototypes */
> > > +
> > > +void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, 
> > > void *);
> > > +int evtls_read(struct evbuffer *, int, int, struct tls *);
> > > +int evtls_write(struct evbuffer *, int, struct tls *);
> > > +
> > > +static int
> > > +bufferevent_add(struct event *ev, int timeout)
> > > +{
> > > + struct timeval tv, *ptv = NULL;
> > > +
> > > + if (timeout) {
> > > +         timerclear(&tv);
> > > +         tv.tv_sec = timeout;
> > > +         ptv = &tv;
> > > + }
> > > +
> > > + return (event_add(ev, ptv));
> > > +}
> > > +
> > > +static void
> > > +buffertls_readcb(int fd, short event, void *arg)
> > > +{
> > > + struct buffertls *buftls = arg;
> > > + struct bufferevent *bufev = buftls->bt_bufev;
> > > + struct tls *ctx = buftls->bt_ctx;
> > > + int res = 0;
> > > + short what = EVBUFFER_READ;
> > > + size_t len;
> > > + int howmuch = -1;
> > > +
> > > + if (event == EV_TIMEOUT) {
> > > +         what |= EVBUFFER_TIMEOUT;
> > > +         goto error;
> > > + }
> > > +
> > > + /*
> > > +  * If we have a high watermark configured then we don't want to
> > > +  * read more data than would make us reach the watermark.
> > > +  */
> > > + if (bufev->wm_read.high != 0) {
> > > +         howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
> > > +         /* we might have lowered the watermark, stop reading */
> > > +         if (howmuch <= 0) {
> > > +                 struct evbuffer *buf = bufev->input;
> > > +                 event_del(&bufev->ev_read);
> > > +                 evbuffer_setcb(buf,
> > > +                     bufferevent_read_pressure_cb, bufev);
> > > +                 return;
> > > +         }
> > > + }
> > > +
> > > + res = evtls_read(bufev->input, fd, howmuch, ctx);
> > > + switch (res) {
> > > + case TLS_READ_AGAIN:
> > > +         event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb,
> > > +             buftls);
> > > +         goto reschedule;
> > > + case TLS_WRITE_AGAIN:
> > > +         event_set(&bufev->ev_read, fd, EV_WRITE, buffertls_readcb,
> > > +             buftls);
> > > +         goto reschedule;
> > > + case -1:
> > > +         if (errno == EAGAIN || errno == EINTR)
> > > +                 goto reschedule;
> > > +         /* error case */
> > > +         what |= EVBUFFER_ERROR;
> > > +         break;
> > > + case 0:
> > > +         /* eof case */
> > > +         what |= EVBUFFER_EOF;
> > > +         break;
> > > + }
> > > + if (res <= 0)
> > > +         goto error;
> > > +
> > > + event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
> > > + bufferevent_add(&bufev->ev_read, bufev->timeout_read);
> > > +
> > > + /* See if this callbacks meets the water marks */
> > > + len = EVBUFFER_LENGTH(bufev->input);
> > > + if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
> > > +         return;
> > > + if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
> > > +         struct evbuffer *buf = bufev->input;
> > > +         event_del(&bufev->ev_read);
> > > +
> > > +         /* Now schedule a callback for us when the buffer changes */
> > > +         evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
> > > + }
> > > +
> > > + /* Invoke the user callback - must always be called last */
> > > + if (bufev->readcb != NULL)
> > > +         (*bufev->readcb)(bufev, bufev->cbarg);
> > > + return;
> > > +
> > > + reschedule:
> > > + bufferevent_add(&bufev->ev_read, bufev->timeout_read);
> > > + return;
> > > +
> > > + error:
> > > + (*bufev->errorcb)(bufev, what, bufev->cbarg);
> > > +}
> > > +
> > > +static void
> > > +buffertls_writecb(int fd, short event, void *arg)
> > > +{
> > > + struct buffertls *buftls = arg;
> > > + struct bufferevent *bufev = buftls->bt_bufev;
> > > + struct tls *ctx = buftls->bt_ctx;
> > > + int res = 0;
> > > + short what = EVBUFFER_WRITE;
> > > +
> > > + if (event == EV_TIMEOUT) {
> > > +         what |= EVBUFFER_TIMEOUT;
> > > +         goto error;
> > > + }
> > > +
> > > + if (EVBUFFER_LENGTH(bufev->output) != 0) {
> > > +         res = evtls_write(bufev->output, fd, ctx);
> > > +         switch (res) {
> > > +         case TLS_READ_AGAIN:
> > > +                 event_set(&bufev->ev_write, fd, EV_READ,
> > > +                     buffertls_writecb, buftls);
> > > +                 goto reschedule;
> > > +         case TLS_WRITE_AGAIN:
> > > +                 event_set(&bufev->ev_write, fd, EV_WRITE,
> > > +                     buffertls_writecb, buftls);
> > > +                 goto reschedule;
> > > +         case -1:
> > > +                 if (errno == EAGAIN || errno == EINTR ||
> > > +                     errno == EINPROGRESS)
> > > +                         goto reschedule;
> > > +                 /* error case */
> > > +                 what |= EVBUFFER_ERROR;
> > > +                 break;
> > > +         case 0:
> > > +                 /* eof case */
> > > +                 what |= EVBUFFER_EOF;
> > > +                 break;
> > > +         }
> > > +         if (res <= 0)
> > > +                 goto error;
> > > + }
> > > +
> > > + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> > > + if (EVBUFFER_LENGTH(bufev->output) != 0)
> > > +         bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> > > +
> > > + /*
> > > +  * Invoke the user callback if our buffer is drained or below the
> > > +  * low watermark.
> > > +  */
> > > + if (bufev->writecb != NULL &&
> > > +     EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
> > > +         (*bufev->writecb)(bufev, bufev->cbarg);
> > > +
> > > + return;
> > > +
> > > + reschedule:
> > > + if (EVBUFFER_LENGTH(bufev->output) != 0)
> > > +         bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> > > + return;
> > > +
> > > + error:
> > > + (*bufev->errorcb)(bufev, what, bufev->cbarg);
> > > +}
> > > +
> > > +static void
> > > +buffertls_connectcb(int fd, short event, void *arg)
> > > +{
> > > + struct buffertls *buftls = arg;
> > > + struct bufferevent *bufev = buftls->bt_bufev;
> > > + struct tls *ctx = buftls->bt_ctx;
> > > + const char *hostname = buftls->bt_hostname;
> > > + int res = 0;
> > > + short what = EVBUFFER_CONNECT;
> > > +
> > > + if (event == EV_TIMEOUT) {
> > > +         what |= EVBUFFER_TIMEOUT;
> > > +         goto error;
> > > + }
> > > +
> > > + res = tls_connect_socket(ctx, fd, hostname);
> > > + switch (res) {
> > > + case TLS_READ_AGAIN:
> > > +         event_set(&bufev->ev_write, fd, EV_READ,
> > > +             buffertls_connectcb, buftls);
> > > +         goto reschedule;
> > > + case TLS_WRITE_AGAIN:
> > > +         event_set(&bufev->ev_write, fd, EV_WRITE,
> > > +             buffertls_connectcb, buftls);
> > > +         goto reschedule;
> > > + case -1:
> > > +         if (errno == EAGAIN || errno == EINTR ||
> > > +             errno == EINPROGRESS)
> > > +                 goto reschedule;
> > > +         /* error case */
> > > +         what |= EVBUFFER_ERROR;
> > > +         break;
> > > + }
> > > + if (res < 0)
> > > +         goto error;
> > > +
> > > + /*
> > > +  * There might be data available in the tls layer.  Try
> > > +  * an read operation and setup the callbacks.  Call the read
> > > +  * callback after enabling the write callback to give the
> > > +  * read error handler a chance to disable the write event.
> > > +  */
> > > + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> > > + if (EVBUFFER_LENGTH(bufev->output) != 0)
> > > +         bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> > > + buffertls_readcb(fd, 0, buftls);
> > > +
> > > + return;
> > > +
> > > + reschedule:
> > > + bufferevent_add(&bufev->ev_write, bufev->timeout_write);
> > > + return;
> > > +
> > > + error:
> > > + (*bufev->errorcb)(bufev, what, bufev->cbarg);
> > > +}
> > > +
> > > +void
> > > +buffertls_set(struct buffertls *buftls, struct bufferevent *bufev,
> > > +    struct tls *ctx, int fd)
> > > +{
> > > + bufferevent_setfd(bufev, fd);
> > > + event_set(&bufev->ev_read, fd, EV_READ, buffertls_readcb, buftls);
> > > + event_set(&bufev->ev_write, fd, EV_WRITE, buffertls_writecb, buftls);
> > > + buftls->bt_bufev = bufev;
> > > + buftls->bt_ctx = ctx;
> > > +}
> > > +
> > > +void
> > > +buffertls_connect(struct buffertls *buftls, int fd, const char *hostname)
> > > +{
> > > + struct bufferevent *bufev = buftls->bt_bufev;
> > > +
> > > + event_del(&bufev->ev_read);
> > > + event_del(&bufev->ev_write);
> > > +
> > > + buftls->bt_hostname = hostname;
> > > + buffertls_connectcb(fd, 0, buftls);
> > > +}
> > > +
> > > +/*
> > > + * Reads data from a file descriptor into a buffer.
> > > + */
> > > +
> > > +#define EVBUFFER_MAX_READ        4096
> > > +
> > > +int
> > > +evtls_read(struct evbuffer *buf, int fd, int howmuch, struct tls *ctx)
> > > +{
> > > + u_char *p;
> > > + size_t len, oldoff = buf->off;
> > > + int n = EVBUFFER_MAX_READ;
> > > +
> > > + if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
> > > +         n = EVBUFFER_MAX_READ;
> > > + } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
> > > +         /*
> > > +          * It's possible that a lot of data is available for
> > > +          * reading.  We do not want to exhaust resources
> > > +          * before the reader has a chance to do something
> > > +          * about it.  If the reader does not tell us how much
> > > +          * data we should read, we artifically limit it.
> > > +          */
> > > +         if ((size_t)n > buf->totallen << 2)
> > > +                 n = buf->totallen << 2;
> > > +         if (n < EVBUFFER_MAX_READ)
> > > +                 n = EVBUFFER_MAX_READ;
> > > + }
> > > + if (howmuch < 0 || howmuch > n)
> > > +         howmuch = n;
> > > +
> > > + /* If we don't have FIONREAD, we might waste some space here */
> > > + if (evbuffer_expand(buf, howmuch) == -1)
> > > +         return (-1);
> > > +
> > > + /* We can append new data at this point */
> > > + p = buf->buffer + buf->off;
> > > +
> > > + n = tls_read(ctx, p, howmuch, &len);
> > > + if (n < 0 || len == 0)
> > > +         return (n);
> > > +
> > > + buf->off += len;
> > > +
> > > + /* Tell someone about changes in this buffer */
> > > + if (buf->off != oldoff && buf->cb != NULL)
> > > +         (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
> > > +
> > > + return (len);
> > > +}
> > > +
> > > +int
> > > +evtls_write(struct evbuffer *buffer, int fd, struct tls *ctx)
> > > +{
> > > + size_t len;
> > > + int n;
> > > +
> > > + n = tls_write(ctx, buffer->buffer, buffer->off, &len);
> > > + if (n < 0 || len == 0)
> > > +         return (n);
> > > +
> > > + evbuffer_drain(buffer, len);
> > > +
> > > + return (len);
> > > +}
> > > Index: usr.sbin/syslogd/evbuffer_tls.h
> > > ===================================================================
> > > RCS file: usr.sbin/syslogd/evbuffer_tls.h
> > > diff -N usr.sbin/syslogd/evbuffer_tls.h
> > > --- /dev/null     1 Jan 1970 00:00:00 -0000
> > > +++ usr.sbin/syslogd/evbuffer_tls.h       15 Jan 2015 15:10:02 -0000
> > > @@ -0,0 +1,37 @@
> > > +/*       $OpenBSD$ */
> > > +
> > > +/*
> > > + * Copyright (c) 2014-2015 Alexander Bluhm <bl...@openbsd.org>
> > > + *
> > > + * Permission to use, copy, modify, and distribute this software for any
> > > + * purpose with or without fee is hereby granted, provided that the above
> > > + * copyright notice and this permission notice appear in all copies.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
> > > WARRANTIES
> > > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> > > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 
> > > FOR
> > > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> > > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> > > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
> > > OF
> > > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _EVBUFFER_TLS_H_
> > > +#define _EVBUFFER_TLS_H_
> > > +
> > > +#define EVBUFFER_CONNECT 0x80
> > > +
> > > +struct bufferevent;
> > > +struct tls;
> > > +
> > > +struct buffertls {
> > > + struct bufferevent      *bt_bufev;
> > > + struct tls              *bt_ctx;
> > > + const char              *bt_hostname;
> > > +};
> > > +
> > > +void     buffertls_set(struct buffertls *, struct bufferevent *, struct 
> > > tls *,
> > > +    int);
> > > +void     buffertls_connect(struct buffertls *, int, const char *);
> > > +
> > > +#endif /* _EVBUFFER_TLS_H_ */
> > > Index: usr.sbin/syslogd/syslogd.c
> > > ===================================================================
> > > RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
> > > retrieving revision 1.141
> > > diff -u -p -r1.141 syslogd.c
> > > --- usr.sbin/syslogd/syslogd.c    15 Jan 2015 11:49:59 -0000      1.141
> > > +++ usr.sbin/syslogd/syslogd.c    15 Jan 2015 20:51:27 -0000
> > > @@ -50,7 +50,7 @@
> > >   * extensive changes by Ralph Campbell
> > >   * more extensive changes by Eric Allman (again)
> > >   * memory buffer logging by Damien Miller
> > > - * IPv6, libevent, sending via TCP by Alexander Bluhm
> > > + * IPv6, libevent, sending over TCP and TLS by Alexander Bluhm
> > >   */
> > >  
> > >  #define  MAXLINE         1024            /* maximum line length */
> > > @@ -92,6 +92,7 @@
> > >  #include <stdio.h>
> > >  #include <stdlib.h>
> > >  #include <string.h>
> > > +#include <tls.h>
> > >  #include <unistd.h>
> > >  #include <utmp.h>
> > >  #include <vis.h>
> > > @@ -100,6 +101,7 @@
> > >  #include <sys/syslog.h>
> > >  
> > >  #include "syslogd.h"
> > > +#include "evbuffer_tls.h"
> > >  
> > >  char *ConfFile = _PATH_LOGCONF;
> > >  const char ctty[] = _PATH_CONSOLE;
> > > @@ -133,9 +135,11 @@ struct filed {
> > >           struct {
> > >                   char    f_loghost[1+4+3+1+MAXHOSTNAMELEN+1+NI_MAXSERV];
> > >                           /* @proto46://[hostname]:servname\0 */
> > > -                 struct sockaddr_storage f_addr;
> > > +                 struct sockaddr_storage  f_addr;
> > > +                 struct buffertls         f_buftls;
> > >                   struct bufferevent      *f_bufev;
> > > -                 int     f_reconnectwait;
> > > +                 struct tls              *f_ctx;
> > > +                 int                      f_reconnectwait;
> > >           } f_forw;               /* forwarding address */
> > >           char    f_fname[MAXPATHLEN];
> > >           struct {
> > > @@ -180,11 +184,12 @@ int repeatinterval[] = { 30, 120, 600 };
> > >  #define F_MEMBUF 7               /* memory buffer */
> > >  #define F_PIPE           8               /* pipe to external program */
> > >  #define F_FORWTCP        9               /* remote machine via TCP */
> > > +#define F_FORWTLS        10              /* remote machine via TLS */
> > >  
> > >  char     *TypeNames[] = {
> > >   "UNUSED",       "FILE",         "TTY",          "CONSOLE",
> > >   "FORWUDP",      "USERS",        "WALL",         "MEMBUF",
> > > - "PIPE",         "FORWTCP",
> > > + "PIPE",         "FORWTCP",      "FORWTLS",
> > >  };
> > >  
> > >  SIMPLEQ_HEAD(filed_list, filed) Files;
> > > @@ -269,6 +274,7 @@ void   tcp_readcb(struct bufferevent *, v
> > >  void      tcp_writecb(struct bufferevent *, void *);
> > >  void      tcp_errorcb(struct bufferevent *, short, void *);
> > >  void      tcp_connectcb(int, short, void *);
> > > +struct tls *tls_socket(struct filed *);
> > >  void      die_signalcb(int, short, void *);
> > >  void      mark_timercb(int, short, void *);
> > >  void      init_signalcb(int, short, void *);
> > > @@ -713,8 +719,7 @@ tcp_readcb(struct bufferevent *bufev, vo
> > >    * Drop data received from the forward log server.
> > >    */
> > >   dprintf("loghost \"%s\" did send %zu bytes back\n",
> > > -     f->f_un.f_forw.f_loghost,
> > > -     EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->input));
> > > +     f->f_un.f_forw.f_loghost, EVBUFFER_LENGTH(bufev->input));
> > >   evbuffer_drain(bufev->input, -1);
> > >  }
> > >  
> > > @@ -743,10 +748,16 @@ tcp_errorcb(struct bufferevent *bufev, s
> > >   else
> > >           snprintf(ebuf, sizeof(ebuf),
> > >               "syslogd: loghost \"%s\" connection error: %s",
> > > -             f->f_un.f_forw.f_loghost, strerror(errno));
> > > +             f->f_un.f_forw.f_loghost, f->f_un.f_forw.f_ctx ?
> > > +             tls_error(f->f_un.f_forw.f_ctx) : strerror(errno));
> > >   dprintf("%s\n", ebuf);
> > >  
> > >   /* The SIGHUP handler may also close the socket, so invalidate it. */
> > > + if (f->f_un.f_forw.f_ctx) {
> > > +         tls_close(f->f_un.f_forw.f_ctx);
> > > +         tls_free(f->f_un.f_forw.f_ctx);
> > > +         f->f_un.f_forw.f_ctx = NULL;
> > > + }
> > >   close(f->f_file);
> > >   f->f_file = -1;
> > >  
> > > @@ -766,6 +777,7 @@ tcp_connectcb(int fd, short event, void 
> > >  {
> > >   struct filed            *f = arg;
> > >   struct bufferevent      *bufev = f->f_un.f_forw.f_bufev;
> > > + struct tls              *ctx;
> > >   struct timeval           to;
> > >   int                      s;
> > >  
> > > @@ -778,8 +790,9 @@ tcp_connectcb(int fd, short event, void 
> > >  
> > >   if ((s = tcp_socket(f)) == -1)
> > >           goto retry;
> > > + dprintf("tcp connect callback: socket success, event %#x\n", event);
> > > + f->f_file = s;
> > >  
> > > - dprintf("tcp connect callback: success, event %#x\n", event);
> > >   bufferevent_setfd(bufev, s);
> > >   bufferevent_setcb(bufev, tcp_readcb, tcp_writecb, tcp_errorcb, f);
> > >   /*
> > > @@ -787,7 +800,20 @@ tcp_connectcb(int fd, short event, void 
> > >    * the socket to detect connection close and errors.
> > >    */
> > >   bufferevent_enable(bufev, EV_READ|EV_WRITE);
> > > - f->f_file = s;
> > > +
> > > + if (f->f_type == F_FORWTLS) {
> > > +         if ((ctx = tls_socket(f)) == NULL) {
> > > +                 close(f->f_file);
> > > +                 f->f_file = -1;
> > > +                 goto retry;
> > > +         }
> > > +         dprintf("tcp connect callback: TLS context success\n");
> > > +         f->f_un.f_forw.f_ctx = ctx;
> > > +
> > > +         buffertls_set(&f->f_un.f_forw.f_buftls, bufev, ctx, s);
> > > +         /* XXX no host given */
> > > +         buffertls_connect(&f->f_un.f_forw.f_buftls, s, NULL);
> > > + }
> > >  
> > >   return;
> > >  
> > > @@ -806,6 +832,46 @@ tcp_connectcb(int fd, short event, void 
> > >   evtimer_add(&bufev->ev_write, &to);
> > >  }
> > >  
> > > +struct tls *
> > > +tls_socket(struct filed *f)
> > > +{
> > > + static struct tls_config *config;
> > > + struct tls      *ctx;
> > > + char             ebuf[100];
> > > +
> > > + if (config == NULL) {
> > > +         if (tls_init() < 0) {
> > > +                 snprintf(ebuf, sizeof(ebuf), "tls_init \"%s\"",
> > > +                     f->f_un.f_forw.f_loghost);
> > > +                 logerror(ebuf);
> > > +                 return (NULL);
> > > +         }
> > > +         if ((config = tls_config_new()) == NULL) {
> > > +                 snprintf(ebuf, sizeof(ebuf), "tls_config_new \"%s\"",
> > > +                     f->f_un.f_forw.f_loghost);
> > > +                 logerror(ebuf);
> > > +                 return (NULL);
> > > +         }
> > > +         /* XXX No verify for now, ca certs are outside of privsep. */
> > > +         tls_config_insecure_noverifyhost(config);
> > > +         tls_config_insecure_noverifycert(config);
> > > + }
> > > + if ((ctx = tls_client()) == NULL) {
> > > +         snprintf(ebuf, sizeof(ebuf), "tls_client \"%s\"",
> > > +             f->f_un.f_forw.f_loghost);
> > > +         logerror(ebuf);
> > > +         return (NULL);
> > > + }
> > > + if (tls_configure(ctx, config) < 0) {
> > > +         snprintf(ebuf, sizeof(ebuf), "tls_configure \"%s\": %s",
> > > +             f->f_un.f_forw.f_loghost, tls_error(ctx));
> > > +         logerror(ebuf);
> > > +         tls_free(ctx);
> > > +         return (NULL);
> > > + }
> > > + return (ctx);
> > > +}
> > > +
> > >  void
> > >  usage(void)
> > >  {
> > > @@ -1112,6 +1178,7 @@ fprintlog(struct filed *f, int flags, ch
> > >           break;
> > >  
> > >   case F_FORWTCP:
> > > + case F_FORWTLS:
> > >           dprintf(" %s\n", f->f_un.f_forw.f_loghost);
> > >           if (EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output) >=
> > >               MAX_TCPBUF)
> > > @@ -1400,6 +1467,12 @@ init(void)
> > >                   fprintlog(f, 0, (char *)NULL);
> > >  
> > >           switch (f->f_type) {
> > > +         case F_FORWTLS:
> > > +                 if (f->f_un.f_forw.f_ctx) {
> > > +                         tls_close(f->f_un.f_forw.f_ctx);
> > > +                         tls_free(f->f_un.f_forw.f_ctx);
> > > +                 }
> > > +                 /* FALLTHROUGH */
> > >           case F_FORWTCP:
> > >                   /* XXX Save messages in output buffer for reconnect. */
> > >                   bufferevent_free(f->f_un.f_forw.f_bufev);
> > > @@ -1540,6 +1613,7 @@ init(void)
> > >  
> > >                   case F_FORWUDP:
> > >                   case F_FORWTCP:
> > > +                 case F_FORWTLS:
> > >                           printf("%s", f->f_un.f_forw.f_loghost);
> > >                           break;
> > >  
> > > @@ -1602,9 +1676,10 @@ cfline(char *line, char *prog)
> > >  {
> > >   int i, pri;
> > >   size_t rb_len;
> > > - char *bp, *p, *q, *proto, *host, *port;
> > > + char *bp, *p, *q, *proto, *host, *port, *ipproto;
> > >   char buf[MAXLINE], ebuf[100];
> > >   struct filed *xf, *f, *d;
> > > + struct timeval to;
> > >  
> > >   dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
> > >  
> > > @@ -1712,11 +1787,13 @@ cfline(char *line, char *prog)
> > >           }
> > >           if (proto == NULL)
> > >                   proto = "udp";
> > > +         ipproto = proto;
> > >           if (strcmp(proto, "udp") == 0) {
> > >                   if (fd_udp == -1)
> > >                           proto = "udp6";
> > >                   if (fd_udp6 == -1)
> > >                           proto = "udp4";
> > > +                 ipproto = proto;
> > >           } else if (strcmp(proto, "udp4") == 0) {
> > >                   if (fd_udp == -1) {
> > >                           snprintf(ebuf, sizeof(ebuf), "no udp4 \"%s\"",
> > > @@ -1734,6 +1811,12 @@ cfline(char *line, char *prog)
> > >           } else if (strcmp(proto, "tcp") == 0 ||
> > >               strcmp(proto, "tcp4") == 0 || strcmp(proto, "tcp6") == 0) {
> > >                   ;
> > > +         } else if (strcmp(proto, "tls") == 0) {
> > > +                 ipproto = "tcp";
> > > +         } else if (strcmp(proto, "tls4") == 0) {
> > > +                 ipproto = "tcp4";
> > > +         } else if (strcmp(proto, "tls6") == 0) {
> > > +                 ipproto = "tcp6";
> > >           } else {
> > >                   snprintf(ebuf, sizeof(ebuf), "bad protocol \"%s\"",
> > >                       f->f_un.f_forw.f_loghost);
> > > @@ -1747,14 +1830,15 @@ cfline(char *line, char *prog)
> > >                   break;
> > >           }
> > >           if (port == NULL)
> > > -                 port = "syslog";
> > > +                 port = strncmp(proto, "tls", 3) == 0 ?
> > > +                     "syslog-tls" : "syslog";
> > >           if (strlen(port) >= NI_MAXSERV) {
> > >                   snprintf(ebuf, sizeof(ebuf), "port too long \"%s\"",
> > >                       f->f_un.f_forw.f_loghost);
> > >                   logerror(ebuf);
> > >                   break;
> > >           }
> > > -         if (priv_getaddrinfo(proto, host, port,
> > > +         if (priv_getaddrinfo(ipproto, 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\"",
> > > @@ -1773,7 +1857,7 @@ cfline(char *line, char *prog)
> > >                           break;
> > >                   }
> > >                   f->f_type = F_FORWUDP;
> > > -         } else if (strncmp(proto, "tcp", 3) == 0) {
> > > +         } else if (strncmp(ipproto, "tcp", 3) == 0) {
> > >                   if ((f->f_un.f_forw.f_bufev = bufferevent_new(-1,
> > >                       tcp_readcb, tcp_writecb, tcp_errorcb, f)) == NULL) {
> > >                           snprintf(ebuf, sizeof(ebuf),
> > > @@ -1782,8 +1866,23 @@ cfline(char *line, char *prog)
> > >                           logerror(ebuf);
> > >                           break;
> > >                   }
> > > -                 f->f_type = F_FORWTCP;
> > > -                 tcp_connectcb(-1, 0, f);
> > > +                 if (strncmp(proto, "tls", 3) == 0) {
> > > +                         f->f_type = F_FORWTLS;
> > > +                 } else {
> > > +                         f->f_type = F_FORWTCP;
> > > +                 }
> > > +                 /*
> > > +                  * If we try to connect to a TLS server immediately
> > > +                  * syslogd gets an SIGPIPE as the signal handlers have
> > > +                  * not been set up.  Delay the connection until the
> > > +                  * event loop is started.  We can reuse the write event
> > > +                  * for that as bufferevent is still disabled.
> > > +                  */
> > > +                 to.tv_sec = 0;
> > > +                 to.tv_usec = 1;
> > > +                 evtimer_set(&f->f_un.f_forw.f_bufev->ev_write,
> > > +                     tcp_connectcb, f);
> > > +                 evtimer_add(&f->f_un.f_forw.f_bufev->ev_write, &to);
> > >           }
> > >           break;
> > >  
> > > 
> > 
> > -- 
> > 

-- 

Reply via email to