Hi,
This diff allows to send messages over TCP to syslogd.
ok?
bluhm
Index: usr.sbin/syslogd/privsep.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/privsep.c,v
retrieving revision 1.53
diff -u -p -r1.53 privsep.c
--- usr.sbin/syslogd/privsep.c 6 Jul 2015 16:12:16 -0000 1.53
+++ usr.sbin/syslogd/privsep.c 6 Jul 2015 17:42:36 -0000
@@ -182,6 +182,8 @@ priv_init(char *conf, int numeric, int l
close(fd_udp6);
if (fd_bind != -1)
close(fd_bind);
+ if (fd_listen != -1)
+ close(fd_listen);
for (i = 0; i < nunix; i++)
if (fd_unix[i] != -1)
close(fd_unix[i]);
Index: usr.sbin/syslogd/syslogd.8
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.8,v
retrieving revision 1.36
diff -u -p -r1.36 syslogd.8
--- usr.sbin/syslogd/syslogd.8 30 Jun 2015 12:03:32 -0000 1.36
+++ usr.sbin/syslogd/syslogd.8 6 Jul 2015 21:31:24 -0000
@@ -46,6 +46,7 @@
.Op Fl m Ar mark_interval
.Op Fl p Ar log_socket
.Op Fl s Ar reporting_socket
+.Op Fl T Ar listen_address
.Op Fl U Ar bind_address
.Ek
.Sh DESCRIPTION
@@ -112,6 +113,20 @@ Specify path to an
.Dv AF_LOCAL
socket for use in reporting logs stored in memory buffers using
.Xr syslogc 8 .
+.It Fl T Ar listen_address
+Create a TCP listen socket for receiving messages and bind it to
+the specified address.
+There is no well-known port for syslog over TCP, so a port number
+must be specified using the
+.Ar host:port
+syntax.
+IPv6 addresses can be used by surrounding the address portion with
+square brackets
+.Po
+.Ql [\&
+and
+.Ql ]\&
+.Pc .
.It Fl U Ar bind_address
Create a UDP socket for receiving messages and bind it to the
specified address.
Index: usr.sbin/syslogd/syslogd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.170
diff -u -p -r1.170 syslogd.c
--- usr.sbin/syslogd/syslogd.c 6 Jul 2015 16:12:16 -0000 1.170
+++ usr.sbin/syslogd/syslogd.c 6 Jul 2015 18:15:07 -0000
@@ -60,6 +60,7 @@
#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 MAXTCP 20 /* maximum incomming connections */
#define DEFUPRI (LOG_USER|LOG_NOTICE)
#define DEFSPRI (LOG_KERN|LOG_CRIT)
#define TIMERINTVL 30 /* interval for checking flush, mark */
@@ -216,7 +217,8 @@ int IncludeHostname = 0; /* include RFC
int Family = PF_UNSPEC; /* protocol family, may disable IPv4 or IPv6 */
char *bind_host = NULL; /* bind UDP receive socket */
char *bind_port = NULL;
-
+char *listen_host = NULL; /* listen on TCP receive socket */
+char *listen_port = NULL;
char *path_ctlsock = NULL; /* Path to control socket */
struct tls_config *tlsconfig = NULL;
@@ -272,16 +274,30 @@ char *linebuf;
int linesize;
int fd_ctlsock, fd_ctlconn, fd_klog, fd_sendsys,
- fd_udp, fd_udp6, fd_bind, fd_unix[MAXUNIX];
+ fd_udp, fd_udp6, fd_bind, fd_listen, fd_unix[MAXUNIX];
struct event ev_ctlaccept, ev_ctlread, ev_ctlwrite, ev_klog, ev_sendsys,
- ev_udp, ev_udp6, ev_bind, ev_unix[MAXUNIX],
+ ev_udp, ev_udp6, ev_bind, ev_listen, ev_unix[MAXUNIX],
ev_hup, ev_int, ev_quit, ev_term, ev_mark;
+LIST_HEAD(peer_list, peer) peers;
+struct peer {
+ LIST_ENTRY(peer) p_entry;
+ struct bufferevent *p_bufev;
+ char *p_peername;
+ char *p_hostname;
+ int p_fd;
+};
+int peernum = 0;
+char hostname_unknown[] = "???";
+
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_acceptcb(int, short, void *);
void tcp_readcb(struct bufferevent *, void *);
+void tcp_closecb(struct bufferevent *, short, void *);
+int tcp_socket(struct filed *);
+void tcp_dropcb(struct bufferevent *, void *);
void tcp_writecb(struct bufferevent *, void *);
void tcp_errorcb(struct bufferevent *, short, void *);
void tcp_connectcb(int, short, void *);
@@ -328,7 +344,7 @@ main(int argc, char *argv[])
int ch, i;
int lockpipe[2] = { -1, -1}, pair[2], nullfd, fd;
- while ((ch = getopt(argc, argv, "46a:C:dFf:hm:np:s:U:uV")) != -1)
+ while ((ch = getopt(argc, argv, "46a:C:dFf:hm:np:s:T:U:uV")) != -1)
switch (ch) {
case '4': /* disable IPv6 */
Family = PF_INET;
@@ -371,6 +387,11 @@ main(int argc, char *argv[])
case 's':
path_ctlsock = optarg;
break;
+ case 'T': /* allow tcp and listen on address */
+ if (loghost_parse(optarg, NULL, &listen_host,
+ &listen_port) == -1)
+ errx(1, "bad listen address: %s", optarg);
+ break;
case 'U': /* allow udp only from address */
if (loghost_parse(optarg, NULL, &bind_host, &bind_port)
== -1)
@@ -435,6 +456,14 @@ main(int argc, char *argv[])
if (!Debug)
die(0);
}
+ fd_listen = -1;
+ if (listen_host && socket_bind("tcp", listen_host, listen_port, 1, 0,
+ &fd_listen, &fd_listen) == -1) {
+ errno = 0;
+ logerror("socket listen tcp");
+ if (!Debug)
+ die(0);
+ }
#ifndef SUN_LEN
#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
@@ -571,6 +600,8 @@ main(int argc, char *argv[])
event_set(&ev_udp, fd_udp, EV_READ|EV_PERSIST, udp_readcb, &ev_udp);
event_set(&ev_udp6, fd_udp6, EV_READ|EV_PERSIST, udp_readcb, &ev_udp6);
event_set(&ev_bind, fd_bind, EV_READ|EV_PERSIST, udp_readcb, &ev_bind);
+ event_set(&ev_listen, fd_listen, EV_READ|EV_PERSIST, tcp_acceptcb,
+ &ev_listen);
for (i = 0; i < nunix; i++)
event_set(&ev_unix[i], fd_unix[i], EV_READ|EV_PERSIST,
unix_readcb, &ev_unix[i]);
@@ -623,6 +654,8 @@ main(int argc, char *argv[])
}
if (fd_bind != -1)
event_add(&ev_bind, NULL);
+ if (fd_listen != -1)
+ event_add(&ev_listen, NULL);
for (i = 0; i < nunix; i++)
if (fd_unix[i] != -1)
event_add(&ev_unix[i], NULL);
@@ -707,6 +740,7 @@ socket_bind(const char *proto, const cha
sizeof(hostname), servname, sizeof(servname),
NI_NUMERICHOST | NI_NUMERICSERV |
(res->ai_socktype == SOCK_DGRAM ? NI_DGRAM : 0)) != 0) {
+ dprintf("Malformed bind address\n");
hostname[0] = servname[0] = '\0';
}
if (shutread && shutdown(*fdp, SHUT_RD) == -1) {
@@ -737,6 +771,16 @@ socket_bind(const char *proto, const cha
*fdp = -1;
continue;
}
+ if (!shutread && res->ai_protocol == IPPROTO_TCP &&
+ listen(*fdp, MAXTCP) == -1) {
+ snprintf(ebuf, sizeof(ebuf), "listen "
+ "protocol %d, address %s, portnum %s",
+ res->ai_protocol, hostname, servname);
+ logerror(ebuf);
+ close(*fdp);
+ *fdp = -1;
+ continue;
+ }
if (!shutread && res->ai_protocol == IPPROTO_UDP)
double_rbuf(*fdp);
}
@@ -800,6 +844,130 @@ unix_readcb(int fd, short event, void *a
logerror("recvfrom unix");
}
+void
+tcp_acceptcb(int fd, short event, void *arg)
+{
+ struct peer *p;
+ struct sockaddr_storage ss;
+ socklen_t sslen;
+ char hostname[NI_MAXHOST], servname[NI_MAXSERV];
+ char *peername, ebuf[ERRBUFSIZE];
+
+ dprintf("Accepting tcp connection\n");
+ sslen = sizeof(ss);
+ fd = accept4(fd, (struct sockaddr *)&ss, &sslen, SOCK_NONBLOCK);
+ if (fd == -1) {
+ if (errno != EINTR && errno != EWOULDBLOCK &&
+ errno != ECONNABORTED)
+ logerror("accept tcp socket");
+ return;
+ }
+
+ if (getnameinfo((struct sockaddr *)&ss, sslen, hostname,
+ sizeof(hostname), servname, sizeof(servname),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0 ||
+ asprintf(&peername, ss.ss_family == AF_INET6 ?
+ "[%s]:%s" : "%s:%s", hostname, servname) == -1) {
+ dprintf("Malformed accept address\n");
+ peername = hostname_unknown;
+ }
+ dprintf("Peer addresss and port %s\n", peername);
+ if (peernum >= MAXTCP) {
+ snprintf(ebuf, sizeof(ebuf), "syslogd: tcp logger \"%s\" "
+ "denied: maximum %d reached", peername, MAXTCP);
+ logmsg(LOG_SYSLOG|LOG_WARNING, ebuf, LocalHostName, ADDDATE);
+ close(fd);
+ return;
+ }
+ if ((p = malloc(sizeof(*p))) == NULL) {
+ snprintf(ebuf, sizeof(ebuf), "malloc \"%s\"", peername);
+ logerror(ebuf);
+ close(fd);
+ return;
+ }
+ p->p_fd = fd;
+ if ((p->p_bufev = bufferevent_new(fd, tcp_readcb, NULL, tcp_closecb,
+ p)) == NULL) {
+ snprintf(ebuf, sizeof(ebuf), "bufferevent \"%s\"", peername);
+ logerror(ebuf);
+ free(p);
+ close(fd);
+ return;
+ }
+ if (!NoDNS && peername != hostname_unknown &&
+ priv_getnameinfo((struct sockaddr *)&ss, ss.ss_len, hostname,
+ sizeof(hostname)) != 0) {
+ dprintf("Host name for accept address (%s) unknown\n",
+ hostname);
+ }
+ if (peername == hostname_unknown ||
+ (p->p_hostname = strdup(hostname)) == NULL)
+ p->p_hostname = hostname_unknown;
+ dprintf("Peer hostname %s\n", hostname);
+ p->p_peername = peername;
+ LIST_INSERT_HEAD(&peers, p, p_entry);
+ peernum++;
+ bufferevent_enable(p->p_bufev, EV_READ);
+
+ snprintf(ebuf, sizeof(ebuf), "syslogd: tcp logger \"%s\" accepted",
+ peername);
+ logmsg(LOG_SYSLOG|LOG_INFO, ebuf, LocalHostName, ADDDATE);
+}
+
+void
+tcp_readcb(struct bufferevent *bufev, void *arg)
+{
+ struct peer *p = arg;
+ char *line;
+
+ /*
+ * Syslog over TCP RFC 6587 3.4.2. Non-Transparent-Framing
+ * XXX Incompatible to ourself, should do: 3.4.1. Octet Counting
+ */
+ while ((line = evbuffer_readline(bufev->input))) {
+ dprintf("tcp logger \"%s\" complete line\n", p->p_peername);
+ printline(p->p_hostname, line);
+ free(line);
+ }
+ if (EVBUFFER_LENGTH(bufev->input) >= MAXLINE) {
+ dprintf("tcp logger \"%s\" incomplete line, use %zu bytes\n",
+ p->p_peername, EVBUFFER_LENGTH(bufev->input));
+ printline(p->p_hostname, EVBUFFER_DATA(bufev->input));
+ evbuffer_drain(bufev->input, -1);
+ }
+ if (EVBUFFER_LENGTH(bufev->input) > 0) {
+ dprintf("tcp logger \"%s\" buffer %zu bytes\n",
+ p->p_peername, EVBUFFER_LENGTH(bufev->input));
+ }
+}
+
+void
+tcp_closecb(struct bufferevent *bufev, short event, void *arg)
+{
+ struct peer *p = arg;
+ char ebuf[ERRBUFSIZE];
+
+ if (event & EVBUFFER_EOF) {
+ snprintf(ebuf, sizeof(ebuf), "syslogd: tcp logger \"%s\" "
+ "connection close", p->p_peername);
+ logmsg(LOG_SYSLOG|LOG_INFO, ebuf, LocalHostName, ADDDATE);
+ } else {
+ snprintf(ebuf, sizeof(ebuf), "syslogd: tcp logger \"%s\" "
+ "connection error: %s", p->p_peername, strerror(errno));
+ logmsg(LOG_SYSLOG|LOG_NOTICE, ebuf, LocalHostName, ADDDATE);
+ }
+
+ peernum--;
+ LIST_REMOVE(p, p_entry);
+ if (p->p_peername != hostname_unknown)
+ free(p->p_peername);
+ if (p->p_hostname != hostname_unknown)
+ free(p->p_hostname);
+ bufferevent_free(p->p_bufev);
+ close(p->p_fd);
+ free(p);
+}
+
int
tcp_socket(struct filed *f)
{
@@ -825,7 +993,7 @@ tcp_socket(struct filed *f)
}
void
-tcp_readcb(struct bufferevent *bufev, void *arg)
+tcp_dropcb(struct bufferevent *bufev, void *arg)
{
struct filed *f = arg;
@@ -943,7 +1111,7 @@ tcp_connectcb(int fd, short event, void
f->f_file = s;
bufferevent_setfd(bufev, s);
- bufferevent_setcb(bufev, tcp_readcb, tcp_writecb, tcp_errorcb, f);
+ bufferevent_setcb(bufev, tcp_dropcb, tcp_writecb, tcp_errorcb, f);
/*
* Although syslog is a write only protocol, enable reading from
* the socket to detect connection close and errors.
@@ -1027,7 +1195,7 @@ usage(void)
(void)fprintf(stderr,
"usage: syslogd [-46dFhnuV] [-a path] [-C CAfile] [-f
config_file]\n"
" [-m mark_interval] [-p log_socket] [-s
reporting_socket]\n"
- " [-U bind_address]\n");
+ " [-T listen_address] [-U bind_address]\n");
exit(1);
}
@@ -1541,7 +1709,7 @@ cvthname(struct sockaddr *f, char *resul
if (getnameinfo(f, f->sa_len, result, res_len, NULL, 0,
NI_NUMERICHOST|NI_NUMERICSERV|NI_DGRAM) != 0) {
dprintf("Malformed from address\n");
- strlcpy(result, "???", res_len);
+ strlcpy(result, hostname_unknown, res_len);
return;
}
dprintf("cvthname(%s)\n", result);
@@ -1549,7 +1717,7 @@ cvthname(struct sockaddr *f, char *resul
return;
if (priv_getnameinfo(f, f->sa_len, result, res_len) != 0)
- dprintf("Host name for your address (%s) unknown\n", result);
+ dprintf("Host name for from address (%s) unknown\n", result);
}
void
@@ -2114,7 +2282,7 @@ cfline(char *line, char *progblock, char
f->f_type = F_FORWUDP;
} 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) {
+ tcp_dropcb, tcp_writecb, tcp_errorcb, f)) == NULL) {
snprintf(ebuf, sizeof(ebuf),
"bufferevent \"%s\"",
f->f_un.f_forw.f_loghost);
Index: usr.sbin/syslogd/syslogd.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.h,v
retrieving revision 1.18
diff -u -p -r1.18 syslogd.h
--- usr.sbin/syslogd/syslogd.h 6 Jul 2015 16:12:16 -0000 1.18
+++ usr.sbin/syslogd/syslogd.h 6 Jul 2015 17:42:36 -0000
@@ -44,7 +44,7 @@ extern int nunix;
extern char *path_unix[MAXUNIX];
extern char *path_ctlsock;
extern int fd_ctlsock, fd_ctlconn, fd_klog, fd_sendsys;
-extern int fd_udp, fd_udp6, fd_bind, fd_unix[MAXUNIX];
+extern int fd_udp, fd_udp6, fd_bind, fd_listen, fd_unix[MAXUNIX];
#define dprintf(_f...) do { if (Debug) printf(_f); } while (0)
extern int Debug;