/* imrelp.c
*
* This is the implementation of the RELP input module.
*
* File begun on 2008-03-13 by RGerhards
*
* Copyright 2008, 2009 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 .
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "rsyslog.h"
#include "dirty.h"
#include "errmsg.h"
#include "cfsysline.h"
#include "module-template.h"
#include "net.h"
#include "msg.h"
#include "unicode-helper.h"
#include "prop.h"
#include "ruleset.h"
MODULE_TYPE_INPUT
MODULE_TYPE_NOKEEP
MODULE_CNFNAME("imrelp")
/* static data */
DEF_IMOD_STATIC_DATA
DEFobjCurrIf(net)
DEFobjCurrIf(prop)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(ruleset)
/* forward definitions */
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
/* Module static data */
/* config vars for legacy config system */
static relpEngine_t *pRelpEngine; /* our relp engine */
static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */
static struct configSettings_s {
uchar *pszBindRuleset; /* name of Ruleset to bind to */
} cs;
struct instanceConf_s {
uchar *pszBindPort; /* port to bind to */
struct instanceConf_s *next;
};
struct modConfData_s {
rsconf_t *pConf; /* our overall config object */
instanceConf_t *root, *tail;
uchar *pszBindRuleset; /* name of Ruleset to bind to */
ruleset_t *pBindRuleset; /* due to librelp limitation, we need to bind all listerns to the same set */
};
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
/* ------------------------------ callbacks ------------------------------ */
/* callback for receiving syslog messages. This function is invoked from the
* RELP engine when a syslog message arrived. It must return a relpRetVal,
* with anything else but RELP_RET_OK terminating the relp session. Please note
* that RELP_RET_OK is equal to RS_RET_OK and the other libRELP error codes
* are different from our rsRetVal. So we can simply use our own iRet system
* to fulfill the requirement.
* rgerhards, 2008-03-21
* Note: librelp 1.0.0 is required in order to receive the IP address, otherwise
* we will only see the hostname (twice). -- rgerhards, 2009-10-14
*/
static relpRetVal
onSyslogRcv(uchar *pHostname, uchar *pIP, uchar *pMsg, size_t lenMsg)
{
DEFiRet;
parseAndSubmitMessage(pHostname, pIP, pMsg, lenMsg, PARSE_HOSTNAME,
eFLOWCTL_LIGHT_DELAY, pInputName, NULL, 0, runModConf->pBindRuleset);
RETiRet;
}
/* ------------------------------ end callbacks ------------------------------ */
/* modified to work for module, not instance (as usual) */
static inline void
std_checkRuleset_genErrMsg(modConfData_t *modConf, __attribute__((unused)) instanceConf_t *inst)
{
errmsg.LogError(0, NO_ERRCODE, "imrelp: ruleset '%s' not found - "
"using default ruleset instead", modConf->pszBindRuleset);
}
/* This function is called when a new listener instace shall be added to
* the current config object via the legacy config system. It just shuffles
* all parameters to the listener in-memory instance.
* rgerhards, 2011-05-04
*/
static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
{
instanceConf_t *inst;
DEFiRet;
CHKmalloc(inst = MALLOC(sizeof(instanceConf_t)));
if(pNewVal == NULL || *pNewVal == '\0') {
errmsg.LogError(0, NO_ERRCODE, "imrelp: port number must be specified, listener ignored");
}
inst->pszBindPort = pNewVal;
inst->next = NULL;
/* node created, let's add to config */
if(loadModConf->tail == NULL) {
loadModConf->tail = loadModConf->root = inst;
} else {
loadModConf->tail->next = inst;
loadModConf->tail = inst;
}
finalize_it:
RETiRet;
}
static rsRetVal
addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst)
{
DEFiRet;
if(pRelpEngine == NULL) {
CHKiRet(relpEngineConstruct(&pRelpEngine));
CHKiRet(relpEngineSetDbgprint(pRelpEngine, dbgprintf));
CHKiRet(relpEngineSetEnableCmd(pRelpEngine, (uchar*) "syslog", eRelpCmdState_Required));
CHKiRet(relpEngineSetSyslogRcv(pRelpEngine, onSyslogRcv));
}
CHKiRet(relpEngineAddListner(pRelpEngine, inst->pszBindPort));
finalize_it:
RETiRet;
}
BEGINbeginCnfLoad
CODESTARTbeginCnfLoad
loadModConf = pModConf;
pModConf->pConf = pConf;
/* init legacy config variables */
cs.pszBindRuleset = NULL;
ENDbeginCnfLoad
BEGINendCnfLoad
CODESTARTendCnfLoad
if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) {
loadModConf->pszBindRuleset = NULL;
} else {
CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset));
}
loadModConf->pBindRuleset = NULL;
finalize_it:
free(cs.pszBindRuleset);
loadModConf = NULL; /* done loading */
ENDendCnfLoad
BEGINcheckCnf
rsRetVal localRet;
ruleset_t *pRuleset;
CODESTARTcheckCnf
/* we emulate the standard "ruleset query" code provided by the framework
* for *instances* (which we can currently not support due to librelp).
*/
if(pModConf->pszBindRuleset == NULL) {
pModConf->pBindRuleset = NULL;
} else {
localRet = ruleset.GetRuleset(pModConf->pConf, &pRuleset, pModConf->pszBindRuleset);
if(localRet == RS_RET_NOT_FOUND) {
std_checkRuleset_genErrMsg(pModConf, NULL);
}
CHKiRet(localRet);
pModConf->pBindRuleset = pRuleset;
}
finalize_it:
ENDcheckCnf
BEGINactivateCnfPrePrivDrop
instanceConf_t *inst;
CODESTARTactivateCnfPrePrivDrop
runModConf = pModConf;
for(inst = runModConf->root ; inst != NULL ; inst = inst->next) {
addListner(pModConf, inst);
}
if(pRelpEngine == NULL)
ABORT_FINALIZE(RS_RET_NO_RUN);
finalize_it:
ENDactivateCnfPrePrivDrop
BEGINactivateCnf
CODESTARTactivateCnf
ENDactivateCnf
BEGINfreeCnf
CODESTARTfreeCnf
ENDfreeCnf
/* This function is called to gather input.
*/
BEGINrunInput
CODESTARTrunInput
/* TODO: we must be careful to start the listener here. Currently, tcpsrv.c seems to
* do that in ConstructFinalize
*/
iRet = relpEngineRun(pRelpEngine);
ENDrunInput
BEGINwillRun
CODESTARTwillRun
ENDwillRun
BEGINafterRun
CODESTARTafterRun
/* do cleanup here */
ENDafterRun
BEGINmodExit
CODESTARTmodExit
if(pRelpEngine != NULL)
iRet = relpEngineDestruct(&pRelpEngine);
/* global variable cleanup */
if(pInputName != NULL)
prop.Destruct(&pInputName);
/* release objects we used */
objRelease(ruleset, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
objRelease(errmsg, CORE_COMPONENT);
ENDmodExit
static rsRetVal
resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
free(cs.pszBindRuleset);
cs.pszBindRuleset = NULL;
return RS_RET_OK;
}
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES
ENDqueryEtryPt
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
pRelpEngine = NULL;
/* request objects we use */
CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(net, LM_NET_FILENAME));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
/* register config file handlers */
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverbindruleset", 0, eCmdHdlrGetWord,
NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, eConfObjGlobal));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverrun", 0, eCmdHdlrGetWord,
addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal));
/* we need to create the inputName property (only once during our lifetime) */
CHKiRet(prop.Construct(&pInputName));
CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imrelp"), sizeof("imrelp") - 1));
CHKiRet(prop.ConstructFinalize(pInputName));
ENDmodInit
/* vim:set ai:
*/