summaryrefslogtreecommitdiffstats
path: root/syslogd.c
diff options
context:
space:
mode:
Diffstat (limited to 'syslogd.c')
-rw-r--r--syslogd.c1481
1 files changed, 21 insertions, 1460 deletions
diff --git a/syslogd.c b/syslogd.c
index ef80657b..929a3df5 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -133,7 +133,6 @@
* most probably be able to survive it and carry on with processing
* once the situation has been resolved.
*/
-#define MAXLINE 2048 /* maximum line length */
#define DEFUPRI (LOG_USER|LOG_NOTICE)
#define DEFSPRI (LOG_KERN|LOG_CRIT)
#define TIMERINTVL 30 /* interval for checking flush, mark */
@@ -173,7 +172,6 @@
#include <netinet/in.h>
#include <netdb.h>
#include <fnmatch.h>
-#include "net.h" /* struct NetAddr */
#ifndef __sun
#endif
@@ -194,21 +192,6 @@
#include <paths.h>
#endif
-#ifdef USE_NETZIP
-#include <zlib.h>
-/* config param: minimum message size to try compression. The smaller
- * the message, the less likely is any compression gain. We check for
- * gain before we submit the message. But to do so we still need to
- * do the (costly) compress() call. The following setting sets a size
- * for which no call to compress() is done at all. This may result in
- * a few more bytes being transmited but better overall performance.
- * Note: I have not yet checked the minimum UDP packet size. It might be
- * that we do not save anything by compressing very small messages, because
- * UDP might need to pad ;)
- * rgerhards, 2006-11-30
- */
-#define MIN_SIZE_FOR_COMPRESS 60
-#endif
/* handle some defines missing on more than one platform */
#ifndef SUN_LEN
@@ -225,14 +208,17 @@
#include "template.h"
#include "outchannel.h"
#include "syslogd.h"
+#include "net.h" /* struct NetAddr */
#include "stringbuf.h"
#include "parse.h"
#include "srUtils.h"
#include "msg.h"
+#include "tcpsyslog.h"
#include "omshell.h"
#include "omusrmsg.h"
#include "ommysql.h"
+#include "omfwd.h"
/* We define our own set of syslog defintions so that we
* do not need to rely on (possibly different) implementations.
@@ -369,53 +355,6 @@ syslogCODE rs_facilitynames[] =
#endif
-/* The following #ifdef sequence is a small compatibility
- * layer. It tries to work around the different availality
- * levels of SO_BSDCOMPAT on linuxes...
- * I borrowed this code from
- * http://www.erlang.org/ml-archive/erlang-questions/200307/msg00037.html
- * It still needs to be a bit better adapted to rsyslog.
- * rgerhards 2005-09-19
- */
-#ifndef BSD
-#include <sys/utsname.h>
-static int should_use_so_bsdcompat(void)
-{
- static int init_done;
- static int so_bsdcompat_is_obsolete;
-
- if (!init_done) {
- struct utsname utsname;
- unsigned int version, patchlevel;
-
- init_done = 1;
- if (uname(&utsname) < 0) {
- dprintf("uname: %s\r\n", strerror(errno));
- return 1;
- }
- /* Format is <version>.<patchlevel>.<sublevel><extraversion>
- where the first three are unsigned integers and the last
- is an arbitrary string. We only care about the first two. */
- if (sscanf(utsname.release, "%u.%u", &version, &patchlevel) != 2) {
- dprintf("uname: unexpected release '%s'\r\n",
- utsname.release);
- return 1;
- }
- /* SO_BSCOMPAT is deprecated and triggers warnings in 2.5
- kernels. It is a no-op in 2.4 but not in 2.2 kernels. */
- if (version > 2 || (version == 2 && patchlevel >= 5))
- so_bsdcompat_is_obsolete = 1;
- }
- return !so_bsdcompat_is_obsolete;
-}
-#else /* #ifndef BSD */
-#define should_use_so_bsdcompat() 1
-#endif /* #ifndef BSD */
-#ifndef SO_BSDCOMPAT
-/* this shall prevent compiler errors due to undfined name */
-#define SO_BSDCOMPAT 0
-#endif
-
static char *ConfFile = _PATH_LOGCONF; /* read-only after startup */
static char *PidFile = _PATH_LOGPID; /* read-only after startup */
static char ctty[] = _PATH_CONSOLE; /* this is read-only */
@@ -453,19 +392,6 @@ int funix[MAXFUNIX] = { -1, }; /* read-only after startup */
#define ADDDATE 0x004 /* add a date to the message */
#define MARK 0x008 /* this message is a mark */
-/*
- * This table contains plain text for h_errno errors used by the
- * net subsystem.
- */
-static const char *sys_h_errlist[] = {
- "No problem", /* NETDB_SUCCESS */
- "Authoritative answer: host not found", /* HOST_NOT_FOUND */
- "Non-authoritative answer: host not found, or serverfail", /* TRY_AGAIN */
- "Non recoverable errors", /* NO_RECOVERY */
- "Valid name, no data record of requested type", /* NO_DATA */
- "no address, look for MX record" /* NO_ADDRESS */
- };
-
/* This table lists the directive lines:
*/
static const char *directive_name_list[] = {
@@ -542,21 +468,6 @@ union sockunion {
struct sockaddr_in su_sin;
struct sockaddr_in6 su_sin6;
};
-
-#define INET_SUSPEND_TIME 60 /* equal to 1 minute
- * rgerhards, 2005-07-26: This was 3 minutes. As the
- * same timer is used for tcp based syslog, we have
- * reduced it. However, it might actually be worth
- * thinking about a buffered tcp sender, which would be
- * a much better alternative. When that happens, this
- * time here can be re-adjusted to 3 minutes (or,
- * even better, made configurable).
- */
-#define INET_RETRY_MAX 30 /* maximum of retries for gethostbyname() */
- /* was 10, changed to 30 because we reduced INET_SUSPEND_TIME by one third. So
- * this "fixes" some of implications of it (see comment on INET_SUSPEND_TIME).
- * rgerhards, 2005-07-26
- */
#endif
#define LIST_DELIMITER ':' /* delimiter between two hosts */
@@ -626,7 +537,7 @@ static struct code FacNames[] = {
};
/* global variables for config file state */
-static int Debug; /* debug flag - read-only after startup */
+int Debug; /* debug flag - read-only after startup */
static int bFailOnChown; /* fail if chown fails? */
static uid_t fileUID; /* UID to be used for newly created files */
static uid_t fileGID; /* GID to be used for newly created files */
@@ -634,7 +545,7 @@ static uid_t dirUID; /* UID to be used for newly created directories */
static uid_t dirGID; /* GID to be used for newly created directories */
static int bDebugPrintTemplateList;/* output template list in debug mode? */
static int bCreateDirs; /* auto-create directories for dynaFiles: 0 - no, 1 - yes */
-static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
+int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
static uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */
static int bEscapeCCOnRcv; /* escape control characters on reception: 0 - no, 1 - yes */
static int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
@@ -644,21 +555,21 @@ static int logEveryMsg = 0;/* no repeat message processing - read-only after st
*/
/* end global config file state variables */
-static char LocalHostName[MAXHOSTNAMELEN+1];/* our hostname - read-only after startup */
-static char *LocalDomain; /* our local domain name - read-only after startup */
-static int *finet = NULL; /* Internet datagram sockets, first element is nbr of elements
+char LocalHostName[MAXHOSTNAMELEN+1];/* our hostname - read-only after startup */
+char *LocalDomain; /* our local domain name - read-only after startup */
+int *finet = NULL; /* Internet datagram sockets, first element is nbr of elements
* read-only after init(), but beware of restart! */
static char *LogPort = "514"; /* port number for INET connections */
static int MarkInterval = 5;//20 * 60; /* interval between marks in seconds - read-only after startup */
-static int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both), set via cmdline */
-static int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
+int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both), set via cmdline */
+int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
static int MarkSeq = 0; /* mark sequence number - modified in domark() only */
static int NoFork = 0; /* don't fork - don't run in daemon mode - read-only after startup */
-static int DisableDNS = 0; /* don't look up IP addresses of remote messages */
static int AcceptRemote = 0;/* receive messages that come via UDP - read-only after startup */
-static char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u.*/
-static char **LocalHosts = NULL;/* these hosts are logged with their hostname - read-only after startup*/
-static int NoHops = 1; /* Can we bounce syslog messages through an
+int DisableDNS = 0; /* don't look up IP addresses of remote messages */
+char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u.*/
+char **LocalHosts = NULL;/* these hosts are logged with their hostname - read-only after startup*/
+int NoHops = 1; /* Can we bounce syslog messages through an
intermediate host. Read-only after startup */
static int Initialized = 0; /* set when we have initialized ourselves
* rgerhards 2004-11-09: and by initialized, we mean that
@@ -729,20 +640,14 @@ static void resetConfigVariables(void)
* rgerhards, 2005-09-26
*/
#ifdef SYSLOG_INET
-struct AllowedSenders {
- struct NetAddr allowedSender; /* ip address allowed */
- uint8_t SignificantBits; /* defines how many bits should be discarded (eqiv to mask) */
- struct AllowedSenders *pNext;
-};
-
/* All of the five below are read-only after startup */
static struct AllowedSenders *pAllowedSenders_UDP = NULL; /* the roots of the allowed sender */
-static struct AllowedSenders *pAllowedSenders_TCP = NULL; /* lists. If NULL, all senders are ok! */
+struct AllowedSenders *pAllowedSenders_TCP = NULL; /* lists. If NULL, all senders are ok! */
static struct AllowedSenders *pLastAllowedSenders_UDP = NULL; /* and now the pointers to the last */
static struct AllowedSenders *pLastAllowedSenders_TCP = NULL; /* element in the respective list */
#endif /* #ifdef SYSLOG_INET */
-static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
+int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
/* hardcoded standard templates (used for defaults) */
@@ -761,12 +666,10 @@ static void *singleWorker(); /* REMOVEME later 2005-10-24 */
#endif
/* Function prototypes. */
static char **crunch_list(char *list);
-static void printchopped(char *hname, char *msg, int len, int fd, int iSourceType);
static void printline(char *hname, char *msg, int iSource);
static void logmsg(int pri, msg_t*, int flags);
static void fprintlog(register selector_t *f);
static void reapchild();
-static int cvthname(struct sockaddr_storage *f, uchar *pszHost, uchar *pszHostFQDN);
static void debug_switch();
static rsRetVal cfline(char *line, register selector_t *f);
static int decode(uchar *name, struct code *codetab);
@@ -1016,18 +919,6 @@ static rsRetVal AddAllowedSender(struct AllowedSenders **ppRoot, struct AllowedS
* rgerhards, 2005-09-27
*/
-#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
-#define SALEN(sa) ((sa)->sa_len)
-#else
-static inline size_t SALEN(struct sockaddr *sa) {
- switch (sa->sa_family) {
- case AF_INET: return (sizeof (struct sockaddr_in));
- case AF_INET6: return (sizeof (struct sockaddr_in6));
- default: return 0;
- }
-}
-#endif
-
static void PrintAllowedSenders(int iListToPrint)
{
struct AllowedSenders *pSender;
@@ -1142,7 +1033,7 @@ static inline int MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr
* returns 1, if the sender is allowed, 0 otherwise.
* rgerhards, 2005-09-26
*/
-static int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost)
+int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *pFrom, const char *pszFromHost)
{
struct AllowedSenders *pAllow;
@@ -1176,7 +1067,7 @@ static int isAllowedSender(struct AllowedSenders *pAllowRoot, struct sockaddr *p
* double indirection!
* rgerhards, 2007-06-28
*/
-static void freeAllSockets(int **socks)
+void freeAllSockets(int **socks)
{
assert(socks != NULL);
assert(*socks != NULL);
@@ -1189,1023 +1080,6 @@ static void freeAllSockets(int **socks)
socks = NULL;
}
-/********************************************************************
- * ### SYSLOG/TCP CODE ###
- * This is code for syslog/tcp. This code would belong to a separate
- * file - but I have put it here to avoid hassle with CVS. Over
- * time, I expect rsyslog to utilize liblogging for actual network
- * I/O. So the tcp code will be (re)moved some time. I don't like
- * to add a new file to cvs that I will push to the attic in just
- * a few weeks (month at most...). So I simply add the code here.
- *
- * Place no unrelated code between this comment and the
- * END tcp comment!
- *
- * 2005-07-04 RGerhards (Happy independence day to our US friends!)
- ********************************************************************/
-#ifdef SYSLOG_INET
-
-#define TCPSESS_MAX_DEFAULT 200 /* default for nbr of tcp sessions if no number is given */
-
-static int iTCPSessMax = TCPSESS_MAX_DEFAULT; /* actual number of sessions */
-static char *TCPLstnPort = "0"; /* read-only after startup */
-static int bEnableTCP = 0; /* read-only after startup */
-static int *sockTCPLstn = NULL; /* read-only after startup, modified by restart */
-struct TCPSession {
- int sock;
- int iMsg; /* index of next char to store in msg */
- int bAtStrtOfFram; /* are we at the very beginning of a new frame? */
- int iOctetsRemain; /* Number of Octets remaining in message */
- TCPFRAMINGMODE eFraming;
- char msg[MAXLINE+1];
- char *fromHost;
-} *pTCPSessions = NULL;
-/* The thread-safeness of the sesion table is doubtful */
-
-
-/* configure TCP listener settings. This is called during command
- * line parsing. The argument following -t is supplied as an argument.
- * The format of this argument is
- * "<port-to-use>, <nbr-of-sessions>"
- * Typically, there is no whitespace between port and session number.
- * (but it may be...).
- * NOTE: you can not use dprintf() in here - the dprintf() system is
- * not yet initilized when this function is called.
- * rgerhards, 2007-06-21
- * We can also not use logerror(), as that system is also not yet
- * initialized... rgerhards, 2007-06-28
- */
-static void configureTCPListen(char *cOptarg)
-{
- register int i;
- register char *pArg = cOptarg;
-
- assert(cOptarg != NULL);
- bEnableTCP = -1; /* enable TCP listening */
-
- /* extract port */
- i = 0;
- while(isdigit((int) *pArg)) {
- i = i * 10 + *pArg++ - '0';
- }
-
- if( i >= 0 && i <= 65535) {
- TCPLstnPort = cOptarg;
- } else {
- fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i);
- TCPLstnPort = "514";
- }
-
- /* number of sessions */
- if(*pArg == ','){
- *pArg = '\0'; /* hack: terminates port (see a few lines above, same buffer!) */
- ++pArg;
- while(isspace((int) *pArg))
- ++pArg;
- /* ok, here should be the number... */
- i = 0;
- while(isdigit((int) *pArg)) {
- i = i * 10 + *pArg++ - '0';
- }
- if(i > 1)
- iTCPSessMax = i;
- else {
- /* too small, need to adjust */
- fprintf(stderr,
- "rsyslogd: TCP session max configured to %d [-t %s] - changing to 1.\n",
- i, cOptarg);
- iTCPSessMax = 1;
- }
- } else if(*pArg == '\0') {
- /* use default for session number - that's already set...*/
- /*EMPTY BY INTENSION*/
- } else {
- fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", cOptarg);
- }
-}
-
-
-/* Initialize the session table
- * returns 0 if OK, somewhat else otherwise
- */
-static int TCPSessInit(void)
-{
- register int i;
-
- assert(pTCPSessions == NULL);
- dprintf("Allocating buffer for %d TCP sessions.\n", iTCPSessMax);
- if((pTCPSessions = (struct TCPSession *) malloc(sizeof(struct TCPSession) * iTCPSessMax))
- == NULL) {
- dprintf("Error: TCPSessInit() could not alloc memory for TCP session table.\n");
- return(1);
- }
-
- for(i = 0 ; i < iTCPSessMax ; ++i) {
- pTCPSessions[i].sock = -1; /* no sock */
- pTCPSessions[i].iMsg = 0; /* just make sure... */
- pTCPSessions[i].bAtStrtOfFram = 1; /* indicate frame header expected */
- pTCPSessions[i].eFraming = TCP_FRAMING_OCTET_STUFFING; /* just make sure... */
- }
- return(0);
-}
-
-
-/* find a free spot in the session table. If the table
- * is full, -1 is returned, else the index of the free
- * entry (0 or higher).
- */
-static int TCPSessFindFreeSpot(void)
-{
- register int i;
-
- for(i = 0 ; i < iTCPSessMax ; ++i) {
- if(pTCPSessions[i].sock == -1)
- break;
- }
-
- return((i < iTCPSessMax) ? i : -1);
-}
-
-
-/* Get the next session index. Free session tables entries are
- * skipped. This function is provided the index of the last
- * session entry, or -1 if no previous entry was obtained. It
- * returns the index of the next session or -1, if there is no
- * further entry in the table. Please note that the initial call
- * might as well return -1, if there is no session at all in the
- * session table.
- */
-static int TCPSessGetNxtSess(int iCurr)
-{
- register int i;
-
- for(i = iCurr + 1 ; i < iTCPSessMax ; ++i)
- if(pTCPSessions[i].sock != -1)
- break;
-
- return((i < iTCPSessMax) ? i : -1);
-}
-
-
-/* De-Initialize TCP listner sockets.
- * This function deinitializes everything, including freeing the
- * session table. No TCP listen receive operations are permitted
- * unless the subsystem is reinitialized.
- * rgerhards, 2007-06-21
- */
-static void deinit_tcp_listener(void)
-{
- int iTCPSess;
-
- assert(pTCPSessions != NULL);
- /* close all TCP connections! */
- iTCPSess = TCPSessGetNxtSess(-1);
- while(iTCPSess != -1) {
- int fd;
- fd = pTCPSessions[iTCPSess].sock;
- dprintf("Closing TCP Session %d\n", fd);
- close(fd);
- /* now get next... */
- iTCPSess = TCPSessGetNxtSess(iTCPSess);
- }
-
- /* we are done with the session table - so get rid of it...
- */
- free(pTCPSessions);
- pTCPSessions = NULL; /* just to make sure... */
-
- /* finally close the listen sockets themselfs */
- freeAllSockets(&sockTCPLstn);
-}
-
-
-/* Initialize TCP sockets (for listener)
- * This function returns either NULL (which means it failed) or
- * a pointer to an array of file descriptiors. If the pointer is
- * returned, the zeroest element [0] contains the count of valid
- * descriptors. The descriptors themself follow in range
- * [1] ... [num-descriptors]. It is guaranteed that each of these
- * descriptors is valid, at least when this function returns.
- * Please note that technically the array may be larger than the number
- * of valid pointers stored in it. The memory overhead is minimal, so
- * we do not bother to re-allocate an array of the exact size. Logically,
- * the array still contains the exactly correct number of descriptors.
- */
-static int *create_tcp_socket(void)
-{
- struct addrinfo hints, *res, *r;
- int error, maxs, *s, *socks, on = 1;
-
- if(!strcmp(TCPLstnPort, "0"))
- TCPLstnPort = "514";
- /* use default - we can not do service db update, because there is
- * no IANA-assignment for syslog/tcp. In the long term, we might
- * re-use RFC 3195 port of 601, but that would probably break to
- * many existing configurations.
- * rgerhards, 2007-06-28
- */
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
- hints.ai_family = family;
- hints.ai_socktype = SOCK_STREAM;
-
- error = getaddrinfo(NULL, TCPLstnPort, &hints, &res);
- if(error) {
- logerror((char*) gai_strerror(error));
- return NULL;
- }
-
- /* Count max number of sockets we may open */
- for (maxs = 0, r = res; r != NULL ; r = r->ai_next, maxs++)
- /* EMPTY */;
- socks = malloc((maxs+1) * sizeof(int));
- if (socks == NULL) {
- logerror("couldn't allocate memory for TCP listen sockets, suspending TCP message reception.");
- freeaddrinfo(res);
- return NULL;
- }
-
- *socks = 0; /* num of sockets counter at start of array */
- s = socks + 1;
- for (r = res; r != NULL ; r = r->ai_next) {
- *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
- if (*s < 0) {
- if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT))
- logerror("create_udp_socket(), socket");
- /* it is debatable if PF_INET with EAFNOSUPPORT should
- * also be ignored...
- */
- continue;
- }
-
-#ifdef IPV6_V6ONLY
- if (r->ai_family == AF_INET6) {
- int iOn = 1;
- if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *)&iOn, sizeof (iOn)) < 0) {
- logerror("TCP setsockopt");
- close(*s);
- *s = -1;
- continue;
- }
- }
-#endif
- if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
- (char *) &on, sizeof(on)) < 0 ) {
- logerror("TCP setsockopt(REUSEADDR)");
- close(*s);
- *s = -1;
- continue;
- }
-
- /* We need to enable BSD compatibility. Otherwise an attacker
- * could flood our log files by sending us tons of ICMP errors.
- */
-#ifndef BSD
- if (should_use_so_bsdcompat()) {
- if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
- (char *) &on, sizeof(on)) < 0) {
- logerror("TCP setsockopt(BSDCOMPAT)");
- close(*s);
- *s = -1;
- continue;
- }
- }
-#endif
-
- if( (bind(*s, r->ai_addr, r->ai_addrlen) < 0)
-#ifndef IPV6_V6ONLY
- && (errno != EADDRINUSE)
-#endif
- ) {
- logerror("TCP bind");
- close(*s);
- *s = -1;
- continue;
- }
-
- if( listen(*s,iTCPSessMax / 10 + 5) < 0) {
- /* If the listen fails, it most probably fails because we ask
- * for a too-large backlog. So in this case we first set back
- * to a fixed, reasonable, limit that should work. Only if
- * that fails, too, we give up.
- */
- logerrorInt("listen with a backlog of %d failed - retrying with default of 32.",
- iTCPSessMax / 10 + 5);
- if(listen(*s, 32) < 0) {
- logerror("TCP listen, suspending tcp inet");
- close(*s);
- *s = -1;
- continue;
- }
- }
-
- (*socks)++;
- s++;
- }
-
- if(res != NULL)
- freeaddrinfo(res);
-
- if(Debug && *socks != maxs)
- dprintf("We could initialize %d TCP listen sockets out of %d we received "
- "- this may or may not be an error indication.\n", *socks, maxs);
-
- if(*socks == 0) {
- logerror("No TCP listen socket could successfully be initialized, "
- "message reception via TCP disabled.\n");
- free(socks);
- return(NULL);
- }
-
- /* OK, we had success. Now it is also time to
- * initialize our connections
- */
- if(TCPSessInit() != 0) {
- /* OK, we are in some trouble - we could not initialize the
- * session table, so we can not continue. We need to free all
- * we have assigned so far, because we can not really use it...
- */
- logerror("Could not initialize TCP session table, suspending TCP message reception.");
- freeAllSockets(&socks); /* prevent a socket leak */
- return(NULL);
- }
-
- return(socks);
-}
-
-
-/* Accept new TCP connection; make entry in session table. If there
- * is no more space left in the connection table, the new TCP
- * connection is immediately dropped.
- */
-static void TCPSessAccept(int fd)
-{
- int newConn;
- int iSess;
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(struct sockaddr_storage);
- size_t lenHostName;
- uchar fromHost[NI_MAXHOST];
- uchar fromHostFQDN[NI_MAXHOST];
- char *pBuf;
-
- newConn = accept(fd, (struct sockaddr*) &addr, &addrlen);
- if (newConn < 0) {
- logerror("tcp accept, ignoring error and connection request");
- return;
- }
-
- /* Add to session list */
- iSess = TCPSessFindFreeSpot();
- if(iSess == -1) {
- errno = 0;
- logerror("too many tcp sessions - dropping incoming request");
- close(newConn);
- return;
- }
-
- /* OK, we have a "good" index... */
- /* get the host name */
- if(cvthname(&addr, fromHost, fromHostFQDN) == 0) {
- /* we seem to have something malicous - at least we
- * are now told to discard the connection request.
- * Error message has been generated by cvthname.
- */
- close (newConn);
- return;
- }
-
- /* Here we check if a host is permitted to send us
- * syslog messages. If it isn't, we do not further
- * process the message but log a warning (if we are
- * configured to do this).
- * rgerhards, 2005-09-26
- */
- if(!isAllowedSender(pAllowedSenders_TCP, (struct sockaddr *)&addr, (char*)fromHostFQDN)) {
- if(option_DisallowWarning) {
- errno = 0;
- logerrorSz("TCP message from disallowed sender %s discarded",
- (char*)fromHost);
- }
- close(newConn);
- return;
- }
-
- /* OK, we have an allowed sender, so let's continue */
- lenHostName = strlen((char*)fromHost) + 1; /* for \0 byte */
- if((pBuf = (char*) malloc(sizeof(char) * lenHostName)) == NULL) {
- glblHadMemShortage = 1;
- pTCPSessions[iSess].fromHost = "NO-MEMORY-FOR-HOSTNAME";
- } else {
- memcpy(pBuf, fromHost, lenHostName);
- pTCPSessions[iSess].fromHost = pBuf;
- }
-
- pTCPSessions[iSess].sock = newConn;
- pTCPSessions[iSess].iMsg = 0; /* init msg buffer! */
-}
-
-
-/* This should be called before a normal (non forced) close
- * of a TCP session. This function checks if there is any unprocessed
- * message left in the TCP stream. Such a message is probably a
- * fragement. If evrything goes well, we must be right at the
- * beginnig of a new frame without any data received from it. If
- * not, there is some kind of a framing error. I think I remember that
- * some legacy syslog/TCP implementations have non-LF terminated
- * messages at the end of the stream. For now, we allow this behaviour.
- * Later, it should probably become a configuration option.
- * rgerhards, 2006-12-07
- */
-static void TCPSessPrepareClose(int iTCPSess)
-{
- if(iTCPSess < 0 || iTCPSess > iTCPSessMax) {
- errno = 0;
- logerror("internal error, trying to close an invalid TCP session!");
- return;
- }
-
- if(pTCPSessions[iTCPSess].bAtStrtOfFram == 1) {
- /* this is how it should be. There is no unprocessed
- * data left and such we have nothing to do. For simplicity
- * reasons, we immediately return in that case.
- */
- return;
- }
-
- /* we have some data left! */
- if(pTCPSessions[iTCPSess].eFraming == TCP_FRAMING_OCTET_COUNTING) {
- /* In this case, we have an invalid frame count and thus
- * generate an error message and discard the frame.
- */
- logerrorInt("Incomplete frame at end of stream in session %d - "
- "ignoring extra data (a message may be lost).\n",
- pTCPSessions[iTCPSess].sock);
- /* nothing more to do */
- } else { /* here, we have traditional framing. Missing LF at the end
- * of message may occur. As such, we process the message in
- * this case.
- */
- dprintf("Extra data at end of stream in legacy syslog/tcp message - processing\n");
- printchopped(pTCPSessions[iTCPSess].fromHost, pTCPSessions[iTCPSess].msg,
- pTCPSessions[iTCPSess].iMsg, pTCPSessions[iTCPSess].sock, 1);
- pTCPSessions[iTCPSess].bAtStrtOfFram = 1;
- }
-}
-
-
-/* Closes a TCP session and marks its slot in the session
- * table as unused. No attention is paid to the return code
- * of close, so potential-double closes are not detected.
- */
-static void TCPSessClose(int iSess)
-{
- if(iSess < 0 || iSess > iTCPSessMax) {
- errno = 0;
- logerror("internal error, trying to close an invalid TCP session!");
- return;
- }
-
- close(pTCPSessions[iSess].sock);
- pTCPSessions[iSess].sock = -1;
- free(pTCPSessions[iSess].fromHost);
- pTCPSessions[iSess].fromHost = NULL; /* not really needed, but... */
-}
-
-
-/* Processes the data received via a TCP session. If there
- * is no other way to handle it, data is discarded.
- * Input parameter data is the data received, iLen is its
- * len as returned from recv(). iLen must be 1 or more (that
- * is errors must be handled by caller!). iTCPSess must be
- * the index of the TCP session that received the data.
- * rgerhards 2005-07-04
- * Changed this functions interface. We now return a status of
- * what shall happen with the session. This is information for
- * the caller. If 1 is returned, the session should remain open
- * and additional data be accepted. If we return 0, the TCP
- * session is to be closed by the caller. This functionality is
- * needed in order to support framing errors, from which there
- * is no recovery possible other than session termination and
- * re-establishment. The need for this functionality thus is
- * primarily rooted in support for -transport-tls I-D framing.
- * rgerhards, 2006-12-07
- */
-static int TCPSessDataRcvd(int iTCPSess, char *pData, int iLen)
-{
- register int iMsg;
- char *pMsg;
- char *pEnd;
- assert(pData != NULL);
- assert(iLen > 0);
- assert(iTCPSess >= 0);
- assert(iTCPSess < iTCPSessMax);
- assert(pTCPSessions[iTCPSess].sock != -1);
-
- /* 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 = pTCPSessions[iTCPSess].iMsg; /* copy for speed */
- pMsg = pTCPSessions[iTCPSess].msg; /* just a shortcut */
- pEnd = pData + iLen; /* this is one off, which is intensional */
-
- while(pData < pEnd) {
- /* Check if we are at a new frame */
- if(pTCPSessions[iTCPSess].bAtStrtOfFram) {
- /* we need to look at the message and detect
- * the framing mode used
- *//*
- * Contrary to -transport-tls, we accept leading zeros in the message
- * length. We do this in the spirit of "Be liberal in what you accept,
- * and conservative in what you send". We expect that including leading
- * zeros could be a common coding error.
- * rgerhards, 2006-12-07
- * The chairs of the IETF syslog-sec WG have announced that it is
- * consensus to do the octet count on the SYSLOG-MSG part only. I am
- * now changing the code to reflect this. Hopefully, it will not change
- * once again (there can no compatibility layer programmed for this).
- * To be on the save side, I just comment the code out. I mark these
- * comments with "IETF20061218".
- * rgerhards, 2006-12-19
- */
- if(isdigit((int) *pData)) {
- int iCnt; /* the frame count specified */
- pTCPSessions[iTCPSess].eFraming = TCP_FRAMING_OCTET_COUNTING;
- /* in this mode, we have OCTET-COUNT SP MSG - so we now need
- * to extract the OCTET-COUNT and the SP and then extract
- * the msg.
- */
- iCnt = 0;
- /* IETF20061218 int iNbrOctets = 0; / * number of octets already consumed */
- while(isdigit((int) *pData)) {
- iCnt = iCnt * 10 + *pData - '0';
- /* IETF20061218 ++iNbrOctets; */
- ++pData;
- }
- dprintf("TCP Message with octet-counter, size %d.\n", iCnt);
- if(*pData == ' ') {
- ++pData; /* skip over SP */
- /* IETF20061218 ++iNbrOctets; */
- } else {
- /* TODO: handle "invalid frame" case */
- logerrorInt("Framing Error in received TCP message: "
- "delimiter is not SP but has ASCII value %d.\n",
- *pData);
- return(0); /* unconditional error exit */
- }
- /* IETF20061218 pTCPSessions[iTCPSess].iOctetsRemain = iCnt - iNbrOctets; */
- pTCPSessions[iTCPSess].iOctetsRemain = iCnt;
- if(pTCPSessions[iTCPSess].iOctetsRemain < 1) {
- /* TODO: handle the case where the octet count is 0 or negative! */
- dprintf("Framing Error: invalid octet count\n");
- logerrorInt("Framing Error in received TCP message: "
- "invalid octet count %d.\n",
- pTCPSessions[iTCPSess].iOctetsRemain);
- return(0); /* unconditional error exit */
- }
- } else {
- pTCPSessions[iTCPSess].eFraming = TCP_FRAMING_OCTET_STUFFING;
- /* No need to do anything else here in this case */
- }
- pTCPSessions[iTCPSess].bAtStrtOfFram = 0; /* done frame header */
- }
-
- /* now copy message until end of record */
-
- if(iMsg >= MAXLINE) {
- /* emergency, we now need to flush, no matter if
- * we are at end of message or not...
- */
- printchopped(pTCPSessions[iTCPSess].fromHost, pMsg, iMsg,
- pTCPSessions[iTCPSess].sock, 1);
- iMsg = 0;
- /* we might think if it is better to ignore the rest of the
- * message than to treat it as a new one. Maybe this is a good
- * candidate for a configuration parameter...
- * rgerhards, 2006-12-04
- */
- }
-
- if(*pData == '\n' &&
- pTCPSessions[iTCPSess].eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delemiter? */
- printchopped(pTCPSessions[iTCPSess].fromHost, pMsg, iMsg,
- pTCPSessions[iTCPSess].sock, 1);
- iMsg = 0;
- pTCPSessions[iTCPSess].bAtStrtOfFram = 1;
- ++pData;
- } else {
- /* IMPORTANT: here we copy the actual frame content to the message! */
- *(pMsg + iMsg++) = *pData++;
- }
-
- if(pTCPSessions[iTCPSess].eFraming == TCP_FRAMING_OCTET_COUNTING) {
- /* do we need to find end-of-frame via octet counting? */
- pTCPSessions[iTCPSess].iOctetsRemain--;
- if(pTCPSessions[iTCPSess].iOctetsRemain < 1) {
- /* we have end of frame! */
- printchopped(pTCPSessions[iTCPSess].fromHost, pMsg, iMsg,
- pTCPSessions[iTCPSess].sock, 1);
- iMsg = 0;
- pTCPSessions[iTCPSess].bAtStrtOfFram = 1;
- }
- }
- }
-
- pTCPSessions[iTCPSess].iMsg = iMsg; /* persist value */
-
- return(1); /* successful return */
-}
-
-
-/* CODE FOR SENDING TCP MESSAGES */
-
-/* get send status
- * rgerhards, 2005-10-24
- */
-static void TCPSendSetStatus(selector_t *f, enum TCPSendStatus iNewState)
-{
- assert(f != NULL);
- assert(f->f_type == F_FORW);
- assert(f->f_un.f_forw.protocol == FORW_TCP);
- assert( (iNewState == TCP_SEND_NOTCONNECTED)
- || (iNewState == TCP_SEND_CONNECTING)
- || (iNewState == TCP_SEND_READY));
-
- /* there can potentially be a race condition, so guard by mutex */
-# ifdef USE_PTHREADS
- pthread_mutex_lock(&f->f_un.f_forw.mtxTCPSend);
-# endif
- f->f_un.f_forw.status = iNewState;
-# ifdef USE_PTHREADS
- pthread_mutex_unlock(&f->f_un.f_forw.mtxTCPSend);
-# endif
-}
-
-
-/* set send status
- * rgerhards, 2005-10-24
- */
-static enum TCPSendStatus TCPSendGetStatus(selector_t *f)
-{
- enum TCPSendStatus eState;
- assert(f != NULL);
- assert(f->f_type == F_FORW);
- assert(f->f_un.f_forw.protocol == FORW_TCP);
-
- /* there can potentially be a race condition, so guard by mutex */
-# ifdef USE_PTHREADS
- pthread_mutex_lock(&f->f_un.f_forw.mtxTCPSend);
-# endif
- eState = f->f_un.f_forw.status;
-# ifdef USE_PTHREADS
- pthread_mutex_unlock(&f->f_un.f_forw.mtxTCPSend);
-# endif
-
- return eState;
-}
-
-
-/* Initialize TCP sockets (for sender)
- * This is done once per selector line, if not yet initialized.
- */
-static int TCPSendCreateSocket(selector_t *f)
-{
- int fd;
- struct addrinfo *r;
-
- assert(f != NULL);
-
- r = f->f_un.f_forw.f_addr;
-
- while(r != NULL) {
- fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
- if (fd != -1) {
- /* We can not allow the TCP sender to block syslogd, at least
- * not in a single-threaded design. That would cause rsyslogd to
- * loose input messages - which obviously also would affect
- * other selector lines, too. So we do set it to non-blocking and
- * handle the situation ourselfs (by discarding messages). IF we run
- * dual-threaded, however, the situation is different: in this case,
- * the receivers and the selector line processing are only loosely
- * coupled via a memory buffer. Now, I think, we can afford the extra
- * wait time. Thus, we enable blocking mode for TCP if we compile with
- * pthreads.
- * rgerhards, 2005-10-25
- */
-# ifndef USE_PTHREADS
- /* set to nonblocking - rgerhards 2005-07-20 */
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
-# endif
- if (connect (fd, r->ai_addr, r->ai_addrlen) != 0) {
- if(errno == EINPROGRESS) {
- /* this is normal - will complete during select */
- TCPSendSetStatus(f, TCP_SEND_CONNECTING);
- return fd;
- } else {
- dprintf("create tcp connection failed, reason %s",
- strerror(errno));
- }
-
- }
- else {
- TCPSendSetStatus(f, TCP_SEND_READY);
- return fd;
- }
- close(fd);
- }
- else {
- dprintf("couldn't create send socket, reason %s", strerror(errno));
- }
- r = r->ai_next;
- }
-
- dprintf("no working socket could be obtained");
-
- return -1;
-}
-
-
-/* Sends a TCP message. It is first checked if the
- * session is open and, if not, it is opened. Then the send
- * is tried. If it fails, one silent re-try is made. If the send
- * fails again, an error status (-1) is returned. If all goes well,
- * 0 is returned. The TCP session is NOT torn down.
- * For now, EAGAIN is ignored (causing message loss) - but it is
- * hard to do something intelligent in this case. With this
- * implementation here, we can not block and/or defer. Things are
- * probably a bit better when we move to liblogging. The alternative
- * would be to enhance the current select server with buffering and
- * write descriptors. This seems not justified, given the expected
- * short life span of this code (and the unlikeliness of this event).
- * rgerhards 2005-07-06
- * This function is now expected to stay. Libloging won't be used for
- * that purpose. I have added the param "len", because it is known by the
- * caller and so safes us some time. Also, it MUST be given because there
- * may be NULs inside msg so that we can not rely on strlen(). Please note
- * that the restrictions outlined above do not existin in multi-threaded
- * mode, which we assume will now be most often used. So there is no
- * real issue with the potential message loss in single-threaded builds.
- * rgerhards, 2006-11-30
- *
- * In order to support compressed messages via TCP, we must support an
- * octet-counting based framing (LF may be part of the compressed message).
- * We are now supporting the same mode that is available in IETF I-D
- * syslog-transport-tls-05 (current at the time of this writing). This also
- * eases things when we go ahead and implement that framing. I have now made
- * available two cases where this framing is used: either by explitely
- * specifying it in the config file or implicitely when sending a compressed
- * message. In the later case, compressed and uncompressed messages within
- * the same session have different framings. If it is explicitely set to
- * octet-counting, only this framing mode is used within the session.
- * rgerhards, 2006-12-07
- */
-static int TCPSend(selector_t *f, char *msg, size_t len)
-{
- int retry = 0;
- int done = 0;
- int bIsCompressed;
- int lenSend;
- short f_type;
- char *buf = NULL; /* if this is non-NULL, it MUST be freed before return! */
- enum TCPSendStatus eState;
- TCPFRAMINGMODE framingToUse;
-
- assert(f != NULL);
- assert(msg != NULL);
- assert(len > 0);
-
- bIsCompressed = *msg == 'z'; /* cache this, so that we can modify the message buffer */
- /* select framing for this record. If we have a compressed record, we always need to
- * use octet counting because the data potentially contains all control characters
- * including LF.
- */
- framingToUse = bIsCompressed ? TCP_FRAMING_OCTET_COUNTING : f->f_un.f_forw.tcp_framing;
-
- do { /* try to send message */
- if(f->f_file <= 0) {
- /* we need to open the socket first */
- if((f->f_file = TCPSendCreateSocket(f)) <= 0) {
- return -1;
- }
- }
-
- eState = TCPSendGetStatus(f); /* cache info */
-
- if(eState == TCP_SEND_CONNECTING) {
- /* In this case, we save the buffer. If we have a
- * system with few messages, that hopefully prevents
- * message loss at all. However, we make no further attempts,
- * just the first message is saved. So we only try this
- * if there is not yet a saved message present.
- * rgerhards 2005-07-20
- */
- if(f->f_un.f_forw.savedMsg == NULL) {
- f->f_un.f_forw.savedMsg = malloc(len * sizeof(char));
- if(f->f_un.f_forw.savedMsg == NULL)
- return 0; /* nothing we can do... */
- memcpy(f->f_un.f_forw.savedMsg, msg, len);
- f->f_un.f_forw.savedMsgLen = len;
- }
- return 0;
- } else if(eState != TCP_SEND_READY)
- /* This here is debatable. For the time being, we
- * accept the loss of a single message (e.g. during
- * connection setup in favour of not messing with
- * wait time and timeouts. The reason is that such
- * things might otherwise cost us considerable message
- * loss on the receiving side (even at a timeout set
- * to just 1 second). - rgerhards 2005-07-20
- */
- return 0;
-
- /* now check if we need to add a line terminator. We need to
- * copy the string in memory in this case, this is probably
- * quicker than using writev and definitely quicker than doing
- * two socket calls.
- * rgerhards 2005-07-22
- *//*
- * Some messages already contain a \n character at the end
- * of the message. We append one only if we there is not
- * already one. This seems the best fit, though this also
- * means the message does not arrive unaltered at the final
- * destination. But in the spirit of legacy syslog, this is
- * probably the best to do...
- * rgerhards 2005-07-20
- */
-
- /* Build frame based on selected framing */
- if(framingToUse == TCP_FRAMING_OCTET_STUFFING) {
- if((*(msg+len-1) != '\n')) {
- if(buf != NULL)
- free(buf);
- /* in the malloc below, we need to add 2 to the length. The
- * reason is that we a) add one character and b) len does
- * not take care of the '\0' byte. Up until today, it was just
- * +1 , which caused rsyslogd to sometimes dump core.
- * I have added this comment so that the logic is not accidently
- * changed again. rgerhards, 2005-10-25
- */
- if((buf = malloc((len + 2) * sizeof(char))) == NULL) {
- /* extreme mem shortage, try to solve
- * as good as we can. No point in calling
- * any alarms, they might as well run out
- * of memory (the risk is very high, so we
- * do NOT risk that). If we have a message of
- * more than 1 byte (what I guess), we simply
- * overwrite the last character.
- * rgerhards 2005-07-22
- */
- if(len > 1) {
- *(msg+len-1) = '\n';
- } else {
- /* we simply can not do anything in
- * this case (its an error anyhow...).
- */
- }
- } else {
- /* we got memory, so we can copy the message */
- memcpy(buf, msg, len); /* do not copy '\0' */
- *(buf+len) = '\n';
- *(buf+len+1) = '\0';
- msg = buf; /* use new one */
- ++len; /* care for the \n */
- }
- }
- } else {
- /* Octect-Counting
- * In this case, we need to always allocate a buffer. This is because
- * we need to put a header in front of the message text
- */
- char szLenBuf[16];
- int iLenBuf;
-
- /* important: the printf-mask is "%d<sp>" because there must be a
- * space after the len!
- *//* The chairs of the IETF syslog-sec WG have announced that it is
- * consensus to do the octet count on the SYSLOG-MSG part only. I am
- * now changing the code to reflect this. Hopefully, it will not change
- * once again (there can no compatibility layer programmed for this).
- * To be on the save side, I just comment the code out. I mark these
- * comments with "IETF20061218".
- * rgerhards, 2006-12-19
- */
- iLenBuf = snprintf(szLenBuf, sizeof(szLenBuf)/sizeof(char), "%d ", (int) len);
- /* IETF20061218 iLenBuf =
- snprintf(szLenBuf, sizeof(szLenBuf)/sizeof(char), "%d ", len + iLenBuf);*/
-
- if((buf = malloc((len + iLenBuf) * sizeof(char))) == NULL) {
- /* we are out of memory. This is an extreme situation. We do not
- * call any alarm handlers because they most likely run out of mem,
- * too. We are brave enough to call debug output, though. Other than
- * that, there is nothing left to do. We can not sent the message (as
- * in case of the other framing, because the message is incomplete.
- * We could, however, send two chunks (header and text separate), but
- * that would cause a lot of complexity in the code. So we think it
- * is appropriate enough to just make sure we do not crash in this
- * very unlikely case. For this, it is justified just to loose
- * the message. Rgerhards, 2006-12-07
- */
- dprintf("Error: out of memory when building TCP octet-counted "
- "frame. Message is lost, trying to continue.\n");
- return 0;
- }
-
- memcpy(buf, szLenBuf, iLenBuf); /* header */
- memcpy(buf + iLenBuf, msg, len); /* message */
- len += iLenBuf; /* new message size */
- msg = buf; /* set message buffer */
- }
-
- /* frame building complete, on to actual sending */
-
- lenSend = send(f->f_file, msg, len, 0);
- dprintf("TCP sent %d bytes, requested %d, msg: '%s'\n", lenSend, len,
- bIsCompressed ? "***compressed***" : msg);
- if((unsigned)lenSend == len) {
- /* all well */
- if(buf != NULL) {
- free(buf);
- }
- return 0;
- } else if(lenSend != -1) {
- /* no real error, could "just" not send everything...
- * For the time being, we ignore this...
- * rgerhards, 2005-10-25
- */
- dprintf("message not completely (tcp)send, ignoring %d\n", lenSend);
-# if USE_PTHREADS
- usleep(1000); /* experimental - might be benefitial in this situation */
-# endif
- if(buf != NULL)
- free(buf);
- return 0;
- }
-
- switch(errno) {
- case EMSGSIZE:
- dprintf("message not (tcp)send, too large\n");
- /* This is not a real error, so it is not flagged as one */
- if(buf != NULL)
- free(buf);
- return 0;
- break;
- case EINPROGRESS:
- case EAGAIN:
- dprintf("message not (tcp)send, would block\n");
-# if USE_PTHREADS
- usleep(1000); /* experimental - might be benefitial in this situation */
-# endif
- /* we loose this message, but that's better than loosing
- * all ;)
- */
- /* This is not a real error, so it is not flagged as one */
- if(buf != NULL)
- free(buf);
- return 0;
- break;
- default:
- f_type = f->f_type;
- f->f_type = F_UNUSED;
- logerror("message not (tcp)send");
- f->f_type = f_type;
- break;
- }
-
- if(retry == 0) {
- ++retry;
- /* try to recover */
- close(f->f_file);
- TCPSendSetStatus(f, TCP_SEND_NOTCONNECTED);
- f->f_file = -1;
- } else {
- if(buf != NULL)
- free(buf);
- return -1;
- }
- } while(!done); /* warning: do ... while() */
- /*NOT REACHED*/
-
- if(buf != NULL)
- free(buf);
- return -1; /* only to avoid compiler warning! */
-}
-
-#endif
-/********************************************************************
- * ### END OF SYSLOG/TCP CODE ###
- ********************************************************************/
-
/* get the syslog forward port from selector_t. The passed in
* struct must be one that is setup for forwarding.
@@ -2213,7 +1087,7 @@ static int TCPSend(selector_t *f, char *msg, size_t len)
* We may change the implementation to try to lookup the port
* if it is unspecified. So far, we use the IANA default auf 514.
*/
-static char *getFwdSyslogPt(selector_t *f)
+char *getFwdSyslogPt(selector_t *f)
{
assert(f != NULL);
if(f->f_un.f_forw.port == NULL)
@@ -2237,8 +1111,6 @@ static char *getFwdSyslogPt(selector_t *f)
* DO NOT PUT ANY OTHER CODE IN THIS BEGIN ... END BLOCK!!!!
*/
-#define FALSE 0
-#define TRUE 1
/**
* Parse a 32 bit integer number from a string.
*
@@ -3554,7 +2426,7 @@ static void untty()
* no longer rely just on the source (rfc3195d forwarded messages arrive via
* unix domain sockets but contain the hostname). rgerhards, 2005-10-06
*/
-static void printchopped(char *hname, char *msg, int len, int fd, int bParseHost)
+void printchopped(char *hname, char *msg, int len, int fd, int bParseHost)
{
register int iMsg;
char *pMsg;
@@ -5443,19 +4315,8 @@ again:
*/
void fprintlog(register selector_t *f)
{
- char *psz; /* temporary buffering */
- register unsigned l;
msg_t *pMsgSave; /* to save current message pointer, necessary to restore
it in case it needs to be updated (e.g. repeated msgs) */
-#ifdef SYSLOG_INET
- int i;
- unsigned e, lsent = 0;
- int bSendSuccess;
- time_t fwd_suspend;
- struct addrinfo *res, *r;
- struct addrinfo hints;
-#endif
-
pMsgSave = NULL; /* indicate message poiner not saved */
/* first check if this is a regular message or the repeation of
@@ -5499,169 +4360,13 @@ void fprintlog(register selector_t *f)
dprintf("\n");
break;
-#ifdef SYSLOG_INET
case F_FORW_SUSP:
- fwd_suspend = time(NULL) - f->f_time;
- if ( fwd_suspend >= INET_SUSPEND_TIME ) {
- dprintf("\nForwarding suspension over, retrying FORW ");
- f->f_type = F_FORW;
- goto f_forw;
- }
- else {
- dprintf(" %s\n", f->f_un.f_forw.f_hname);
- dprintf("Forwarding suspension not over, time left: %d.\n",
- INET_SUSPEND_TIME - fwd_suspend);
- }
- break;
-
- /* The trick is to wait some time, then retry to get the
- * address. If that fails retry x times and then give up.
- *
- * You'll run into this problem mostly if the name server you
- * need for resolving the address is on the same machine, but
- * is started after syslogd.
- */
case F_FORW_UNKN:
- /* The remote address is not yet known and needs to be obtained */
- dprintf(" %s\n", f->f_un.f_forw.f_hname);
- fwd_suspend = time(NULL) - f->f_time;
- if(fwd_suspend >= INET_SUSPEND_TIME) {
- dprintf("Forwarding suspension to unknown over, retrying\n");
- memset(&hints, 0, sizeof(hints));
- /* port must be numeric, because config file syntax requests this */
- /* TODO: this code is a duplicate from cfline() - we should later create
- * a common function.
- */
- hints.ai_flags = AI_NUMERICSERV;
- hints.ai_family = family;
- hints.ai_socktype = f->f_un.f_forw.protocol == FORW_UDP ? SOCK_DGRAM : SOCK_STREAM;
- if((e = getaddrinfo(f->f_un.f_forw.f_hname,
- getFwdSyslogPt(f), &hints, &res)) != 0) {
- dprintf("Failure: %s\n", sys_h_errlist[h_errno]);
- dprintf("Retries: %d\n", f->f_prevcount);
- if ( --f->f_prevcount < 0 ) {
- dprintf("Giving up.\n");
- f->f_type = F_UNUSED;
- }
- else
- dprintf("Left retries: %d\n", f->f_prevcount);
- }
- else {
- dprintf("%s found, resuming.\n", f->f_un.f_forw.f_hname);
- f->f_un.f_forw.f_addr = res;
- f->f_prevcount = 0;
- f->f_type = F_FORW;
- goto f_forw;
- }
- }
- else
- dprintf("Forwarding suspension not over, time " \
- "left: %d\n", INET_SUSPEND_TIME - fwd_suspend);
- break;
-
case F_FORW:
- f_forw:
- dprintf(" %s:%s/%s\n", f->f_un.f_forw.f_hname, getFwdSyslogPt(f),
- f->f_un.f_forw.protocol == FORW_UDP ? "udp" : "tcp");
- iovCreate(f);
- if ( strcmp(getHOSTNAME(f->f_pMsg), LocalHostName) && NoHops )
- dprintf("Not sending message to remote.\n");
- else {
- f->f_time = now;
- psz = iovAsString(f);
- l = f->f_iLenpsziov;
- if (l > MAXLINE)
- l = MAXLINE;
-
-# ifdef USE_NETZIP
- /* Check if we should compress and, if so, do it. We also
- * check if the message is large enough to justify compression.
- * The smaller the message, the less likely is a gain in compression.
- * To save CPU cycles, we do not try to compress very small messages.
- * What "very small" means needs to be configured. Currently, it is
- * hard-coded but this may be changed to a config parameter.
- * rgerhards, 2006-11-30
- */
- if(f->f_un.f_forw.compressionLevel && (l > MIN_SIZE_FOR_COMPRESS)) {
- Bytef out[MAXLINE+MAXLINE/100+12] = "z";
- uLongf destLen = sizeof(out) / sizeof(Bytef);
- uLong srcLen = l;
- int ret;
- ret = compress2((Bytef*) out+1, &destLen, (Bytef*) psz,
- srcLen, f->f_un.f_forw.compressionLevel);
- dprintf("Compressing message, length was %d now %d, return state %d.\n",
- l, (int) destLen, ret);
- if(ret != Z_OK) {
- /* if we fail, we complain, but only in debug mode
- * Otherwise, we are silent. In any case, we ignore the
- * failed compression and just sent the uncompressed
- * data, which is still valid. So this is probably the
- * best course of action.
- * rgerhards, 2006-11-30
- */
- dprintf("Compression failed, sending uncompressed message\n");
- } else if(destLen+1 < l) {
- /* only use compression if there is a gain in using it! */
- dprintf("there is gain in compression, so we do it\n");
- psz = (char*) out;
- l = destLen + 1; /* take care for the "z" at message start! */
- }
- ++destLen;
- }
-# endif
-
- if(f->f_un.f_forw.protocol == FORW_UDP) {
- /* forward via UDP */
- if(finet != NULL) {
- /* we need to track if we have success sending to the remote
- * peer. Success is indicated by at least one sendto() call
- * succeeding. We track this be bSendSuccess. We can not simply
- * rely on lsent, as a call might initially work, but a later
- * call fails. Then, lsent has the error status, even though
- * the sendto() succeeded.
- * rgerhards, 2007-06-22
- */
- bSendSuccess = FALSE;
- for (r = f->f_un.f_forw.f_addr; r; r = r->ai_next) {
- for (i = 0; i < *finet; i++) {
- lsent = sendto(finet[i+1], psz, l, 0,
- r->ai_addr, r->ai_addrlen);
- if (lsent == l) {
- bSendSuccess = TRUE;
- break;
- } else {
- int eno = errno;
- dprintf("sendto() error: %d = %s.\n",
- eno, strerror(eno));
- }
- }
- if (lsent == l && !send_to_all)
- break;
- }
- /* finished looping */
- if (bSendSuccess == FALSE) {
- f->f_type = F_FORW_SUSP;
- errno = 0;
- logerror("error forwarding via udp, suspending");
- }
- }
- } else {
- /* forward via TCP */
- if(TCPSend(f, psz, l) != 0) {
- /* error! */
- f->f_type = F_FORW_SUSP;
- errno = 0;
- logerror("error forwarding via tcp, suspending...");
- }
- }
- }
+ doActionFwd(f, now);
break;
-#endif
case F_CONSOLE:
- f->f_time = now;
- /* FALLTHROUGH */
-
case F_TTY:
case F_FILE:
case F_PIPE:
@@ -5721,150 +4426,6 @@ static void reapchild()
errno = saved_errno;
}
-/* Return a printable representation of a host address.
- * Now (2007-07-16) also returns the full host name (if it could be obtained)
- * in the second param [thanks to mildew@gmail.com for the patch].
- * The caller must provide buffer space for pszHost and pszHostFQDN. These
- * buffers must be of size NI_MAXHOST. This is not checked here, because
- * there is no way to check it. We use this way of doing things because it
- * frees us from using dynamic memory allocation where it really does not
- * pay.
- * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats)
- * for some explanation of the code found below. We do by default not
- * discard message where we detected malicouos DNS PTR records. However,
- * there is a user-configurabel option that will tell us if
- * we should abort. For this, the return value tells the caller if the
- * message should be processed (1) or discarded (0).
- */
-static int cvthname(struct sockaddr_storage *f, uchar *pszHost, uchar *pszHostFQDN)
-{
- register uchar *p;
- int count, error;
- sigset_t omask, nmask;
- char ip[NI_MAXHOST];
- struct addrinfo hints, *res;
-
- assert(f != NULL);
- assert(pszHost != NULL);
- assert(pszHostFQDN != NULL);
-
- error = getnameinfo((struct sockaddr *)f, SALEN((struct sockaddr *)f),
- ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
-
- if (error) {
- dprintf("Malformed from address %s\n", gai_strerror(error));
- strcpy((char*) pszHost, "???");
- strcpy((char*) pszHostFQDN, "???");
- return 1;
- }
-
- if (!DisableDNS) {
- sigemptyset(&nmask);
- sigaddset(&nmask, SIGHUP);
- sigprocmask(SIG_BLOCK, &nmask, &omask);
-
- error = getnameinfo((struct sockaddr *)f, sizeof(*f),
- (char*)pszHostFQDN, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
-
- if (error == 0) {
- memset (&hints, 0, sizeof (struct addrinfo));
- hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_DGRAM;
-
- /* we now do a lookup once again. This one should fail,
- * because we should not have obtained a numeric address. If
- * we got a numeric one, someone messed with DNS!
- */
- if (getaddrinfo ((char*)pszHostFQDN, NULL, &hints, &res) == 0) {
- uchar szErrMsg[1024];
- freeaddrinfo (res);
- /* OK, we know we have evil. The question now is what to do about
- * it. One the one hand, the message might probably be intended
- * to harm us. On the other hand, losing the message may also harm us.
- * Thus, the behaviour is controlled by the $DropMsgsWithMaliciousDnsPTRRecords
- * option. If it tells us we should discard, we do so, else we proceed,
- * but log an error message together with it.
- * time being, we simply drop the name we obtained and use the IP - that one
- * is OK in any way. We do also log the error message. rgerhards, 2007-07-16
- */
- if(bDropMalPTRMsgs == 1) {
- snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar),
- "Malicious PTR record, message dropped "
- "IP = \"%s\" HOST = \"%s\"",
- ip, pszHostFQDN);
- logerror((char*)szErrMsg);
- return 0;
- }
-
- /* Please note: we deal with a malicous entry. Thus, we have crafted
- * the snprintf() below so that all text is in front of the entry - maybe
- * it would contain characters that would make the message unreadble
- * (OK, I admit this is more or less impossible, but I am paranoid...)
- * rgerhards, 2007-07-16
- */
- snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar),
- "Malicious PTR record (message accepted, but used IP "
- "instead of PTR name: IP = \"%s\" HOST = \"%s\"",
- ip, pszHostFQDN);
- logerror((char*)szErrMsg);
-
- error = 1; /* that will trigger using IP address below. */
- }
- }
- sigprocmask(SIG_SETMASK, &omask, NULL);
- }
-
- if (error || DisableDNS) {
- dprintf("Host name for your address (%s) unknown\n", ip);
- strcpy((char*) pszHostFQDN, ip);
- strcpy((char*) pszHost, ip);
- return 1;
- }
-
- /* Convert to lower case, just like LocalDomain above
- */
- for (p = pszHostFQDN ; *p ; p++)
- if (isupper((int) *p))
- *p = tolower(*p);
-
- /* OK, the fqdn is now known. Now it is time to extract only the hostname
- * part if we were instructed to do so.
- */
- /* TODO: quick and dirty right now: we need to optimize that. We simply
- * copy over the buffer and then use the old code.
- */
- strcpy((char*)pszHost, (char*)pszHostFQDN);
- if ((p = (uchar*) strchr((char*)pszHost, '.'))) {
- if(strcmp((char*) (p + 1), LocalDomain) == 0) {
- *p = '\0'; /* simply terminate the string */
- return 1;
- } else {
- if (StripDomains) {
- count=0;
- while (StripDomains[count]) {
- if (strcmp((char*)(p + 1), StripDomains[count]) == 0) {
- *p = '\0';
- return 1;
- }
- count++;
- }
- }
- /* TODO: bug in syslogd? That all doesn't make so much sense... rger 2007-07-16 */
- if (LocalHosts) {
- count=0;
- while (LocalHosts[count]) {
- if (!strcmp((char*)pszHost, LocalHosts[count])) {
- *p = '\0';
- return 1;
- }
- count++;
- }
- }
- }
- }
- return 1;
-}
-
/* This method writes mark messages and - some time later - flushes reapeat
* messages.