summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/im3195/im3195.c1
-rw-r--r--plugins/imdiag/imdiag.c5
-rw-r--r--plugins/imfile/imfile.c74
-rw-r--r--plugins/imgssapi/imgssapi.c1
-rw-r--r--plugins/imklog/imklog.c1
-rw-r--r--plugins/immark/immark.c1
-rw-r--r--plugins/impstats/Makefile.am6
-rw-r--r--plugins/impstats/impstats.c229
-rw-r--r--plugins/imptcp/imptcp.c1
-rw-r--r--plugins/imrelp/imrelp.c1
-rw-r--r--plugins/imsolaris/imsolaris.c1
-rw-r--r--plugins/imtcp/imtcp.c1
-rw-r--r--plugins/imtemplate/imtemplate.c1
-rw-r--r--plugins/imudp/Makefile.am2
-rw-r--r--plugins/imudp/imudp.c136
-rw-r--r--plugins/imuxsock/Makefile.am4
-rw-r--r--plugins/imuxsock/imuxsock.c686
-rw-r--r--plugins/omdbalerting/omdbalerting.c1
-rw-r--r--plugins/omgssapi/omgssapi.c1
-rw-r--r--plugins/omhdfs/Makefile.am6
-rw-r--r--plugins/omhdfs/omhdfs.c476
-rw-r--r--plugins/omlibdbi/omlibdbi.c1
-rw-r--r--plugins/ommail/ommail.c1
-rw-r--r--plugins/ommysql/ommysql.c40
-rw-r--r--plugins/omoracle/omoracle.c20
-rw-r--r--plugins/ompgsql/ompgsql.c1
-rw-r--r--plugins/omprog/omprog.c1
-rw-r--r--plugins/omrelp/omrelp.c1
-rw-r--r--plugins/omruleset/omruleset.c1
-rw-r--r--plugins/omsnmp/omsnmp.c1
-rw-r--r--plugins/omstdout/omstdout.c1
-rw-r--r--plugins/omtemplate/omtemplate.c1
-rw-r--r--plugins/omtesting/omtesting.c1
-rw-r--r--plugins/omudpspoof/omudpspoof.c1
-rw-r--r--plugins/omuxsock/omuxsock.c1
-rw-r--r--plugins/pmaixforwardedfrom/Makefile.am8
-rw-r--r--plugins/pmaixforwardedfrom/pmaixforwardedfrom.c167
-rw-r--r--plugins/pmcisconames/Makefile.am8
-rw-r--r--plugins/pmcisconames/pmcisconames.c178
-rw-r--r--plugins/pmlastmsg/pmlastmsg.c1
-rw-r--r--plugins/pmrfc3164sd/pmrfc3164sd.c1
-rw-r--r--plugins/pmsnare/Makefile.am8
-rw-r--r--plugins/pmsnare/pmsnare.c239
43 files changed, 2199 insertions, 118 deletions
diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c
index 106da2c8..156524c9 100644
--- a/plugins/im3195/im3195.c
+++ b/plugins/im3195/im3195.c
@@ -51,6 +51,7 @@
#include "errmsg.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* Module static data */
DEF_IMOD_STATIC_DATA
diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c
index 81b357ef..0a69ee43 100644
--- a/plugins/imdiag/imdiag.c
+++ b/plugins/imdiag/imdiag.c
@@ -57,6 +57,7 @@
#include "net.h" /* for permittedPeers, may be removed when this is removed */
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* static data */
DEF_IMOD_STATIC_DATA
@@ -291,6 +292,7 @@ OnMsgReceived(tcps_sess_t *pSess, uchar *pRcv, int iLenMsg)
{
int iMsgQueueSize;
uchar *pszMsg;
+ uchar *pToFree = NULL;
uchar cmdBuf[1024];
DEFiRet;
@@ -302,6 +304,7 @@ OnMsgReceived(tcps_sess_t *pSess, uchar *pRcv, int iLenMsg)
* before proceeding.
*/
CHKmalloc(pszMsg = MALLOC(sizeof(uchar) * (iLenMsg + 1)));
+ pToFree = pszMsg;
memcpy(pszMsg, pRcv, iLenMsg);
pszMsg[iLenMsg] = '\0';
@@ -321,6 +324,8 @@ OnMsgReceived(tcps_sess_t *pSess, uchar *pRcv, int iLenMsg)
}
finalize_it:
+ if(pToFree != NULL)
+ free(pToFree);
RETiRet;
}
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 686fa048..acb58dad 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -48,8 +48,10 @@
#include "unicode-helper.h"
#include "prop.h"
#include "stringbuf.h"
+#include "ruleset.h"
MODULE_TYPE_INPUT /* must be present for input modules, do not remove */
+MODULE_TYPE_NOKEEP
/* defines */
@@ -60,6 +62,7 @@ DEFobjCurrIf(glbl)
DEFobjCurrIf(datetime)
DEFobjCurrIf(strm)
DEFobjCurrIf(prop)
+DEFobjCurrIf(ruleset)
typedef struct fileInfo_s {
uchar *pszFileName;
@@ -71,6 +74,8 @@ typedef struct fileInfo_s {
int nRecords; /**< How many records did we process before persisting the stream? */
int iPersistStateInterval; /**< how often should state be persisted? (0=on close only) */
strm_t *pStrm; /* its stream (NULL if not assigned) */
+ int readMode; /* which mode to use in ReadMulteLine call? */
+ ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */
} fileInfo_t;
@@ -85,6 +90,8 @@ static int iPollInterval = 10; /* number of seconds to sleep when there was no f
static int iPersistStateInterval = 0; /* how often if state file to be persisted? (default 0->never) */
static int iFacility = 128; /* local0 */
static int iSeverity = 5; /* notice, as of rfc 3164 */
+static int readMode = 0; /* mode to use for ReadMultiLine call */
+static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
static int iFilPtr = 0; /* number of files to be monitored; pointer to next free spot during config */
#define MAX_INPUT_FILES 100
@@ -114,6 +121,7 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine)
MsgSetTAG(pMsg, pInfo->pszTag, pInfo->lenTag);
pMsg->iFacility = LOG_FAC(pInfo->iFacility);
pMsg->iSeverity = LOG_PRI(pInfo->iSeverity);
+ MsgSetRuleset(pMsg, pInfo->pRuleset);
CHKiRet(submitMsg(pMsg));
finalize_it:
RETiRet;
@@ -211,8 +219,8 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData)
}
/* loop below will be exited when strmReadLine() returns EOF */
- while(1) {
- CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr));
+ while(glbl.GetGlobalInputTermState() == 0) {
+ CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr, pThis->readMode));
*pbHadFileData = 1; /* this is just a flag, so set it and forget it */
CHKiRet(enqLine(pThis, pCStr)); /* process line */
rsCStrDestruct(&pCStr); /* discard string (must be done by us!) */
@@ -287,23 +295,24 @@ BEGINrunInput
int bHadFileData; /* were there at least one file with data during this run? */
CODESTARTrunInput
pthread_cleanup_push(inputModuleCleanup, NULL);
- while(1) {
-
+ while(glbl.GetGlobalInputTermState() == 0) {
do {
bHadFileData = 0;
for(i = 0 ; i < iFilPtr ; ++i) {
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
pollFile(&files[i], &bHadFileData);
}
- } while(iFilPtr > 1 && bHadFileData == 1); /* warning: do...while()! */
+ } while(iFilPtr > 1 && bHadFileData == 1 && glbl.GetGlobalInputTermState() == 0); /* warning: do...while()! */
/* Note: the additional 10ns wait is vitally important. It guards rsyslog against totally
* hogging the CPU if the users selects a polling interval of 0 seconds. It doesn't hurt any
* other valid scenario. So do not remove. -- rgerhards, 2008-02-14
*/
- srSleep(iPollInterval, 10);
-
+ if(glbl.GetGlobalInputTermState() == 0)
+ srSleep(iPollInterval, 10);
}
- /*NOTREACHED*/
+ DBGPRINTF("imfile: terminating upon request of rsyslog core\n");
pthread_cleanup_pop(0); /* just for completeness, but never called... */
RETiRet; /* use it to make sure the housekeeping is done! */
@@ -353,7 +362,7 @@ persistStrmState(fileInfo_t *pInfo)
/* TODO: create a function persistObj in obj.c? */
CHKiRet(strm.Construct(&psSF));
- lenDir = strlen((char*)glbl.GetWorkDir());
+ lenDir = ustrlen(glbl.GetWorkDir());
if(lenDir > 0)
CHKiRet(strm.SetDir(psSF, glbl.GetWorkDir(), lenDir));
CHKiRet(strm.SettOperationsMode(psSF, STREAMMODE_WRITE_TRUNC));
@@ -396,6 +405,13 @@ CODESTARTafterRun
ENDafterRun
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
/* The following entry points are defined in module-template.h.
* In general, they need to be present, but you do NOT need to provide
* any code here.
@@ -408,12 +424,14 @@ CODESTARTmodExit
objRelease(glbl, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
ENDqueryEtryPt
@@ -447,6 +465,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
iPollInterval = 10;
iFacility = 128; /* local0 */
iSeverity = 5; /* notice, as of rfc 3164 */
+ readMode = 0;
+ pBindRuleset = NULL;
RETiRet;
}
@@ -488,6 +508,10 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal)
pThis->iSeverity = iSeverity;
pThis->iFacility = iFacility;
pThis->iPersistStateInterval = iPersistStateInterval;
+ pThis->nRecords = 0;
+ pThis->readMode = readMode;
+ pThis->pRuleset = pBindRuleset;
+ iPersistStateInterval = 0;
} else {
errmsg.LogError(0, RS_RET_OUT_OF_DESRIPTORS, "Too many file monitors configured - ignoring this one");
ABORT_FINALIZE(RS_RET_OUT_OF_DESRIPTORS);
@@ -502,6 +526,29 @@ finalize_it:
RETiRet;
}
+
+/* accept a new ruleset to bind. Checks if it exists and complains, if not */
+static rsRetVal
+setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ ruleset_t *pRuleset;
+ rsRetVal localRet;
+ DEFiRet;
+
+ localRet = ruleset.GetRuleset(&pRuleset, pszName);
+ if(localRet == RS_RET_NOT_FOUND) {
+ errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName);
+ }
+ CHKiRet(localRet);
+ pBindRuleset = pRuleset;
+ DBGPRINTF("imfile current bind ruleset %p: '%s'\n", pRuleset, pszName);
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
/* modInit() is called once the module is loaded. It must perform all module-wide
* initialization tasks. There are also a number of housekeeping tasks that the
* framework requires. These are handled by the macros. Please note that the
@@ -519,8 +566,10 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(strm, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
CHKiRet(objUse(prop, CORE_COMPONENT));
+ DBGPRINTF("imfile: version %s initializing\n", VERSION);
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilename", 0, eCmdHdlrGetWord,
NULL, &pszFileName, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfiletag", 0, eCmdHdlrGetWord,
@@ -533,9 +582,12 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &iFacility, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt,
NULL, &iPollInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilereadmode", 0, eCmdHdlrInt,
+ NULL, &readMode, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepersiststateinterval", 0, eCmdHdlrInt,
-
- NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID));
+ NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilebindruleset", 0, eCmdHdlrGetWord,
+ setRuleset, NULL, STD_LOADABLE_MODULE_ID));
/* that command ads a new file! */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrunfilemonitor", 0, eCmdHdlrGetWord,
addMonitor, NULL, STD_LOADABLE_MODULE_ID));
diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c
index dd3d67e3..446795d6 100644
--- a/plugins/imgssapi/imgssapi.c
+++ b/plugins/imgssapi/imgssapi.c
@@ -62,6 +62,7 @@
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* defines */
#define ALLOWEDMETHOD_GSS 2
diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c
index c59ce04f..69c8cd1a 100644
--- a/plugins/imklog/imklog.c
+++ b/plugins/imklog/imklog.c
@@ -58,6 +58,7 @@
#include "unicode-helper.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* Module static data */
DEF_IMOD_STATIC_DATA
diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c
index 5d48369e..6410003d 100644
--- a/plugins/immark/immark.c
+++ b/plugins/immark/immark.c
@@ -46,6 +46,7 @@
#include "glbl.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* defines */
#define DEFAULT_MARK_PERIOD (20 * 60)
diff --git a/plugins/impstats/Makefile.am b/plugins/impstats/Makefile.am
new file mode 100644
index 00000000..187bbca4
--- /dev/null
+++ b/plugins/impstats/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = impstats.la
+
+impstats_la_SOURCES = impstats.c
+impstats_la_CPPFLAGS = $(RSRT_CFLAGS) -I$(top_srcdir) $(PTHREADS_CFLAGS)
+impstats_la_LDFLAGS = -module -avoid-version
+impstats_la_LIBADD =
diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c
new file mode 100644
index 00000000..aa98ae9d
--- /dev/null
+++ b/plugins/impstats/impstats.c
@@ -0,0 +1,229 @@
+/* impstats.c
+ * A module to periodically output statistics gathered by rsyslog.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c)
+ * This file is under development and has not yet arrived at being fully
+ * self-contained and a real object. So far, it is mostly an excerpt
+ * of the "old" message code without any modifications. However, it
+ * helps to have things at the right place one we go to the meat of it.
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include "dirty.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "msg.h"
+#include "srUtils.h"
+#include "unicode-helper.h"
+#include "glbl.h"
+#include "statsobj.h"
+#include "prop.h"
+
+MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
+
+/* defines */
+#define DEFAULT_STATS_PERIOD (5 * 60)
+#define DEFAULT_FACILITY 5 /* syslog */
+#define DEFAULT_SEVERITY 6 /* info */
+
+/* Module static data */
+DEF_IMOD_STATIC_DATA
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(prop)
+DEFobjCurrIf(statsobj)
+DEFobjCurrIf(errmsg)
+
+typedef struct configSettings_s {
+ int iStatsInterval;
+ int iFacility;
+ int iSeverity;
+} configSettings_t;
+
+static configSettings_t cs;
+
+static prop_t *pInputName = NULL;
+static prop_t *pLocalHostIP = NULL;
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURENonCancelInputTermination)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+static inline void
+initConfigSettings(void)
+{
+ cs.iStatsInterval = DEFAULT_STATS_PERIOD;
+ cs.iFacility = DEFAULT_FACILITY;
+ cs.iSeverity = DEFAULT_SEVERITY;
+}
+
+
+/* actually submit a message to the rsyslog core
+ */
+static inline rsRetVal
+doSubmitMsg(uchar *line)
+{
+ msg_t *pMsg;
+ DEFiRet;
+
+ CHKiRet(msgConstruct(&pMsg));
+ MsgSetInputName(pMsg, pInputName);
+ MsgSetRawMsgWOSize(pMsg, (char*)line);
+ MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
+ MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
+ MsgSetRcvFromIP(pMsg, pLocalHostIP);
+ MsgSetMSGoffs(pMsg, 0);
+ MsgSetTAG(pMsg, UCHAR_CONSTANT("rsyslogd-pstats:"), sizeof("rsyslogd-pstats:") - 1);
+ pMsg->iFacility = cs.iFacility;
+ pMsg->iSeverity = cs.iSeverity;
+ pMsg->msgFlags = 0;
+
+ submitMsg(pMsg);
+
+finalize_it:
+ RETiRet;
+
+}
+
+
+/* callback for statsobj
+ * Note: usrptr exists only to satisfy requirements of statsobj callback interface!
+ */
+static rsRetVal
+doStatsLine(void __attribute__((unused)) *usrptr, cstr_t *cstr)
+{
+ DEFiRet;
+ doSubmitMsg(rsCStrGetSzStrNoNULL(cstr));
+ RETiRet;
+}
+
+
+/* the function to generate the actual statistics messages
+ * rgerhards, 2010-09-09
+ */
+static inline void
+generateStatsMsgs(void)
+{
+ statsobj.GetAllStatsLines(doStatsLine, NULL);
+}
+
+
+BEGINrunInput
+CODESTARTrunInput
+ /* this is an endless loop - it is terminated when the thread is
+ * signalled to do so. This, however, is handled by the framework,
+ * right into the sleep below.
+ */
+ while(1) {
+ srSleep(cs.iStatsInterval, 0); /* seconds, micro seconds */
+
+ if(glbl.GetGlobalInputTermState() == 1)
+ break; /* terminate input! */
+
+ generateStatsMsgs();
+ }
+ENDrunInput
+
+
+BEGINwillRun
+ rsRetVal localRet;
+CODESTARTwillRun
+ DBGPRINTF("impstats: stats interval %d seconds\n", cs.iStatsInterval);
+ if(cs.iStatsInterval == 0)
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ localRet = statsobj.EnableStats();
+ if(localRet != RS_RET_OK) {
+ errmsg.LogError(0, localRet, "impstat: error enabling statistics gathering");
+ ABORT_FINALIZE(RS_RET_NO_RUN);
+ }
+finalize_it:
+ENDwillRun
+
+
+BEGINafterRun
+CODESTARTafterRun
+ENDafterRun
+
+
+BEGINmodExit
+CODESTARTmodExit
+ prop.Destruct(&pInputName);
+ prop.Destruct(&pLocalHostIP);
+ /* release objects we used */
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(prop, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(statsobj, CORE_COMPONENT);
+ENDmodExit
+
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_IMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ initConfigSettings();
+ return RS_RET_OK;
+}
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ DBGPRINTF("impstats version %s loading\n", VERSION);
+ initConfigSettings();
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(statsobj, CORE_COMPONENT));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatsinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatfacility", 0, eCmdHdlrInt, NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatseverity", 0, eCmdHdlrInt, NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+
+ CHKiRet(prop.Construct(&pInputName));
+ CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("impstats"), sizeof("impstats") - 1));
+ CHKiRet(prop.ConstructFinalize(pInputName));
+
+ CHKiRet(prop.Construct(&pLocalHostIP));
+ CHKiRet(prop.SetString(pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1));
+ CHKiRet(prop.ConstructFinalize(pLocalHostIP));
+ENDmodInit
+/* vi:set ai:
+ */
diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c
index 6449ad62..3197564e 100644
--- a/plugins/imptcp/imptcp.c
+++ b/plugins/imptcp/imptcp.c
@@ -73,6 +73,7 @@
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* static data */
DEF_IMOD_STATIC_DATA
diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c
index 9be38f8f..13fd4428 100644
--- a/plugins/imrelp/imrelp.c
+++ b/plugins/imrelp/imrelp.c
@@ -47,6 +47,7 @@
#include "prop.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* static data */
DEF_IMOD_STATIC_DATA
diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c
index f801833b..ee9ec5c6 100644
--- a/plugins/imsolaris/imsolaris.c
+++ b/plugins/imsolaris/imsolaris.c
@@ -85,6 +85,7 @@
#include "sun_cddl.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* defines */
#define PATH_LOG "/dev/log"
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 0cfae057..d3e9cabe 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -65,6 +65,7 @@
#include "net.h" /* for permittedPeers, may be removed when this is removed */
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* static data */
DEF_IMOD_STATIC_DATA
diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c
index e5e43025..0e2cac11 100644
--- a/plugins/imtemplate/imtemplate.c
+++ b/plugins/imtemplate/imtemplate.c
@@ -80,6 +80,7 @@
#include "debug.h" /* some debug helper functions */
MODULE_TYPE_INPUT /* must be present for input modules, do not remove */
+MODULE_TYPE_NOKEEP
/* defines */
diff --git a/plugins/imudp/Makefile.am b/plugins/imudp/Makefile.am
index 517b1287..bc64b8c8 100644
--- a/plugins/imudp/Makefile.am
+++ b/plugins/imudp/Makefile.am
@@ -3,4 +3,4 @@ pkglib_LTLIBRARIES = imudp.la
imudp_la_SOURCES = imudp.c
imudp_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
imudp_la_LDFLAGS = -module -avoid-version
-imudp_la_LIBADD =
+imudp_la_LIBADD = $(IMUDP_LIBS)
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 99b69731..56cdab28 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -35,6 +35,9 @@
#if HAVE_SYS_EPOLL_H
# include <sys/epoll.h>
#endif
+#ifdef HAVE_SCHED_H
+# include <sched.h>
+#endif
#include "rsyslog.h"
#include "dirty.h"
#include "net.h"
@@ -51,6 +54,7 @@
#include "unicode-helper.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* defines */
@@ -78,12 +82,103 @@ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a
* termination if we can not get it. -- rgerhards, 2007-12-27
*/
static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */
+static uchar *pszSchedPolicy = NULL; /* scheduling policy string */
+static int iSchedPolicy; /* scheduling policy as SCHED_xxx */
+static int iSchedPrio; /* scheduling priority */
+static int seen_iSchedPrio = 0; /* have we seen scheduling priority in the config file? */
static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */
#define TIME_REQUERY_DFLT 2
static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */
/* config settings */
+static rsRetVal check_scheduling_priority(int report_error)
+{
+ DEFiRet;
+
+#ifdef HAVE_SCHED_GET_PRIORITY_MAX
+ if (iSchedPrio < sched_get_priority_min(iSchedPolicy) ||
+ iSchedPrio > sched_get_priority_max(iSchedPolicy)) {
+ if (report_error)
+ errmsg.LogError(errno, NO_ERRCODE,
+ "imudp: scheduling priority %d out of range (%d - %d)"
+ " for scheduling policy '%s' - ignoring settings",
+ iSchedPrio,
+ sched_get_priority_min(iSchedPolicy),
+ sched_get_priority_max(iSchedPolicy),
+ pszSchedPolicy);
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+ }
+#endif
+
+finalize_it:
+ RETiRet;
+}
+
+/* Set scheduling priority in the supplied variable (will be iSchedPrio)
+ * and record that we have seen the directive (in seen_iSchedPrio).
+ */
+static rsRetVal set_scheduling_priority(void *pVal, int value)
+{
+ DEFiRet;
+
+ if (seen_iSchedPrio) {
+ errmsg.LogError(0, NO_ERRCODE, "directive already seen");
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+ }
+ *(int *)pVal = value;
+ seen_iSchedPrio = 1;
+ if (pszSchedPolicy != NULL)
+ CHKiRet(check_scheduling_priority(1));
+
+finalize_it:
+ RETiRet;
+}
+
+/* Set scheduling policy in iSchedPolicy */
+static rsRetVal set_scheduling_policy(void *pVal, uchar *pNewVal)
+{
+ int have_sched_policy = 0;
+ DEFiRet;
+
+ if (pszSchedPolicy != NULL) {
+ errmsg.LogError(0, NO_ERRCODE, "directive already seen");
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+ }
+ *((uchar**)pVal) = pNewVal; /* pVal is pszSchedPolicy */
+ if (0) { /* trick to use conditional compilation */
+#ifdef SCHED_FIFO
+ } else if (!strcasecmp((char*)pszSchedPolicy, "fifo")) {
+ iSchedPolicy = SCHED_FIFO;
+ have_sched_policy = 1;
+#endif
+#ifdef SCHED_RR
+ } else if (!strcasecmp((char*)pszSchedPolicy, "rr")) {
+ iSchedPolicy = SCHED_RR;
+ have_sched_policy = 1;
+#endif
+#ifdef SCHED_OTHER
+ } else if (!strcasecmp((char*)pszSchedPolicy, "other")) {
+ iSchedPolicy = SCHED_OTHER;
+ have_sched_policy = 1;
+#endif
+ } else {
+ errmsg.LogError(errno, NO_ERRCODE,
+ "imudp: invalid scheduling policy '%s' "
+ "- ignoring setting", pszSchedPolicy);
+ }
+ if (have_sched_policy == 0) {
+ free(pszSchedPolicy);
+ pszSchedPolicy = NULL;
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+ }
+ if (seen_iSchedPrio)
+ CHKiRet(check_scheduling_priority(1));
+
+finalize_it:
+ RETiRet;
+}
+
/* This function is called when a new listener shall be added. It takes
* the configured parameters, tries to bind the socket and, if that
@@ -294,6 +389,41 @@ finalize_it:
RETiRet;
}
+static void set_thread_schedparam(void)
+{
+ struct sched_param sparam;
+
+ if (pszSchedPolicy != NULL && seen_iSchedPrio == 0) {
+ errmsg.LogError(0, NO_ERRCODE,
+ "imudp: scheduling policy set, but without priority - ignoring settings");
+ } else if (pszSchedPolicy == NULL && seen_iSchedPrio != 0) {
+ errmsg.LogError(0, NO_ERRCODE,
+ "imudp: scheduling priority set, but without policy - ignoring settings");
+ } else if (pszSchedPolicy != NULL && seen_iSchedPrio != 0 &&
+ check_scheduling_priority(0) == 0) {
+#ifndef HAVE_PTHREAD_SETSCHEDPARAM
+ errmsg.LogError(0, NO_ERRCODE,
+ "imudp: cannot set thread scheduling policy, "
+ "pthread_setschedparam() not available");
+#else
+ int err;
+
+ memset(&sparam, 0, sizeof sparam);
+ sparam.sched_priority = iSchedPrio;
+ dbgprintf("imudp trying to set sched policy to '%s', prio %d\n",
+ pszSchedPolicy, iSchedPrio);
+ err = pthread_setschedparam(pthread_self(), iSchedPolicy, &sparam);
+ if (err != 0) {
+ errmsg.LogError(err, NO_ERRCODE, "imudp: pthread_setschedparam() failed");
+ }
+#endif
+ }
+
+ if (pszSchedPolicy != NULL) {
+ free(pszSchedPolicy);
+ pszSchedPolicy = NULL;
+ }
+}
/* This function implements the main reception loop. Depending on the environment,
* we either use the traditional (but slower) select() or the Linux-specific epoll()
@@ -317,6 +447,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
/* start "name caching" algo by making sure the previous system indicator
* is invalidated.
*/
+ set_thread_schedparam();
bIsPermitted = 0;
memset(&frominetPrev, 0, sizeof(frominetPrev));
@@ -384,6 +515,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd)
/* start "name caching" algo by making sure the previous system indicator
* is invalidated.
*/
+ set_thread_schedparam();
bIsPermitted = 0;
memset(&frominetPrev, 0, sizeof(frominetPrev));
DBGPRINTF("imudp uses select()\n");
@@ -539,6 +671,10 @@ CODEmodInit_QueryRegCFSLineHdlr
addListner, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord,
NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord,
+ &set_scheduling_policy, &pszSchedPolicy, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt,
+ &set_scheduling_priority, &iSchedPrio, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt,
NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
diff --git a/plugins/imuxsock/Makefile.am b/plugins/imuxsock/Makefile.am
index a2fe0baa..34a0ad9a 100644
--- a/plugins/imuxsock/Makefile.am
+++ b/plugins/imuxsock/Makefile.am
@@ -1,6 +1,6 @@
pkglib_LTLIBRARIES = imuxsock.la
imuxsock_la_SOURCES = imuxsock.c
-imuxsock_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
+imuxsock_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -I../../runtime/hashtable -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS)
imuxsock_la_LDFLAGS = -module -avoid-version
-imuxsock_la_LIBADD =
+imuxsock_la_LIBADD = $(RSRT_LIBS)
diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c
index 046f12f0..86393ba6 100644
--- a/plugins/imuxsock/imuxsock.c
+++ b/plugins/imuxsock/imuxsock.c
@@ -6,7 +6,7 @@
*
* File begun on 2007-12-20 by RGerhards (extracted from syslogd.c)
*
- * Copyright 2007-2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2010 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -29,12 +29,14 @@
#include "rsyslog.h"
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/un.h>
+#include <sys/socket.h>
#include "dirty.h"
#include "cfsysline.h"
#include "unicode-helper.h"
@@ -44,14 +46,20 @@
#include "net.h"
#include "glbl.h"
#include "msg.h"
+#include "parser.h"
#include "prop.h"
#include "debug.h"
#include "unlimited_select.h"
+#include "sd-daemon.h"
+#include "statsobj.h"
+#include "datetime.h"
+#include "hashtable.h"
MODULE_TYPE_INPUT
+MODULE_TYPE_NOKEEP
/* defines */
-#define MAXFUNIX 20
+#define MAXFUNIX 50
#ifndef _PATH_LOG
#ifdef BSD
#define _PATH_LOG "/var/run/log"
@@ -60,6 +68,10 @@ MODULE_TYPE_INPUT
#endif
#endif
+/* emulate struct ucred for platforms that do not have it */
+#ifndef HAVE_SCM_CREDENTIALS
+struct ucred { int pid; };
+#endif
/* handle some defines missing on more than one platform */
#ifndef SUN_LEN
@@ -71,30 +83,157 @@ DEF_IMOD_STATIC_DATA
DEFobjCurrIf(errmsg)
DEFobjCurrIf(glbl)
DEFobjCurrIf(prop)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+DEFobjCurrIf(statsobj)
+
+statsobj_t *modStats;
+STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit)
+STATSCOUNTER_DEF(ctrLostRatelimit, mutCtrLostRatelimit)
+STATSCOUNTER_DEF(ctrNumRatelimiters, mutCtrNumRatelimiters)
+
+struct rs_ratelimit_state {
+ unsigned short interval;
+ unsigned short burst;
+ unsigned done;
+ unsigned missed;
+ time_t begin;
+};
+typedef struct rs_ratelimit_state rs_ratelimit_state_t;
+
+
+/* a very simple "hash function" for process IDs - we simply use the
+ * pid itself: it is quite expected that all pids may log some time, but
+ * from a collision point of view it is likely that long-running daemons
+ * start early and so will stay right in the top spots of the
+ * collision list.
+ */
+static unsigned int
+hash_from_key_fn(void *k)
+{
+ return((unsigned) *((pid_t*) k));
+}
+
+static int
+key_equals_fn(void *key1, void *key2)
+{
+ return *((pid_t*) key1) == *((pid_t*) key2);
+}
+
+
+/* structure to describe a specific listener */
+typedef struct lstn_s {
+ uchar *sockName; /* read-only after startup */
+ prop_t *hostName; /* host-name override - if set, use this instead of actual name */
+ int fd; /* read-only after startup */
+ int flags; /* should parser parse host name? read-only after startup */
+ int flowCtl; /* flow control settings for this socket */
+ int ratelimitInterval;
+ int ratelimitBurst;
+ intTiny ratelimitSev; /* severity level (and below) for which rate-limiting shall apply */
+ struct hashtable *ht; /* our hashtable for rate-limiting */
+ sbool bParseHost; /* should parser parse host name? read-only after startup */
+ sbool bCreatePath; /* auto-creation of socket directory? */
+ sbool bUseCreds; /* pull original creator credentials from socket */
+ sbool bWritePid; /* write original PID into tag */
+} lstn_t;
+static lstn_t listeners[MAXFUNIX];
static prop_t *pLocalHostIP = NULL; /* there is only one global IP for all internally-generated messages */
static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */
-static int startIndexUxLocalSockets; /* process funix from that index on (used to
+static int startIndexUxLocalSockets; /* process fd from that index on (used to
* suppress local logging. rgerhards 2005-08-01
* read-only after startup
*/
-static int funixParseHost[MAXFUNIX] = { 0, }; /* should parser parse host name? read-only after startup */
-static int funixFlags[MAXFUNIX] = { IGNDATE, }; /* should parser parse host name? read-only after startup */
-static int funixCreateSockPath[MAXFUNIX] = { 0, }; /* auto-creation of socket directory? */
-static uchar *funixn[MAXFUNIX] = { (uchar*) _PATH_LOG }; /* read-only after startup */
-static prop_t *funixHName[MAXFUNIX] = { NULL, }; /* host-name override - if set, use this instead of actual name */
-static int funixFlowCtl[MAXFUNIX] = { eFLOWCTL_NO_DELAY, }; /* flow control settings for this socket */
-static int funix[MAXFUNIX] = { -1, }; /* read-only after startup */
-static int nfunix = 1; /* number of Unix sockets open / read-only after startup */
+static int nfd = 1; /* number of Unix sockets open / read-only after startup */
+static int sd_fds = 0; /* number of systemd activated sockets */
/* config settings */
static int bOmitLocalLogging = 0;
static uchar *pLogSockName = NULL;
static uchar *pLogHostName = NULL; /* host name to use with this socket */
static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */
-static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */
-#define DFLT_bCreateSockPath 0
-static int bCreateSockPath = DFLT_bCreateSockPath; /* auto-create socket path? */
+static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */
+static int bWritePid = 0; /* use credentials from recvmsg() and fixup PID in TAG */
+static int bWritePidSysSock = 0; /* use credentials from recvmsg() and fixup PID in TAG */
+#define DFLT_bCreatePath 0
+static int bCreatePath = DFLT_bCreatePath; /* auto-create socket path? */
+#define DFLT_ratelimitInterval 5
+static int ratelimitInterval = DFLT_ratelimitInterval; /* interval in seconds, 0 = off */
+static int ratelimitIntervalSysSock = DFLT_ratelimitInterval;
+#define DFLT_ratelimitBurst 200
+static int ratelimitBurst = DFLT_ratelimitBurst; /* max nbr of messages in interval */
+static int ratelimitBurstSysSock = DFLT_ratelimitBurst; /* max nbr of messages in interval */
+#define DFLT_ratelimitSeverity 1 /* do not rate-limit emergency messages */
+static int ratelimitSeverity = DFLT_ratelimitSeverity;
+static int ratelimitSeveritySysSock = DFLT_ratelimitSeverity;
+
+
+
+static void
+initRatelimitState(struct rs_ratelimit_state *rs, unsigned short interval, unsigned short burst)
+{
+ rs->interval = interval;
+ rs->burst = burst;
+ rs->done = 0;
+ rs->missed = 0;
+ rs->begin = 0;
+}
+
+
+/* ratelimiting support, modelled after the linux kernel
+ * returns 1 if message is within rate limit and shall be
+ * processed, 0 otherwise.
+ * This implementation is NOT THREAD-SAFE and must not
+ * be called concurrently.
+ */
+static inline int
+withinRatelimit(struct rs_ratelimit_state *rs, time_t tt, pid_t pid)
+{
+ int ret;
+ uchar msgbuf[1024];
+
+ if(rs->interval == 0) {
+ ret = 1;
+ goto finalize_it;
+ }
+
+ assert(rs->burst != 0);
+
+ if(rs->begin == 0)
+ rs->begin = tt;
+
+ /* resume if we go out of out time window */
+ if(tt > rs->begin + rs->interval) {
+ if(rs->missed) {
+ snprintf((char*)msgbuf, sizeof(msgbuf),
+ "imuxsock lost %u messages from pid %lu due to rate-limiting",
+ rs->missed, (unsigned long) pid);
+ logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0);
+ rs->missed = 0;
+ }
+ rs->begin = 0;
+ rs->done = 0;
+ }
+
+ /* do actual limit check */
+ if(rs->burst > rs->done) {
+ rs->done++;
+ ret = 1;
+ } else {
+ if(rs->missed == 0) {
+ snprintf((char*)msgbuf, sizeof(msgbuf),
+ "imuxsock begins to drop messages from pid %lu due to rate-limiting",
+ (unsigned long) pid);
+ logmsgInternal(RS_RET_RATE_LIMITED, LOG_SYSLOG|LOG_INFO, msgbuf, 0);
+ }
+ rs->missed++;
+ ret = 0;
+ }
+
+finalize_it:
+ return ret;
+}
/* set the timestamp ignore / not ignore option for the system
@@ -104,7 +243,7 @@ static int bCreateSockPath = DFLT_bCreateSockPath; /* auto-create socket path? *
static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal, int iNewVal)
{
DEFiRet;
- funixFlags[0] = iNewVal ? IGNDATE : NOFLAG;
+ listeners[0].flags = iNewVal ? IGNDATE : NOFLAG;
RETiRet;
}
@@ -113,7 +252,7 @@ static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal,
static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal)
{
DEFiRet;
- funixFlowCtl[0] = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+ listeners[0].flowCtl = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
RETiRet;
}
@@ -130,26 +269,40 @@ addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
DEFiRet;
- if(nfunix < MAXFUNIX) {
+ if(nfd < MAXFUNIX) {
if(*pNewVal == ':') {
- funixParseHost[nfunix] = 1;
+ listeners[nfd].bParseHost = 1;
} else {
- funixParseHost[nfunix] = 0;
+ listeners[nfd].bParseHost = 0;
}
- CHKiRet(prop.Construct(&(funixHName[nfunix])));
+ CHKiRet(prop.Construct(&(listeners[nfd].hostName)));
if(pLogHostName == NULL) {
- CHKiRet(prop.SetString(funixHName[nfunix], glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())));
+ CHKiRet(prop.SetString(listeners[nfd].hostName, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())));
} else {
- CHKiRet(prop.SetString(funixHName[nfunix], pLogHostName, ustrlen(pLogHostName)));
+ CHKiRet(prop.SetString(listeners[nfd].hostName, pLogHostName, ustrlen(pLogHostName)));
/* reset hostname for next socket */
free(pLogHostName);
pLogHostName = NULL;
}
- CHKiRet(prop.ConstructFinalize(funixHName[nfunix]));
- funixFlowCtl[nfunix] = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
- funixFlags[nfunix] = bIgnoreTimestamp ? IGNDATE : NOFLAG;
- funixCreateSockPath[nfunix] = bCreateSockPath;
- funixn[nfunix++] = pNewVal;
+ CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName));
+ if(ratelimitInterval > 0) {
+ if((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) {
+ /* in this case, we simply turn of rate-limiting */
+ dbgprintf("imuxsock: turning off rate limiting because we could not "
+ "create hash table\n");
+ ratelimitInterval = 0;
+ }
+ }
+ listeners[nfd].ratelimitInterval = ratelimitInterval;
+ listeners[nfd].ratelimitBurst = ratelimitBurst;
+ listeners[nfd].ratelimitSev = ratelimitSeverity;
+ listeners[nfd].flowCtl = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY;
+ listeners[nfd].flags = bIgnoreTimestamp ? IGNDATE : NOFLAG;
+ listeners[nfd].bCreatePath = bCreatePath;
+ listeners[nfd].sockName = pNewVal;
+ listeners[nfd].bUseCreds = (bWritePid || ratelimitInterval) ? 1 : 0;
+ listeners[nfd].bWritePid = bWritePid;
+ nfd++;
} else {
errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n",
pNewVal);
@@ -160,80 +313,281 @@ finalize_it:
}
-/* free the funixn[] socket names - needed as cleanup on several places
- * note that nfunix is NOT reset! funixn[0] is never freed, as it comes from
+/* discard all log sockets except for "socket" 0. Data for it comes from
* the constant memory pool - and if not, it is freeed via some other pointer.
*/
-static rsRetVal discardFunixn(void)
+static rsRetVal discardLogSockets(void)
{
int i;
- for (i = 1; i < nfunix; i++) {
- if(funixn[i] != NULL) {
- free(funixn[i]);
- funixn[i] = NULL;
+ for (i = 1; i < nfd; i++) {
+ if(listeners[i].sockName != NULL) {
+ free(listeners[i].sockName);
+ listeners[i].sockName = NULL;
}
- if(funixHName[i] != NULL) {
- prop.Destruct(&(funixHName[i]));
+ if(listeners[i].hostName != NULL) {
+ prop.Destruct(&(listeners[i].hostName));
+ }
+ if(listeners[i].ht != NULL) {
+ hashtable_destroy(listeners[i].ht, 1); /* 1 => free all values automatically */
}
}
-
+
return RS_RET_OK;
}
-static int create_unix_socket(const char *path, int bCreatePath)
+/* used to create a log socket if NOT passed in via systemd.
+ */
+static inline rsRetVal
+createLogSocket(lstn_t *pLstn)
{
struct sockaddr_un sunx;
- int fd;
-
- if (path[0] == '\0')
- return -1;
-
- unlink(path);
+ DEFiRet;
+ unlink((char*)pLstn->sockName);
memset(&sunx, 0, sizeof(sunx));
sunx.sun_family = AF_UNIX;
- if(bCreatePath) {
- makeFileParentDirs((uchar*)path, strlen(path), 0755, -1, -1, 0);
+ if(pLstn->bCreatePath) {
+ makeFileParentDirs((uchar*)pLstn->sockName, ustrlen(pLstn->sockName), 0755, -1, -1, 0);
}
- (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path));
- fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (fd < 0 || bind(fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 ||
- chmod(path, 0666) < 0) {
- errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", path);
- dbgprintf("cannot create %s (%d).\n", path, errno);
- close(fd);
+ strncpy(sunx.sun_path, (char*)pLstn->sockName, sizeof(sunx.sun_path));
+ pLstn->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(pLstn->fd < 0 || bind(pLstn->fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 ||
+ chmod((char*)pLstn->sockName, 0666) < 0) {
+ errmsg.LogError(errno, NO_ERRCODE, "connot create '%s'", pLstn->sockName);
+ dbgprintf("cannot create %s (%d).\n", pLstn->sockName, errno);
+ close(pLstn->fd);
+ pLstn->fd = -1;
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
+finalize_it:
+ RETiRet;
+}
+
+
+static inline rsRetVal
+openLogSocket(lstn_t *pLstn)
+{
+ DEFiRet;
+ int one;
+
+ if(pLstn->sockName[0] == '\0')
return -1;
+
+ pLstn->fd = -1;
+
+ if (sd_fds > 0) {
+ /* Check if the current socket is a systemd activated one.
+ * If so, just use it.
+ */
+ int fd;
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + sd_fds; fd++) {
+ if( sd_is_socket_unix(fd, SOCK_DGRAM, -1, (const char*) pLstn->sockName, 0) == 1) {
+ /* ok, it matches -- just use as is */
+ pLstn->fd = fd;
+
+ dbgprintf("imuxsock: Acquired UNIX socket '%s' (fd %d) from systemd.\n",
+ pLstn->sockName, pLstn->fd);
+ break;
+ }
+ /*
+ * otherwise it either didn't matched *this* socket and
+ * we just continue to check the next one or there were
+ * an error and we will create a new socket bellow.
+ */
+ }
+ }
+
+ if (pLstn->fd == -1) {
+ CHKiRet(createLogSocket(pLstn));
+ }
+
+# if HAVE_SCM_CREDENTIALS
+ if(pLstn->bUseCreds) {
+ one = 1;
+ if(setsockopt(pLstn->fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t) sizeof(one)) != 0) {
+ errmsg.LogError(errno, NO_ERRCODE, "set SO_PASSCRED failed on '%s'", pLstn->sockName);
+ pLstn->bUseCreds = 0;
+ }
+ if(setsockopt(pLstn->fd, SOL_SOCKET, SCM_CREDENTIALS, &one, sizeof(one)) != 0) {
+ errmsg.LogError(errno, NO_ERRCODE, "set SCM_CREDENTIALS failed on '%s'", pLstn->sockName);
+ pLstn->bUseCreds = 0;
+ }
+ }
+# else /* HAVE_SCM_CREDENTIALS */
+ pLstn->bUseCreds = 0;
+# endif /* HAVE_SCM_CREDENTIALS */
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ close(pLstn->fd);
+ pLstn->fd = -1;
+ }
+
+ RETiRet;
+}
+
+
+/* find ratelimiter to use for this message. Currently, we use the
+ * pid, but may change to cgroup later (probably via a config switch).
+ * Returns NULL if not found.
+ */
+static inline rsRetVal
+findRatelimiter(lstn_t *pLstn, struct ucred *cred, rs_ratelimit_state_t **prl)
+{
+ rs_ratelimit_state_t *rl;
+ int r;
+ pid_t *keybuf;
+ DEFiRet;
+
+ if(cred == NULL)
+ FINALIZE;
+
+ rl = hashtable_search(pLstn->ht, &cred->pid);
+ if(rl == NULL) {
+ /* we need to add a new ratelimiter, process not seen before! */
+ dbgprintf("imuxsock: no ratelimiter for pid %lu, creating one\n",
+ (unsigned long) cred->pid);
+ STATSCOUNTER_INC(ctrNumRatelimiters, mutCtrNumRatelimiters);
+ CHKmalloc(rl = malloc(sizeof(rs_ratelimit_state_t)));
+ CHKmalloc(keybuf = malloc(sizeof(pid_t)));
+ *keybuf = cred->pid;
+ initRatelimitState(rl, ratelimitInterval, pLstn->ratelimitBurst);
+ r = hashtable_insert(pLstn->ht, keybuf, rl);
+ if(r == 0)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
}
- return fd;
+
+ *prl = rl;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* patch correct pid into tag. bufTAG MUST be CONF_TAG_MAXSIZE long!
+ */
+static inline void
+fixPID(uchar *bufTAG, int *lenTag, struct ucred *cred)
+{
+ int i;
+ char bufPID[16];
+ int lenPID;
+
+ if(cred == NULL)
+ return;
+
+ lenPID = snprintf(bufPID, sizeof(bufPID), "[%lu]:", (unsigned long) cred->pid);
+
+ for(i = *lenTag ; i >= 0 && bufTAG[i] != '[' ; --i)
+ /*JUST SKIP*/;
+
+ if(i < 0)
+ i = *lenTag - 1; /* go right at end of TAG, pid was not present (-1 for ':') */
+
+ if(i + lenPID > CONF_TAG_MAXSIZE)
+ return; /* do not touch, as things would break */
+
+ memcpy(bufTAG + i, bufPID, lenPID);
+ *lenTag = i + lenPID;
}
/* submit received message to the queue engine
+ * We now parse the message according to expected format so that we
+ * can also mangle it if necessary.
*/
static inline rsRetVal
-SubmitMsg(uchar *pRcv, int lenRcv, int iSock)
+SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred)
{
msg_t *pMsg;
+ int lenMsg;
+ int offs;
+ int i;
+ uchar *parse;
+ int pri;
+ int facil;
+ int sever;
+ uchar bufParseTAG[CONF_TAG_MAXSIZE];
+ struct syslogTime st;
+ time_t tt;
+ rs_ratelimit_state_t *ratelimiter = NULL;
DEFiRet;
+ /* TODO: handle format errors?? */
+ /* we need to parse the pri first, because we need the severity for
+ * rate-limiting as well.
+ */
+ parse = pRcv;
+ lenMsg = lenRcv;
+ offs = 1; /* '<' */
+
+ parse++;
+ pri = 0;
+ while(offs < lenMsg && isdigit(*parse)) {
+ pri = pri * 10 + *parse - '0';
+ ++parse;
+ ++offs;
+ }
+ facil = LOG_FAC(pri);
+ sever = LOG_PRI(pri);
+
+ if(sever >= pLstn->ratelimitSev) {
+ /* note: if cred == NULL, then ratelimiter == NULL as well! */
+ findRatelimiter(pLstn, cred, &ratelimiter); /* ignore error, better so than others... */
+ }
+
+ datetime.getCurrTime(&st, &tt);
+ if(ratelimiter != NULL && !withinRatelimit(ratelimiter, tt, cred->pid)) {
+ STATSCOUNTER_INC(ctrLostRatelimit, mutCtrLostRatelimit);
+ FINALIZE;
+ }
+
/* we now create our own message object and submit it to the queue */
- CHKiRet(msgConstruct(&pMsg));
+ CHKiRet(msgConstructWithTime(&pMsg, &st, tt));
MsgSetRawMsg(pMsg, (char*)pRcv, lenRcv);
+ parser.SanitizeMsg(pMsg);
+ lenMsg = pMsg->iLenRawMsg - offs;
MsgSetInputName(pMsg, pInputName);
- MsgSetFlowControlType(pMsg, funixFlowCtl[iSock]);
+ MsgSetFlowControlType(pMsg, pLstn->flowCtl);
+
+ pMsg->iFacility = facil;
+ pMsg->iSeverity = sever;
+ MsgSetAfterPRIOffs(pMsg, offs);
- if(funixParseHost[iSock]) {
- pMsg->msgFlags = funixFlags[iSock] | NEEDS_PARSING | PARSE_HOSTNAME;
+ parse++; lenMsg--; /* '>' */
+
+ if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &parse, &lenMsg) != RS_RET_OK) {
+ DBGPRINTF("we have a problem, invalid timestamp in msg!\n");
+ }
+
+ /* pull tag */
+
+ i = 0;
+ while(lenMsg > 0 && *parse != ' ' && i < CONF_TAG_MAXSIZE) {
+ bufParseTAG[i++] = *parse++;
+ --lenMsg;
+ }
+ bufParseTAG[i] = '\0'; /* terminate string */
+ if(pLstn->bWritePid)
+ fixPID(bufParseTAG, &i, cred);
+ MsgSetTAG(pMsg, bufParseTAG, i);
+
+ MsgSetMSGoffs(pMsg, pMsg->iLenRawMsg - lenMsg);
+
+ if(pLstn->bParseHost) {
+ pMsg->msgFlags = pLstn->flags | PARSE_HOSTNAME;
} else {
- pMsg->msgFlags = funixFlags[iSock] | NEEDS_PARSING;
+ pMsg->msgFlags = pLstn->flags;
}
- MsgSetRcvFrom(pMsg, funixHName[iSock]);
+ MsgSetRcvFrom(pMsg, pLstn->hostName);
CHKiRet(MsgSetRcvFromIP(pMsg, pLocalHostIP));
CHKiRet(submitMsg(pMsg));
+ STATSCOUNTER_INC(ctrSubmit, mutCtrSubmit);
finalize_it:
RETiRet;
}
@@ -246,15 +600,22 @@ finalize_it:
* of the socket which is to be processed. This eases access to the
* growing number of properties. -- rgerhards, 2008-08-01
*/
-static rsRetVal readSocket(int fd, int iSock)
+static rsRetVal readSocket(lstn_t *pLstn)
{
DEFiRet;
int iRcvd;
int iMaxLine;
+ struct msghdr msgh;
+ struct iovec msgiov;
+# if HAVE_SCM_CREDENTIALS
+ struct cmsghdr *cm;
+# endif
+ struct ucred *cred;
uchar bufRcv[4096+1];
+ char aux[128];
uchar *pRcv = NULL; /* receive buffer */
- assert(iSock >= 0);
+ assert(pLstn->fd >= 0);
iMaxLine = glbl.GetMaxLine();
@@ -270,15 +631,44 @@ static rsRetVal readSocket(int fd, int iSock)
CHKmalloc(pRcv = (uchar*) MALLOC(sizeof(uchar) * (iMaxLine + 1)));
}
- iRcvd = recv(fd, pRcv, iMaxLine, 0);
- dbgprintf("Message from UNIX socket: #%d\n", fd);
- if (iRcvd > 0) {
- CHKiRet(SubmitMsg(pRcv, iRcvd, iSock));
- } else if (iRcvd < 0 && errno != EINTR) {
+ memset(&msgh, 0, sizeof(msgh));
+ memset(&msgiov, 0, sizeof(msgiov));
+# if HAVE_SCM_CREDENTIALS
+ if(pLstn->bUseCreds) {
+ memset(&aux, 0, sizeof(aux));
+ msgh.msg_control = aux;
+ msgh.msg_controllen = sizeof(aux);
+ }
+# endif
+ msgiov.iov_base = pRcv;
+ msgiov.iov_len = iMaxLine;
+ msgh.msg_iov = &msgiov;
+ msgh.msg_iovlen = 1;
+ iRcvd = recvmsg(pLstn->fd, &msgh, MSG_DONTWAIT);
+
+ dbgprintf("Message from UNIX socket: #%d\n", pLstn->fd);
+ if(iRcvd > 0) {
+ cred = NULL;
+# if HAVE_SCM_CREDENTIALS
+ if(pLstn->bUseCreds) {
+ dbgprintf("XXX: pre CM loop, length of control message %d\n", (int) msgh.msg_controllen);
+ for (cm = CMSG_FIRSTHDR(&msgh); cm; cm = CMSG_NXTHDR(&msgh, cm)) {
+ dbgprintf("XXX: in CM loop, %d, %d\n", cm->cmsg_level, cm->cmsg_type);
+ if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) {
+ cred = (struct ucred*) CMSG_DATA(cm);
+ dbgprintf("XXX: got credentials pid %d\n", (int) cred->pid);
+ break;
+ }
+ }
+ dbgprintf("XXX: post CM loop\n");
+ }
+# endif /* HAVE_SCM_CREDENTIALS */
+ CHKiRet(SubmitMsg(pRcv, iRcvd, pLstn, cred));
+ } else if(iRcvd < 0 && errno != EINTR) {
char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
dbgprintf("UNIX socket error: %d = %s.\n", errno, errStr);
- errmsg.LogError(errno, NO_ERRCODE, "recvfrom UNIX");
+ errmsg.LogError(errno, NO_ERRCODE, "imuxsock: recvfrom UNIX");
}
finalize_it:
@@ -317,10 +707,11 @@ CODESTARTrunInput
maxfds = 0;
FD_ZERO (pReadfds);
/* Copy master connections */
- for (i = startIndexUxLocalSockets; i < nfunix; i++) {
- if (funix[i] != -1) {
- FD_SET(funix[i], pReadfds);
- if (funix[i]>maxfds) maxfds=funix[i];
+ for (i = startIndexUxLocalSockets; i < nfd; i++) {
+ if (listeners[i].fd!= -1) {
+ FD_SET(listeners[i].fd, pReadfds);
+ if(listeners[i].fd > maxfds)
+ maxfds=listeners[i].fd;
}
}
@@ -337,11 +728,11 @@ CODESTARTrunInput
if(glbl.GetGlobalInputTermState() == 1)
break; /* terminate input! */
- for (i = 0; i < nfunix && nfds > 0; i++) {
+ for (i = 0; i < nfd && nfds > 0; i++) {
if(glbl.GetGlobalInputTermState() == 1)
ABORT_FINALIZE(RS_RET_FORCE_TERM); /* terminate input! */
- if ((fd = funix[i]) != -1 && FD_ISSET(fd, pReadfds)) {
- readSocket(fd, i);
+ if ((fd = listeners[i].fd) != -1 && FD_ISSET(fd, pReadfds)) {
+ readSocket(&(listeners[i]));
--nfds; /* indicate we have processed one */
}
}
@@ -356,6 +747,7 @@ ENDrunInput
BEGINwillRun
CODESTARTwillRun
register int i;
+ int actSocks;
/* first apply some config settings */
# ifdef OS_SOLARIS
@@ -369,12 +761,39 @@ CODESTARTwillRun
startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0;
# endif
if(pLogSockName != NULL)
- funixn[0] = pLogSockName;
+ listeners[0].sockName = pLogSockName;
+ if(ratelimitIntervalSysSock > 0) {
+ if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) {
+ /* in this case, we simply turn of rate-limiting */
+ dbgprintf("imuxsock: turning off rate limiting because we could not "
+ "create hash table\n");
+ ratelimitIntervalSysSock = 0;
+ }
+ }
+ listeners[0].ratelimitInterval = ratelimitIntervalSysSock;
+ listeners[0].ratelimitBurst = ratelimitBurstSysSock;
+ listeners[0].ratelimitSev = ratelimitSeveritySysSock;
+ listeners[0].bUseCreds = (bWritePidSysSock || ratelimitIntervalSysSock) ? 1 : 0;
+ listeners[0].bWritePid = bWritePidSysSock;
+
+ sd_fds = sd_listen_fds(0);
+ if (sd_fds < 0) {
+ errmsg.LogError(-sd_fds, NO_ERRCODE, "imuxsock: Failed to acquire systemd socket");
+ ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX);
+ }
/* initialize and return if will run or not */
- for (i = startIndexUxLocalSockets ; i < nfunix ; i++) {
- if ((funix[i] = create_unix_socket((char*) funixn[i], funixCreateSockPath[i])) != -1)
- dbgprintf("Opened UNIX socket '%s' (fd %d).\n", funixn[i], funix[i]);
+ actSocks = 0;
+ for (i = startIndexUxLocalSockets ; i < nfd ; i++) {
+ if(openLogSocket(&(listeners[i])) == RS_RET_OK) {
+ ++actSocks;
+ dbgprintf("imuxsock: Opened UNIX socket '%s' (fd %d).\n", listeners[i].sockName, listeners[i].fd);
+ }
+ }
+
+ if(actSocks == 0) {
+ errmsg.LogError(0, NO_ERRCODE, "imuxsock does not run because we could not aquire any socket\n");
+ ABORT_FINALIZE(RS_RET_ERR);
}
/* we need to create the inputName property (only once during our lifetime) */
@@ -391,31 +810,49 @@ CODESTARTafterRun
int i;
/* do cleanup here */
/* Close the UNIX sockets. */
- for (i = 0; i < nfunix; i++)
- if (funix[i] != -1)
- close(funix[i]);
-
- /* Clean-up files. */
- for(i = startIndexUxLocalSockets; i < nfunix; i++)
- if (funixn[i] && funix[i] != -1)
- unlink((char*) funixn[i]);
+ for (i = 0; i < nfd; i++)
+ if (listeners[i].fd != -1)
+ close(listeners[i].fd);
+
+ /* Clean-up files. */
+ for(i = startIndexUxLocalSockets; i < nfd; i++)
+ if (listeners[i].sockName && listeners[i].fd != -1) {
+
+ /* If systemd passed us a socket it is systemd's job to clean it up.
+ * Do not unlink it -- we will get same socket (node) from systemd
+ * e.g. on restart again.
+ */
+ if (sd_fds > 0 &&
+ listeners[i].fd >= SD_LISTEN_FDS_START &&
+ listeners[i].fd < SD_LISTEN_FDS_START + sd_fds)
+ continue;
+
+ DBGPRINTF("imuxsock: unlinking unix socket file[%d] %s\n", i, listeners[i].sockName);
+ unlink((char*) listeners[i].sockName);
+ }
/* free no longer needed string */
free(pLogSockName);
free(pLogHostName);
- discardFunixn();
- nfunix = 1;
+ discardLogSockets();
+ nfd = 1;
if(pInputName != NULL)
prop.Destruct(&pInputName);
+
ENDafterRun
BEGINmodExit
CODESTARTmodExit
+ statsobj.Destruct(&modStats);
+
+ objRelease(parser, CORE_COMPONENT);
objRelease(glbl, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
+ objRelease(statsobj, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
ENDmodExit
@@ -444,11 +881,19 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
pLogHostName = NULL;
}
- discardFunixn();
- nfunix = 1;
+ discardLogSockets();
+ nfd = 1;
bIgnoreTimestamp = 1;
bUseFlowCtl = 0;
- bCreateSockPath = DFLT_bCreateSockPath;
+ bWritePid = 0;
+ bWritePidSysSock = 0;
+ bCreatePath = DFLT_bCreatePath;
+ ratelimitInterval = DFLT_ratelimitInterval;
+ ratelimitIntervalSysSock = DFLT_ratelimitInterval;
+ ratelimitBurst = DFLT_ratelimitBurst;
+ ratelimitBurstSysSock = DFLT_ratelimitBurst;
+ ratelimitSeverity = DFLT_ratelimitSeverity;
+ ratelimitSeveritySysSock = DFLT_ratelimitSeverity;
return RS_RET_OK;
}
@@ -462,13 +907,26 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(prop, CORE_COMPONENT));
+ CHKiRet(objUse(statsobj, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION);
- /* initialize funixn[] array */
+ /* init system log socket settings */
+ listeners[0].flags = IGNDATE;
+ listeners[0].sockName = UCHAR_CONSTANT(_PATH_LOG);
+ listeners[0].hostName = NULL;
+ listeners[0].flowCtl = eFLOWCTL_NO_DELAY;
+ listeners[0].fd = -1;
+ listeners[0].bParseHost = 0;
+ listeners[0].bUseCreds = 0;
+ listeners[0].bCreatePath = 0;
+
+ /* initialize socket names */
for(i = 1 ; i < MAXFUNIX ; ++i) {
- funixn[i] = NULL;
- funix[i] = -1;
+ listeners[i].sockName = NULL;
+ listeners[i].fd = -1;
}
CHKiRet(prop.Construct(&pLocalHostIP));
@@ -476,9 +934,9 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(prop.ConstructFinalize(pLocalHostIP));
/* now init listen socket zero, the local log socket */
- CHKiRet(prop.Construct(&(funixHName[0])));
- CHKiRet(prop.SetString(funixHName[0], glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())));
- CHKiRet(prop.ConstructFinalize(funixHName[0]));
+ CHKiRet(prop.Construct(&(listeners[0].hostName)));
+ CHKiRet(prop.SetString(listeners[0].hostName, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())));
+ CHKiRet(prop.ConstructFinalize(listeners[0].hostName));
/* register config file handlers */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary,
@@ -492,9 +950,17 @@ CODEmodInit_QueryRegCFSLineHdlr
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary,
NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary,
- NULL, &bCreateSockPath, STD_LOADABLE_MODULE_ID));
+ NULL, &bCreatePath, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary,
+ NULL, &bWritePid, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord,
addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitinterval", 0, eCmdHdlrInt,
+ NULL, &ratelimitInterval, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitburst", 0, eCmdHdlrInt,
+ NULL, &ratelimitBurst, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitseverity", 0, eCmdHdlrInt,
+ NULL, &ratelimitSeverity, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
/* the following one is a (dirty) trick: the system log socket is not added via
@@ -507,6 +973,26 @@ CODEmodInit_QueryRegCFSLineHdlr
setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary,
setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary,
+ NULL, &bWritePidSysSock, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt,
+ NULL, &ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitburst", 0, eCmdHdlrInt,
+ NULL, &ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitseverity", 0, eCmdHdlrInt,
+ NULL, &ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID));
+
+ /* support statistics gathering */
+ CHKiRet(statsobj.Construct(&modStats));
+ CHKiRet(statsobj.SetName(modStats, UCHAR_CONSTANT("imuxsock")));
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("submitted"),
+ ctrType_IntCtr, &ctrSubmit));
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.discarded"),
+ ctrType_IntCtr, &ctrLostRatelimit));
+ CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("ratelimit.numratelimiters"),
+ ctrType_IntCtr, &ctrNumRatelimiters));
+ CHKiRet(statsobj.ConstructFinalize(modStats));
+
ENDmodInit
/* vim:set ai:
*/
diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c
index 2e04391c..35de5818 100644
--- a/plugins/omdbalerting/omdbalerting.c
+++ b/plugins/omdbalerting/omdbalerting.c
@@ -44,6 +44,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c
index 605e5ed9..e4fdf0c0 100644
--- a/plugins/omgssapi/omgssapi.c
+++ b/plugins/omgssapi/omgssapi.c
@@ -58,6 +58,7 @@
#include "errmsg.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
diff --git a/plugins/omhdfs/Makefile.am b/plugins/omhdfs/Makefile.am
new file mode 100644
index 00000000..95e6b102
--- /dev/null
+++ b/plugins/omhdfs/Makefile.am
@@ -0,0 +1,6 @@
+pkglib_LTLIBRARIES = omhdfs.la
+
+omhdfs_la_SOURCES = omhdfs.c
+omhdfs_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(JAVA_INCLUDES)
+omhdfs_la_LDFLAGS = -module -avoid-version -lhdfs $(JAVA_LIBS)
+omhdfs_la_LIBADD = $(RSRT_LIBS)
diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c
new file mode 100644
index 00000000..8b72747f
--- /dev/null
+++ b/plugins/omhdfs/omhdfs.c
@@ -0,0 +1,476 @@
+/* omhdfs.c
+ * This is an output module to support Hadoop's HDFS.
+ *
+ * NOTE: read comments in module-template.h to understand how this file
+ * works!
+ *
+ * Copyright 2010 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <pthread.h>
+#include <hdfs.h>
+
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "conf.h"
+#include "cfsysline.h"
+#include "module-template.h"
+#include "unicode-helper.h"
+#include "errmsg.h"
+#include "hashtable.h"
+#include "hashtable_itr.h"
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+
+/* internal structures
+ */
+DEF_OMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+
+/* global data */
+static struct hashtable *files; /* holds all file objects that we know */
+
+/* globals for default values */
+static uchar *fileName = NULL;
+static uchar *hdfsHost = NULL;
+static uchar *dfltTplName = NULL; /* default template name to use */
+int hdfsPort = 0;
+/* end globals for default values */
+
+typedef struct {
+ uchar *name;
+ hdfsFS fs;
+ hdfsFile fh;
+ const char *hdfsHost;
+ tPort hdfsPort;
+ int nUsers;
+ pthread_mutex_t mut;
+} file_t;
+
+
+typedef struct _instanceData {
+ file_t *pFile;
+} instanceData;
+
+/* forward definitions (down here, need data types) */
+static inline rsRetVal fileClose(file_t *pFile);
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATURERepeatedMsgReduction)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ printf("omhdfs: file:%s", pData->pFile->name);
+ENDdbgPrintInstInfo
+
+
+/* note that hdfsFileExists() does not work, so we did our
+ * own function to see if a pathname exists. Returns 0 if the
+ * file does not exists, something else otherwise. Note that
+ * we can also check a directroy (if that matters...)
+ */
+static int
+HDFSFileExists(hdfsFS fs, uchar *name)
+{
+ int r;
+ hdfsFileInfo *info;
+
+ info = hdfsGetPathInfo(fs, (char*)name);
+ /* if things go wrong, we assume it is because the file
+ * does not exist. We do not get too much information...
+ */
+ if(info == NULL) {
+ r = 0;
+ } else {
+ r = 1;
+ hdfsFreeFileInfo(info, 1);
+ }
+ return r;
+}
+
+static inline rsRetVal
+HDFSmkdir(hdfsFS fs, uchar *name)
+{
+ DEFiRet;
+ if(hdfsCreateDirectory(fs, (char*)name) == -1)
+ ABORT_FINALIZE(RS_RET_ERR);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* ---BEGIN FILE OBJECT---------------------------------------------------- */
+/* This code handles the "file object". This is split from the actual
+ * instance data, because several instances may write into the same file.
+ * If so, we need to use a single object, and also synchronize their writes.
+ * So we keep the file object separately, and just stick a reference into
+ * the instance data.
+ */
+
+static inline rsRetVal
+fileObjConstruct(file_t **ppFile)
+{
+ file_t *pFile;
+ DEFiRet;
+
+ CHKmalloc(pFile = malloc(sizeof(file_t)));
+ pFile->name = NULL;
+ pFile->hdfsHost = NULL;
+ pFile->fh = NULL;
+ pFile->nUsers = 0;
+
+ *ppFile = pFile;
+finalize_it:
+ RETiRet;
+}
+
+static inline void
+fileObjAddUser(file_t *pFile)
+{
+ /* init mutex only when second user is added */
+ ++pFile->nUsers;
+ if(pFile->nUsers == 2)
+ pthread_mutex_init(&pFile->mut, NULL);
+ DBGPRINTF("omhdfs: file %s now being used by %d actions\n", pFile->name, pFile->nUsers);
+}
+
+static rsRetVal
+fileObjDestruct(file_t **ppFile)
+{
+ file_t *pFile = *ppFile;
+ if(pFile->nUsers > 1)
+ pthread_mutex_destroy(&pFile->mut);
+ fileClose(pFile);
+ free(pFile->name);
+ free((char*)pFile->hdfsHost);
+ free(pFile->fh);
+
+ return RS_RET_OK;
+}
+
+
+/* check, and potentially create, all names inside a path */
+static rsRetVal
+filePrepare(file_t *pFile)
+{
+ uchar *p;
+ uchar *pszWork;
+ size_t len;
+ DEFiRet;
+
+ if(HDFSFileExists(pFile->fs, pFile->name))
+ FINALIZE;
+
+ /* file does not exist, create it (and eventually parent directories */
+ if(1) { // check if bCreateDirs
+ len = ustrlen(pFile->name) + 1;
+ CHKmalloc(pszWork = MALLOC(sizeof(uchar) * len));
+ memcpy(pszWork, pFile->name, len);
+ for(p = pszWork+1 ; *p ; p++)
+ if(*p == '/') {
+ /* temporarily terminate string, create dir and go on */
+ *p = '\0';
+ if(!HDFSFileExists(pFile->fs, pszWork)) {
+ CHKiRet(HDFSmkdir(pFile->fs, pszWork));
+ }
+ *p = '/';
+ }
+ free(pszWork);
+ return 0;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* this function is to be used as destructor for the
+ * hash table code.
+ */
+static void
+fileObjDestruct4Hashtable(void *ptr)
+{
+ file_t *pFile = (file_t*) ptr;
+ fileObjDestruct(&pFile);
+}
+
+
+static inline rsRetVal
+fileOpen(file_t *pFile)
+{
+ DEFiRet;
+
+ assert(pFile->fh == NULL);
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_lock(&pFile->mut);
+
+ DBGPRINTF("omhdfs: try to connect to HDFS at host '%s', port %d\n",
+ pFile->hdfsHost, pFile->hdfsPort);
+ pFile->fs = hdfsConnect(pFile->hdfsHost, pFile->hdfsPort);
+ if(pFile->fs == NULL) {
+ DBGPRINTF("omhdfs: error can not connect to hdfs\n");
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+
+ CHKiRet(filePrepare(pFile));
+
+ pFile->fh = hdfsOpenFile(pFile->fs, (char*)pFile->name, O_WRONLY|O_APPEND, 0, 0, 0);
+ if(pFile->fh == NULL) {
+ /* maybe the file does not exist, so we try to create it now.
+ * Note that we can not use hdfsExists() because of a deficit in
+ * it: https://issues.apache.org/jira/browse/HDFS-1154
+ * As of my testing, libhdfs at least seems to return ENOENT if
+ * the file does not exist.
+ */
+ if(errno == ENOENT) {
+ DBGPRINTF("omhdfs: ENOENT trying to append to '%s', now trying create\n",
+ pFile->name);
+ pFile->fh = hdfsOpenFile(pFile->fs, (char*)pFile->name, O_WRONLY|O_CREAT, 0, 0, 0);
+ }
+ }
+ if(pFile->fh == NULL) {
+ DBGPRINTF("omhdfs: failed to open %s for writing!\n", pFile->name);
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+
+finalize_it:
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_unlock(&pFile->mut);
+ RETiRet;
+}
+
+
+static inline rsRetVal
+fileWrite(file_t *pFile, uchar *buf)
+{
+ size_t lenWrite;
+ DEFiRet;
+
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_lock(&pFile->mut);
+
+ /* open file if not open. This must be done *here* and while mutex-protected
+ * because of HUP handling (which is async to normal processing!).
+ */
+ if(pFile->fh == NULL) {
+ fileOpen(pFile);
+ if(pFile->fh == NULL) {
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+ }
+
+ lenWrite = strlen((char*) buf);
+ tSize num_written_bytes = hdfsWrite(pFile->fs, pFile->fh, buf, lenWrite);
+ if((unsigned) num_written_bytes != lenWrite) {
+ errmsg.LogError(errno, RS_RET_ERR_HDFS_WRITE, "omhdfs: failed to write %s, expected %lu bytes, "
+ "written %lu\n", pFile->name, (unsigned long) lenWrite,
+ (unsigned long) num_written_bytes);
+ ABORT_FINALIZE(RS_RET_SUSPENDED);
+ }
+
+finalize_it:
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_unlock(&pFile->mut);
+ RETiRet;
+}
+
+
+static inline rsRetVal
+fileClose(file_t *pFile)
+{
+ DEFiRet;
+
+ if(pFile->fh == NULL)
+ FINALIZE;
+
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_lock(&pFile->mut);
+
+ hdfsCloseFile(pFile->fs, pFile->fh);
+ pFile->fh = NULL;
+
+ if(pFile->nUsers > 1)
+ d_pthread_mutex_unlock(&pFile->mut);
+
+finalize_it:
+ RETiRet;
+}
+
+/* ---END FILE OBJECT---------------------------------------------------- */
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ pData->pFile = NULL;
+ENDcreateInstance
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ if(pData->pFile != NULL)
+ fileObjDestruct(&pData->pFile);
+ENDfreeInstance
+
+
+BEGINtryResume
+CODESTARTtryResume
+ fileClose(pData->pFile);
+ fileOpen(pData->pFile);
+ if(pData->pFile->fh == NULL){
+ dbgprintf("omhdfs: tried to resume file %s, but still no luck...\n",
+ pData->pFile->name);
+ iRet = RS_RET_SUSPENDED;
+ }
+ENDtryResume
+
+BEGINdoAction
+CODESTARTdoAction
+ DBGPRINTF("omuxsock: action to to write to %s\n", pData->pFile->name);
+ iRet = fileWrite(pData->pFile, ppString[0]);
+ENDdoAction
+
+
+BEGINparseSelectorAct
+ file_t *pFile;
+ int r;
+ uchar *keybuf;
+CODESTARTparseSelectorAct
+
+ /* first check if this config line is actually for us */
+ if(strncmp((char*) p, ":omhdfs:", sizeof(":omhdfs:") - 1)) {
+ ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
+ }
+
+ /* ok, if we reach this point, we have something for us */
+ p += sizeof(":omhdfs:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
+ CHKiRet(createInstance(&pData));
+ CODE_STD_STRING_REQUESTparseSelectorAct(1)
+ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0,
+ (dfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : dfltTplName));
+
+ if(fileName == NULL) {
+ errmsg.LogError(0, RS_RET_ERR_HDFS_OPEN, "omhdfs: no file name specified, can not continue");
+ ABORT_FINALIZE(RS_RET_FILE_NOT_SPECIFIED);
+ }
+
+ pFile = hashtable_search(files, fileName);
+ if(pFile == NULL) {
+ /* we need a new file object, this one not seen before */
+ CHKiRet(fileObjConstruct(&pFile));
+ CHKmalloc(pFile->name = fileName);
+ CHKmalloc(keybuf = ustrdup(fileName));
+ fileName = NULL; /* re-set, data passed to file object */
+ CHKmalloc(pFile->hdfsHost = strdup((hdfsHost == NULL) ? "default" : (char*) hdfsHost));
+ pFile->hdfsPort = hdfsPort;
+ fileOpen(pFile);
+ if(pFile->fh == NULL){
+ errmsg.LogError(0, RS_RET_ERR_HDFS_OPEN, "omhdfs: failed to open %s - "
+ "retrying later", pFile->name);
+ iRet = RS_RET_SUSPENDED;
+ }
+ r = hashtable_insert(files, keybuf, pFile);
+ if(r == 0)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+ fileObjAddUser(pFile);
+ pData->pFile = pFile;
+
+CODE_STD_FINALIZERparseSelectorAct
+ENDparseSelectorAct
+
+
+BEGINdoHUP
+ file_t *pFile;
+ struct hashtable_itr *itr;
+CODESTARTdoHUP
+ DBGPRINTF("omhdfs: HUP received (file count %d)\n", hashtable_count(files));
+ /* Iterator constructor only returns a valid iterator if
+ * the hashtable is not empty */
+ itr = hashtable_iterator(files);
+ if(hashtable_count(files) > 0)
+ {
+ do {
+ pFile = (file_t *) hashtable_iterator_value(itr);
+ fileClose(pFile);
+ DBGPRINTF("omhdfs: HUP, closing file %s\n", pFile->name);
+ } while (hashtable_iterator_advance(itr));
+ }
+ENDdoHUP
+
+
+/* Reset config variables for this module to default values.
+ * rgerhards, 2007-07-17
+ */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ hdfsHost = NULL;
+ hdfsPort = 0;
+ return RS_RET_OK;
+}
+
+
+BEGINmodExit
+CODESTARTmodExit
+ objRelease(errmsg, CORE_COMPONENT);
+ if(files != NULL)
+ hashtable_destroy(files, 1); /* 1 => free all values automatically */
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_doHUP
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION;
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKmalloc(files = create_hashtable(20, hash_from_string, key_equals_string,
+ fileObjDestruct4Hashtable));
+
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsfilename", 0, eCmdHdlrGetWord, NULL, &fileName, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfshost", 0, eCmdHdlrGetWord, NULL, &hdfsHost, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsport", 0, eCmdHdlrInt, NULL, &hdfsPort, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"omhdfsdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &dfltTplName, NULL));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+CODEmodInit_QueryRegCFSLineHdlr
+ENDmodInit
diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c
index 67b1edf9..f49bef42 100644
--- a/plugins/omlibdbi/omlibdbi.c
+++ b/plugins/omlibdbi/omlibdbi.c
@@ -50,6 +50,7 @@
#include "errmsg.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c
index 324e1a77..886513c0 100644
--- a/plugins/ommail/ommail.c
+++ b/plugins/ommail/ommail.c
@@ -54,6 +54,7 @@
#include "glbl.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c
index d6870a7b..f8bb4aa6 100644
--- a/plugins/ommysql/ommysql.c
+++ b/plugins/ommysql/ommysql.c
@@ -46,6 +46,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
@@ -60,9 +61,13 @@ typedef struct _instanceData {
char f_dbuid[_DB_MAXUNAMELEN+1]; /* DB user */
char f_dbpwd[_DB_MAXPWDLEN+1]; /* DB user's password */
unsigned uLastMySQLErrno; /* last errno returned by MySQL or 0 if all is well */
+ uchar * f_configfile; /* MySQL Client Configuration File */
+ uchar * f_configsection; /* MySQL Client Configuration Section */
} instanceData;
/* config variables */
+static uchar * pszMySQLConfigFile = NULL; /* MySQL Client Configuration File */
+static uchar * pszMySQLConfigSection = NULL; /* MySQL Client Configuration Section */
static int iSrvPort = 0; /* database server port */
@@ -91,6 +96,14 @@ static void closeMySQL(instanceData *pData)
mysql_close(pData->f_hmysql);
pData->f_hmysql = NULL;
}
+ if(pData->f_configfile!=NULL){
+ free(pData->f_configfile);
+ pData->f_configfile=NULL;
+ }
+ if(pData->f_configsection!=NULL){
+ free(pData->f_configsection);
+ pData->f_configsection=NULL;
+ }
}
BEGINfreeInstance
@@ -152,6 +165,25 @@ static rsRetVal initMySQL(instanceData *pData, int bSilent)
errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize MySQL handle");
iRet = RS_RET_SUSPENDED;
} else { /* we could get the handle, now on with work... */
+ mysql_options(pData->f_hmysql,MYSQL_READ_DEFAULT_GROUP,((pData->f_configsection!=NULL)?(char*)pData->f_configsection:"client"));
+ if(pData->f_configfile!=NULL){
+ FILE * fp;
+ fp=fopen((char*)pData->f_configfile,"r");
+ int err=errno;
+ if(fp==NULL){
+ char msg[512];
+ snprintf(msg,sizeof(msg)/sizeof(char),"Could not open '%s' for reading",pData->f_configfile);
+ if(bSilent) {
+ char errStr[512];
+ rs_strerror_r(err, errStr, sizeof(errStr));
+ dbgprintf("mysql configuration error(%d): %s - %s\n",err,msg,errStr);
+ } else
+ errmsg.LogError(err,NO_ERRCODE,"mysql configuration error: %s\n",msg);
+ } else {
+ fclose(fp);
+ mysql_options(pData->f_hmysql,MYSQL_READ_DEFAULT_FILE,pData->f_configfile);
+ }
+ }
/* Connect to database */
if(mysql_real_connect(pData->f_hmysql, pData->f_dbsrv, pData->f_dbuid,
pData->f_dbpwd, pData->f_dbname, pData->f_dbsrvPort, NULL, 0) == NULL) {
@@ -278,6 +310,8 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
} else {
pData->f_dbsrvPort = (unsigned) iSrvPort; /* set configured port */
+ pData->f_configfile = pszMySQLConfigFile;
+ pData->f_configsection = pszMySQLConfigSection;
pData->f_hmysql = NULL; /* initialize, but connect only on first message (important for queued mode!) */
}
@@ -302,6 +336,10 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a
{
DEFiRet;
iSrvPort = 0; /* zero is the default port */
+ free(pszMySQLConfigFile);
+ pszMySQLConfigFile = NULL;
+ free(pszMySQLConfigSection);
+ pszMySQLConfigSection = NULL;
RETiRet;
}
@@ -313,6 +351,8 @@ CODEmodInit_QueryRegCFSLineHdlr
/* register our config handlers */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionommysqlserverport", 0, eCmdHdlrInt, NULL, &iSrvPort, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigfile",0,eCmdHdlrGetWord,NULL,&pszMySQLConfigFile,STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"ommysqlconfigsection",0,eCmdHdlrGetWord,NULL,&pszMySQLConfigSection,STD_LOADABLE_MODULE_ID));
ENDmodInit
/* vi:set ai:
diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c
index 48ee1fa4..a37533ee 100644
--- a/plugins/omoracle/omoracle.c
+++ b/plugins/omoracle/omoracle.c
@@ -82,6 +82,7 @@
#include "omoracle.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/** */
DEF_OMOD_STATIC_DATA
@@ -127,6 +128,13 @@ typedef struct _instanceData {
struct oracle_batch batch;
} instanceData;
+/* To be honest, strlcpy is faster than strncpy and makes very easy to
+ * detect if a message has been truncated. */
+#ifndef strlcpy
+#define strlcpy(dst,src,sz) snprintf((dst), (sz), "%s", (src))
+#endif
+
+
/** Database name, to be filled by the $OmoracleDB directive */
static char* db_name;
/** Database user name, to be filled by the $OmoracleDBUser
@@ -529,7 +537,7 @@ CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
BEGINdoAction
- int i;
+ int i, sz;
char **params = (char**) ppString[0];
CODESTARTdoAction
@@ -540,9 +548,13 @@ CODESTARTdoAction
for (i = 0; i < pData->batch.arguments && params[i]; i++) {
dbgprintf("batch[%d][%d]=%s\n", i, pData->batch.n, params[i]);
- strncpy(pData->batch.parameters[i][pData->batch.n], params[i],
- pData->batch.param_size);
- CHKmalloc(pData->batch.parameters[i][pData->batch.n]);
+ sz = strlcpy(pData->batch.parameters[i][pData->batch.n],
+ params[i], pData->batch.param_size);
+ if (sz >= pData->batch.param_size)
+ errmsg.LogError(0, NO_ERRCODE,
+ "Possibly truncated %d column of '%s' "
+ "statement: %s", i,
+ pData->txt_statement, params[i]);
}
pData->batch.n++;
diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c
index ffdcc532..ab8e4d2c 100644
--- a/plugins/ompgsql/ompgsql.c
+++ b/plugins/ompgsql/ompgsql.c
@@ -49,6 +49,7 @@
#include "errmsg.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c
index 2687e7a3..56192579 100644
--- a/plugins/omprog/omprog.c
+++ b/plugins/omprog/omprog.c
@@ -45,6 +45,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c
index 349e45aa..cf70381f 100644
--- a/plugins/omrelp/omrelp.c
+++ b/plugins/omrelp/omrelp.c
@@ -46,6 +46,7 @@
#include "debug.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c
index 0e0fc13b..c439bd83 100644
--- a/plugins/omruleset/omruleset.c
+++ b/plugins/omruleset/omruleset.c
@@ -49,6 +49,7 @@
#include "dirty.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* static data */
DEFobjCurrIf(ruleset);
diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c
index b973b09d..443cfaab 100644
--- a/plugins/omsnmp/omsnmp.c
+++ b/plugins/omsnmp/omsnmp.c
@@ -47,6 +47,7 @@
#include "errmsg.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c
index 929de703..dc9912e3 100644
--- a/plugins/omstdout/omstdout.c
+++ b/plugins/omstdout/omstdout.c
@@ -44,6 +44,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c
index 5577f8c6..1472ebeb 100644
--- a/plugins/omtemplate/omtemplate.c
+++ b/plugins/omtemplate/omtemplate.c
@@ -45,6 +45,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c
index c474bb41..6d178467 100644
--- a/plugins/omtesting/omtesting.c
+++ b/plugins/omtesting/omtesting.c
@@ -57,6 +57,7 @@
#include "cfsysline.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c
index 3ead5447..48d7a68e 100644
--- a/plugins/omudpspoof/omudpspoof.c
+++ b/plugins/omudpspoof/omudpspoof.c
@@ -82,6 +82,7 @@
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c
index c66e63aa..0e336c51 100644
--- a/plugins/omuxsock/omuxsock.c
+++ b/plugins/omuxsock/omuxsock.c
@@ -52,6 +52,7 @@
#include "unicode-helper.h"
MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
/* internal structures
*/
diff --git a/plugins/pmaixforwardedfrom/Makefile.am b/plugins/pmaixforwardedfrom/Makefile.am
new file mode 100644
index 00000000..af359d31
--- /dev/null
+++ b/plugins/pmaixforwardedfrom/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = pmaixforwardedfrom.la
+
+pmaixforwardedfrom_la_SOURCES = pmaixforwardedfrom.c
+pmaixforwardedfrom_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) -I ../../tools
+pmaixforwardedfrom_la_LDFLAGS = -module -avoid-version
+pmaixforwardedfrom_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c
new file mode 100644
index 00000000..11634199
--- /dev/null
+++ b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c
@@ -0,0 +1,167 @@
+/* pmaixforwardedfrom.c
+ *
+ * this detects logs sent by Cisco devices that mangle their syslog output when you tell them to log by name by adding ' :' between the name and the %XXX-X-XXXXXXX: tag
+ *
+ * instead of actually parsing the message, this modifies the message and then falls through to allow a later parser to handle the now modified message
+ *
+ * created 2010-12-13 by David Lang based on pmlastmsg
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "glbl.h"
+#include "errmsg.h"
+#include "parser.h"
+#include "datetime.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_PARSER
+PARSER_NAME("rsyslog.aixforwardedfrom")
+
+/* internal structures
+ */
+DEF_PMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+
+
+/* static data */
+static int bParseHOSTNAMEandTAG; /* cache for the equally-named global param - performance enhancement */
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATUREAutomaticSanitazion)
+ iRet = RS_RET_OK;
+ if(eFeat == sFEATUREAutomaticPRIParsing)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINparse
+ uchar *p2parse;
+ uchar *opening;
+ int lenMsg;
+#define OpeningText "Message forwarded from "
+CODESTARTparse
+ dbgprintf("Message will now be parsed by fix AIX Forwarded From parser.\n");
+ assert(pMsg != NULL);
+ assert(pMsg->pszRawMsg != NULL);
+ lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */
+ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
+
+ /* check if this message is of the type we handle in this (very limited) parser */
+ /* first, we permit SP */
+ while(lenMsg && *p2parse == ' ') {
+ --lenMsg;
+ ++p2parse;
+ }
+dbgprintf("pmaixforwardedfrom: msg to look at: [%d]'%s'\n", lenMsg, p2parse);
+ if((unsigned) lenMsg < 42) {
+ /* too short, can not be "our" message */
+ /* minimum message, 16 character timestamp, 'Message forwarded from ", 1 character name, ': '*/
+dbgprintf("msg too short!\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+
+ /* skip over timestamp */
+ lenMsg -=16;
+ p2parse +=16;
+ /* if there is the string "Message forwarded from " were the hostname should be */
+ if(strncasecmp((char*) p2parse, OpeningText, sizeof(OpeningText)-1) != 0) {
+ /* wrong opening text */
+dbgprintf("not a AIX message forwarded from mangled log!\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+ /* bump the message portion up by 23 characters to overwrite the "Message forwarded from " with the hostname */
+ lenMsg -=23;
+ memmove(p2parse, p2parse + 23, lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=23;
+ pMsg->iLenMSG -=23;
+ /* now look for the : after the hostname to walk past the hostname, also watch for a space in case this isn't really an AIX log, but has a similar preamble */
+ while(lenMsg && *p2parse != ' ' && *p2parse != ':') {
+ --lenMsg;
+ ++p2parse;
+ }
+ if (lenMsg && *p2parse != ':') {
+dbgprintf("not a AIX message forwarded from mangled log but similar enough that the preamble has been removed\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+ /* bump the message portion up by one character to overwrite the extra : */
+ lenMsg -=1;
+ memmove(p2parse, p2parse + 1, lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=1;
+ pMsg->iLenMSG -=1;
+ /* now, claim to abort so that something else can parse the now modified message */
+ DBGPRINTF("pmaixforwardedfrom: new mesage: [%d]'%s'\n", lenMsg, pMsg->pszRawMsg + pMsg->offAfterPRI);
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+
+finalize_it:
+ENDparse
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(parser, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_PMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+
+ DBGPRINTF("aixforwardedfrom parser init called, compiled with version %s\n", VERSION);
+ bParseHOSTNAMEandTAG = glbl.GetParseHOSTNAMEandTAG(); /* cache value, is set only during rsyslogd option processing */
+
+
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/plugins/pmcisconames/Makefile.am b/plugins/pmcisconames/Makefile.am
new file mode 100644
index 00000000..16ed347d
--- /dev/null
+++ b/plugins/pmcisconames/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = pmcisconames.la
+
+pmcisconames_la_SOURCES = pmcisconames.c
+pmcisconames_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) -I ../../tools
+pmcisconames_la_LDFLAGS = -module -avoid-version
+pmcisconames_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/pmcisconames/pmcisconames.c b/plugins/pmcisconames/pmcisconames.c
new file mode 100644
index 00000000..61688cbf
--- /dev/null
+++ b/plugins/pmcisconames/pmcisconames.c
@@ -0,0 +1,178 @@
+/* pmcisconames.c
+ *
+ * this detects logs sent by Cisco devices that mangle their syslog output when you tell them to log by name by adding ' :' between the name and the %XXX-X-XXXXXXX: tag
+ *
+ * instead of actually parsing the message, this modifies the message and then falls through to allow a later parser to handle the now modified message
+ *
+ * created 2010-12-13 by David Lang based on pmlastmsg
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "glbl.h"
+#include "errmsg.h"
+#include "parser.h"
+#include "datetime.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_PARSER
+MODULE_TYPE_NOKEEP
+PARSER_NAME("rsyslog.cisconames")
+
+/* internal structures
+ */
+DEF_PMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+
+
+/* static data */
+static int bParseHOSTNAMEandTAG; /* cache for the equally-named global param - performance enhancement */
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATUREAutomaticSanitazion)
+ iRet = RS_RET_OK;
+ if(eFeat == sFEATUREAutomaticPRIParsing)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINparse
+ uchar *p2parse;
+ int lenMsg;
+#define OpeningText ": %"
+CODESTARTparse
+ dbgprintf("Message will now be parsed by fix Cisco Names parser.\n");
+ assert(pMsg != NULL);
+ assert(pMsg->pszRawMsg != NULL);
+ lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */
+ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
+
+ /* check if this message is of the type we handle in this (very limited) parser */
+ /* first, we permit SP */
+ while(lenMsg && *p2parse == ' ') {
+ --lenMsg;
+ ++p2parse;
+ }
+dbgprintf("pmcisconames: msg to look at: [%d]'%s'\n", lenMsg, p2parse);
+ if((unsigned) lenMsg < 34) {
+ /* too short, can not be "our" message */
+ /* minimum message, 16 character timestamp, 1 character name, ' : %ASA-1-000000: '*/
+dbgprintf("msg too short!\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+ /* check if the timestamp is a 16 character or 21 character timestamp
+ 'Mmm DD HH:MM:SS ' spaces at 3,6,15 : at 9,12
+ 'Mmm DD YYYY HH:MM:SS ' spaces at 3,6,11,20 : at 14,17
+ check for the : first as that will differentiate the two conditions the fastest
+ this allows the compiler to short circuit the rst of the tests if it is the wrong timestamp
+ but still check the rest to see if it looks correct
+ */
+ if ( *(p2parse + 9) == ':' && *(p2parse + 12) == ':' && *(p2parse + 3) == ' ' && *(p2parse + 6) == ' ' && *(p2parse + 15) == ' ') {
+ /* skip over timestamp */
+ dbgprintf("short timestamp found\n");
+ lenMsg -=16;
+ p2parse +=16;
+ } else {
+ if ( *(p2parse + 14) == ':' && *(p2parse + 17) == ':' && *(p2parse + 3) == ' ' && *(p2parse + 6) == ' ' && *(p2parse + 11) == ' ' && *(p2parse + 20) == ' ') {
+ /* skip over timestamp */
+ dbgprintf("long timestamp found\n");
+ lenMsg -=21;
+ p2parse +=21;
+ } else {
+ dbgprintf("timestamp is not one of the valid formats\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+ }
+ /* now look for the next space to walk past the hostname */
+ while(lenMsg && *p2parse != ' ') {
+ --lenMsg;
+ ++p2parse;
+ }
+ /* skip the space after the hostname */
+ lenMsg -=1;
+ p2parse +=1;
+ /* if the syslog tag is : and the next thing starts with a % assume that this is a mangled cisco log and fix it */
+ if(strncasecmp((char*) p2parse, OpeningText, sizeof(OpeningText)-1) != 0) {
+ /* wrong opening text */
+dbgprintf("not a cisco name mangled log!\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+ /* bump the message portion up by two characters to overwrite the extra : */
+ lenMsg -=2;
+ memmove(p2parse, p2parse + 2, lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=2;
+ pMsg->iLenMSG -=2;
+ /* now, claim to abort so that something else can parse the now modified message */
+ DBGPRINTF("pmcisconames: new mesage: [%d]'%s'\n", lenMsg, p2parse);
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+
+finalize_it:
+ENDparse
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(parser, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_PMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+
+ DBGPRINTF("cisconames parser init called, compiled with version %s\n", VERSION);
+ bParseHOSTNAMEandTAG = glbl.GetParseHOSTNAMEandTAG(); /* cache value, is set only during rsyslogd option processing */
+
+
+ENDmodInit
+
+/* vim:set ai:
+ */
diff --git a/plugins/pmlastmsg/pmlastmsg.c b/plugins/pmlastmsg/pmlastmsg.c
index 275f1c1f..259c5d41 100644
--- a/plugins/pmlastmsg/pmlastmsg.c
+++ b/plugins/pmlastmsg/pmlastmsg.c
@@ -47,6 +47,7 @@
#include "unicode-helper.h"
MODULE_TYPE_PARSER
+MODULE_TYPE_NOKEEP
PARSER_NAME("rsyslog.lastline")
/* internal structures
diff --git a/plugins/pmrfc3164sd/pmrfc3164sd.c b/plugins/pmrfc3164sd/pmrfc3164sd.c
index 5598c025..53204ece 100644
--- a/plugins/pmrfc3164sd/pmrfc3164sd.c
+++ b/plugins/pmrfc3164sd/pmrfc3164sd.c
@@ -45,6 +45,7 @@
#include "unicode-helper.h"
MODULE_TYPE_PARSER
+MODULE_TYPE_NOKEEP
PARSER_NAME("contrib.rfc3164sd")
/* internal structures
diff --git a/plugins/pmsnare/Makefile.am b/plugins/pmsnare/Makefile.am
new file mode 100644
index 00000000..5b2696ac
--- /dev/null
+++ b/plugins/pmsnare/Makefile.am
@@ -0,0 +1,8 @@
+pkglib_LTLIBRARIES = pmsnare.la
+
+pmsnare_la_SOURCES = pmsnare.c
+pmsnare_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) -I ../../tools
+pmsnare_la_LDFLAGS = -module -avoid-version
+pmsnare_la_LIBADD =
+
+EXTRA_DIST =
diff --git a/plugins/pmsnare/pmsnare.c b/plugins/pmsnare/pmsnare.c
new file mode 100644
index 00000000..f3658d11
--- /dev/null
+++ b/plugins/pmsnare/pmsnare.c
@@ -0,0 +1,239 @@
+/* pmsnare.c
+ *
+ * this detects logs sent by Snare and cleans them up so that they can be processed by the normal parser
+ *
+ * there are two variations of this, if the client is set to 'syslog' mode it sends
+ *
+ * <pri>timestamp<sp>hostname<sp>tag<tab>otherstuff
+ *
+ * if the client is not set to syslog it sends
+ *
+ * hostname<tab>tag<tab>otherstuff
+ *
+ * ToDo, take advantage of items in the message itself to set more friendly information
+ * where the normal parser will find it by re-writing more of the message
+ *
+ * Intereting information includes:
+ *
+ * in the case of windows snare messages:
+ * the system hostname is field 12
+ * the severity is field 3 (criticality ranging form 0 to 4)
+ * the source of the log is field 4 and may be able to be mapped to facility
+ *
+ *
+ * created 2010-12-13 by David Lang based on pmlastmsg
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "template.h"
+#include "msg.h"
+#include "module-template.h"
+#include "glbl.h"
+#include "errmsg.h"
+#include "parser.h"
+#include "datetime.h"
+#include "unicode-helper.h"
+
+MODULE_TYPE_PARSER
+MODULE_TYPE_NOKEEP
+PARSER_NAME("rsyslog.snare")
+
+/* internal structures
+ */
+DEF_PMOD_STATIC_DATA
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+
+
+/* static data */
+static int bParseHOSTNAMEandTAG; /* cache for the equally-named global param - performance enhancement */
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ if(eFeat == sFEATUREAutomaticSanitazion)
+ iRet = RS_RET_OK;
+ if(eFeat == sFEATUREAutomaticPRIParsing)
+ iRet = RS_RET_OK;
+ENDisCompatibleWithFeature
+
+
+BEGINparse
+ uchar *p2parse;
+ int lenMsg;
+ int snaremessage;
+ int tablength;
+
+CODESTARTparse
+ #define TabRepresentation "#011"
+ tablength=sizeof(TabRepresentation);
+ dbgprintf("Message will now be parsed by fix Snare parser.\n");
+ assert(pMsg != NULL);
+ assert(pMsg->pszRawMsg != NULL);
+
+ /* check if this message is of the type we handle in this (very limited) parser
+
+ find out if we have a space separated or tab separated for the first item
+ if tab separated see if the second word is one of our expected tags
+ if so replace the tabs with spaces so that hostname and syslog tag are going to be parsed properly
+ optionally replace the hostname at the beginning of the message with one from later in the message
+ else, wrong message, abort
+ else, assume that we have a valid timestamp, move over to the syslog tag
+ if that is tab separated from the rest of the message and one of our expected tags
+ if so, replace the tab with a space so that it will be parsed properly
+ optionally replace the hostname at the beginning of the message withone from later in the message
+
+ */
+ snaremessage=0;
+ lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */
+ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
+ dbgprintf("pmsnare: msg to look at: [%d]'%s'\n", lenMsg, p2parse);
+ if((unsigned) lenMsg < 30) {
+ /* too short, can not be "our" message */
+ dbgprintf("msg too short!\n");
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+ }
+
+ while(lenMsg && *p2parse != ' ' && *p2parse != '\t' && *p2parse != '#') {
+ --lenMsg;
+ ++p2parse;
+ }
+ dbgprintf("pmsnare: separator [%d]'%s' msg after the first separator: [%d]'%s'\n", tablength,TabRepresentation,lenMsg, p2parse);
+ if ((lenMsg > tablength) && (*p2parse == '\t' || strncasecmp((char*) p2parse, TabRepresentation , tablength-1) == 0)) {
+ //if ((lenMsg > tablength) && (*p2parse == '\t' || *p2parse == '#')) {
+ dbgprintf("pmsnare: tab separated message\n");
+ if(strncasecmp((char*) (p2parse + tablength - 1), "MSWinEventLog", 13) == 0) {
+ snaremessage=13; /* 0 means not a snare message, a number is how long the tag is */
+ }
+ if(strncasecmp((char*) (p2parse + tablength - 1), "LinuxKAudit", 11) == 0) {
+ snaremessage=11; /* 0 means not a snare message, a number is how long the tag is */
+ }
+ if(snaremessage) {
+ /* replace the tab with a space and if needed move the message portion up by the length of TabRepresentation -2 characters to overwrite the extra : */
+ *p2parse = ' ';
+ lenMsg -=(tablength-2);
+ p2parse++;
+ lenMsg--;
+ memmove(p2parse, p2parse + (tablength-2), lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=(tablength-2);
+ pMsg->iLenMSG -=(tablength-2);
+ p2parse += snaremessage;
+ lenMsg -= snaremessage;
+ *p2parse = ' ';
+ p2parse++;
+ lenMsg--;
+ lenMsg -=(tablength-2);
+ memmove(p2parse, p2parse + (tablength-2), lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=(tablength-2);
+ pMsg->iLenMSG -=(tablength-2);
+ dbgprintf("found a Snare message with snare not set to send syslog messages\n");
+ }
+ } else {
+ /* go back to the beginning of the message */
+ lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */
+ p2parse = pMsg->pszRawMsg + pMsg->offAfterPRI; /* point to start of text, after PRI */
+ /* skip over timestamp and space*/
+ lenMsg -=17;
+ p2parse +=17;
+ /* skip over what should be the hostname */
+ while(lenMsg && *p2parse != ' ') {
+ --lenMsg;
+ ++p2parse;
+ }
+ if (lenMsg){
+ --lenMsg;
+ ++p2parse;
+ }
+ dbgprintf("pmsnare: separator [%d]'%s' msg after the timestamp and hostname: [%d]'%s'\n", tablength,TabRepresentation,lenMsg, p2parse);
+ if(lenMsg > 13 && strncasecmp((char*) p2parse, "MSWinEventLog", 13) == 0) {
+ snaremessage=13; /* 0 means not a snare message, a number is how long the tag is */
+ }
+ if(lenMsg > 11 && strncasecmp((char*) p2parse, "LinuxKAudit", 11) == 0) {
+ snaremessage=11; /* 0 means not a snare message, a number is how long the tag is */
+ }
+ if(snaremessage) {
+ p2parse += snaremessage;
+ lenMsg -= snaremessage;
+ *p2parse = ' ';
+ p2parse++;
+ lenMsg--;
+ lenMsg -=(tablength-2);
+ memmove(p2parse, p2parse + (tablength-2), lenMsg);
+ *(p2parse + lenMsg) = '\n';
+ *(p2parse + lenMsg + 1) = '\0';
+ pMsg->iLenRawMsg -=(tablength-2);
+ pMsg->iLenMSG -=(tablength-2);
+ dbgprintf("found a Snare message with snare set to send syslog messages\n");
+ }
+
+ }
+ DBGPRINTF("pmsnare: new message: [%d]'%s'\n", lenMsg, pMsg->pszRawMsg + pMsg->offAfterPRI);
+ ABORT_FINALIZE(RS_RET_COULD_NOT_PARSE);
+
+finalize_it:
+ENDparse
+
+
+BEGINmodExit
+CODESTARTmodExit
+ /* release what we no longer need */
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(parser, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_PMOD_QUERIES
+CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+
+ DBGPRINTF("snare parser init called, compiled with version %s\n", VERSION);
+ bParseHOSTNAMEandTAG = glbl.GetParseHOSTNAMEandTAG(); /* cache value, is set only during rsyslogd option processing */
+
+
+ENDmodInit
+
+/* vim:set ai:
+ */