-/* $OpenBSD: privsep.c,v 1.48 2014/10/05 18:14:01 bluhm Exp $ */
+/* $OpenBSD: privsep.c,v 1.49 2014/12/31 13:55:57 bluhm Exp $ */
/*
* Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
servname[servname_len - 1] = '\0';
memset(&hints, 0, sizeof(hints));
- if (strcmp(protoname, "udp") == 0) {
+ switch (strlen(protoname)) {
+ case 3:
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;
+ break;
+ case 4:
+ switch (protoname[3]) {
+ case '4':
+ hints.ai_family = AF_INET;
+ break;
+ case '6':
+ hints.ai_family = AF_INET6;
+ break;
+ default:
+ errx(1, "bad ip version %s", protoname);
+ }
+ break;
+ default:
+ errx(1, "bad protocol length %s", protoname);
+ }
+ if (strncmp(protoname, "udp", 3) == 0) {
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ } else if (strncmp(protoname, "tcp", 3) == 0) {
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
} 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;
-/* $OpenBSD: syslogd.c,v 1.136 2014/12/10 19:42:14 tobias Exp $ */
+/* $OpenBSD: syslogd.c,v 1.137 2014/12/31 13:55:57 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 by Alexander Bluhm
+ * IPv6, libevent, sending via TCP by Alexander Bluhm
*/
#define MAXLINE 1024 /* maximum line length */
#define MIN_MEMBUF (MAXLINE * 4) /* Minimum memory buffer size */
#define MAX_MEMBUF (256 * 1024) /* Maximum memory buffer size */
#define MAX_MEMBUF_NAME 64 /* Max length of membuf log name */
+#define MAX_TCPBUF (256 * 1024) /* Maximum tcp event buffer size */
#define MAXSVLINE 120 /* maximum saved line length */
#define DEFUPRI (LOG_USER|LOG_NOTICE)
#define DEFSPRI (LOG_KERN|LOG_CRIT)
char f_loghost[1+4+3+1+MAXHOSTNAMELEN+1+NI_MAXSERV];
/* @proto46://[hostname]:servname\0 */
struct sockaddr_storage f_addr;
+ struct bufferevent *f_bufev;
+ int f_fd;
} f_forw; /* forwarding address */
char f_fname[MAXPATHLEN];
struct {
#define F_FILE 1 /* regular file */
#define F_TTY 2 /* terminal */
#define F_CONSOLE 3 /* console terminal */
-#define F_FORW 4 /* remote machine */
+#define F_FORWUDP 4 /* remote machine via UDP */
#define F_USERS 5 /* list of users */
#define F_WALL 6 /* everyone logged on */
#define F_MEMBUF 7 /* memory buffer */
#define F_PIPE 8 /* pipe to external program */
+#define F_FORWTCP 9 /* remote machine via TCP */
-char *TypeNames[9] = {
+char *TypeNames[] = {
"UNUSED", "FILE", "TTY", "CONSOLE",
- "FORW", "USERS", "WALL", "MEMBUF",
- "PIPE"
+ "FORWUDP", "USERS", "WALL", "MEMBUF",
+ "PIPE", "FORWTCP",
};
struct filed *Files;
void klog_readcb(int, short, void *);
void udp_readcb(int, short, void *);
void unix_readcb(int, short, void *);
+int tcp_socket(struct filed *);
+void tcp_readcb(struct bufferevent *, void *);
+void tcp_errorcb(struct bufferevent *, short, void *);
void die_signalcb(int, short, void *);
void mark_timercb(int, short, void *);
void init_signalcb(int, short, void *);
logerror("recvfrom unix");
}
+int
+tcp_socket(struct filed *f)
+{
+ int s, flags;
+ char ebuf[100];
+
+ if ((s = socket(f->f_un.f_forw.f_addr.ss_family, SOCK_STREAM,
+ IPPROTO_TCP)) == -1) {
+ snprintf(ebuf, sizeof(ebuf), "socket \"%s\"",
+ f->f_un.f_forw.f_loghost);
+ logerror(ebuf);
+ return (-1);
+ }
+ /* Connect must not block the process. */
+ if ((flags = fcntl(s, F_GETFL)) == -1 ||
+ fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
+ snprintf(ebuf, sizeof(ebuf), "fcntl \"%s\" O_NONBLOCK",
+ f->f_un.f_forw.f_loghost);
+ logerror(ebuf);
+ close(s);
+ return (-1);
+ }
+ if (connect(s, (struct sockaddr *)&f->f_un.f_forw.f_addr,
+ f->f_un.f_forw.f_addr.ss_len) == -1 && errno != EINPROGRESS) {
+ snprintf(ebuf, sizeof(ebuf), "connect \"%s\"",
+ f->f_un.f_forw.f_loghost);
+ logerror(ebuf);
+ close(s);
+ return (-1);
+ }
+ return (s);
+}
+
+void
+tcp_readcb(struct bufferevent *bufev, void *arg)
+{
+ struct filed *f = arg;
+
+ /*
+ * 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));
+ evbuffer_drain(bufev->input, -1);
+}
+
+void
+tcp_errorcb(struct bufferevent *bufev, short event, void *arg)
+{
+ struct filed *f = arg;
+ char ebuf[100];
+
+ if (event & EVBUFFER_EOF)
+ snprintf(ebuf, sizeof(ebuf),
+ "syslogd: loghost \"%s\" connection close",
+ f->f_un.f_forw.f_loghost);
+ else
+ snprintf(ebuf, sizeof(ebuf),
+ "syslogd: loghost \"%s\" connection error: %s",
+ f->f_un.f_forw.f_loghost, strerror(errno));
+ dprintf("%s\n", ebuf);
+
+ close(f->f_un.f_forw.f_fd);
+ if ((f->f_un.f_forw.f_fd = tcp_socket(f)) == -1) {
+ /* XXX reconnect later */
+ bufferevent_free(bufev);
+ f->f_type = F_UNUSED;
+ } else {
+ /* XXX The messages in the output buffer may be out of sync. */
+ bufferevent_setfd(bufev, f->f_un.f_forw.f_fd);
+ bufferevent_enable(f->f_un.f_forw.f_bufev, EV_READ);
+ }
+ logmsg(LOG_SYSLOG|LOG_WARNING, ebuf, LocalHostName, ADDDATE);
+}
+
void
usage(void)
{
{
struct iovec iov[6];
struct iovec *v;
- int fd, l, retryonce;
+ int l, retryonce;
char line[MAXLINE + 1], repbuf[80], greetings[500];
v = iov;
dprintf("\n");
break;
- case F_FORW:
+ case F_FORWUDP:
dprintf(" %s\n", f->f_un.f_forw.f_loghost);
- switch (f->f_un.f_forw.f_addr.ss_family) {
- case AF_INET:
- fd = fd_udp;
- break;
- case AF_INET6:
- fd = fd_udp6;
- break;
- default:
- fd = -1;
- break;
- }
l = snprintf(line, sizeof(line), "<%d>%.15s %s%s%s",
f->f_prevpri, (char *)iov[0].iov_base,
IncludeHostname ? LocalHostName : "",
(char *)iov[4].iov_base);
if (l < 0 || (size_t)l >= sizeof(line))
l = strlen(line);
- if (sendto(fd, line, l, 0,
+ if (sendto(f->f_un.f_forw.f_fd, line, l, 0,
(struct sockaddr *)&f->f_un.f_forw.f_addr,
f->f_un.f_forw.f_addr.ss_len) != l) {
switch (errno) {
}
break;
+ case F_FORWTCP:
+ dprintf(" %s\n", f->f_un.f_forw.f_loghost);
+ if (EVBUFFER_LENGTH(f->f_un.f_forw.f_bufev->output) >=
+ MAX_TCPBUF)
+ break; /* XXX log error message */
+ /*
+ * RFC 6587 3.4.2. Non-Transparent-Framing
+ * Use \n to split messages for now.
+ * 3.4.1. Octet Counting might be implemented later.
+ */
+ l = evbuffer_add_printf(f->f_un.f_forw.f_bufev->output,
+ "<%d>%.15s %s%s%s\n", f->f_prevpri, (char *)iov[0].iov_base,
+ IncludeHostname ? LocalHostName : "",
+ IncludeHostname ? " " : "",
+ (char *)iov[4].iov_base);
+ if (l < 0)
+ break; /* XXX log error message */
+ bufferevent_enable(f->f_un.f_forw.f_bufev, EV_WRITE);
+ break;
+
case F_CONSOLE:
if (flags & IGN_CONS) {
dprintf(" (ignored)\n");
case F_PIPE:
(void)close(f->f_file);
break;
- case F_FORW:
+ case F_FORWUDP:
+ case F_FORWTCP: /* XXX close and reconnect? */
break;
}
next = f->f_next;
printf("%s", f->f_un.f_fname);
break;
- case F_FORW:
+ case F_FORWUDP:
+ case F_FORWTCP:
printf("%s", f->f_un.f_forw.f_loghost);
break;
logerror(ebuf);
break;
}
+ } else if (strcmp(proto, "tcp") == 0 ||
+ strcmp(proto, "tcp4") == 0 || strcmp(proto, "tcp6") == 0) {
+ ;
} else {
snprintf(ebuf, sizeof(ebuf), "bad protocol \"%s\"",
f->f_un.f_forw.f_loghost);
logerror(ebuf);
break;
}
- f->f_type = F_FORW;
+ f->f_un.f_forw.f_fd = -1;
+ if (strncmp(proto, "udp", 3) == 0) {
+ switch (f->f_un.f_forw.f_addr.ss_family) {
+ case AF_INET:
+ f->f_un.f_forw.f_fd = fd_udp;
+ break;
+ case AF_INET6:
+ f->f_un.f_forw.f_fd = fd_udp6;
+ break;
+ }
+ f->f_type = F_FORWUDP;
+ } else if (strncmp(proto, "tcp", 3) == 0) {
+ int s;
+
+ if ((s = tcp_socket(f)) == -1)
+ break;
+ if ((f->f_un.f_forw.f_bufev = bufferevent_new(s,
+ tcp_readcb, NULL, tcp_errorcb, f)) == NULL) {
+ snprintf(ebuf, sizeof(ebuf),
+ "bufferevent \"%s\"",
+ f->f_un.f_forw.f_loghost);
+ logerror(ebuf);
+ close(s);
+ break;
+ }
+ bufferevent_enable(f->f_un.f_forw.f_bufev, EV_READ);
+ f->f_un.f_forw.f_fd = s;
+ f->f_type = F_FORWTCP;
+ }
break;
case '/':
if ((flags = fcntl(fd, F_GETFL)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- logerror("fcntl ctlconn");
+ logerror("fcntl ctlconn O_NONBLOCK");
close(fd);
return;
}