diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2005-07-05 10:36:52 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2005-07-05 10:36:52 +0000 |
commit | 29976dd902982188dec55bbfa2281bce7ea1151c (patch) | |
tree | f285c3d9910942c91ed3851036eeca87546be5fd | |
parent | 46dc7803fffd06178b07d907e5a44042abeee504 (diff) | |
download | rsyslog-29976dd902982188dec55bbfa2281bce7ea1151c.tar.gz rsyslog-29976dd902982188dec55bbfa2281bce7ea1151c.tar.xz rsyslog-29976dd902982188dec55bbfa2281bce7ea1151c.zip |
hopefully this is 0.9.2, with tcp listener and full man pages...
-rw-r--r-- | ANNOUNCE | 13 | ||||
-rw-r--r-- | NEWS | 13 | ||||
-rw-r--r-- | rsyslogd.8 | 23 | ||||
-rw-r--r-- | syslogd.c | 212 |
4 files changed, 180 insertions, 81 deletions
@@ -4,12 +4,13 @@ Rsyslog has been forked from the sysklogd package. It currently shares its base design but includes many important enhancements. Most importantly it supports +- the ability to receive syslog messages via tcp +- direct logging to MySQL database servers - fully configurable output formats, including * high precision timestamps with year ;) * access to each of the message parts as well as substrings thereof (includes access to facility and priority) * access to the raw message received -- direct logging to MySQL database servers - compatibility to stock linux syslogd Rsyslog is GPL'ed software. Details and the download on it can be found at @@ -18,8 +19,8 @@ Rsyslog is GPL'ed software. Details and the download on it can be found at This package has performed well in our test environments but it is a beta release. So you might experience problems of all kind when you try it. So far, -it has been compiled under both Red Hat and Debian Linux, only (we did not -try some other system, so others hopefully will work, too). +it has been compiled Red Hat and Debian Linux as well as FreeBSD (but BSD +sometimes slips final testing and thus there might be some compile issues). We would appreciate any feedback from early testers, including bug reports, additional platforms it runs on and new ideas. @@ -31,8 +32,10 @@ made it into rsyslog ;)). We hope to receive ample feedback. The more feedback we receive, the more enhancements will happen (and the faster they will appear). You can -send any feedback and suggestion to me at rgerhards@adiscon.com (A mailing -list will be added soon). +send any feedback and suggestion to the rsyslog mailing list. Archive +and subscription management is available at + +http://lists.adiscon.net/mailman/listinfo/rsyslog Rainer Gerhards Adiscon @@ -1,11 +1,14 @@ --------------------------------------------------------------------------- Version 0.9.2 (RGer), around 2005-07-05 -- changed the max supported message size to 32K. This is to satisfy - the needs of the IHE (Integrating the Healthcare Environment) - initiative. They use syslog for auditing and may generate messages - that large. +- I intended to change the maxsupported message size to 32k to + support IHE - but given the memory inefficiency in the usual use + cases, I have not done this. I have, however, included very + specific instructions on how to do this in the source code. I have + also done some testing with 32k messages, so you can change the + max size without taking too much risk. - added a syslog/tcp receiver; we now can receive messages via - plain tcp, but we can still send only via UDP. + plain tcp, but we can still send only via UDP. The syslog/tcp + receiver is the primary enhancement of this release. - slightly changed some error messages that contained a spurios \n at the end of the line (which gives empty lines in your log...) @@ -1,7 +1,7 @@ -.\" Copyright 2004 Rainer Gerhards and Adiscon for the rsyslog modifications +.\" Copyright 2004-2005 Rainer Gerhards and Adiscon for the rsyslog modifications .\" May be distributed under the GNU General Public License .\" -.TH RSYSLOGD 8 "18 March 2005" "Version 0.8" "Linux System Administration" +.TH RSYSLOGD 8 "05 July 2005" "Version 0.9.2" "Linux System Administration" .SH NAME rsyslogd \- reliable and extended syslogd .SH SYNOPSIS @@ -28,6 +28,10 @@ rsyslogd \- reliable and extended syslogd .RB [ " \-s " .I domainlist ] +.br +.RB [ " \-t " +.I port +] .RB [ " \-v " ] .LP .SH DESCRIPTION @@ -35,7 +39,7 @@ rsyslogd \- reliable and extended syslogd is a system utility providing support for message logging. Support of both internet and unix domain sockets enables this utility to support both local -and remote logging. +and remote logging (via UDP and TCP). .BR Rsyslogd (8) is derived from the sysklogd package which in turn is derived from the @@ -159,6 +163,11 @@ is specified and the host logging resolves to satu.infodrom.north.de no domain would be cut, you will have to specify two domains like: .BR "\-s north.de:infodrom.north.de" . .TP +.BI "\-t " "port" +Activates the syslog/tcp listener service. The listener will listen to +the specified port. Please note that syslog/tcp is not standardized, +but the implementation in rsyslogd follows common practice and is +compatible with e.G. Cisco PIX, syslog-ng and MonitorWare (Windows). .B "\-v" Print version and exit. .LP @@ -209,11 +218,15 @@ Network support means that messages can be forwarded from one node running rsyslogd to another node running rsyslogd where they will be actually logged to a disk file. -To enable this you have to specify the +To enable this you have to specify either the .B "\-r" +or +.B "\-t" option on the command line. The default behavior is that .B rsyslogd -won't listen to the network. +won't listen to the network. You can also combine these two +options if you want rsyslogd to listen to bost TCP and UDP +messages. The strategy is to have rsyslogd listen on a unix domain socket for locally generated log messages. This behavior will allow rsyslogd to @@ -10,7 +10,7 @@ * - selector line for MySQL aborts if no template is given and * also no semicolon is present at the end of the line * - * \brief This is what will become the rsyslogd daemon. + * \brief This is the maint file of the rsyslogd daemon. * * Please note that as of now, a lot of the code in this file stems * from the sysklogd project. To learn more over this project, please @@ -32,6 +32,11 @@ * * As I have made a lot of modifications, please assume that all bugs * in this package are mine and not those of the sysklogd team. + * + * As of this writing, there already exist heavy + * modifications to the orginal sysklogd package. I suggest to no + * longer rely too much on code knowledge you eventually have with + * sysklogd - rgerhards 2005-07-05 * * I have decided to put my code under the GPL. The sysklog package * is distributed under the BSD license. As such, this package here @@ -82,22 +87,27 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ - -#if !defined(lint) && !defined(NO_SCCS) -char copyright2[] = -"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#if !defined(lint) && !defined(NO_SCCS) -static char sccsid[] = "@(#)rsyslogd.c 0.8 (Adiscon) 18/03/2005"; -#endif /* not lint */ - #ifdef __FreeBSD__ #define BSD #endif -#define MAXLINE 32768 /* maximum line length */ +/* change the following setting to e.g. 32768 if you would like to + * support large message sizes for IHE (32k is the current maximum + * needed for IHE). I was initially tempted to increase it to 32k, + * but there is a large memory footprint with the current + * implementation in rsyslog. This will change as the processing + * changes, but I have re-set it to 1k, because the vast majority + * of messages is below that and the memory savings is huge, at + * least compared to the overall memory footprint. + * + * If you intend to receive Windows Event Log data (e.g. via + * EventReporter - www.eventreporter.com), you might want to + * increase this number to an even higher value, as event + * log messages can be very lengthy. + * + * rgerhards, 2005-07-05 + */ +#define MAXLINE 1024 /* maximum line length */ #define DEFUPRI (LOG_USER|LOG_NOTICE) #define DEFSPRI (LOG_KERN|LOG_CRIT) #define TIMERINTVL 30 /* interval for checking flush, mark */ @@ -626,11 +636,13 @@ static int create_udp_socket(); #ifdef SYSLOG_INET #define TCPSESS_MAX 100 /* TODO: remove hardcoded limit */ +static int TCPLstnPort = 0; +static int bEnableTCP = 0; static int sockTCPLstn = -1; struct TCPSession { int sock; - char msg[MAXLINE]; -/* struct sockaddr remHost; maybe not needed...*/ + int iMsg; /* index of next char to store in msg */ + char msg[MAXLINE+1]; char *fromHost; } TCPSessions[TCPSESS_MAX]; @@ -643,7 +655,7 @@ void TCPSessInit(void) for(i = 0 ; i < TCPSESS_MAX ; ++i) { TCPSessions[i].sock = -1; /* no sock */ - TCPSessions[i].msg[0] = '\0'; /* just make sure... */ + TCPSessions[i].iMsg = 0; /* just make sure... */ } } @@ -698,10 +710,19 @@ static int create_tcp_socket(void) return fd; } + if(TCPLstnPort == 0) { + TCPLstnPort = 514; /* use default, no error */ + } + if(TCPLstnPort < 1 || TCPLstnPort > 65535) { + TCPLstnPort = 514; /* just let's use our default... */ + errno = 0; + logerror("TCP listen port was invalid, changed to 514"); + } + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = 514; /* TODO: get this from a variable!!! */ + sin.sin_port = htons(TCPLstnPort); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, \ (char *) &on, sizeof(on)) < 0 ) { logerror("setsockopt(REUSEADDR), suspending tcp inet"); @@ -762,7 +783,6 @@ void TCPSessAccept(void) logerror("tcp accept, ignoring error and connection request"); return; } - /* TODO: must change to nonblocking! */ /* Add to session list */ iSess = TCPSessFindFreeSpot(); @@ -786,7 +806,7 @@ void TCPSessAccept(void) } TCPSessions[iSess].sock = newConn; - TCPSessions[iSess].msg[0] = '\0'; /* init msg buffer! */ + TCPSessions[iSess].iMsg = 0; /* init msg buffer! */ } @@ -817,19 +837,58 @@ void TCPSessClose(int iSess) * the index of the TCP session that received the data. * rgerhards 2005-07-04 */ -void TCPSessDataRcvd(int iTCPSess, char *data, int iLen) +void TCPSessDataRcvd(int iTCPSess, char *pData, int iLen) { - assert(data != NULL); + register int iMsg; + char *pMsg; + char *pEnd; + assert(pData != NULL); assert(iLen > 0); assert(iTCPSess >= 0); assert(iTCPSess < TCPSESS_MAX); assert(TCPSessions[iTCPSess].sock != -1); - if(*(data+iLen - 1) == '\n') - *(data+iLen-1) = '\0'; - else - *(data+iLen) = '\0'; - printline(TCPSessions[iTCPSess].fromHost, data, SOURCE_INET); + /* We now copy the message to the session buffer. As + * it looks, we need to do this in any case because + * we might run into multiple messages inside a single + * buffer. Of course, we could think about optimizations, + * but as this code is to be replaced by liblogging, it + * probably doesn't make so much sense... + * rgerhards 2005-07-04 + * + * Algo: + * - copy message to buffer until the first LF is found + * - printline() the buffer + * - continue with copying + */ + iMsg = TCPSessions[iTCPSess].iMsg; /* copy for speed */ + pMsg = TCPSessions[iTCPSess].msg; /* just a shortcut */ + pEnd = pData + iLen; /* this is one off, which is intensional */ + + while(pData < pEnd) { + if(iMsg >= MAXLINE) { + /* emergency, we now need to flush, no matter if + * we are at end of message or not... + */ + *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */ + printline(TCPSessions[iTCPSess].fromHost, pMsg, SOURCE_INET); + iMsg = 0; + } + if(*pData == '\0') { /* guard against \0 characters... */ + *(pMsg + iMsg++) = '\\'; + *(pMsg + iMsg++) = '0'; + ++pData; + } else if(*pData == '\n') { /* record delemiter */ + *(pMsg + iMsg) = '\0'; /* space *is* reserved for this! */ + printline(TCPSessions[iTCPSess].fromHost, pMsg, SOURCE_INET); + iMsg = 0; + ++pData; + } else { + *(pMsg + iMsg++) = *pData++; + } + } + + TCPSessions[iTCPSess].iMsg = iMsg; /* persist value */ } @@ -1909,7 +1968,7 @@ int main(argc, argv) funix[i] = -1; } - while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF) + while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:t:v")) != EOF) switch((char)ch) { case 'a': if (nfunix < MAXFUNIX) @@ -1954,6 +2013,10 @@ int main(argc, argv) } StripDomains = crunch_list(optarg); break; + case 't': /* enable tcp logging */ + bEnableTCP = -1; + TCPLstnPort = atoi(optarg); + break; case 'v': printf("syslogd %s.%s\n", VERSION, PATCHLEVEL); exit (0); @@ -2154,6 +2217,7 @@ int main(argc, argv) /* Add the TCP socket to the list of read descriptors. */ + if(bEnableTCP) { FD_SET(sockTCPLstn, &readfds); if (sockTCPLstn>maxfds) maxfds=sockTCPLstn; dprintf("Listening on syslog TCP port.\n"); @@ -2168,6 +2232,7 @@ int main(argc, argv) /* now get next... */ iTCPSess = TCPSessGetNxtSess(iTCPSess); } + } #endif #endif #ifdef TESTING @@ -2265,43 +2330,45 @@ int main(argc, argv) } } - /* Now check for TCP */ - if(FD_ISSET(sockTCPLstn, &readfds)) { - dprintf("New connect on TCP inetd socket: #%d\n", sockTCPLstn); - TCPSessAccept(); - } + if(bEnableTCP) { + /* Now check for TCP */ + if(FD_ISSET(sockTCPLstn, &readfds)) { + dprintf("New connect on TCP inetd socket: #%d\n", sockTCPLstn); + TCPSessAccept(); + } - /* now check the sessions */ - /* TODO: optimize the whole thing. We could stop enumerating as - * soon as we have found all sockets flagged as active. */ - iTCPSess = TCPSessGetNxtSess(-1); - while(iTCPSess != -1) { - int fd; - int state; - fd = TCPSessions[iTCPSess].sock; - if(FD_ISSET(fd, &readfds)) { - char buf[MAXLINE]; - dprintf("tcp session socket with new data: #%d\n", fd); - - /* Receive message */ - state = recv(fd, buf, sizeof(buf), 0); - printf("recv state %d\n", state); - if(state == 0) { - /* Session closed */ - TCPSessClose(iTCPSess); - } else if(state == -1) { - char errmsg[128]; - snprintf(errmsg, sizeof(errmsg)/sizeof(char), - "TCP session %d will be closed, error ignored", - fd); - logerror(errmsg); - TCPSessClose(iTCPSess); - } else { - /* valid data received, process it! */ - TCPSessDataRcvd(iTCPSess, buf, state); + /* now check the sessions */ + /* TODO: optimize the whole thing. We could stop enumerating as + * soon as we have found all sockets flagged as active. */ + iTCPSess = TCPSessGetNxtSess(-1); + while(iTCPSess != -1) { + int fd; + int state; + fd = TCPSessions[iTCPSess].sock; + if(FD_ISSET(fd, &readfds)) { + char buf[MAXLINE]; + dprintf("tcp session socket with new data: #%d\n", fd); + + /* Receive message */ + state = recv(fd, buf, sizeof(buf), 0); + printf("recv state %d\n", state); + if(state == 0) { + /* Session closed */ + TCPSessClose(iTCPSess); + } else if(state == -1) { + char errmsg[128]; + snprintf(errmsg, sizeof(errmsg)/sizeof(char), + "TCP session %d will be closed, error ignored", + fd); + logerror(errmsg); + TCPSessClose(iTCPSess); + } else { + /* valid data received, process it! */ + TCPSessDataRcvd(iTCPSess, buf, state); + } } + iTCPSess = TCPSessGetNxtSess(iTCPSess); } - iTCPSess = TCPSessGetNxtSess(iTCPSess); } #endif #else @@ -2379,7 +2446,7 @@ static int create_udp_socket() memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; - sin.sin_port = LogPort; + sin.sin_port = htons(LogPort); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, \ (char *) &on, sizeof(on)) < 0 ) { logerror("setsockopt(REUSEADDR), suspending inet"); @@ -3864,10 +3931,23 @@ void die(sig) close(funix[i]); /* Close the UDP inet socket. */ if (InetInuse) close(inetm); + /* Close the TCP inet socket. */ - /* TODO: close all TCP connections! */ + if(bEnableTCP) { + int iTCPSess; + /* close all TCP connections! */ + iTCPSess = TCPSessGetNxtSess(-1); + while(iTCPSess != -1) { + int fd; + fd = TCPSessions[iTCPSess].sock; + dprintf("Closing TCP Session %d\n", fd); + close(fd); + /* now get next... */ + iTCPSess = TCPSessGetNxtSess(iTCPSess); + } - if (InetInuse) close(sockTCPLstn); + close(sockTCPLstn); + } /* Clean-up files. */ for (i = 0; i < nfunix; i++) @@ -4164,7 +4244,7 @@ void init() #endif #ifdef SYSLOG_INET - if (1) { /* TODO: create a real condition! */ + if (bEnableTCP) { if (sockTCPLstn < 0) { sockTCPLstn = create_tcp_socket(); if (sockTCPLstn >= 0) { @@ -4679,7 +4759,7 @@ void cfline(line, f) memset((char *) &f->f_un.f_forw.f_addr, 0, sizeof(f->f_un.f_forw.f_addr)); f->f_un.f_forw.f_addr.sin_family = AF_INET; - f->f_un.f_forw.f_addr.sin_port = LogPort; + f->f_un.f_forw.f_addr.sin_port = htons(LogPort); if ( f->f_type == F_FORW ) memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); /* |