diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 16:28:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 16:28:20 +0000 |
commit | dcc721a95bef6f0d8e6d8775b8efe33e5aecd562 (patch) | |
tree | 66a2774cd0ee294d019efd71d2544c70f42b2842 /plugins/omrelp/omrelp.c | |
parent | Initial commit. (diff) | |
download | rsyslog-dcc721a95bef6f0d8e6d8775b8efe33e5aecd562.tar.xz rsyslog-dcc721a95bef6f0d8e6d8775b8efe33e5aecd562.zip |
Adding upstream version 8.2402.0.upstream/8.2402.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | plugins/omrelp/omrelp.c | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c new file mode 100644 index 0000000..5fc1dcc --- /dev/null +++ b/plugins/omrelp/omrelp.c @@ -0,0 +1,826 @@ +/* omrelp.c + * + * This is the implementation of the RELP output module. + * + * Note that when multiple action workers are activated, we currently + * also create multiple actions. This may be the source of some mild + * message loss (!) if the worker instance is shut down while the + * connection to the remote system is in retry state. + * TODO: think if we should implement a mode where we do NOT + * support multiple action worker instances. This would be + * slower, but not have this loss opportunity. But it should + * definitely be optional and by default off due to the + * performance implications (and given the fact that message + * loss is pretty unlikely in usual cases). + * + * + * File begun on 2008-03-13 by RGerhards + * + * Copyright 2008-2019 Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "config.h" +#include "rsyslog.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <ctype.h> +#include <librelp.h> +#include "conf.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "cfsysline.h" +#include "module-template.h" +#include "glbl.h" +#include "errmsg.h" +#include "debug.h" +#include "parserif.h" +#include "unicode-helper.h" + +#ifndef RELP_DFLT_PT +# define RELP_DFLT_PT "514" +#endif + +MODULE_TYPE_OUTPUT +MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omrelp") + +/* internal structures + */ +DEF_OMOD_STATIC_DATA +DEFobjCurrIf(glbl) + +#define DFLT_ENABLE_TLS 0 +#define DFLT_ENABLE_TLSZIP 0 + +static relpEngine_t *pRelpEngine; /* our relp engine */ + +typedef struct _instanceData { + uchar *target; + uchar *port; + int sizeWindow; /**< the RELP window size - 0=use default */ + unsigned timeout; + int connTimeout; + unsigned rebindInterval; + sbool bEnableTLS; + sbool bEnableTLSZip; + sbool bHadAuthFail; /**< set on auth failure, will cause retry to disable action */ + uchar *pristring; /* GnuTLS priority string (NULL if not to be provided) */ + uchar *authmode; + uchar *caCertFile; + uchar *myCertFile; + uchar *myPrivKeyFile; +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + uchar *tlscfgcmd; +#endif + uchar *tplName; + uchar *localClientIP; + struct { + int nmemb; + uchar **name; + } permittedPeers; +} instanceData; + +typedef struct wrkrInstanceData { + instanceData *pData; + int bInitialConnect; /* is this the initial connection request of our module? (0-no, 1-yes) */ + int bIsConnected; /* currently connected to server? 0 - no, 1 - yes */ + int bIsSuspended; /* currently suspended (than no more error messages) */ + relpClt_t *pRelpClt; /* relp client for this instance */ + unsigned nSent; /* number msgs sent - for rebind support */ +} wrkrInstanceData_t; + +typedef struct configSettings_s { + EMPTY_STRUCT +} configSettings_t; +static configSettings_t __attribute__((unused)) cs; + +static rsRetVal doCreateRelpClient(instanceData *pData, relpClt_t **pRelpClt); + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + const char *tlslib; +}; + +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 exec process */ + +/* tables for interfacing with the v6 config system */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "tls.tlslib", eCmdHdlrString, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "target", eCmdHdlrGetWord, 1 }, + { "tls", eCmdHdlrBinary, 0 }, + { "tls.compression", eCmdHdlrBinary, 0 }, + { "tls.prioritystring", eCmdHdlrString, 0 }, + { "tls.cacert", eCmdHdlrString, 0 }, + { "tls.mycert", eCmdHdlrString, 0 }, + { "tls.myprivkey", eCmdHdlrString, 0 }, + { "tls.authmode", eCmdHdlrString, 0 }, + { "tls.tlscfgcmd", eCmdHdlrString, 0 }, + { "tls.permittedpeer", eCmdHdlrArray, 0 }, + { "port", eCmdHdlrGetWord, 0 }, + { "rebindinterval", eCmdHdlrInt, 0 }, + { "windowsize", eCmdHdlrInt, 0 }, + { "timeout", eCmdHdlrInt, 0 }, + { "conn.timeout", eCmdHdlrInt, 0 }, + { "localclientip", eCmdHdlrGetWord, 0 }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + +BEGINinitConfVars /* (re)set config variables to default values */ +CODESTARTinitConfVars +ENDinitConfVars + +/* We may change the implementation to try to lookup the port + * if it is unspecified. So far, we use 514 as default (what probably + * is not a really bright idea, but kept for backward compatibility). + */ + +PRAGMA_DIAGNOSTIC_PUSH +PRAGMA_IGNORE_Wformat_nonliteral +static void __attribute__((format(printf, 1, 2))) +omrelp_dbgprintf(const char *fmt, ...) +{ + va_list ap; + char pszWriteBuf[32*1024+1]; //this function has to be able to + /*generate a buffer longer than that of r_dbgprintf, so + r_dbgprintf can properly truncate*/ + if(!(Debug && debugging_on)) { + return; + } + + va_start(ap, fmt); + vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap); + va_end(ap); + r_dbgprintf("omrelp.c", "%s", pszWriteBuf); +} +PRAGMA_DIAGNOSTIC_POP + + +static uchar *getRelpPt(instanceData *pData) +{ + assert(pData != NULL); + if(pData->port == NULL) + return((uchar*)RELP_DFLT_PT); + else + return(pData->port); +} + +static void +onErr(void *pUsr, char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode) +{ + wrkrInstanceData_t *pWrkrData = (wrkrInstanceData_t*) pUsr; + LogError(0, RS_RET_RELP_AUTH_FAIL, "omrelp[%s:%s]: error '%s', object " + " '%s' - action may not work as intended", + pWrkrData->pData->target, pWrkrData->pData->port, errmesg, objinfo); +} + +static void +onGenericErr(char *objinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode) +{ + LogError(0, RS_RET_RELP_ERR, "omrelp: librelp error '%s', object " + "'%s' - action may not work as intended", + errmesg, objinfo); +} + +static void +onAuthErr(void *pUsr, char *authinfo, char* errmesg, __attribute__((unused)) relpRetVal errcode) +{ + instanceData *pData = ((wrkrInstanceData_t*) pUsr)->pData; + LogError(0, RS_RET_RELP_AUTH_FAIL, "omrelp[%s:%s]: authentication error '%s', peer " + "is '%s' - DISABLING action", pData->target, pData->port, errmesg, authinfo); + pData->bHadAuthFail = 1; +} + +static rsRetVal +doCreateRelpClient(instanceData *pData, relpClt_t **pRelpClt) +{ + int i; + DEFiRet; + + if(relpEngineCltConstruct(pRelpEngine, pRelpClt) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(relpCltSetTimeout(*pRelpClt, pData->timeout) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(relpCltSetConnTimeout(*pRelpClt, pData->connTimeout) != RELP_RET_OK) { + ABORT_FINALIZE(RS_RET_RELP_ERR); + } + if(relpCltSetWindowSize(*pRelpClt, pData->sizeWindow) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(pData->bEnableTLS) { + if(relpCltEnableTLS(*pRelpClt) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(pData->bEnableTLSZip) { + if(relpCltEnableTLSZip(*pRelpClt) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + } + if(relpCltSetGnuTLSPriString(*pRelpClt, (char*) pData->pristring) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + + + if(relpCltSetAuthMode(*pRelpClt, (char*) pData->authmode) != RELP_RET_OK) { + LogError(0, RS_RET_RELP_ERR, + "omrelp: invalid auth mode '%s'\n", pData->authmode); + ABORT_FINALIZE(RS_RET_RELP_ERR); + } + + if(relpCltSetCACert(*pRelpClt, (char*) pData->caCertFile) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(relpCltSetOwnCert(*pRelpClt, (char*) pData->myCertFile) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + if(relpCltSetPrivKey(*pRelpClt, (char*) pData->myPrivKeyFile) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + if (pData->tlscfgcmd != NULL) { + if(relpCltSetTlsConfigCmd(*pRelpClt, (char*) pData->tlscfgcmd) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + } +#endif + for(i = 0 ; i < pData->permittedPeers.nmemb ; ++i) { + relpCltAddPermittedPeer(*pRelpClt, (char*)pData->permittedPeers.name[i]); + } + } + if(pData->localClientIP != NULL) { + if(relpCltSetClientIP(*pRelpClt, pData->localClientIP) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); + } +finalize_it: + + RETiRet; +} + +BEGINendCnfLoad +CODESTARTendCnfLoad + loadModConf = NULL; + runModConf = pModConf; +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf + free((void*)pModConf->tlslib); +ENDfreeCnf + +BEGINcreateInstance +CODESTARTcreateInstance + pData->sizeWindow = 0; + pData->timeout = 90; + pData->connTimeout = 10; + pData->rebindInterval = 0; + pData->bEnableTLS = DFLT_ENABLE_TLS; + pData->bEnableTLSZip = DFLT_ENABLE_TLSZIP; + pData->bHadAuthFail = 0; + pData->pristring = NULL; + pData->authmode = NULL; + pData->localClientIP = NULL; + pData->caCertFile = NULL; + pData->myCertFile = NULL; + pData->myPrivKeyFile = NULL; +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + pData->tlscfgcmd = NULL; +#endif + pData->permittedPeers.nmemb = 0; +ENDcreateInstance + +BEGINcreateWrkrInstance +CODESTARTcreateWrkrInstance + pWrkrData->pRelpClt = NULL; + iRet = doCreateRelpClient(pWrkrData->pData, &pWrkrData->pRelpClt); + if(relpCltSetUsrPtr(pWrkrData->pRelpClt, pWrkrData) != RELP_RET_OK) + LogError(0, RS_RET_NO_ERRCODE, "omrelp: error when creating relp client"); + pWrkrData->bInitialConnect = 1; + pWrkrData->nSent = 0; +ENDcreateWrkrInstance + +BEGINfreeInstance + int i; +CODESTARTfreeInstance + free(pData->target); + free(pData->port); + free(pData->tplName); + free(pData->pristring); + free(pData->authmode); + free(pData->localClientIP); + free(pData->caCertFile); + free(pData->myCertFile); + free(pData->myPrivKeyFile); +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + free(pData->tlscfgcmd); +#endif + if(pData->permittedPeers.name != NULL) { + for(i = 0 ; i < pData->permittedPeers.nmemb ; ++i) { + free(pData->permittedPeers.name[i]); + } + } +ENDfreeInstance + +BEGINfreeWrkrInstance +CODESTARTfreeWrkrInstance + if(pWrkrData->pRelpClt != NULL) + relpEngineCltDestruct(pRelpEngine, &pWrkrData->pRelpClt); +ENDfreeWrkrInstance + +static void +setInstParamDefaults(instanceData *pData) +{ + pData->target = NULL; + pData->port = NULL; + pData->tplName = NULL; + pData->timeout = 90; + pData->connTimeout = 10; + pData->sizeWindow = 0; + pData->rebindInterval = 0; + pData->bEnableTLS = DFLT_ENABLE_TLS; + pData->bEnableTLSZip = DFLT_ENABLE_TLSZIP; + pData->pristring = NULL; + pData->authmode = NULL; + if(glbl.GetSourceIPofLocalClient() == NULL) + pData->localClientIP = NULL; + else + pData->localClientIP = (uchar*)strdup((char*)glbl.GetSourceIPofLocalClient()); + pData->caCertFile = NULL; + pData->myCertFile = NULL; + pData->myPrivKeyFile = NULL; +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + pData->tlscfgcmd = NULL; +#endif + pData->permittedPeers.name = NULL; + pData->permittedPeers.nmemb = 0; +} + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tlslib = NULL; + /* create our relp engine */ + CHKiRet(relpEngineConstruct(&pRelpEngine)); + CHKiRet(relpEngineSetDbgprint(pRelpEngine, (void (*)(char *, ...))omrelp_dbgprintf)); + CHKiRet(relpEngineSetOnAuthErr(pRelpEngine, onAuthErr)); + CHKiRet(relpEngineSetOnGenericErr(pRelpEngine, onGenericErr)); + CHKiRet(relpEngineSetOnErr(pRelpEngine, onErr)); + CHKiRet(relpEngineSetEnableCmd(pRelpEngine, (uchar*) "syslog", eRelpCmdState_Required)); +finalize_it: +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + parser_errmsg("imrelp: error processing module config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for omrelp:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) { + continue; + } + if(!strcmp(modpblk.descr[i].name, "tls.tlslib")) { + #if defined(HAVE_RELPENGINESETTLSLIBBYNAME) + loadModConf->tlslib = es_str2cstr(pvals[i].val.d.estr, NULL); + if(relpEngineSetTLSLibByName(pRelpEngine, loadModConf->tlslib) != RELP_RET_OK) { + LogMsg(0, RS_RET_CONF_PARAM_INVLD, LOG_WARNING, + "omrelp: tlslib '%s' not accepted as valid by librelp - using default", + loadModConf->tlslib); + } + #else + LogError(0, RS_RET_NOT_IMPLEMENTED, + "omrelp warning: parameter tls.tlslib ignored - librelp does not support " + "this API call. Using whatever librelp was compiled with."); + #endif + } else { + dbgprintf("imfile: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + +BEGINnewActInst + struct cnfparamvals *pvals; + int i,j; + FILE *fp; + relpClt_t *pRelpClt = NULL; +CODESTARTnewActInst + if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "target")) { + pData->target = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "port")) { + pData->port = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "localclientip")) { + pData->localClientIP = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "timeout")) { + pData->timeout = (unsigned) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "conn.timeout")) { + pData->connTimeout = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "rebindinterval")) { + pData->rebindInterval = (unsigned) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "windowsize")) { + pData->sizeWindow = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "tls")) { + pData->bEnableTLS = (unsigned) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "tls.compression")) { + pData->bEnableTLSZip = (unsigned) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "tls.prioritystring")) { + pData->pristring = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "tls.cacert")) { + pData->caCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->caCertFile, "r"); + if(fp == NULL) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + LogError(0, RS_RET_NO_FILE_ACCESS, + "error: certificate file %s couldn't be accessed: %s\n", + pData->caCertFile, errStr); + } else { + fclose(fp); + } + } else if(!strcmp(actpblk.descr[i].name, "tls.mycert")) { + pData->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->myCertFile, "r"); + if(fp == NULL) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + LogError(0, RS_RET_NO_FILE_ACCESS, + "error: certificate file %s couldn't be accessed: %s\n", + pData->myCertFile, errStr); + } else { + fclose(fp); + } + } else if(!strcmp(actpblk.descr[i].name, "tls.myprivkey")) { + pData->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + fp = fopen((const char*)pData->myPrivKeyFile, "r"); + if(fp == NULL) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + LogError(0, RS_RET_NO_FILE_ACCESS, + "error: certificate file %s couldn't be accessed: %s\n", + pData->myPrivKeyFile, errStr); + } else { + fclose(fp); + } + } else if(!strcmp(actpblk.descr[i].name, "tls.tlscfgcmd")) { +#if defined(HAVE_RELPENGINESETTLSCFGCMD) + pData->tlscfgcmd = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); +#else + LogError(0, RS_RET_NOT_IMPLEMENTED, "omrelp: librelp does not support input parameter " + "'tls.tlscfgcmd'; it probably is too old (1.5.0 or higher should be fine); " + "ignoring setting now."); +#endif + } else if(!strcmp(actpblk.descr[i].name, "tls.authmode")) { + pData->authmode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "tls.permittedpeer")) { + pData->permittedPeers.nmemb = pvals[i].val.d.ar->nmemb; + CHKmalloc(pData->permittedPeers.name = + malloc(sizeof(uchar*) * pData->permittedPeers.nmemb)); + for(j = 0 ; j < pData->permittedPeers.nmemb ; ++j) { + pData->permittedPeers.name[j] = (uchar*)es_str2cstr(pvals[i].val.d.ar->arr[j], NULL); + } + } else { + dbgprintf("omrelp: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + CODE_STD_STRING_REQUESTnewActInst(1) + + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*)strdup((pData->tplName == NULL) ? + "RSYSLOG_ForwardFormat" : (char*)pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + + iRet = doCreateRelpClient(pData, &pRelpClt); + if(pRelpClt != NULL) + relpEngineCltDestruct(pRelpEngine, &pRelpClt); + +CODE_STD_FINALIZERnewActInst + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature + if(eFeat == sFEATURERepeatedMsgReduction) + iRet = RS_RET_OK; +ENDisCompatibleWithFeature + +BEGINSetShutdownImmdtPtr +CODESTARTSetShutdownImmdtPtr + relpEngineSetShutdownImmdtPtr(pRelpEngine, pPtr); + DBGPRINTF("omrelp: shutdownImmediate ptr now is %p\n", pPtr); +ENDSetShutdownImmdtPtr + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo + dbgprintf("RELP/%s", pData->target); +ENDdbgPrintInstInfo + + +/* try to connect to server + * rgerhards, 2008-03-21 + */ +static rsRetVal ATTR_NONNULL() +doConnect(wrkrInstanceData_t *const pWrkrData) +{ + DEFiRet; + + if(pWrkrData->bInitialConnect) { + iRet = relpCltConnect(pWrkrData->pRelpClt, glbl.GetDefPFFamily(runModConf->pConf), + getRelpPt(pWrkrData->pData), pWrkrData->pData->target); + if(iRet == RELP_RET_OK) + pWrkrData->bInitialConnect = 0; + } else { + iRet = relpCltReconnect(pWrkrData->pRelpClt); + } + + if(iRet == RELP_RET_OK) { + pWrkrData->bIsConnected = 1; + } else if(iRet == RELP_RET_ERR_NO_TLS) { + LogError(0, iRet, "omrelp: Could not connect, librelp does NOT " + "support TLS (most probably GnuTLS lib " + "is too old)!"); + FINALIZE; + } else if(iRet == RELP_RET_ERR_NO_TLS_AUTH) { + LogError(0, iRet, "omrelp: could not activate relp TLS with " + "authentication, librelp does not support it " + "(most probably GnuTLS lib is too old)! " + "Note: anonymous TLS is probably supported."); + FINALIZE; + } else { + if(pWrkrData->bIsSuspended == 0) { + LogError(0, RS_RET_RELP_ERR, "omrelp: could not connect to " + "remote server, librelp error %d", iRet); + } + pWrkrData->bIsConnected = 0; + pWrkrData->bIsSuspended = 1; + iRet = RS_RET_SUSPENDED; + } + +finalize_it: + RETiRet; +} + + +BEGINtryResume +CODESTARTtryResume + if(pWrkrData->pData->bHadAuthFail) { + ABORT_FINALIZE(RS_RET_DISABLE_ACTION); + } + iRet = doConnect(pWrkrData); +finalize_it: +ENDtryResume + +static rsRetVal +doRebind(wrkrInstanceData_t *pWrkrData) +{ + DEFiRet; + DBGPRINTF("omrelp: destructing relp client due to rebindInterval\n"); + CHKiRet(relpEngineCltDestruct(pRelpEngine, &pWrkrData->pRelpClt)); + pWrkrData->bIsConnected = 0; + CHKiRet(doCreateRelpClient(pWrkrData->pData, &pWrkrData->pRelpClt)); + if(relpCltSetUsrPtr(pWrkrData->pRelpClt, pWrkrData) != RELP_RET_OK) + LogError(0, RS_RET_NO_ERRCODE, "omrelp: error when creating relp client"); + pWrkrData->bInitialConnect = 1; + pWrkrData->nSent = 0; +finalize_it: + RETiRet; +} + +BEGINbeginTransaction +CODESTARTbeginTransaction + DBGPRINTF("omrelp: beginTransaction\n"); + if(!pWrkrData->bIsConnected) { + CHKiRet(doConnect(pWrkrData)); + } + relpCltHintBurstBegin(pWrkrData->pRelpClt); +finalize_it: +ENDbeginTransaction + +BEGINdoAction + uchar *pMsg; /* temporary buffering */ + size_t lenMsg; + relpRetVal ret; + instanceData *pData; +CODESTARTdoAction + pData = pWrkrData->pData; + dbgprintf(" %s:%s/RELP\n", pData->target, getRelpPt(pData)); + + if(!pWrkrData->bIsConnected) { + CHKiRet(doConnect(pWrkrData)); + } + + pMsg = ppString[0]; + lenMsg = strlen((char*) pMsg); /* TODO: don't we get this? */ + + /* we need to truncate oversize msgs - no way around that... */ + if((int) lenMsg > glbl.GetMaxLine(runModConf->pConf)) + lenMsg = glbl.GetMaxLine(runModConf->pConf); + + /* forward */ + ret = relpCltSendSyslog(pWrkrData->pRelpClt, (uchar*) pMsg, lenMsg); + if(ret != RELP_RET_OK) { + LogError(0, RS_RET_RELP_ERR, "librelp error %d%s forwarding " + "to server %s:%s - suspending\n", ret, + (ret == RELP_RET_SESSION_BROKEN) ? + "[connection broken]" : "", + pData->target, getRelpPt(pData)); + ABORT_FINALIZE(RS_RET_SUSPENDED); + } + + if(pData->rebindInterval != 0 && + (++pWrkrData->nSent >= pData->rebindInterval)) { + doRebind(pWrkrData); + } +finalize_it: + if(pData->bHadAuthFail) + iRet = RS_RET_DISABLE_ACTION; + if(iRet == RS_RET_OK) { + /* we mimic non-commit, as otherwise our endTransaction handler + * will not get called. While this is not 100% correct, the worst + * that can happen is some message duplication, something that + * rsyslog generally accepts and prefers over message loss. + */ + iRet = RS_RET_PREVIOUS_COMMITTED; + } else if(iRet == RS_RET_SUSPENDED) { + pWrkrData->bIsSuspended = 1; + } +ENDdoAction + + +BEGINendTransaction +CODESTARTendTransaction + DBGPRINTF("omrelp: endTransaction, connected %d\n", pWrkrData->bIsConnected); + if(pWrkrData->bIsConnected) { + relpCltHintBurstEnd(pWrkrData->pRelpClt); + } +ENDendTransaction + +BEGINparseSelectorAct + uchar *q; + int i; + int bErr; +CODESTARTparseSelectorAct +CODE_STD_STRING_REQUESTparseSelectorAct(1) + if(!strncmp((char*) p, ":omrelp:", sizeof(":omrelp:") - 1)) { + p += sizeof(":omrelp:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ + } else { + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + } + + /* ok, if we reach this point, we have something for us */ + if((iRet = createInstance(&pData)) != RS_RET_OK) + FINALIZE; + + /* extract the host first (we do a trick - we replace the ';' or ':' with a '\0') + * now skip to port and then template name. rgerhards 2005-07-06 + */ + if(*p == '[') { /* everything is hostname upto ']' */ + ++p; /* skip '[' */ + for(q = p ; *p && *p != ']' ; ++p) + /* JUST SKIP */; + if(*p == ']') { + *p = '\0'; /* trick to obtain hostname (later)! */ + ++p; /* eat it */ + } + } else { /* traditional view of hostname */ + for(q = p ; *p && *p != ';' && *p != ':' && *p != '#' ; ++p) + /* JUST SKIP */; + } + + pData->port = NULL; + if(*p == ':') { /* process port */ + uchar * tmp; + + *p = '\0'; /* trick to obtain hostname (later)! */ + tmp = ++p; + for(i=0 ; *p && isdigit((int) *p) ; ++p, ++i) + /* SKIP AND COUNT */; + pData->port = malloc(i + 1); + if(pData->port == NULL) { + LogError(0, NO_ERRCODE, "Could not get memory to store relp port, " + "using default port, results may not be what you intend\n"); + /* we leave f_forw.port set to NULL, this is then handled by getRelpPt() */ + } else { + memcpy(pData->port, tmp, i); + *(pData->port + i) = '\0'; + } + } + + /* now skip to template */ + bErr = 0; + while(*p && *p != ';') { + if(*p && *p != ';' && !isspace((int) *p)) { + if(bErr == 0) { /* only 1 error msg! */ + bErr = 1; + errno = 0; + LogError(0, NO_ERRCODE, "invalid selector line (port), probably not doing " + "what was intended"); + } + } + ++p; + } + + if(*p == ';') { + *p = '\0'; /* trick to obtain hostname (later)! */ + CHKmalloc(pData->target = ustrdup(q)); + *p = ';'; + } else { + CHKmalloc(pData->target = ustrdup(q)); + } + + /* process template */ + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_ForwardFormat")); + +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + + +BEGINmodExit +CODESTARTmodExit + relpEngineDestruct(&pRelpEngine); + + /* release what we no longer need */ + objRelease(glbl, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_OMOD8_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES +CODEqueryEtryPt_TXIF_OMOD_QUERIES +CODEqueryEtryPt_SetShutdownImmdtPtr +ENDqueryEtryPt + + +BEGINmodInit() +CODESTARTmodInit +INITLegCnfVars + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + /* tell which objects we need */ + CHKiRet(objUse(glbl, CORE_COMPONENT)); +ENDmodInit |