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; > > > > > > > > > > -- > > --