diff --git a/ai/rsyslog_memory_auditor/audit_leaks.txt b/ai/rsyslog_memory_auditor/audit_leaks.txt new file mode 100644 index 000000000..52e792abd --- /dev/null +++ b/ai/rsyslog_memory_auditor/audit_leaks.txt @@ -0,0 +1,17 @@ +You are a senior C security and performance auditor. Analyze the following rsyslog module code specifically for memory leaks on error paths. + +**Audit Focus: Error Path Leaks & Ownership** + +1. **Error Path Leaks**: + - Trace every `RS_RET` return path. + - Ensure that any memory allocated via `malloc`, `calloc`, or `strdup` (common in `setInstParam`) is freed before an error return. + - Check if `pData` or `WID` sub-elements are leaked during partial initialization failure. + +2. **Ownership Ambiguity**: + - Determine if memory passed to a function is "owned" (caller must free) or "transferred" (callee must free). + - In rsyslog, `pData` is typically freed in `freeInstance`, and `WID` in `freeWrkrInstance`. Ensure no double-frees occur during HUP or teardown. + +**Output**: +- List any identified leaks (e.g., "Line 45: ptr is not freed on RS_RET_PARAM_ERROR"). +- Provide a summary of "Clean" vs "At Risk" allocations. +- Suggest specific `free()` placements for identified leaks. diff --git a/ai/rsyslog_memory_auditor/audit_lifecycle.txt b/ai/rsyslog_memory_auditor/audit_lifecycle.txt new file mode 100644 index 000000000..30feddece --- /dev/null +++ b/ai/rsyslog_memory_auditor/audit_lifecycle.txt @@ -0,0 +1,15 @@ +You are a senior C security and performance auditor. Analyze the following rsyslog module code specifically for global and instance lifecycle symmetry. + +**Audit Focus: Lifecycle Symmetry** + +1. **Module Lifecycle**: + - Verify `modInit` and `modExit` balance global resource allocations (mutexes, global hashes, etc.). + - Ensure `createInstance` results in a fully initialized `pData` that `freeInstance` can safely clean up (even if only partially initialized). + +2. **Worker Symmetry**: + - Check that `createWrkrInstance` and `freeWrkrInstance` are balanced. + - Look for thread-local storage or resources that might not be cleaned up if a thread terminates unexpectedly. + +**Output**: +- List any identified symmetry issues (e.g., "Mutex initialized in modInit but not destroyed in modExit"). +- Verify if `freeInstance` handles NULL pointers safely. diff --git a/ai/rsyslog_memory_auditor/audit_null_checks.txt b/ai/rsyslog_memory_auditor/audit_null_checks.txt new file mode 100644 index 000000000..3faa04106 --- /dev/null +++ b/ai/rsyslog_memory_auditor/audit_null_checks.txt @@ -0,0 +1,18 @@ +You are a senior C security and performance auditor. Analyze the following rsyslog module code specifically for NULL check compliance and macro usage. + +**Audit Focus: NULL Checks & Memory Macros** + +1. **Memory Macros**: + - Prefer `CHKmalloc()` for allocations. It handles the `NULL` check and jumps to `finalize_it` (or the local error label) automatically. + - If `malloc` or `strdup` is used directly, verify there is an immediate `NULL` check. + +2. **Function-Specific Checks**: + - `es_str2cstr()` can fail and return `NULL`. Every call MUST be followed by a `NULL` check (or wrapped in `CHKmalloc` logic if applicable). + +3. **String Handling**: + - Look for `strdup()` calls. Are they matched by a `free()`? + - Check for buffer overflows in `snprintf` or `strcpy` (though `format-code.sh` helps, logic errors remain). + +**Output**: +- List any identified risks (e.g., "Line 123: es_str2cstr return is not checked"). +- Suggest macro replacements (like `CHKmalloc`) where appropriate. diff --git a/contrib/imhttp/imhttp.c b/contrib/imhttp/imhttp.c index 3b02e384a..d0b8a18b6 100644 --- a/contrib/imhttp/imhttp.c +++ b/contrib/imhttp/imhttp.c @@ -110,8 +110,9 @@ struct instanceConf_s { uchar *pszBasicAuthFile; /* file containing basic auth users/pass */ ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ ratelimit_t *ratelimiter; - unsigned int ratelimitInterval; - unsigned int ratelimitBurst; + int ratelimitInterval; + int ratelimitBurst; + uchar *pszRatelimitName; uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ prop_t *pInputName; sbool flowControl; @@ -162,6 +163,7 @@ static struct cnfparamdescr inppdescr[] = {{"endpoint", eCmdHdlrString, 0}, {"name", eCmdHdlrString, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, {"ratelimit.burst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}, {"addmetadata", eCmdHdlrBinary, 0}}; #include "im-helper.h" /* must be included AFTER the type definitions! */ @@ -218,8 +220,9 @@ static rsRetVal createInstance(instanceConf_t **pinst) { inst->ratelimiter = NULL; inst->pszInputName = NULL; inst->pInputName = NULL; - inst->ratelimitBurst = 10000; /* arbitrary high limit */ - inst->ratelimitInterval = 0; /* off */ + inst->ratelimitBurst = -1; + inst->ratelimitInterval = -1; + inst->pszRatelimitName = NULL; inst->flowControl = 1; inst->bDisableLFDelim = 0; inst->bSuppOctetFram = 0; @@ -1069,9 +1072,11 @@ BEGINnewInpInst } else if (!strcmp(inppblk.descr[i].name, "name")) { inst->pszInputName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(inppblk.descr[i].name, "ratelimit.burst")) { - inst->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + inst->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(inppblk.descr[i].name, "ratelimit.interval")) { - inst->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + inst->ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(inppblk.descr[i].name, "ratelimit.name")) { + inst->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(inppblk.descr[i].name, "flowcontrol")) { inst->flowControl = (int)pvals[i].val.d.n; } else if (!strcmp(inppblk.descr[i].name, "disablelfdelimiter")) { @@ -1088,13 +1093,31 @@ BEGINnewInpInst } } + if (inst->pszRatelimitName != NULL) { + if (inst->ratelimitInterval != -1 || inst->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "imhttp: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + inst->ratelimitInterval = 0; + inst->ratelimitBurst = 0; + } else { + if (inst->ratelimitInterval == -1) inst->ratelimitInterval = 0; + if (inst->ratelimitBurst == -1) inst->ratelimitBurst = 10000; + } + if (inst->pszInputName) { CHKiRet(prop.Construct(&inst->pInputName)); CHKiRet(prop.SetString(inst->pInputName, inst->pszInputName, ustrlen(inst->pszInputName))); CHKiRet(prop.ConstructFinalize(inst->pInputName)); } - CHKiRet(ratelimitNew(&inst->ratelimiter, "imphttp", NULL)); - ratelimitSetLinuxLike(inst->ratelimiter, inst->ratelimitInterval, inst->ratelimitBurst); + if (inst->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&inst->ratelimiter, loadModConf->pConf, (char *)inst->pszRatelimitName, "imhttp", + NULL)); + } else { + CHKiRet(ratelimitNew(&inst->ratelimiter, "imhttp", NULL)); + ratelimitSetLinuxLike(inst->ratelimiter, (unsigned)inst->ratelimitInterval, (unsigned)inst->ratelimitBurst); + } finalize_it: CODE_STD_FINALIZERnewInpInst cnfparamvalsDestruct(pvals, &inppblk); @@ -1336,6 +1359,7 @@ BEGINfreeCnf free(inst->pszBasicAuthFile); free(inst->pszBindRuleset); free(inst->pszInputName); + free(inst->pszRatelimitName); del = inst; inst = inst->next; diff --git a/contrib/omhttp/omhttp.c b/contrib/omhttp/omhttp.c index fd70829d2..616a9067a 100644 --- a/contrib/omhttp/omhttp.c +++ b/contrib/omhttp/omhttp.c @@ -190,8 +190,9 @@ typedef struct instanceConf_s { unsigned int *httpRetryCodes; int nIgnorableCodes; unsigned int *ignorableCodes; - unsigned int ratelimitInterval; - unsigned int ratelimitBurst; + int ratelimitInterval; + int ratelimitBurst; + uchar *pszRatelimitName; /* for retries */ ratelimit_t *ratelimiter; uchar *retryRulesetName; @@ -283,6 +284,7 @@ static struct cnfparamdescr actpdescr[] = { {"retry.ruleset", eCmdHdlrString, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, {"ratelimit.burst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}, {"name", eCmdHdlrGetWord, 0}, {"httpignorablecodes", eCmdHdlrArray, 0}, {"profile", eCmdHdlrGetWord, 0}, @@ -387,6 +389,7 @@ BEGINfreeInstance free(pData->retryRulesetName); free(pData->ignorableCodes); if (pData->ratelimiter != NULL) ratelimitDestruct(pData->ratelimiter); + free(pData->pszRatelimitName); if (pData->bFreeBatchFormatName) free(pData->batchFormatName); if (pData->listObjStats != NULL) { const int numStats = pData->statsBySenders ? pData->numServers : 1; @@ -473,8 +476,8 @@ BEGINdbgPrintInstInfo dbgprintf("\tretry='%d'\n", pData->retryFailures); dbgprintf("\tretry.addmetadata='%d'\n", pData->retryAddMetadata); dbgprintf("\tretry.ruleset='%s'\n", pData->retryRulesetName); - dbgprintf("\tratelimit.interval='%u'\n", pData->ratelimitInterval); - dbgprintf("\tratelimit.burst='%u'\n", pData->ratelimitBurst); + dbgprintf("\tratelimit.interval='%d'\n", pData->ratelimitInterval); + dbgprintf("\tratelimit.burst='%d'\n", pData->ratelimitBurst); for (i = 0; i < pData->nIgnorableCodes; ++i) dbgprintf("%c'%d'", i == 0 ? '[' : ' ', pData->ignorableCodes[i]); dbgprintf("]\n"); dbgprintf("\tratelimit.interval='%d'\n", pData->ratelimitInterval); @@ -1981,9 +1984,10 @@ static void ATTR_NONNULL() setInstParamDefaults(instanceData *const pData) { pData->retryAddMetadata = 0; pData->nhttpRetryCodes = 0; pData->httpRetryCodes = NULL; - pData->ratelimitBurst = 20000; - pData->ratelimitInterval = 600; + pData->ratelimitBurst = -1; + pData->ratelimitInterval = -1; pData->ratelimiter = NULL; + pData->pszRatelimitName = NULL; pData->retryRulesetName = NULL; pData->retryRuleset = NULL; pData->nIgnorableCodes = 0; @@ -2433,9 +2437,11 @@ BEGINnewActInst } else if (!strcmp(actpblk.descr[i].name, "retry.addmetadata")) { pData->retryAddMetadata = pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.burst")) { - pData->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + pData->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.interval")) { - pData->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + pData->ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "ratelimit.name")) { + pData->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(actpblk.descr[i].name, "name")) { pData->statsName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(actpblk.descr[i].name, "httpignorablecodes")) { @@ -2467,6 +2473,19 @@ BEGINnewActInst } } + if (pData->pszRatelimitName != NULL) { + if (pData->ratelimitInterval != -1 || pData->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "omhttp: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + pData->ratelimitInterval = 0; + pData->ratelimitBurst = 0; + } else { + if (pData->ratelimitInterval == -1) pData->ratelimitInterval = 600; + if (pData->ratelimitBurst == -1) pData->ratelimitBurst = 20000; + } + if (pData->pwd != NULL && pData->uid == NULL) { LogError(0, RS_RET_UID_MISSING, "omhttp: password is provided, but no uid " @@ -2611,8 +2630,14 @@ BEGINnewActInst } if (pData->retryFailures) { - CHKiRet(ratelimitNew(&pData->ratelimiter, "omhttp", NULL)); - ratelimitSetLinuxLike(pData->ratelimiter, pData->ratelimitInterval, pData->ratelimitBurst); + if (pData->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&pData->ratelimiter, loadModConf->pConf, (char *)pData->pszRatelimitName, + "omhttp", NULL)); + } else { + CHKiRet(ratelimitNew(&pData->ratelimiter, "omhttp", NULL)); + ratelimitSetLinuxLike(pData->ratelimiter, (unsigned)pData->ratelimitInterval, + (unsigned)pData->ratelimitBurst); + } ratelimitSetNoTimeCache(pData->ratelimiter); } diff --git a/doc/Makefile.am b/doc/Makefile.am index 265167817..3ef051db7 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -520,6 +520,7 @@ EXTRA_DIST = \ source/reference/parameters/imgssapi-inputgssserverpermitplaintcp.rst \ source/reference/parameters/imgssapi-inputgssserverrun.rst \ source/reference/parameters/imgssapi-inputgssserverservicename.rst \ + source/reference/parameters/imhttp-ratelimit-name.rst \ source/reference/parameters/imjournal-defaultfacility.rst \ source/reference/parameters/imjournal-defaultseverity.rst \ source/reference/parameters/imjournal-defaulttag.rst \ @@ -531,6 +532,7 @@ EXTRA_DIST = \ source/reference/parameters/imjournal-persiststateinterval.rst \ source/reference/parameters/imjournal-ratelimit-burst.rst \ source/reference/parameters/imjournal-ratelimit-interval.rst \ + source/reference/parameters/imjournal-ratelimit-name.rst \ source/reference/parameters/imjournal-remote.rst \ source/reference/parameters/imjournal-statefile.rst \ source/reference/parameters/imjournal-usepid.rst \ @@ -551,6 +553,7 @@ EXTRA_DIST = \ source/reference/parameters/imklog-permitnonkernelfacility.rst \ source/reference/parameters/imklog-ratelimitburst.rst \ source/reference/parameters/imklog-ratelimitinterval.rst \ + source/reference/parameters/imklog-ratelimit-name.rst \ source/reference/parameters/immark-interval.rst \ source/reference/parameters/immark-markmessagetext.rst \ source/reference/parameters/immark-ruleset.rst \ @@ -709,6 +712,7 @@ EXTRA_DIST = \ source/reference/parameters/imuxsock-parsetrusted.rst \ source/reference/parameters/imuxsock-ratelimit-burst.rst \ source/reference/parameters/imuxsock-ratelimit-interval.rst \ + source/reference/parameters/imuxsock-ratelimit-name.rst \ source/reference/parameters/imuxsock-ratelimit-severity.rst \ source/reference/parameters/imuxsock-ruleset.rst \ source/reference/parameters/imuxsock-socket.rst \ @@ -721,6 +725,7 @@ EXTRA_DIST = \ source/reference/parameters/imuxsock-syssock-parsetrusted.rst \ source/reference/parameters/imuxsock-syssock-ratelimit-burst.rst \ source/reference/parameters/imuxsock-syssock-ratelimit-interval.rst \ + source/reference/parameters/imuxsock-syssock-ratelimit-name.rst \ source/reference/parameters/imuxsock-syssock-ratelimit-severity.rst \ source/reference/parameters/imuxsock-syssock-unlink.rst \ source/reference/parameters/imuxsock-syssock-use.rst \ @@ -878,6 +883,7 @@ EXTRA_DIST = \ source/reference/parameters/omelasticsearch-pwd.rst \ source/reference/parameters/omelasticsearch-ratelimit-burst.rst \ source/reference/parameters/omelasticsearch-ratelimit-interval.rst \ + source/reference/parameters/omelasticsearch-ratelimit-name.rst \ source/reference/parameters/omelasticsearch-rebindinterval.rst \ source/reference/parameters/omelasticsearch-retryfailures.rst \ source/reference/parameters/omelasticsearch-retryruleset.rst \ @@ -895,6 +901,7 @@ EXTRA_DIST = \ source/reference/parameters/omelasticsearch-uid.rst \ source/reference/parameters/omelasticsearch-usehttps.rst \ source/reference/parameters/omelasticsearch-writeoperation.rst \ + source/reference/parameters/omfwd-ratelimit-name.rst \ source/reference/parameters/omfile-addlf.rst \ source/reference/parameters/omfile-asyncwriting.rst \ source/reference/parameters/omfile-closetimeout.rst \ @@ -959,6 +966,7 @@ EXTRA_DIST = \ source/reference/parameters/omhttp-pwd.rst \ source/reference/parameters/omhttp-ratelimit-burst.rst \ source/reference/parameters/omhttp-ratelimit-interval.rst \ + source/reference/parameters/omhttp-ratelimit-name.rst \ source/reference/parameters/omhttp-reloadonhup.rst \ source/reference/parameters/omhttp-restpath.rst \ source/reference/parameters/omhttp-restpathtimeout.rst \ diff --git a/doc/source/configuration/modules/imhttp.rst b/doc/source/configuration/modules/imhttp.rst index 148b9b8b0..14279ed74 100644 --- a/doc/source/configuration/modules/imhttp.rst +++ b/doc/source/configuration/modules/imhttp.rst @@ -264,6 +264,13 @@ RateLimit.Burst Specifies the rate-limiting burst in number of messages. +RateLimit.Name +^^^^^^^^^^^^^^ + +.. include:: ../../reference/parameters/imhttp-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end + flowControl ^^^^^^^^^^^ diff --git a/doc/source/configuration/modules/imjournal.rst b/doc/source/configuration/modules/imjournal.rst index ed7a1f544..68c07f645 100644 --- a/doc/source/configuration/modules/imjournal.rst +++ b/doc/source/configuration/modules/imjournal.rst @@ -77,6 +77,10 @@ Module Parameters - .. include:: ../../reference/parameters/imjournal-ratelimit-burst.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-imjournal-ratelimit-name` + - .. include:: ../../reference/parameters/imjournal-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end * - :ref:`param-imjournal-ignorepreviousmessages` - .. include:: ../../reference/parameters/imjournal-ignorepreviousmessages.rst :start-after: .. summary-start @@ -143,6 +147,7 @@ Parameters specific to the input module. ../../reference/parameters/imjournal-statefile ../../reference/parameters/imjournal-ratelimit-interval ../../reference/parameters/imjournal-ratelimit-burst + ../../reference/parameters/imjournal-ratelimit-name ../../reference/parameters/imjournal-ignorepreviousmessages ../../reference/parameters/imjournal-defaultseverity ../../reference/parameters/imjournal-defaultfacility diff --git a/doc/source/configuration/modules/imklog.rst b/doc/source/configuration/modules/imklog.rst index 78bb42348..38f7e446a 100644 --- a/doc/source/configuration/modules/imklog.rst +++ b/doc/source/configuration/modules/imklog.rst @@ -64,6 +64,10 @@ Module Parameters - .. include:: ../../reference/parameters/imklog-ratelimitburst.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-imklog-ratelimit-name` + - .. include:: ../../reference/parameters/imklog-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end Caveats/Known Bugs @@ -136,5 +140,6 @@ Unsupported |FmtObsoleteName| directives ../../reference/parameters/imklog-logpath ../../reference/parameters/imklog-ratelimitinterval ../../reference/parameters/imklog-ratelimitburst + ../../reference/parameters/imklog-ratelimit-name diff --git a/doc/source/configuration/modules/imuxsock.rst b/doc/source/configuration/modules/imuxsock.rst index 2c8fa3250..702112863 100644 --- a/doc/source/configuration/modules/imuxsock.rst +++ b/doc/source/configuration/modules/imuxsock.rst @@ -90,6 +90,10 @@ Module Parameters - .. include:: ../../reference/parameters/imuxsock-syssock-ratelimit-severity.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-imuxsock-syssock-ratelimit-name` + - .. include:: ../../reference/parameters/imuxsock-syssock-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end * - :ref:`param-imuxsock-syssock-usesystimestamp` - .. include:: ../../reference/parameters/imuxsock-syssock-usesystimestamp.rst :start-after: .. summary-start @@ -152,6 +156,10 @@ Input Parameters - .. include:: ../../reference/parameters/imuxsock-ratelimit-severity.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-imuxsock-ratelimit-name` + - .. include:: ../../reference/parameters/imuxsock-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end * - :ref:`param-imuxsock-usepidfromsystem` - .. include:: ../../reference/parameters/imuxsock-usepidfromsystem.rst :start-after: .. summary-start @@ -539,6 +547,7 @@ system log socket. ../../reference/parameters/imuxsock-syssock-ratelimit-interval ../../reference/parameters/imuxsock-syssock-ratelimit-burst ../../reference/parameters/imuxsock-syssock-ratelimit-severity + ../../reference/parameters/imuxsock-syssock-ratelimit-name ../../reference/parameters/imuxsock-syssock-usesystimestamp ../../reference/parameters/imuxsock-syssock-annotate ../../reference/parameters/imuxsock-syssock-parsetrusted @@ -552,6 +561,7 @@ system log socket. ../../reference/parameters/imuxsock-ratelimit-interval ../../reference/parameters/imuxsock-ratelimit-burst ../../reference/parameters/imuxsock-ratelimit-severity + ../../reference/parameters/imuxsock-ratelimit-name ../../reference/parameters/imuxsock-usepidfromsystem ../../reference/parameters/imuxsock-usesystimestamp ../../reference/parameters/imuxsock-createpath diff --git a/doc/source/configuration/modules/omelasticsearch.rst b/doc/source/configuration/modules/omelasticsearch.rst index ab5de44a2..9f5c8b366 100644 --- a/doc/source/configuration/modules/omelasticsearch.rst +++ b/doc/source/configuration/modules/omelasticsearch.rst @@ -201,6 +201,10 @@ Action Parameters - .. include:: ../../reference/parameters/omelasticsearch-ratelimit-burst.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-omelasticsearch-ratelimit-name` + - .. include:: ../../reference/parameters/omelasticsearch-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end * - :ref:`param-omelasticsearch-rebindinterval` - .. include:: ../../reference/parameters/omelasticsearch-rebindinterval.rst :start-after: .. summary-start @@ -246,6 +250,7 @@ Action Parameters ../../reference/parameters/omelasticsearch-retryruleset ../../reference/parameters/omelasticsearch-ratelimit-interval ../../reference/parameters/omelasticsearch-ratelimit-burst + ../../reference/parameters/omelasticsearch-ratelimit-name ../../reference/parameters/omelasticsearch-rebindinterval .. _omelasticsearch-statistic-counter: diff --git a/doc/source/configuration/modules/omfwd.rst b/doc/source/configuration/modules/omfwd.rst index 1eff44497..fca2f57a7 100644 --- a/doc/source/configuration/modules/omfwd.rst +++ b/doc/source/configuration/modules/omfwd.rst @@ -577,6 +577,14 @@ RateLimit.Burst Specifies the rate-limiting burst in number of messages. +RateLimit.Name +^^^^^^^^^^^^^^ + +.. include:: ../../reference/parameters/omfwd-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end + + StreamDriver ^^^^^^^^^^^^ diff --git a/doc/source/configuration/modules/omhttp.rst b/doc/source/configuration/modules/omhttp.rst index dfbff31f1..4a58405ae 100644 --- a/doc/source/configuration/modules/omhttp.rst +++ b/doc/source/configuration/modules/omhttp.rst @@ -164,6 +164,10 @@ Input Parameters - .. include:: ../../reference/parameters/omhttp-ratelimit-burst.rst :start-after: .. summary-start :end-before: .. summary-end + * - :ref:`param-omhttp-ratelimit-name` + - .. include:: ../../reference/parameters/omhttp-ratelimit-name.rst + :start-after: .. summary-start + :end-before: .. summary-end * - :ref:`param-omhttp-errorfile` - .. include:: ../../reference/parameters/omhttp-errorfile.rst :start-after: .. summary-start @@ -241,6 +245,7 @@ Input Parameters ../../reference/parameters/omhttp-retry-addmetadata ../../reference/parameters/omhttp-ratelimit-interval ../../reference/parameters/omhttp-ratelimit-burst + ../../reference/parameters/omhttp-ratelimit-name ../../reference/parameters/omhttp-errorfile ../../reference/parameters/omhttp-compress ../../reference/parameters/omhttp-compress-level diff --git a/doc/source/reference/parameters/imhttp-ratelimit-name.rst b/doc/source/reference/parameters/imhttp-ratelimit-name.rst new file mode 100644 index 000000000..c615a99bb --- /dev/null +++ b/doc/source/reference/parameters/imhttp-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! imhttp; RateLimit.Name + +.. _param-imhttp-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. This allows multiple listeners to share the same rate +limiting configuration (and state). The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, local per-listener limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/imjournal-ratelimit-name.rst b/doc/source/reference/parameters/imjournal-ratelimit-name.rst new file mode 100644 index 000000000..501c6ead9 --- /dev/null +++ b/doc/source/reference/parameters/imjournal-ratelimit-name.rst @@ -0,0 +1,25 @@ +.. index:: ! imjournal; RateLimit.Name + +.. _param-imjournal-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, inline rate limit parameters cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/imklog-ratelimit-name.rst b/doc/source/reference/parameters/imklog-ratelimit-name.rst new file mode 100644 index 000000000..f4bfa2406 --- /dev/null +++ b/doc/source/reference/parameters/imklog-ratelimit-name.rst @@ -0,0 +1,25 @@ +.. index:: ! imklog; RateLimit.Name + +.. _param-imklog-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimitinterval`` and +``ratelimitburst``. If ``ratelimit.name`` is specified, inline rate limit parameters cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/imuxsock-ratelimit-name.rst b/doc/source/reference/parameters/imuxsock-ratelimit-name.rst new file mode 100644 index 000000000..7116186d2 --- /dev/null +++ b/doc/source/reference/parameters/imuxsock-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! imuxsock; RateLimit.Name + +.. _param-imuxsock-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use for this socket. This allows multiple sockets to share +the same rate limiting configuration (and state). The name refers to a :doc:`global rate limit +object <../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, local per-socket limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/imuxsock-syssock-ratelimit-name.rst b/doc/source/reference/parameters/imuxsock-syssock-ratelimit-name.rst new file mode 100644 index 000000000..ad1750514 --- /dev/null +++ b/doc/source/reference/parameters/imuxsock-syssock-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! imuxsock; SysSock.RateLimit.Name + +.. _param-imuxsock-syssock-ratelimit-name: + +SysSock.RateLimit.Name +====================== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use for the system log socket. The name refers to a +:doc:`global rate limit object <../../rainerscript/configuration_objects/ratelimit>` defined in +the configuration. + +**Note:** This parameter is mutually exclusive with ``syssock.ratelimit.interval`` and +``syssock.ratelimit.burst``. If ``syssock.ratelimit.name`` is specified, local limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/omelasticsearch-ratelimit-name.rst b/doc/source/reference/parameters/omelasticsearch-ratelimit-name.rst new file mode 100644 index 000000000..9125ca971 --- /dev/null +++ b/doc/source/reference/parameters/omelasticsearch-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! omelasticsearch; RateLimit.Name + +.. _param-omelasticsearch-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. This allows multiple actions to share the same rate +limiting configuration (and state). The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, local per-action limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/omfwd-ratelimit-name.rst b/doc/source/reference/parameters/omfwd-ratelimit-name.rst new file mode 100644 index 000000000..33a598572 --- /dev/null +++ b/doc/source/reference/parameters/omfwd-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! omfwd; RateLimit.Name + +.. _param-omfwd-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. This allows multiple actions to share the same rate +limiting configuration (and state). The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, local per-action limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/doc/source/reference/parameters/omhttp-ratelimit-name.rst b/doc/source/reference/parameters/omhttp-ratelimit-name.rst new file mode 100644 index 000000000..2bad1a41f --- /dev/null +++ b/doc/source/reference/parameters/omhttp-ratelimit-name.rst @@ -0,0 +1,26 @@ +.. index:: ! omhttp; RateLimit.Name + +.. _param-omhttp-ratelimit-name: + +RateLimit.Name +============== + +.. summary-start + +**Default:** none + +**Type:** string + +**Description:** + +Sets the name of the rate limit to use. This allows multiple actions to share the same rate +limiting configuration (and state). The name refers to a :doc:`global rate limit object +<../../rainerscript/configuration_objects/ratelimit>` defined in the configuration. + +**Note:** This parameter is mutually exclusive with ``ratelimit.interval`` and +``ratelimit.burst``. If ``ratelimit.name`` is specified, local per-action limits cannot be +defined and any attempt to do so will result in an error (and the named rate limit will be used). + +.. versionadded:: 8.2602.0 + +.. summary-end diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c index 0e0df6cb6..7b4e93c16 100644 --- a/plugins/imjournal/imjournal.c +++ b/plugins/imjournal/imjournal.c @@ -87,8 +87,9 @@ static struct configSettings_s { char *stateFile; int fCreateMode; /* default mode to use when creating new files, e.g. stateFile */ int iPersistStateInterval; - unsigned int ratelimitInterval; - unsigned int ratelimitBurst; + int ratelimitInterval; + int ratelimitBurst; + char *pszRatelimitName; int bIgnorePrevious; int bIgnoreNonValidStatefile; int iDfltSeverity; @@ -108,6 +109,7 @@ static struct cnfparamdescr modpdescr[] = {{"statefile", eCmdHdlrGetWord, 0}, {"filecreatemode", eCmdHdlrFileCreateMode, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, {"ratelimit.burst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}, {"persiststateinterval", eCmdHdlrInt, 0}, {"ignorepreviousmessages", eCmdHdlrBinary, 0}, {"ignorenonvalidstatefile", eCmdHdlrBinary, 0}, @@ -1036,9 +1038,14 @@ static void stopSrvWrkr(journal_etry_t *const etry) { BEGINrunInput CODESTARTrunInput; - CHKiRet(ratelimitNew(&ratelimiter, "imjournal", NULL)); - dbgprintf("imjournal: ratelimiting burst %u, interval %u\n", cs.ratelimitBurst, cs.ratelimitInterval); - ratelimitSetLinuxLike(ratelimiter, cs.ratelimitInterval, cs.ratelimitBurst); + if (cs.pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&ratelimiter, runModConf->pConf, cs.pszRatelimitName, "imjournal", NULL)); + } else { + CHKiRet(ratelimitNew(&ratelimiter, "imjournal", NULL)); + dbgprintf("imjournal: ratelimiting burst %u, interval %u\n", (unsigned)cs.ratelimitBurst, + (unsigned)cs.ratelimitInterval); + ratelimitSetLinuxLike(ratelimiter, (unsigned)cs.ratelimitInterval, (unsigned)cs.ratelimitBurst); + } ratelimitSetNoTimeCache(ratelimiter); /* handling old "usepidfromsystem" option */ @@ -1076,8 +1083,9 @@ BEGINbeginCnfLoad cs.iPersistStateInterval = DFLT_persiststateinterval; cs.stateFile = NULL; cs.fCreateMode = 0644; - cs.ratelimitBurst = 20000; - cs.ratelimitInterval = 600; + cs.ratelimitBurst = -1; + cs.ratelimitInterval = -1; + cs.pszRatelimitName = NULL; cs.iDfltSeverity = DFLT_SEVERITY; cs.iDfltFacility = DFLT_FACILITY; cs.bUseJnlPID = -1; @@ -1228,6 +1236,8 @@ BEGINfreeCnf free(cs.stateFile); free(cs.usePid); free(cs.dfltTag); + free(cs.pszRatelimitName); + cs.pszRatelimitName = NULL; statsobj.Destruct(&(statsCounter.stats)); ENDfreeCnf @@ -1266,6 +1276,8 @@ BEGINafterRun if (ratelimiter) { ratelimitDestruct(ratelimiter); } + free(cs.pszRatelimitName); + cs.pszRatelimitName = NULL; ENDafterRun @@ -1311,9 +1323,12 @@ BEGINsetModCnf } else if (!strcmp(modpblk.descr[i].name, "filecreatemode")) { cs.fCreateMode = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "ratelimit.burst")) { - cs.ratelimitBurst = (unsigned int)pvals[i].val.d.n; + cs.ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "ratelimit.interval")) { - cs.ratelimitInterval = (unsigned int)pvals[i].val.d.n; + cs.ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(modpblk.descr[i].name, "ratelimit.name")) { + free(cs.pszRatelimitName); + cs.pszRatelimitName = (char *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(modpblk.descr[i].name, "ignorepreviousmessages")) { cs.bIgnorePrevious = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "ignorenonvalidstatefile")) { @@ -1349,6 +1364,17 @@ BEGINsetModCnf } } + if (cs.pszRatelimitName != NULL) { + if (cs.ratelimitInterval != -1 || cs.ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "imjournal: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + } else { + if (cs.ratelimitInterval == -1) cs.ratelimitInterval = 600; + if (cs.ratelimitBurst == -1) cs.ratelimitBurst = 20000; + } + finalize_it: if (pvals != NULL) cnfparamvalsDestruct(pvals, &modpblk); ENDsetModCnf diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index f10e2eea0..eb963a6de 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -99,7 +99,8 @@ static struct cnfparamdescr modpdescr[] = {{"ruleset", eCmdHdlrString, 0}, {"keepkerneltimestamp", eCmdHdlrBinary, 0}, {"internalmsgfacility", eCmdHdlrFacility, 0}, {"ratelimitinterval", eCmdHdlrInt, 0}, - {"ratelimitburst", eCmdHdlrInt, 0}}; + {"ratelimitburst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}}; static struct cnfparamblk modpblk = {CNFPARAMBLK_VERSION, sizeof(modpdescr) / sizeof(struct cnfparamdescr), modpdescr}; static prop_t *pInputName = NULL; @@ -316,8 +317,9 @@ BEGINbeginCnfLoad pModConf->iFacilIntMsg = klogFacilIntMsg(); loadModConf->configSetViaV2Method = 0; pModConf->ratelimiter = NULL; - pModConf->ratelimitBurst = 10000; /* arbitrary high limit */ - pModConf->ratelimitInterval = 0; /* off */ + pModConf->ratelimitBurst = -1; + pModConf->ratelimitInterval = -1; + pModConf->pszRatelimitName = NULL; bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ initConfigSettings(); @@ -356,9 +358,11 @@ BEGINsetModCnf } else if (!strcmp(modpblk.descr[i].name, "internalmsgfacility")) { loadModConf->iFacilIntMsg = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "ratelimitburst")) { - loadModConf->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + loadModConf->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "ratelimitinterval")) { - loadModConf->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + loadModConf->ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(modpblk.descr[i].name, "ratelimit.name")) { + loadModConf->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(modpblk.descr[i].name, "ruleset")) { loadModConf->pszBindRuleset = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else { @@ -369,6 +373,17 @@ BEGINsetModCnf } } + if (loadModConf->pszRatelimitName != NULL) { + if (loadModConf->ratelimitInterval != -1 || loadModConf->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "imklog: ratelimit.name is mutually exclusive with " + "ratelimitinterval and ratelimitburst - using ratelimit.name"); + } + } else { + if (loadModConf->ratelimitInterval == -1) loadModConf->ratelimitInterval = 0; + if (loadModConf->ratelimitBurst == -1) loadModConf->ratelimitBurst = 10000; + } + /* disable legacy module-global config directives */ bLegacyCnfModGlobalsPermitted = 0; loadModConf->configSetViaV2Method = 1; @@ -415,8 +430,14 @@ ENDactivateCnfPrePrivDrop BEGINactivateCnf CODESTARTactivateCnf; - CHKiRet(ratelimitNew(&runModConf->ratelimiter, "imklog", NULL)); - ratelimitSetLinuxLike(runModConf->ratelimiter, runModConf->ratelimitInterval, runModConf->ratelimitBurst); + if (runModConf->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&runModConf->ratelimiter, runModConf->pConf, + (char *)runModConf->pszRatelimitName, "imklog", NULL)); + } else { + CHKiRet(ratelimitNew(&runModConf->ratelimiter, "imklog", NULL)); + ratelimitSetLinuxLike(runModConf->ratelimiter, (unsigned)runModConf->ratelimitInterval, + (unsigned)runModConf->ratelimitBurst); + } finalize_it: ENDactivateCnf @@ -424,6 +445,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf; free(pModConf->pszBindRuleset); + free(pModConf->pszRatelimitName); ENDfreeCnf @@ -436,7 +458,7 @@ ENDwillRun BEGINafterRun CODESTARTafterRun; - ratelimitDestruct(runModConf->ratelimiter); + if (runModConf->ratelimiter != NULL) ratelimitDestruct(runModConf->ratelimiter); iRet = klogAfterRun(runModConf); ENDafterRun diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index 65841f350..4652ce2a2 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -43,6 +43,7 @@ struct modConfData_s { ratelimit_t *ratelimiter; int ratelimitInterval; int ratelimitBurst; + uchar *pszRatelimitName; ruleset_t *pBindRuleset; /* ruleset to bind (use system default if unspecified) */ uchar *pszBindRuleset; }; diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 9a206c5ad..572f545bb 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -213,9 +213,10 @@ struct instanceConf_s { sbool bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */ sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */ int bCreatePath; /* auto-create socket path? */ - unsigned int ratelimitInterval; /* interval in seconds, 0 = off */ - unsigned int ratelimitBurst; /* max nbr of messages in interval */ + int ratelimitInterval; /* interval in seconds, 0 = off */ + int ratelimitBurst; /* max nbr of messages in interval */ int ratelimitSeverity; + uchar *pszRatelimitName; int bAnnotate; /* annotate trusted properties */ int bParseTrusted; /* parse trusted properties */ sbool bDiscardOwnMsgs; /* discard messages that originated from our own pid? */ @@ -231,9 +232,10 @@ struct modConfData_s { rsconf_t *pConf; /* our overall config object */ instanceConf_t *root, *tail; uchar *pLogSockName; - unsigned int ratelimitIntervalSysSock; - unsigned int ratelimitBurstSysSock; + int ratelimitIntervalSysSock; + int ratelimitBurstSysSock; int ratelimitSeveritySysSock; + uchar *pszRatelimitNameSysSock; int bAnnotateSysSock; int bParseTrusted; int bUseSpecialParser; @@ -265,7 +267,8 @@ static struct cnfparamdescr modpdescr[] = {{"syssock.use", eCmdHdlrBinary, 0}, {"syssock.usepidfromsystem", eCmdHdlrBinary, 0}, {"syssock.ratelimit.interval", eCmdHdlrInt, 0}, {"syssock.ratelimit.burst", eCmdHdlrInt, 0}, - {"syssock.ratelimit.severity", eCmdHdlrInt, 0}}; + {"syssock.ratelimit.severity", eCmdHdlrInt, 0}, + {"syssock.ratelimit.name", eCmdHdlrString, 0}}; static struct cnfparamblk modpblk = {CNFPARAMBLK_VERSION, sizeof(modpdescr) / sizeof(struct cnfparamdescr), modpdescr}; /* input instance parameters */ @@ -286,7 +289,8 @@ static struct cnfparamdescr inppdescr[] = { {"ruleset", eCmdHdlrString, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, {"ratelimit.burst", eCmdHdlrInt, 0}, - {"ratelimit.severity", eCmdHdlrInt, 0}}; + {"ratelimit.severity", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}}; static struct cnfparamblk inppblk = {CNFPARAMBLK_VERSION, sizeof(inppdescr) / sizeof(struct cnfparamdescr), inppdescr}; #include "im-helper.h" /* must be included AFTER the type definitions! */ @@ -305,9 +309,10 @@ static rsRetVal createInstance(instanceConf_t **pinst) { inst->pLogHostName = NULL; inst->pszBindRuleset = NULL; inst->pBindRuleset = NULL; - inst->ratelimitInterval = DFLT_ratelimitInterval; - inst->ratelimitBurst = DFLT_ratelimitBurst; + inst->ratelimitInterval = -1; + inst->ratelimitBurst = -1; inst->ratelimitSeverity = DFLT_ratelimitSeverity; + inst->pszRatelimitName = NULL; inst->bUseFlowCtl = 0; inst->bUseSpecialParser = DFLT_bUseSpecialParser; inst->bParseHost = UNSET; @@ -398,7 +403,7 @@ static rsRetVal addListner(instanceConf_t *inst) { CHKiRet(prop.SetString(listeners[nfd].hostName, inst->pLogHostName, ustrlen(inst->pLogHostName))); CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName)); } - if (inst->ratelimitInterval > 0) { + if (inst->pszRatelimitName != NULL || inst->ratelimitInterval > 0) { if ((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, (void (*)(void *))ratelimitDestruct)) == NULL) { /* in this case, we simply turn off rate-limiting */ @@ -406,6 +411,8 @@ static rsRetVal addListner(instanceConf_t *inst) { "imuxsock: turning off rate limiting because we could not " "create hash table\n"); inst->ratelimitInterval = 0; + free(inst->pszRatelimitName); + inst->pszRatelimitName = NULL; } } else { listeners[nfd].ht = NULL; @@ -418,7 +425,7 @@ static rsRetVal addListner(instanceConf_t *inst) { listeners[nfd].bCreatePath = inst->bCreatePath; listeners[nfd].sockName = ustrdup(inst->sockName); listeners[nfd].bUseCreds = (inst->bDiscardOwnMsgs || inst->bWritePid || inst->ratelimitInterval || - inst->bAnnotate || inst->bUseSysTimeStamp) + inst->pszRatelimitName || inst->bAnnotate || inst->bUseSysTimeStamp) ? 1 : 0; listeners[nfd].bAnnotate = inst->bAnnotate; @@ -429,9 +436,14 @@ static rsRetVal addListner(instanceConf_t *inst) { listeners[nfd].bUseSysTimeStamp = inst->bUseSysTimeStamp; listeners[nfd].bUseSpecialParser = inst->bUseSpecialParser; listeners[nfd].pRuleset = inst->pBindRuleset; - CHKiRet(ratelimitNew(&listeners[nfd].dflt_ratelimiter, "imuxsock", NULL)); - ratelimitSetLinuxLike(listeners[nfd].dflt_ratelimiter, listeners[nfd].ratelimitInterval, - listeners[nfd].ratelimitBurst); + if (inst->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&listeners[nfd].dflt_ratelimiter, runModConf->pConf, + (char *)inst->pszRatelimitName, "imuxsock", NULL)); + } else { + CHKiRet(ratelimitNew(&listeners[nfd].dflt_ratelimiter, "imuxsock", NULL)); + ratelimitSetLinuxLike(listeners[nfd].dflt_ratelimiter, listeners[nfd].ratelimitInterval, + listeners[nfd].ratelimitBurst); + } ratelimitSetSeverity(listeners[nfd].dflt_ratelimiter, listeners[nfd].ratelimitSev); nfd++; @@ -1107,7 +1119,7 @@ static rsRetVal activateListeners(void) { } } #endif - if (runModConf->ratelimitIntervalSysSock > 0) { + if (runModConf->pszRatelimitNameSysSock != NULL || runModConf->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 */ LogError(0, NO_ERRCODE, @@ -1126,11 +1138,11 @@ static rsRetVal activateListeners(void) { listeners[0].ratelimitInterval = runModConf->ratelimitIntervalSysSock; listeners[0].ratelimitBurst = runModConf->ratelimitBurstSysSock; listeners[0].ratelimitSev = runModConf->ratelimitSeveritySysSock; - listeners[0].bUseCreds = - (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || runModConf->bAnnotateSysSock || - runModConf->bDiscardOwnMsgs || runModConf->bUseSysTimeStamp) - ? 1 - : 0; + listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || + runModConf->pszRatelimitNameSysSock || runModConf->bAnnotateSysSock || + runModConf->bDiscardOwnMsgs || runModConf->bUseSysTimeStamp) + ? 1 + : 0; listeners[0].bWritePid = runModConf->bWritePidSysSock; listeners[0].bAnnotate = runModConf->bAnnotateSysSock; listeners[0].bParseTrusted = runModConf->bParseTrusted; @@ -1141,9 +1153,14 @@ static rsRetVal activateListeners(void) { listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp; listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG; listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; - CHKiRet(ratelimitNew(&listeners[0].dflt_ratelimiter, "imuxsock", NULL)); - ratelimitSetLinuxLike(listeners[0].dflt_ratelimiter, listeners[0].ratelimitInterval, - listeners[0].ratelimitBurst); + if (runModConf->pszRatelimitNameSysSock != NULL) { + CHKiRet(ratelimitNewFromConfig(&listeners[0].dflt_ratelimiter, runModConf->pConf, + (char *)runModConf->pszRatelimitNameSysSock, "imuxsock", NULL)); + } else { + CHKiRet(ratelimitNew(&listeners[0].dflt_ratelimiter, "imuxsock", NULL)); + ratelimitSetLinuxLike(listeners[0].dflt_ratelimiter, listeners[0].ratelimitInterval, + listeners[0].ratelimitBurst); + } ratelimitSetSeverity(listeners[0].dflt_ratelimiter, listeners[0].ratelimitSev); } @@ -1196,9 +1213,10 @@ BEGINbeginCnfLoad */ pModConf->bDiscardOwnMsgs = pConf->globals.bProcessInternalMessages; pModConf->bUnlink = 1; - pModConf->ratelimitIntervalSysSock = DFLT_ratelimitInterval; - pModConf->ratelimitBurstSysSock = DFLT_ratelimitBurst; + pModConf->ratelimitIntervalSysSock = -1; + pModConf->ratelimitBurstSysSock = -1; pModConf->ratelimitSeveritySysSock = DFLT_ratelimitSeverity; + pModConf->pszRatelimitNameSysSock = NULL; bLegacyCnfModGlobalsPermitted = 1; /* reset legacy config vars */ resetConfigVariables(NULL, NULL); @@ -1249,11 +1267,13 @@ BEGINsetModCnf } else if (!strcmp(modpblk.descr[i].name, "syssock.usepidfromsystem")) { loadModConf->bWritePidSysSock = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "syssock.ratelimit.interval")) { - loadModConf->ratelimitIntervalSysSock = (unsigned int)pvals[i].val.d.n; + loadModConf->ratelimitIntervalSysSock = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "syssock.ratelimit.burst")) { - loadModConf->ratelimitBurstSysSock = (unsigned int)pvals[i].val.d.n; + loadModConf->ratelimitBurstSysSock = (int)pvals[i].val.d.n; } else if (!strcmp(modpblk.descr[i].name, "syssock.ratelimit.severity")) { loadModConf->ratelimitSeveritySysSock = (int)pvals[i].val.d.n; + } else if (!strcmp(modpblk.descr[i].name, "syssock.ratelimit.name")) { + loadModConf->pszRatelimitNameSysSock = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else { dbgprintf( "imuxsock: program error, non-handled " @@ -1262,6 +1282,17 @@ BEGINsetModCnf } } + if (loadModConf->pszRatelimitNameSysSock != NULL) { + if (loadModConf->ratelimitIntervalSysSock != -1 || loadModConf->ratelimitBurstSysSock != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "imuxsock: syssock.ratelimit.name is mutually exclusive with " + "syssock.ratelimit.interval and syssock.ratelimit.burst - using syssock.ratelimit.name"); + } + } else { + if (loadModConf->ratelimitIntervalSysSock == -1) loadModConf->ratelimitIntervalSysSock = DFLT_ratelimitInterval; + if (loadModConf->ratelimitBurstSysSock == -1) loadModConf->ratelimitBurstSysSock = DFLT_ratelimitBurst; + } + /* disable legacy module-global config directives */ bLegacyCnfModGlobalsPermitted = 0; loadModConf->configSetViaV2Method = 1; @@ -1322,11 +1353,13 @@ BEGINnewInpInst } else if (!strcmp(inppblk.descr[i].name, "ruleset")) { inst->pszBindRuleset = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(inppblk.descr[i].name, "ratelimit.interval")) { - inst->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + inst->ratelimitInterval = (int)pvals[i].val.d.n; } else if (!strcmp(inppblk.descr[i].name, "ratelimit.burst")) { - inst->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + inst->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(inppblk.descr[i].name, "ratelimit.severity")) { inst->ratelimitSeverity = (int)pvals[i].val.d.n; + } else if (!strcmp(inppblk.descr[i].name, "ratelimit.name")) { + inst->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else { dbgprintf( "imuxsock: program error, non-handled " @@ -1334,6 +1367,18 @@ BEGINnewInpInst inppblk.descr[i].name); } } + + if (inst->pszRatelimitName != NULL) { + if (inst->ratelimitInterval != -1 || inst->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "imuxsock: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + } else { + if (inst->ratelimitInterval == -1) inst->ratelimitInterval = DFLT_ratelimitInterval; + if (inst->ratelimitBurst == -1) inst->ratelimitBurst = DFLT_ratelimitBurst; + } + finalize_it: CODE_STD_FINALIZERnewInpInst cnfparamvalsDestruct(pvals, &inppblk); ENDnewInpInst @@ -1432,10 +1477,12 @@ BEGINfreeCnf instanceConf_t *inst, *del; CODESTARTfreeCnf; free(pModConf->pLogSockName); + free(pModConf->pszRatelimitNameSysSock); for (inst = pModConf->root; inst != NULL;) { free(inst->sockName); free(inst->pszBindRuleset); free(inst->pLogHostName); + free(inst->pszRatelimitName); del = inst; inst = inst->next; free(del); diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c index a953178dc..569ceb2c9 100644 --- a/plugins/omelasticsearch/omelasticsearch.c +++ b/plugins/omelasticsearch/omelasticsearch.c @@ -165,8 +165,9 @@ typedef struct instanceConf_s { uchar *myPrivKeyFile; es_write_ops_t writeOperation; sbool retryFailures; - unsigned int ratelimitInterval; - unsigned int ratelimitBurst; + int ratelimitInterval; + int ratelimitBurst; + uchar *pszRatelimitName; /* for retries */ ratelimit_t *ratelimiter; uchar *retryRulesetName; @@ -240,6 +241,7 @@ static struct cnfparamdescr actpdescr[] = {{"server", eCmdHdlrArray, 0}, {"retryfailures", eCmdHdlrBinary, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, {"ratelimit.burst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}, {"retryruleset", eCmdHdlrString, 0}, {"rebindinterval", eCmdHdlrInt, 0}, {"esversion.major", eCmdHdlrPositiveInt, 0}}; @@ -351,6 +353,7 @@ BEGINfreeInstance free(pData->retryRulesetName); free(pData->detectedVersionString); if (pData->ratelimiter != NULL) ratelimitDestruct(pData->ratelimiter); + free(pData->pszRatelimitName); ENDfreeInstance BEGINfreeWrkrInstance @@ -2178,9 +2181,10 @@ static void ATTR_NONNULL() setInstParamDefaults(instanceData *const pData) { pData->myPrivKeyFile = NULL; pData->writeOperation = ES_WRITE_INDEX; pData->retryFailures = 0; - pData->ratelimitBurst = 20000; - pData->ratelimitInterval = 600; + pData->ratelimitBurst = -1; + pData->ratelimitInterval = -1; pData->ratelimiter = NULL; + pData->pszRatelimitName = NULL; pData->retryRulesetName = NULL; pData->retryRuleset = NULL; pData->rebindInterval = DEFAULT_REBIND_INTERVAL; @@ -2309,9 +2313,11 @@ BEGINnewActInst } else if (!strcmp(actpblk.descr[i].name, "retryfailures")) { pData->retryFailures = pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.burst")) { - pData->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + pData->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.interval")) { - pData->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + pData->ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "ratelimit.name")) { + pData->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(actpblk.descr[i].name, "retryruleset")) { pData->retryRulesetName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(actpblk.descr[i].name, "rebindinterval")) { @@ -2326,6 +2332,19 @@ BEGINnewActInst } } + if (pData->pszRatelimitName != NULL) { + if (pData->ratelimitInterval != -1 || pData->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "omelasticsearch: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + pData->ratelimitInterval = 0; + pData->ratelimitBurst = 0; + } else { + if (pData->ratelimitInterval == -1) pData->ratelimitInterval = 600; + if (pData->ratelimitBurst == -1) pData->ratelimitBurst = 20000; + } + if (pData->apiKey != NULL && (pData->uid != NULL || pData->pwd != NULL)) { LogError(0, RS_RET_CONFIG_ERROR, "omelasticsearch: apikey cannot be combined with uid/pwd " @@ -2474,8 +2493,14 @@ BEGINnewActInst } if (pData->retryFailures) { - CHKiRet(ratelimitNew(&pData->ratelimiter, "omelasticsearch", NULL)); - ratelimitSetLinuxLike(pData->ratelimiter, pData->ratelimitInterval, pData->ratelimitBurst); + if (pData->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&pData->ratelimiter, loadModConf->pConf, (char *)pData->pszRatelimitName, + "omelasticsearch", NULL)); + } else { + CHKiRet(ratelimitNew(&pData->ratelimiter, "omelasticsearch", NULL)); + ratelimitSetLinuxLike(pData->ratelimiter, (unsigned)pData->ratelimitInterval, + (unsigned)pData->ratelimitBurst); + } ratelimitSetNoTimeCache(pData->ratelimiter); } diff --git a/tests/Makefile.am b/tests/Makefile.am index b786adbfd..997ea6832 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -239,6 +239,13 @@ TESTS_DEFAULT = \ sndrcv_udp_nonstdpt_v6.sh \ imudp_thread_hang.sh \ imudp_ratelimit_name.sh \ + omfwd_ratelimit_name.sh \ + omelasticsearch_ratelimit_name.sh \ + omhttp_ratelimit_name.sh \ + imhttp_ratelimit_name.sh \ + imjournal_ratelimit_name.sh \ + imklog_ratelimit_name.sh \ + imuxsock_ratelimit_name.sh \ asynwr_simple.sh \ asynwr_simple_2.sh \ asynwr_timeout.sh \ @@ -598,7 +605,11 @@ TESTS_IMTCP_VALGRIND = \ TESTS_RATELIMIT = \ ratelimit_exclusivity.sh \ ratelimit_name.sh \ - ratelimit_duplicate.sh + ratelimit_duplicate.sh \ + omfwd_ratelimit_name.sh \ + omelasticsearch_ratelimit_name.sh \ + imklog_ratelimit_name.sh \ + imuxsock_ratelimit_name.sh TESTS_IMTCP_IMPSTATS = \ imtcp-impstats.sh @@ -757,7 +768,8 @@ TESTS_OMHTTP_FLAKY_VALGRIND = \ TESTS_IMJOURNAL = \ imjournal-basic.sh \ - imjournal-statefile.sh + imjournal-statefile.sh \ + imjournal_ratelimit_name.sh TESTS_IMJOURNAL_VALGRIND = \ imjournal-basic-vg.sh \ @@ -834,7 +846,8 @@ TESTS_OMHTTP = \ omhttp-httpheaderkey.sh \ omhttp-multiplehttpheaders.sh \ omhttp-dynrestpath.sh \ - omhttp-batch-dynrestpath.sh + omhttp-batch-dynrestpath.sh \ + omhttp_ratelimit_name.sh TESTS_OMHTTP_VALGRIND = \ omhttp-auth-vg.sh \ @@ -917,7 +930,8 @@ TESTS_IMHTTP = \ imhttp-post-payload-compress.sh \ imhttp-getrequest-file.sh \ imhttp-healthcheck.sh \ - imhttp-metrics.sh + imhttp-metrics.sh \ + imhttp_ratelimit_name.sh TESTS_IMHTTP_VALGRIND = \ imhttp-post-payload-vg.sh \ diff --git a/tests/imhttp_ratelimit_name.sh b/tests/imhttp_ratelimit_name.sh new file mode 100755 index 000000000..9513bbadf --- /dev/null +++ b/tests/imhttp_ratelimit_name.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Test named rate limits for imhttp (config-validation) +# Verifies that imhttp accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +generate_conf +add_conf ' +ratelimit(name="imhttp_test_limit" interval="2" burst="5") + +module(load="../contrib/imhttp/.libs/imhttp" + ports="0" + listenportfilename="'$RSYSLOG_DYNNAME'.imhttp.port") +input(type="imhttp" endpoint="/test" ratelimit.name="imhttp_test_limit" ruleset="imhttp") + +template(name="outfmt" type="string" string="%msg%\n") +ruleset(name="imhttp") { + action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +} +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/imjournal_ratelimit_name.sh b/tests/imjournal_ratelimit_name.sh new file mode 100755 index 000000000..f72ebdb1d --- /dev/null +++ b/tests/imjournal_ratelimit_name.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Test named rate limits for imjournal (config-validation) +# Verifies that imjournal accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +generate_conf +add_conf ' +ratelimit(name="imjournal_test_limit" interval="2" burst="5") + +module(load="../plugins/imjournal/.libs/imjournal" + ratelimit.name="imjournal_test_limit" + StateFile="'$RSYSLOG_DYNNAME'.imjournal.state" + IgnorePreviousMessages="on") + +template(name="outfmt" type="string" string="%msg%\n") +action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/imklog_ratelimit_name.sh b/tests/imklog_ratelimit_name.sh new file mode 100755 index 000000000..ae55f297f --- /dev/null +++ b/tests/imklog_ratelimit_name.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Test named rate limits for imklog (config-validation) +# Verifies that imklog accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +if [ "$EUID" -ne 0 ]; then + exit 77 # Not root, skip this test +fi +generate_conf +add_conf ' +ratelimit(name="imklog_test_limit" interval="2" burst="5") + +module(load="../plugins/imklog/.libs/imklog" + ratelimit.name="imklog_test_limit") + +template(name="outfmt" type="string" string="%msg%\n") +action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/imuxsock_ratelimit_name.sh b/tests/imuxsock_ratelimit_name.sh new file mode 100755 index 000000000..8ca26b17a --- /dev/null +++ b/tests/imuxsock_ratelimit_name.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Test named rate limits for imuxsock +# Verifies that imuxsock accepts ratelimit.name and +# syssock.ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +generate_conf +add_conf ' +ratelimit(name="imuxsock_test_limit" interval="2" burst="5") +ratelimit(name="imuxsock_syssock_limit" interval="3" burst="10") + +module(load="../plugins/imuxsock/.libs/imuxsock" + SysSock.Use="off") +input(type="imuxsock" Socket="'$RSYSLOG_DYNNAME'-imuxsock.sock" + ratelimit.name="imuxsock_test_limit") + +template(name="outfmt" type="string" string="%msg%\n") +action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/omelasticsearch_ratelimit_name.sh b/tests/omelasticsearch_ratelimit_name.sh new file mode 100755 index 000000000..3c9cc7171 --- /dev/null +++ b/tests/omelasticsearch_ratelimit_name.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Test named rate limits for omelasticsearch (config-validation) +# Verifies that omelasticsearch accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +generate_conf +add_conf ' +ratelimit(name="omelasticsearch_test_limit" interval="2" burst="5") + +module(load="../plugins/omelasticsearch/.libs/omelasticsearch") + +template(name="outfmt" type="string" string="%msg%\n") +action(type="omelasticsearch" server="localhost" serverport="19200" + ratelimit.name="omelasticsearch_test_limit" + retryfailures="on" template="outfmt") +action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/omfwd_ratelimit_name.sh b/tests/omfwd_ratelimit_name.sh new file mode 100755 index 000000000..b7fc30e2b --- /dev/null +++ b/tests/omfwd_ratelimit_name.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Test named rate limits for omfwd (config-validation) +# Verifies that omfwd accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init + +generate_conf +add_conf ' +ratelimit(name="omfwd_test_limit" interval="2" burst="5") + +module(load="../plugins/imudp/.libs/imudp") +input(type="imudp" port="0" listenPortFileName="'$RSYSLOG_DYNNAME'.rcvr.port") + +template(name="outfmt" type="string" string="%msg%\n") +if $msg contains "msgnum:" then + action(type="omfwd" target="127.0.0.1" port="514" protocol="udp" + ratelimit.name="omfwd_test_limit" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tests/omhttp_ratelimit_name.sh b/tests/omhttp_ratelimit_name.sh new file mode 100755 index 000000000..7132fe802 --- /dev/null +++ b/tests/omhttp_ratelimit_name.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Test named rate limits for omhttp (config-validation) +# Verifies that omhttp accepts ratelimit.name without error. +. ${srcdir:=.}/diag.sh init +generate_conf +add_conf ' +ratelimit(name="omhttp_test_limit" interval="2" burst="5") + +module(load="../contrib/omhttp/.libs/omhttp") + +template(name="outfmt" type="string" string="%msg%\n") +action(type="omhttp" server="localhost" serverport="19280" + ratelimit.name="omhttp_test_limit" + retryfailures="on" template="outfmt") +action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt") +' +startup +shutdown_when_empty +wait_shutdown +exit_test diff --git a/tools/omfwd.c b/tools/omfwd.c index c30a03366..9356d5dea 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -145,8 +145,9 @@ typedef struct _instanceData { uint8_t compressionMode; sbool strmCompFlushOnTxEnd; /* flush stream compression on transaction end? */ unsigned poolResumeInterval; - unsigned int ratelimitInterval; - unsigned int ratelimitBurst; + int ratelimitInterval; + int ratelimitBurst; + uchar *pszRatelimitName; ratelimit_t *ratelimiter; targetStats_t *target_stats; } instanceData; @@ -259,7 +260,8 @@ static struct cnfparamdescr actpdescr[] = { {"template", eCmdHdlrGetWord, 0}, {"pool.resumeinterval", eCmdHdlrPositiveInt, 0}, {"ratelimit.interval", eCmdHdlrInt, 0}, - {"ratelimit.burst", eCmdHdlrInt, 0}}; + {"ratelimit.burst", eCmdHdlrInt, 0}, + {"ratelimit.name", eCmdHdlrString, 0}}; static struct cnfparamblk actpblk = {CNFPARAMBLK_VERSION, sizeof(actpdescr) / sizeof(struct cnfparamdescr), actpdescr}; struct modConfData_s { @@ -862,6 +864,7 @@ BEGINfreeInstance free((void *)pData->pszStrmDrvrCRLFile); free((void *)pData->pszStrmDrvrKeyFile); free((void *)pData->pszStrmDrvrCertFile); + free(pData->pszRatelimitName); net.DestructPermittedPeers(&pData->pPermPeers); if (pData->ratelimiter != NULL) { ratelimitDestruct(pData->ratelimiter); @@ -1848,8 +1851,9 @@ static void setInstParamDefaults(instanceData *pData) { pData->ipfreebind = IPFREEBIND_ENABLED_WITH_LOG; pData->poolResumeInterval = 30; pData->ratelimiter = NULL; - pData->ratelimitInterval = 0; - pData->ratelimitBurst = 200; + pData->ratelimitInterval = -1; + pData->ratelimitBurst = -1; + pData->pszRatelimitName = NULL; } @@ -2113,15 +2117,30 @@ BEGINnewActInst } else if (!strcmp(actpblk.descr[i].name, "pool.resumeinterval")) { pData->poolResumeInterval = (unsigned int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.burst")) { - pData->ratelimitBurst = (unsigned int)pvals[i].val.d.n; + pData->ratelimitBurst = (int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "ratelimit.interval")) { - pData->ratelimitInterval = (unsigned int)pvals[i].val.d.n; + pData->ratelimitInterval = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "ratelimit.name")) { + pData->pszRatelimitName = (uchar *)es_str2cstr(pvals[i].val.d.estr, NULL); } else { LogError(0, RS_RET_INTERNAL_ERROR, "omfwd: program error, non-handled parameter '%s'", actpblk.descr[i].name); } } + if (pData->pszRatelimitName != NULL) { + if (pData->ratelimitInterval != -1 || pData->ratelimitBurst != -1) { + LogError(0, RS_RET_INVALID_PARAMS, + "omfwd: ratelimit.name is mutually exclusive with " + "ratelimit.interval and ratelimit.burst - using ratelimit.name"); + } + pData->ratelimitInterval = 0; + pData->ratelimitBurst = 0; + } else { + if (pData->ratelimitInterval == -1) pData->ratelimitInterval = 0; + if (pData->ratelimitBurst == -1) pData->ratelimitBurst = 200; + } + if (pData->targetSrv != NULL && pData->target_name != NULL) { LogError(0, RS_RET_PARAM_ERROR, "omfwd: target and targetSrv are mutually exclusive"); ABORT_FINALIZE(RS_RET_PARAM_ERROR); @@ -2197,9 +2216,13 @@ BEGINnewActInst LogError(0, RS_RET_PARAM_ERROR, "omfwd: parameter \"address\" not supported for tcp -- ignored"); } - if (pData->ratelimitInterval > 0) { + if (pData->pszRatelimitName != NULL) { + CHKiRet(ratelimitNewFromConfig(&pData->ratelimiter, loadModConf->pConf, (char *)pData->pszRatelimitName, + "omfwd", NULL)); + ratelimitSetNoTimeCache(pData->ratelimiter); + } else if (pData->ratelimitInterval > 0) { CHKiRet(ratelimitNew(&pData->ratelimiter, "omfwd", NULL)); - ratelimitSetLinuxLike(pData->ratelimiter, pData->ratelimitInterval, pData->ratelimitBurst); + ratelimitSetLinuxLike(pData->ratelimiter, (unsigned)pData->ratelimitInterval, (unsigned)pData->ratelimitBurst); ratelimitSetNoTimeCache(pData->ratelimiter); }