diff options
author | 2015-07-07 17:53:04 +0000 | |
---|---|---|
committer | 2015-07-07 17:53:04 +0000 | |
commit | f59ab5649b90c401b5950f0d247b4f0c02361a91 (patch) | |
tree | 6952f536651772ebcb7c326090439c9b39f26463 | |
parent | add setlocale test (diff) | |
download | wireguard-openbsd-f59ab5649b90c401b5950f0d247b4f0c02361a91.tar.xz wireguard-openbsd-f59ab5649b90c401b5950f0d247b4f0c02361a91.zip |
When syslogd is invoked with -T listen_address, it creates a TCP
socket and accepts incomming messages. At the moment, only RFC
6587 3.4.2. Non-Transparent-Framing format with new-line separator
is supprted for incomming messsages. Outgoing messages are encoded
as 3.4.1. Octet Counting. Autodetection of incomming format will
be implemented later.
OK deraadt@ jmc@ millert@
-rw-r--r-- | usr.sbin/syslogd/privsep.c | 4 | ||||
-rw-r--r-- | usr.sbin/syslogd/syslogd.8 | 19 | ||||
-rw-r--r-- | usr.sbin/syslogd/syslogd.c | 192 | ||||
-rw-r--r-- | usr.sbin/syslogd/syslogd.h | 4 |
4 files changed, 202 insertions, 17 deletions
diff --git a/usr.sbin/syslogd/privsep.c b/usr.sbin/syslogd/privsep.c index a456b97465f..4af8794f63b 100644 --- a/usr.sbin/syslogd/privsep.c +++ b/usr.sbin/syslogd/privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.c,v 1.53 2015/07/06 16:12:16 millert Exp $ */ +/* $OpenBSD: privsep.c,v 1.54 2015/07/07 17:53:04 bluhm Exp $ */ /* * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> @@ -182,6 +182,8 @@ priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[]) 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]); diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8 index 3ecc9e32f3a..00862ec8d2e 100644 --- a/usr.sbin/syslogd/syslogd.8 +++ b/usr.sbin/syslogd/syslogd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: syslogd.8,v 1.36 2015/06/30 12:03:32 bluhm Exp $ +.\" $OpenBSD: syslogd.8,v 1.37 2015/07/07 17:53:04 bluhm Exp $ .\" .\" Copyright (c) 1983, 1986, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -30,7 +30,7 @@ .\" from: @(#)syslogd.8 8.1 (Berkeley) 6/6/93 .\" $NetBSD: syslogd.8,v 1.3 1996/01/02 17:41:48 perry Exp $ .\" -.Dd $Mdocdate: June 30 2015 $ +.Dd $Mdocdate: July 7 2015 $ .Dt SYSLOGD 8 .Os .Sh NAME @@ -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. diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 67ca3107db6..2c34c3b7041 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syslogd.c,v 1.170 2015/07/06 16:12:16 millert Exp $ */ +/* $OpenBSD: syslogd.c,v 1.171 2015/07/07 17:53:04 bluhm Exp $ */ /* * Copyright (c) 1983, 1988, 1993, 1994 @@ -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 3164 style hostnames when forwarding */ 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 char *host, const char *port, 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 char *host, const char *port, *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 *arg) 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 *arg) 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 *result, size_t res_len) 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 *result, size_t res_len) 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 *hostblock) 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); diff --git a/usr.sbin/syslogd/syslogd.h b/usr.sbin/syslogd/syslogd.h index ac2415c49e3..28fd815acc0 100644 --- a/usr.sbin/syslogd/syslogd.h +++ b/usr.sbin/syslogd/syslogd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syslogd.h,v 1.18 2015/07/06 16:12:16 millert Exp $ */ +/* $OpenBSD: syslogd.h,v 1.19 2015/07/07 17:53:04 bluhm Exp $ */ /* * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> @@ -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; |