-# $OpenBSD: Makefile,v 1.6 2014/10/05 18:14:01 bluhm Exp $
+# $OpenBSD: Makefile,v 1.7 2015/01/18 19:37:59 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>
--- /dev/null
+/* $OpenBSD: evbuffer_tls.c,v 1.1 2015/01/18 19:37:59 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@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);
+}
--- /dev/null
+/* $OpenBSD: evbuffer_tls.h,v 1.1 2015/01/18 19:37:59 bluhm Exp $ */
+
+/*
+ * Copyright (c) 2014-2015 Alexander Bluhm <bluhm@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_ */
-/* $OpenBSD: syslogd.c,v 1.142 2015/01/16 06:40:21 deraadt Exp $ */
+/* $OpenBSD: syslogd.c,v 1.143 2015/01/18 19:37:59 bluhm Exp $ */
/*
* Copyright (c) 1983, 1988, 1993, 1994
* 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 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <tls.h>
#include <unistd.h>
#include <limits.h>
#include <utmp.h>
#include <sys/syslog.h>
#include "syslogd.h"
+#include "evbuffer_tls.h"
char *ConfFile = _PATH_LOGCONF;
const char ctty[] = _PATH_CONSOLE;
struct {
char f_loghost[1+4+3+1+HOST_NAME_MAX+1+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[PATH_MAX];
struct {
#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;
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 *);
* 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);
}
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;
{
struct filed *f = arg;
struct bufferevent *bufev = f->f_un.f_forw.f_bufev;
+ struct tls *ctx;
struct timeval to;
int s;
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);
/*
* 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;
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)
{
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)
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);
case F_FORWUDP:
case F_FORWTCP:
+ case F_FORWTLS:
printf("%s", f->f_un.f_forw.f_loghost);
break;
{
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);
}
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\"",
} 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);
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\"",
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),
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;