import rsyslog-8.37.0-13.el8

This commit is contained in:
CentOS Sources 2019-11-05 14:38:14 -05:00 committed by Andrew Lukoshko
commit 5208615781
18 changed files with 3810 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
SOURCES/rsyslog-8.37.0.tar.gz
SOURCES/rsyslog-doc-8.37.0.tar.gz

2
.rsyslog.metadata Normal file
View File

@ -0,0 +1,2 @@
43076e3010fc3fd5178201a916beb93848b5249c SOURCES/rsyslog-8.37.0.tar.gz
4c75f56e2d55c4c87d07781fb6d9deabf63395fb SOURCES/rsyslog-doc-8.37.0.tar.gz

View File

@ -0,0 +1,21 @@
diff -up ./rsyslog.service.in.service ./rsyslog.service.in
--- ./rsyslog.service.in.service 2018-03-01 13:58:11.480598935 +0100
+++ ./rsyslog.service.in 2018-03-01 13:58:25.433518607 +0100
@@ -1,12 +1,16 @@
[Unit]
Description=System Logging Service
Requires=syslog.socket
+Wants=network.target network-online.target
+After=network.target network-online.target
Documentation=man:rsyslogd(8)
Documentation=http://www.rsyslog.com/doc/
[Service]
Type=notify
-ExecStart=@sbindir@/rsyslogd -n -iNONE
+EnvironmentFile=-/etc/sysconfig/rsyslog
+ExecStart=@sbindir@/rsyslogd -n $SYSLOGD_OPTIONS
+UMask=0066
StandardOutput=null
Restart=on-failure

View File

@ -0,0 +1,416 @@
From 3822da837e4d531e8a9cd78ae76359a410f8d98d Mon Sep 17 00:00:00 2001
From: Jiri Vymazal <jvymazal@redhat.com>
Date: Thu, 31 May 2018 16:30:08 +0200
Subject: [PATCH] Symlink support for imfile
this introduces symlink detection and following as well
as monitoring changes on them. Also added test for the new
functionality and ensuring the original symlink behavior
stays as well.
---
plugins/imfile/imfile.c | 182 +++++++++++++++++++++++++++----------
1 file changed, 133 insertions(+), 49 deletions(-)
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 3c9308bfe..4ca23d2ca 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -152,6 +152,7 @@ struct act_obj_s {
fs_edge_t *edge; /* edge which this object belongs to */
char *name; /* full path name of active object */
char *basename; /* only basename */ //TODO: remove when refactoring rename support
+ char *source_name; /* if this object is target of a symlink, source_name is its name (else NULL) */
//char *statefile; /* base name of state file (for move operations) */
int wd;
#if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE)
@@ -167,6 +168,7 @@ struct act_obj_s {
int nRecords; /**< How many records did we process before persisting the stream? */
ratelimit_t *ratelimiter;
multi_submit_t multiSub;
+ int is_symlink;
};
struct fs_edge_s {
fs_node_t *parent;
@@ -181,7 +182,8 @@ struct act_obj_s {
instanceConf_t **instarr;
};
struct fs_node_s {
- fs_edge_t *edges;
+ fs_edge_t *edges; /* NULL in leaf nodes */
+ fs_node_t *root; /* node one level up (NULL for file system root) */
};
@@ -189,7 +191,7 @@ static rsRetVal persistStrmState(act_obj_t *);
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
static rsRetVal ATTR_NONNULL(1) pollFile(act_obj_t *act);
static int ATTR_NONNULL() getBasename(uchar *const __restrict__ basen, uchar *const __restrict__ path);
-static void ATTR_NONNULL() act_obj_unlink(act_obj_t *const act);
+static void ATTR_NONNULL() act_obj_unlink(act_obj_t *act);
static uchar * ATTR_NONNULL(1, 2) getStateFileName(const act_obj_t *, uchar *, const size_t);
static int ATTR_NONNULL() getFullStateFileName(const uchar *const, uchar *const pszout, const size_t ilenout);
@@ -483,14 +485,17 @@ in_setupWatch(act_obj_t *const act, const int is_file)
goto done;
wd = inotify_add_watch(ino_fd, act->name,
- (is_file) ? IN_MODIFY : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
+ (is_file) ? IN_MODIFY|IN_DONT_FOLLOW : IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO);
if(wd < 0) {
- LogError(errno, RS_RET_IO_ERROR, "imfile: cannot watch object '%s'",
- act->name);
+ if (errno == EACCES) { /* There is high probability of selinux denial on top-level paths */
+ DBGPRINTF("imfile: permission denied when adding watch for '%s'\n", act->name);
+ } else {
+ LogError(errno, RS_RET_IO_ERROR, "imfile: cannot watch object '%s'", act->name);
+ }
goto done;
}
wdmapAdd(wd, act);
- DBGPRINTF("in_setupDirWatch: watch %d added for dir %s(%p)\n", wd, act->name, act);
+ DBGPRINTF("in_setupWatch: watch %d added for %s(object %p)\n", wd, act->name, act);
done: return wd;
}
@@ -605,7 +610,7 @@ done: return;
static void ATTR_NONNULL()
fen_setupWatch(act_obj_t *const act __attribute__((unused)))
{
- DBGPRINTF("fen_setupWatch: DUMMY CALLED - not on Solaris?");
+ DBGPRINTF("fen_setupWatch: DUMMY CALLED - not on Solaris?\n");
}
#endif /* FEN */
@@ -633,38 +638,48 @@ fs_node_print(const fs_node_t *const node, const int level)
}
}
-
/* add a new file system object if it not yet exists, ignore call
* if it already does.
*/
-static rsRetVal ATTR_NONNULL()
+static rsRetVal ATTR_NONNULL(1,2)
act_obj_add(fs_edge_t *const edge, const char *const name, const int is_file,
- const ino_t ino)
+ const ino_t ino, const int is_symlink, const char *const source)
{
act_obj_t *act;
char basename[MAXFNAME];
DEFiRet;
- DBGPRINTF("act_obj_add: edge %p, name '%s'\n", edge, name);
+ DBGPRINTF("act_obj_add: edge %p, name '%s' (source '%s')\n", edge, name, source? source : "---");
for(act = edge->active ; act != NULL ; act = act->next) {
if(!strcmp(act->name, name)) {
- DBGPRINTF("active object '%s' already exists in '%s' - no need to add\n",
- name, edge->path);
- FINALIZE;
+ if (!source || !act->source_name || !strcmp(act->source_name, source)) {
+ DBGPRINTF("active object '%s' already exists in '%s' - no need to add\n",
+ name, edge->path);
+ FINALIZE;
+ }
}
}
DBGPRINTF("add new active object '%s' in '%s'\n", name, edge->path);
CHKmalloc(act = calloc(sizeof(act_obj_t), 1));
CHKmalloc(act->name = strdup(name));
- getBasename((uchar*)basename, (uchar*)name);
- CHKmalloc(act->basename = strdup(basename));
+ if (-1 == getBasename((uchar*)basename, (uchar*)name)) {
+ CHKmalloc(act->basename = strdup(name)); /* assume basename is same as name */
+ } else {
+ CHKmalloc(act->basename = strdup(basename));
+ }
act->edge = edge;
act->ino = ino;
+ act->is_symlink = is_symlink;
+ if (source) { /* we are target of symlink */
+ CHKmalloc(act->source_name = strdup(source));
+ } else {
+ act->source_name = NULL;
+ }
#ifdef HAVE_INOTIFY_INIT
act->wd = in_setupWatch(act, is_file);
#endif
fen_setupWatch(act);
- if(is_file) {
+ if(is_file && !is_symlink) {
const instanceConf_t *const inst = edge->instarr[0];// TODO: same file, multiple instances?
CHKiRet(ratelimitNew(&act->ratelimiter, "imfile", name));
CHKmalloc(act->multiSub.ppMsgs = MALLOC(inst->nMultiSub * sizeof(smsg_t *)));
@@ -702,27 +717,24 @@ detect_updates(fs_edge_t *const edge)
{
act_obj_t *act;
struct stat fileInfo;
+ int restart = 0;
- for(act = edge->active ; act != NULL ; ) {
+ for(act = edge->active ; act != NULL ; act = act->next) {
DBGPRINTF("detect_updates checking active obj '%s'\n", act->name);
- const int r = stat(act->name, &fileInfo);
+ const int r = lstat(act->name, &fileInfo);
if(r == -1) { /* object gone away? */
DBGPRINTF("object gone away, unlinking: '%s'\n", act->name);
- act_obj_t *toDel = act;
- act = act->next;
- DBGPRINTF("new next act %p\n", act);
- act_obj_unlink(toDel);
- continue;
+ act_obj_unlink(act);
+ restart = 1;
+ break;
}
// TODO: add inode check for change notification!
- /* Note: active nodes may get deleted, so we need to do the
- * pointer advancement at the end of the for loop!
- */
- act = act->next;
}
-
+ if (restart) {
+ detect_updates(edge);
+ }
}
@@ -746,14 +758,52 @@ poll_active_files(fs_edge_t *const edge)
}
}
+static rsRetVal ATTR_NONNULL()
+process_symlink(fs_edge_t *const chld, const char *symlink)
+{
+ DEFiRet;
+ char *target = NULL;
+ CHKmalloc(target = realpath(symlink, target));
+ struct stat fileInfo;
+ if(lstat(target, &fileInfo) != 0) {
+ LogError(errno, RS_RET_ERR, "imfile: process_symlink: cannot stat file '%s' - ignored", target);
+ FINALIZE;
+ }
+ const int is_file = (S_ISREG(fileInfo.st_mode));
+ DBGPRINTF("process_symlink: found '%s', File: %d (config file: %d), symlink: %d\n",
+ target, is_file, chld->is_file, 0);
+ if (act_obj_add(chld, target, is_file, fileInfo.st_ino, 0, symlink) == RS_RET_OK) {
+ /* need to watch parent target as well for proper rotation support */
+ uint idx = ustrlen(chld->active->name) - ustrlen(chld->active->basename);
+ if (idx) { /* basename is different from name */
+ char parent[MAXFNAME];
+ idx--; /* move past trailing slash */
+ memcpy(parent, chld->active->name, idx);
+ parent[idx] = '\0';
+ if(lstat(parent, &fileInfo) != 0) {
+ LogError(errno, RS_RET_ERR,
+ "imfile: process_symlink: cannot stat directory '%s' - ignored", parent);
+ FINALIZE;
+ }
+ if (chld->parent->root->edges) {
+ DBGPRINTF("process_symlink: adding parent '%s' of target '%s'\n", parent, target);
+ act_obj_add(chld->parent->root->edges, parent, 0, fileInfo.st_ino, 0, NULL);
+ }
+ }
+ }
+
+finalize_it:
+ free(target);
+ RETiRet;
+}
-static void ATTR_NONNULL() poll_tree(fs_edge_t *const chld);
static void ATTR_NONNULL()
poll_tree(fs_edge_t *const chld)
{
struct stat fileInfo;
glob_t files;
int need_globfree = 0;
+ int issymlink;
DBGPRINTF("poll_tree: chld %p, name '%s', path: %s\n", chld, chld->name, chld->path);
detect_updates(chld);
const int ret = glob((char*)chld->path, runModConf->sortFiles|GLOB_BRACE, NULL, &files);
@@ -766,18 +803,27 @@ poll_tree(fs_edge_t *const chld)
goto done;
}
char *const file = files.gl_pathv[i];
- if(stat(file, &fileInfo) != 0) {
+ if(lstat(file, &fileInfo) != 0) {
LogError(errno, RS_RET_ERR,
"imfile: poll_tree cannot stat file '%s' - ignored", file);
continue;
}
- const int is_file = S_ISREG(fileInfo.st_mode);
- DBGPRINTF("poll_tree: found '%s', File: %d (config file: %d)\n",
- file, is_file, chld->is_file);
+ if (S_ISLNK(fileInfo.st_mode)) {
+ rsRetVal slink_ret = process_symlink(chld, file);
+ if (slink_ret != RS_RET_OK) {
+ continue;
+ }
+ issymlink = 1;
+ } else {
+ issymlink = 0;
+ }
+ const int is_file = (S_ISREG(fileInfo.st_mode) || issymlink);
+ DBGPRINTF("poll_tree: found '%s', File: %d (config file: %d), symlink: %d\n",
+ file, is_file, chld->is_file, issymlink);
if(!is_file && S_ISREG(fileInfo.st_mode)) {
LogMsg(0, RS_RET_ERR, LOG_WARNING,
- "imfile: '%s' is neither a regular file nor a "
+ "imfile: '%s' is neither a regular file, symlink, nor a "
"directory - ignored", file);
continue;
}
@@ -788,7 +834,7 @@ poll_tree(fs_edge_t *const chld)
(chld->is_file) ? "FILE" : "DIRECTORY");
continue;
}
- act_obj_add(chld, file, is_file, fileInfo.st_ino);
+ act_obj_add(chld, file, is_file, fileInfo.st_ino, issymlink, NULL);
}
}
@@ -829,8 +875,20 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted)
if(act == NULL)
return;
- DBGPRINTF("act_obj_destroy: act %p '%s', wd %d, pStrm %p, is_deleted %d, in_move %d\n",
- act, act->name, act->wd, act->pStrm, is_deleted, act->in_move);
+ DBGPRINTF("act_obj_destroy: act %p '%s' (source '%s'), wd %d, pStrm %p, is_deleted %d, in_move %d\n",
+ act, act->name, act->source_name? act->source_name : "---", act->wd, act->pStrm, is_deleted,
+ act->in_move);
+ if(act->is_symlink && is_deleted) {
+ act_obj_t *target_act;
+ for(target_act = act->edge->active ; target_act != NULL ; target_act = target_act->next) {
+ if(target_act->source_name && !strcmp(target_act->source_name, act->name)) {
+ DBGPRINTF("act_obj_destroy: unlinking slink target %s of %s "
+ "symlink\n", target_act->name, act->name);
+ act_obj_unlink(target_act);
+ break;
+ }
+ }
+ }
if(act->ratelimiter != NULL) {
ratelimitDestruct(act->ratelimiter);
}
@@ -862,6 +920,7 @@ act_obj_destroy(act_obj_t *const act, const int is_deleted)
}
#endif
free(act->basename);
+ free(act->source_name);
//free(act->statefile);
free(act->multiSub.ppMsgs);
#if defined(OS_SOLARIS) && defined (HAVE_PORT_SOURCE_FILE)
@@ -909,7 +968,7 @@ chk_active(const act_obj_t *act, const act_obj_t *const deleted)
* destruct it.
*/
static void //ATTR_NONNULL()
-act_obj_unlink(act_obj_t *const act)
+act_obj_unlink(act_obj_t *act)
{
DBGPRINTF("act_obj_unlink %p: %s\n", act, act->name);
if(act->prev == NULL) {
@@ -921,6 +980,7 @@ act_obj_unlink(act_obj_t *const act)
act->next->prev = act->prev;
}
act_obj_destroy(act, 1);
+ act = NULL;
//dbgprintf("printout of fs tree post unlink\n");
//fs_node_print(runModConf->conf_tree, 0);
//dbg_wdmapPrint("wdmap after");
@@ -1025,6 +1038,7 @@ fs_node_walk(fs_node_t *const node,
*/
static rsRetVal
fs_node_add(fs_node_t *const node,
+ fs_node_t *const source,
const uchar *const toFind,
const size_t pathIdx,
instanceConf_t *const inst)
@@ -1053,6 +1067,7 @@ fs_node_add(fs_node_t *const node,
memcpy(name, toFind+pathIdx, len);
name[len] = '\0';
DBGPRINTF("fs_node_add: name '%s'\n", name);
+ node->root = source;
fs_edge_t *chld;
for(chld = node->edges ; chld != NULL ; chld = chld->next) {
@@ -1064,7 +1079,7 @@ fs_node_add(fs_node_t *const node,
chld->instarr[chld->ninst-1] = inst;
/* recurse */
if(!isFile) {
- CHKiRet(fs_node_add(chld->node, toFind, nextPathIdx, inst));
+ CHKiRet(fs_node_add(chld->node, node, toFind, nextPathIdx, inst));
}
FINALIZE;
}
@@ -1086,7 +1101,7 @@ fs_node_add(fs_node_t *const node,
DBGPRINTF("fs_node_add(%p, '%s') returns %p\n", node, toFind, newchld->node);
if(!isFile) {
- CHKiRet(fs_node_add(newchld->node, toFind, nextPathIdx, inst));
+ CHKiRet(fs_node_add(newchld->node, node, toFind, nextPathIdx, inst));
}
/* link to list */
@@ -1162,7 +1222,11 @@ enqLine(act_obj_t *const act,
msgSetPRI(pMsg, inst->iFacility | inst->iSeverity);
MsgSetRuleset(pMsg, inst->pBindRuleset);
if(inst->addMetadata) {
- metadata_values[0] = (const uchar*)act->name;
+ if (act->source_name) {
+ metadata_values[0] = (const uchar*)act->source_name;
+ } else {
+ metadata_values[0] = (const uchar*)act->name;
+ }
snprintf((char *)file_offset, MAX_OFFSET_REPRESENTATION_NUM_BYTES+1, "%lld", strtOffs);
metadata_values[1] = file_offset;
msgAddMultiMetadata(pMsg, metadata_names, metadata_values, 2);
@@ -1389,13 +1453,16 @@ pollFile(act_obj_t *const act)
{
cstr_t *pCStr = NULL;
DEFiRet;
+ if (act->is_symlink) {
+ FINALIZE; /* no reason to poll symlink file */
+ }
/* Note: we must do pthread_cleanup_push() immediately, because the POSIX macros
* otherwise do not work if I include the _cleanup_pop() inside an if... -- rgerhards, 2008-08-14
*/
pthread_cleanup_push(pollFileCancelCleanup, &pCStr);
iRet = pollFileReal(act, &pCStr);
pthread_cleanup_pop(0);
- RETiRet;
+finalize_it: RETiRet;
}
@@ -1931,7 +1946,7 @@ CODESTARTactivateCnf
"be processed. Reason", inst->pszFileName);
}
}
- fs_node_add(runModConf->conf_tree, inst->pszFileName, 0, inst);
+ fs_node_add(runModConf->conf_tree, NULL, inst->pszFileName, 0, inst);
}
if(Debug) {
@@ -2031,6 +2113,9 @@ flag_in_move(fs_edge_t *const edge, const char *name_moved)
DBGPRINTF("name check fails, '%s' != '%s'\n", act->basename, name_moved);
}
}
+ if (!act && edge->next) {
+ flag_in_move(edge->next, name_moved);
+ }
}
static void ATTR_NONNULL(1)
@@ -2057,7 +2145,7 @@ in_processEvent(struct inotify_event *ev)
}
if(ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) {
fs_node_walk(etry->act->edge->node, poll_tree);
- } else if(etry->act->edge->is_file) {
+ } else if(etry->act->edge->is_file && !(etry->act->is_symlink)) {
in_handleFileEvent(ev, etry); // esentially poll_file()!
} else {
fs_node_walk(etry->act->edge->node, poll_tree);

View File

@ -0,0 +1,286 @@
From 9ac54f0d7d70b8a9879889b4522a1d552fca1100 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@momo7.localdomain>
Date: Thu, 12 Jul 2018 11:52:04 -0700
Subject: [PATCH] Introducing an option preservecase to imudp and imtcp module
for managing the case of FROMHOST value.
Usage:
module(load="imudp" [preservecase="on"|"off"])
module(load="imtdp" [preservecase="on"|"off"])
If preservecase="on", FROMHOST value is handled in the case sensitive manner.
If preservecase="off", FROMHOST value is handled in the case insensitive manner.
To maintain the current behaviour, the default value of preservecase is
"on" for imtcp and "off" for imudp.
Incremented tcpsrvCURR_IF_VERSION by 1.
References:
https://github.com/rsyslog/rsyslog/pull/2774
https://bugzilla.redhat.com/show_bug.cgi?id=1309698
---
plugins/imtcp/imtcp.c | 14 ++++++++++++--
plugins/imudp/imudp.c | 15 ++++++++++++---
runtime/msg.c | 6 +++++-
runtime/msg.h | 2 ++
runtime/net.c | 2 +-
runtime/tcpsrv.c | 21 +++++++++++++++++++++
runtime/tcpsrv.h | 5 ++++-
7 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 8e3dcc0a2..45fa240b5 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -100,6 +100,7 @@ static struct configSettings_s {
int bDisableLFDelim;
int discardTruncatedMsg;
int bUseFlowControl;
+ int bPreserveCase;
uchar *gnutlsPriorityString;
uchar *pszStrmDrvrAuthMode;
uchar *pszInputName;
@@ -144,6 +145,7 @@ struct modConfData_s {
uchar *pszStrmDrvrAuthMode; /* authentication mode to use */
struct cnfarray *permittedPeers;
sbool configSetViaV2Method;
+ sbool bPreserveCase; /* preserve case of fromhost; true by default */
};
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
@@ -169,7 +171,8 @@ static struct cnfparamdescr modpdescr[] = {
{ "keepalive.probes", eCmdHdlrPositiveInt, 0 },
{ "keepalive.time", eCmdHdlrPositiveInt, 0 },
{ "keepalive.interval", eCmdHdlrPositiveInt, 0 },
- { "gnutlsprioritystring", eCmdHdlrString, 0 }
+ { "gnutlsprioritystring", eCmdHdlrString, 0 },
+ { "preservecase", eCmdHdlrBinary, 0 }
};
static struct cnfparamblk modpblk =
{ CNFPARAMBLK_VERSION,
@@ -375,6 +378,7 @@ addListner(modConfData_t *modConf, instanceConf_t *inst)
if(pPermPeersRoot != NULL) {
CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot));
}
+ CHKiRet(tcpsrv.SetPreserveCase(pOurTcpsrv, modConf->bPreserveCase));
}
/* initialized, now add socket and listener params */
@@ -473,6 +477,7 @@ CODESTARTbeginCnfLoad
loadModConf->pszStrmDrvrAuthMode = NULL;
loadModConf->permittedPeers = NULL;
loadModConf->configSetViaV2Method = 0;
+ loadModConf->bPreserveCase = 1; /* default to true */
bLegacyCnfModGlobalsPermitted = 1;
/* init legacy config variables */
cs.pszStrmDrvrAuthMode = NULL;
@@ -543,6 +548,8 @@ CODESTARTsetModCnf
loadModConf->pszStrmDrvrName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(modpblk.descr[i].name, "permittedpeer")) {
loadModConf->permittedPeers = cnfarrayDup(pvals[i].val.d.ar);
+ } else if(!strcmp(modpblk.descr[i].name, "preservecase")) {
+ loadModConf->bPreserveCase = (int) pvals[i].val.d.n;
} else {
dbgprintf("imtcp: program error, non-handled "
"param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
@@ -584,6 +591,7 @@ CODESTARTendCnfLoad
loadModConf->pszStrmDrvrAuthMode = cs.pszStrmDrvrAuthMode;
cs.pszStrmDrvrAuthMode = NULL;
}
+ pModConf->bPreserveCase = cs.bPreserveCase;
}
free(cs.pszStrmDrvrAuthMode);
cs.pszStrmDrvrAuthMode = NULL;
@@ -731,6 +739,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus
cs.pszInputName = NULL;
free(cs.pszStrmDrvrAuthMode);
cs.pszStrmDrvrAuthMode = NULL;
+ cs.bPreserveCase = 1;
return RS_RET_OK;
}
@@ -797,7 +806,8 @@ CODEmodInit_QueryRegCFSLineHdlr
NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, eCmdHdlrInt,
NULL, &cs.iStrmDrvrMode, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
-
+ CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverpreservecase"), 1, eCmdHdlrBinary,
+ NULL, &cs.bPreserveCase, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c
index 51a9d712a..74437781c 100644
--- a/plugins/imudp/imudp.c
+++ b/plugins/imudp/imudp.c
@@ -152,6 +152,7 @@ struct modConfData_s {
int batchSize; /* max nbr of input batch --> also recvmmsg() max count */
int8_t wrkrMax; /* max nbr of worker threads */
sbool configSetViaV2Method;
+ sbool bPreserveCase; /* preserves the case of fromhost; "off" by default */
};
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
@@ -162,7 +163,8 @@ static struct cnfparamdescr modpdescr[] = {
{ "schedulingpriority", eCmdHdlrInt, 0 },
{ "batchsize", eCmdHdlrInt, 0 },
{ "threads", eCmdHdlrPositiveInt, 0 },
- { "timerequery", eCmdHdlrInt, 0 }
+ { "timerequery", eCmdHdlrInt, 0 },
+ { "preservecase", eCmdHdlrBinary, 0 }
};
static struct cnfparamblk modpblk =
{ CNFPARAMBLK_VERSION,
@@ -447,8 +449,12 @@ processPacket(struct lstn_s *lstn, struct sockaddr_storage *frominetPrev, int *p
if(lstn->dfltTZ != NULL)
MsgSetDfltTZ(pMsg, (char*) lstn->dfltTZ);
pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL;
- if(*pbIsPermitted == 2)
- pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */
+ if(*pbIsPermitted == 2) {
+ pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */
+ }
+ if(runModConf->bPreserveCase) {
+ pMsg->msgFlags |= PRESERVE_CASE; /* preserve case of fromhost */
+ }
CHKiRet(msgSetFromSockinfo(pMsg, frominet));
CHKiRet(ratelimitAddMsg(lstn->ratelimiter, multiSub, pMsg));
STATSCOUNTER_INC(lstn->ctrSubmit, lstn->mutCtrSubmit);
@@ -1030,6 +1036,7 @@ CODESTARTbeginCnfLoad
loadModConf->iTimeRequery = TIME_REQUERY_DFLT;
loadModConf->iSchedPrio = SCHED_PRIO_UNSET;
loadModConf->pszSchedPolicy = NULL;
+ loadModConf->bPreserveCase = 0; /* off */
bLegacyCnfModGlobalsPermitted = 1;
/* init legacy config vars */
cs.pszBindRuleset = NULL;
@@ -1079,6 +1086,8 @@ CODESTARTsetModCnf
} else {
loadModConf->wrkrMax = wrkrMax;
}
+ } else if(!strcmp(modpblk.descr[i].name, "preservecase")) {
+ loadModConf->bPreserveCase = (int) pvals[i].val.d.n;
} else {
dbgprintf("imudp: program error, non-handled "
"param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
diff --git a/runtime/msg.c b/runtime/msg.c
index c43f81314..9ed4eaf84 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -506,7 +506,11 @@ resolveDNS(smsg_t * const pMsg) {
MsgLock(pMsg);
CHKiRet(objUse(net, CORE_COMPONENT));
if(pMsg->msgFlags & NEEDS_DNSRESOL) {
- localRet = net.cvthname(pMsg->rcvFrom.pfrominet, &localName, NULL, &ip);
+ if (pMsg->msgFlags & PRESERVE_CASE) {
+ localRet = net.cvthname(pMsg->rcvFrom.pfrominet, NULL, &localName, &ip);
+ } else {
+ localRet = net.cvthname(pMsg->rcvFrom.pfrominet, &localName, NULL, &ip);
+ }
if(localRet == RS_RET_OK) {
/* we pass down the props, so no need for AddRef */
MsgSetRcvFromWithoutAddRef(pMsg, localName);
diff --git a/runtime/msg.h b/runtime/msg.h
index cd530aca3..1287cb7a4 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -156,6 +156,8 @@ struct msg {
/* check UDP ACLs after DNS resolution has been done in main queue consumer */
#define NO_PRI_IN_RAW 0x100
/* rawmsg does not include a PRI (Solaris!), but PRI is already set correctly in the msg object */
+#define PRESERVE_CASE 0x200
+/* preserve case in fromhost */
/* (syslog) protocol types */
#define MSG_LEGACY_PROTOCOL 0
diff --git a/runtime/net.c b/runtime/net.c
index d6ff8a3d4..aef906601 100644
--- a/runtime/net.c
+++ b/runtime/net.c
@@ -1152,7 +1152,7 @@ cvthname(struct sockaddr_storage *f, prop_t **localName, prop_t **fqdn, prop_t *
{
DEFiRet;
assert(f != NULL);
- iRet = dnscacheLookup(f, NULL, fqdn, localName, ip);
+ iRet = dnscacheLookup(f, fqdn, NULL, localName, ip);
RETiRet;
}
diff --git a/runtime/tcpsrv.c b/runtime/tcpsrv.c
index 61e9ff4d2..d5993b4f0 100644
--- a/runtime/tcpsrv.c
+++ b/runtime/tcpsrv.c
@@ -495,6 +495,15 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortList_t *pLstnInfo, tcps_sess_t **ppSess,
/* get the host name */
CHKiRet(netstrm.GetRemoteHName(pNewStrm, &fromHostFQDN));
+ if (!pThis->bPreserveCase) {
+ /* preserve_case = off */
+ uchar *p;
+ for(p = fromHostFQDN; *p; p++) {
+ if (isupper((int) *p)) {
+ *p = tolower((int) *p);
+ }
+ }
+ }
CHKiRet(netstrm.GetRemoteIP(pNewStrm, &fromHostIP));
CHKiRet(netstrm.GetRemAddr(pNewStrm, &addr));
/* TODO: check if we need to strip the domain name here -- rgerhards, 2008-04-24 */
@@ -1001,6 +1010,7 @@ BEGINobjConstruct(tcpsrv) /* be sure to specify the object type also in END macr
pThis->ratelimitBurst = 10000;
pThis->bUseFlowControl = 1;
pThis->pszDrvrName = NULL;
+ pThis->bPreserveCase = 1; /* preserve case in fromhost; default to true. */
ENDobjConstruct(tcpsrv)
@@ -1433,6 +1443,16 @@ SetSessMax(tcpsrv_t *pThis, int iMax)
}
+static rsRetVal
+SetPreserveCase(tcpsrv_t *pThis, int bPreserveCase)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+ pThis-> bPreserveCase = bPreserveCase;
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-29
*/
@@ -1491,6 +1511,7 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->SetRuleset = SetRuleset;
pIf->SetLinuxLikeRatelimiters = SetLinuxLikeRatelimiters;
pIf->SetNotificationOnRemoteClose = SetNotificationOnRemoteClose;
+ pIf->SetPreserveCase = SetPreserveCase;
finalize_it:
ENDobjQueryInterface(tcpsrv)
diff --git a/runtime/tcpsrv.h b/runtime/tcpsrv.h
index 22a65c20a..f17b1b438 100644
--- a/runtime/tcpsrv.h
+++ b/runtime/tcpsrv.h
@@ -85,6 +85,7 @@ struct tcpsrv_s {
int maxFrameSize; /**< max frame size for octet counted*/
int bDisableLFDelim; /**< if 1, standard LF frame delimiter is disabled (*very dangerous*) */
int discardTruncatedMsg;/**< discard msg part that has been truncated*/
+ sbool bPreserveCase; /**< preserve case in fromhost */
int ratelimitInterval;
int ratelimitBurst;
tcps_sess_t **pSessions;/**< array of all of our sessions */
@@ -177,8 +178,10 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetbSPFramingFix)(tcpsrv_t*, sbool);
/* added v19 -- PascalWithopf, 2017-08-08 */
rsRetVal (*SetGnutlsPriorityString)(tcpsrv_t*, uchar*);
+ /* added v21 -- Preserve case in fromhost, 2018-08-16 */
+ rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase);
ENDinterface(tcpsrv)
-#define tcpsrvCURR_IF_VERSION 20 /* increment whenever you change the interface structure! */
+#define tcpsrvCURR_IF_VERSION 21 /* increment whenever you change the interface structure! */
/* change for v4:
* - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10
* - SetInputName() added -- rgerhards, 2008-12-10

View File

@ -0,0 +1,761 @@
From 3987cd929d859f900318b393133c3bdde8dfffd5 Mon Sep 17 00:00:00 2001
From: Rich Megginson <rmeggins@redhat.com>
Date: Tue, 28 Aug 2018 12:44:23 -0600
Subject: [PATCH] mmkubertnetes: action fails preparation cycle if kubernetes
API destroys resource during bootup sequence
The plugin was not handling 404 Not Found correctly when looking
up pods and namespaces. In this case, we assume the pod/namespace
was deleted, annotate the record with whatever metadata we have,
and cache the fact that the pod/namespace is missing so we don't
attempt to look it up again.
In addition, the plugin was not handling error 429 Busy correctly.
In this case, it should also annotate the record with whatever
metadata it has, and _not_ cache anything. By default the plugin
will retry every 5 seconds to connect to Kubernetes. This
behavior is controlled by the new config param `busyretryinterval`.
This commit also adds impstats counters so that admins can
view the state of the plugin to see if the lookups are working
or are returning errors. The stats are reported per-instance
or per-action to facilitate using multiple different actions
for different Kubernetes servers.
This commit also adds support for client cert auth to
Kubernetes via the two new config params `tls.mycert` and
`tls.myprivkey`.
---
contrib/mmkubernetes/mmkubernetes.c | 296 ++++++++++++++++++++++++----
7 files changed, 160 insertions(+), 36 deletions(-)
diff --git a/contrib/mmkubernetes/mmkubernetes.c b/contrib/mmkubernetes/mmkubernetes.c
index 422cb2577..5bf5b049d 100644
--- a/contrib/mmkubernetes/mmkubernetes.c
+++ b/contrib/mmkubernetes/mmkubernetes.c
@@ -52,9 +52,12 @@
#include "syslogd-types.h"
#include "module-template.h"
#include "errmsg.h"
+#include "statsobj.h"
#include "regexp.h"
#include "hashtable.h"
#include "srUtils.h"
+#include "unicode-helper.h"
+#include "datetime.h"
/* static data */
MODULE_TYPE_OUTPUT /* this is technically an output plugin */
@@ -62,6 +65,8 @@ MODULE_TYPE_KEEP /* releasing the module would cause a leak through libcurl */
MODULE_CNFNAME("mmkubernetes")
DEF_OMOD_STATIC_DATA
DEFobjCurrIf(regexp)
+DEFobjCurrIf(statsobj)
+DEFobjCurrIf(datetime)
#define HAVE_LOADSAMPLESFROMSTRING 1
#if defined(NO_LOADSAMPLESFROMSTRING)
@@ -95,12 +100,14 @@ DEFobjCurrIf(regexp)
#define DFLT_CONTAINER_NAME "$!CONTAINER_NAME" /* name of variable holding CONTAINER_NAME value */
#define DFLT_CONTAINER_ID_FULL "$!CONTAINER_ID_FULL" /* name of variable holding CONTAINER_ID_FULL value */
#define DFLT_KUBERNETES_URL "https://kubernetes.default.svc.cluster.local:443"
+#define DFLT_BUSY_RETRY_INTERVAL 5 /* retry every 5 seconds */
static struct cache_s {
const uchar *kbUrl;
struct hashtable *mdHt;
struct hashtable *nsHt;
pthread_mutex_t *cacheMtx;
+ int lastBusyTime;
} **caches;
typedef struct {
@@ -116,6 +123,8 @@ struct modConfData_s {
uchar *srcMetadataPath; /* where to get data for kubernetes queries */
uchar *dstMetadataPath; /* where to put metadata obtained from kubernetes */
uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */
+ uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */
+ uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */
sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */
uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */
uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */
@@ -127,6 +136,7 @@ struct modConfData_s {
uchar *fnRulebase; /* lognorm rulebase filename for container log filename match */
char *contRules; /* lognorm rules for CONTAINER_NAME value match */
uchar *contRulebase; /* lognorm rulebase filename for CONTAINER_NAME value match */
+ int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */
};
/* action (instance) configuration data */
@@ -135,6 +145,8 @@ typedef struct _instanceData {
msgPropDescr_t *srcMetadataDescr; /* where to get data for kubernetes queries */
uchar *dstMetadataPath; /* where to put metadata obtained from kubernetes */
uchar *caCertFile; /* File holding the CA cert (+optional chain) of CA that issued the Kubernetes server cert */
+ uchar *myCertFile; /* File holding cert corresponding to private key used for client cert auth */
+ uchar *myPrivKeyFile; /* File holding private key corresponding to cert used for client cert auth */
sbool allowUnsignedCerts; /* For testing/debugging - do not check for CA certs (CURLOPT_SSL_VERIFYPEER FALSE) */
uchar *token; /* The token value to use to authenticate to Kubernetes - takes precedence over tokenFile */
uchar *tokenFile; /* The file whose contents is the token value to use to authenticate to Kubernetes */
@@ -151,6 +163,7 @@ typedef struct _instanceData {
msgPropDescr_t *contNameDescr; /* CONTAINER_NAME field */
msgPropDescr_t *contIdFullDescr; /* CONTAINER_ID_FULL field */
struct cache_s *cache;
+ int busyRetryInterval; /* how to handle 429 response - 0 means error, non-zero means retry every N seconds */
} instanceData;
typedef struct wrkrInstanceData {
@@ -159,6 +172,16 @@ typedef struct wrkrInstanceData {
struct curl_slist *curlHdr;
char *curlRply;
size_t curlRplyLen;
+ statsobj_t *stats; /* stats for this instance */
+ STATSCOUNTER_DEF(k8sRecordSeen, mutK8sRecordSeen)
+ STATSCOUNTER_DEF(namespaceMetadataSuccess, mutNamespaceMetadataSuccess)
+ STATSCOUNTER_DEF(namespaceMetadataNotFound, mutNamespaceMetadataNotFound)
+ STATSCOUNTER_DEF(namespaceMetadataBusy, mutNamespaceMetadataBusy)
+ STATSCOUNTER_DEF(namespaceMetadataError, mutNamespaceMetadataError)
+ STATSCOUNTER_DEF(podMetadataSuccess, mutPodMetadataSuccess)
+ STATSCOUNTER_DEF(podMetadataNotFound, mutPodMetadataNotFound)
+ STATSCOUNTER_DEF(podMetadataBusy, mutPodMetadataBusy)
+ STATSCOUNTER_DEF(podMetadataError, mutPodMetadataError)
} wrkrInstanceData_t;
/* module parameters (v6 config format) */
@@ -167,6 +190,8 @@ static struct cnfparamdescr modpdescr[] = {
{ "srcmetadatapath", eCmdHdlrString, 0 },
{ "dstmetadatapath", eCmdHdlrString, 0 },
{ "tls.cacert", eCmdHdlrString, 0 },
+ { "tls.mycert", eCmdHdlrString, 0 },
+ { "tls.myprivkey", eCmdHdlrString, 0 },
{ "allowunsignedcerts", eCmdHdlrBinary, 0 },
{ "token", eCmdHdlrString, 0 },
{ "tokenfile", eCmdHdlrString, 0 },
@@ -174,7 +199,8 @@ static struct cnfparamdescr modpdescr[] = {
{ "de_dot", eCmdHdlrBinary, 0 },
{ "de_dot_separator", eCmdHdlrString, 0 },
{ "filenamerulebase", eCmdHdlrString, 0 },
- { "containerrulebase", eCmdHdlrString, 0 }
+ { "containerrulebase", eCmdHdlrString, 0 },
+ { "busyretryinterval", eCmdHdlrInt, 0 }
#if HAVE_LOADSAMPLESFROMSTRING == 1
,
{ "filenamerules", eCmdHdlrArray, 0 },
@@ -193,6 +219,8 @@ static struct cnfparamdescr actpdescr[] = {
{ "srcmetadatapath", eCmdHdlrString, 0 },
{ "dstmetadatapath", eCmdHdlrString, 0 },
{ "tls.cacert", eCmdHdlrString, 0 },
+ { "tls.mycert", eCmdHdlrString, 0 },
+ { "tls.myprivkey", eCmdHdlrString, 0 },
{ "allowunsignedcerts", eCmdHdlrBinary, 0 },
{ "token", eCmdHdlrString, 0 },
{ "tokenfile", eCmdHdlrString, 0 },
@@ -200,7 +228,8 @@ static struct cnfparamdescr actpdescr[] = {
{ "de_dot", eCmdHdlrBinary, 0 },
{ "de_dot_separator", eCmdHdlrString, 0 },
{ "filenamerulebase", eCmdHdlrString, 0 },
- { "containerrulebase", eCmdHdlrString, 0 }
+ { "containerrulebase", eCmdHdlrString, 0 },
+ { "busyretryinterval", eCmdHdlrInt, 0 }
#if HAVE_LOADSAMPLESFROMSTRING == 1
,
{ "filenamerules", eCmdHdlrArray, 0 },
@@ -493,8 +522,9 @@ ENDbeginCnfLoad
BEGINsetModCnf
struct cnfparamvals *pvals = NULL;
int i;
- FILE *fp;
+ FILE *fp = NULL;
int ret;
+ char errStr[1024];
CODESTARTsetModCnf
pvals = nvlstGetParams(lst, &modpblk, NULL);
if(pvals == NULL) {
@@ -509,6 +539,7 @@ CODESTARTsetModCnf
}
loadModConf->de_dot = DFLT_DE_DOT;
+ loadModConf->busyRetryInterval = DFLT_BUSY_RETRY_INTERVAL;
for(i = 0 ; i < modpblk.nParams ; ++i) {
if(!pvals[i].bUsed) {
continue;
@@ -528,15 +559,42 @@ CODESTARTsetModCnf
loadModConf->caCertFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)loadModConf->caCertFile, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
- "error: certificate file %s couldn't be accessed: %s\n",
+ "error: 'tls.cacert' file %s couldn't be accessed: %s\n",
loadModConf->caCertFile, errStr);
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
+ }
+ } else if(!strcmp(modpblk.descr[i].name, "tls.mycert")) {
+ free(loadModConf->myCertFile);
+ loadModConf->myCertFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ fp = fopen((const char*)loadModConf->myCertFile, "r");
+ if(fp == NULL) {
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ iRet = RS_RET_NO_FILE_ACCESS;
+ LogError(0, iRet,
+ "error: 'tls.mycert' file %s couldn't be accessed: %s\n",
+ loadModConf->myCertFile, errStr);
+ } else {
+ fclose(fp);
+ fp = NULL;
+ }
+ } else if(!strcmp(modpblk.descr[i].name, "tls.myprivkey")) {
+ loadModConf->myPrivKeyFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ fp = fopen((const char*)loadModConf->myPrivKeyFile, "r");
+ if(fp == NULL) {
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ iRet = RS_RET_NO_FILE_ACCESS;
+ LogError(0, iRet,
+ "error: 'tls.myprivkey' file %s couldn't be accessed: %s\n",
+ loadModConf->myPrivKeyFile, errStr);
+ } else {
+ fclose(fp);
+ fp = NULL;
}
} else if(!strcmp(modpblk.descr[i].name, "allowunsignedcerts")) {
loadModConf->allowUnsignedCerts = pvals[i].val.d.n;
@@ -548,7 +606,6 @@ CODESTARTsetModCnf
loadModConf->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)loadModConf->tokenFile, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -557,6 +614,7 @@ CODESTARTsetModCnf
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
} else if(!strcmp(modpblk.descr[i].name, "annotation_match")) {
free_annotationmatch(&loadModConf->annotation_match);
@@ -577,7 +635,6 @@ CODESTARTsetModCnf
loadModConf->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)loadModConf->fnRulebase, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -586,6 +643,7 @@ CODESTARTsetModCnf
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
#if HAVE_LOADSAMPLESFROMSTRING == 1
} else if(!strcmp(modpblk.descr[i].name, "containerrules")) {
@@ -597,7 +655,6 @@ CODESTARTsetModCnf
loadModConf->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)loadModConf->contRulebase, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -606,7 +663,10 @@ CODESTARTsetModCnf
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
+ } else if(!strcmp(modpblk.descr[i].name, "busyretryinterval")) {
+ loadModConf->busyRetryInterval = pvals[i].val.d.n;
} else {
dbgprintf("mmkubernetes: program error, non-handled "
"param '%s' in module() block\n", modpblk.descr[i].name);
@@ -650,6 +710,8 @@ CODESTARTsetModCnf
caches = calloc(1, sizeof(struct cache_s *));
finalize_it:
+ if (fp)
+ fclose(fp);
if(pvals != NULL)
cnfparamvalsDestruct(pvals, &modpblk);
ENDsetModCnf
@@ -667,6 +729,8 @@ CODESTARTfreeInstance
free(pData->srcMetadataDescr);
free(pData->dstMetadataPath);
free(pData->caCertFile);
+ free(pData->myCertFile);
+ free(pData->myPrivKeyFile);
free(pData->token);
free(pData->tokenFile);
free(pData->fnRules);
@@ -710,6 +774,45 @@ CODESTARTcreateWrkrInstance
char *tokenHdr = NULL;
FILE *fp = NULL;
char *token = NULL;
+ char *statsName = NULL;
+
+ CHKiRet(statsobj.Construct(&(pWrkrData->stats)));
+ if ((-1 == asprintf(&statsName, "mmkubernetes(%s)", pWrkrData->pData->kubernetesUrl)) ||
+ (!statsName)) {
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+ CHKiRet(statsobj.SetName(pWrkrData->stats, (uchar *)statsName));
+ free(statsName);
+ statsName = NULL;
+ CHKiRet(statsobj.SetOrigin(pWrkrData->stats, UCHAR_CONSTANT("mmkubernetes")));
+ STATSCOUNTER_INIT(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("recordseen"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->k8sRecordSeen)));
+ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataSuccess, pWrkrData->mutNamespaceMetadataSuccess);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatasuccess"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataSuccess)));
+ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataNotFound, pWrkrData->mutNamespaceMetadataNotFound);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatanotfound"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataNotFound)));
+ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataBusy, pWrkrData->mutNamespaceMetadataBusy);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadatabusy"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataBusy)));
+ STATSCOUNTER_INIT(pWrkrData->namespaceMetadataError, pWrkrData->mutNamespaceMetadataError);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("namespacemetadataerror"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->namespaceMetadataError)));
+ STATSCOUNTER_INIT(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatasuccess"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataSuccess)));
+ STATSCOUNTER_INIT(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatanotfound"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataNotFound)));
+ STATSCOUNTER_INIT(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadatabusy"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataBusy)));
+ STATSCOUNTER_INIT(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError);
+ CHKiRet(statsobj.AddCounter(pWrkrData->stats, UCHAR_CONSTANT("podmetadataerror"),
+ ctrType_IntCtr, CTR_FLAG_RESETTABLE, &(pWrkrData->podMetadataError)));
+ CHKiRet(statsobj.ConstructFinalize(pWrkrData->stats));
hdr = curl_slist_append(hdr, "Content-Type: text/json; charset=utf-8");
if (pWrkrData->pData->token) {
@@ -749,12 +852,20 @@ CODESTARTcreateWrkrInstance
curl_easy_setopt(ctx, CURLOPT_WRITEDATA, pWrkrData);
if(pWrkrData->pData->caCertFile)
curl_easy_setopt(ctx, CURLOPT_CAINFO, pWrkrData->pData->caCertFile);
+ if(pWrkrData->pData->myCertFile)
+ curl_easy_setopt(ctx, CURLOPT_SSLCERT, pWrkrData->pData->myCertFile);
+ if(pWrkrData->pData->myPrivKeyFile)
+ curl_easy_setopt(ctx, CURLOPT_SSLKEY, pWrkrData->pData->myPrivKeyFile);
if(pWrkrData->pData->allowUnsignedCerts)
curl_easy_setopt(ctx, CURLOPT_SSL_VERIFYPEER, 0);
pWrkrData->curlCtx = ctx;
finalize_it:
free(token);
+ free(statsName);
+ if ((iRet != RS_RET_OK) && pWrkrData->stats) {
+ statsobj.Destruct(&(pWrkrData->stats));
+ }
if (fp) {
fclose(fp);
}
@@ -765,6 +876,7 @@ BEGINfreeWrkrInstance
CODESTARTfreeWrkrInstance
curl_easy_cleanup(pWrkrData->curlCtx);
curl_slist_free_all(pWrkrData->curlHdr);
+ statsobj.Destruct(&(pWrkrData->stats));
ENDfreeWrkrInstance
@@ -790,6 +902,8 @@ cacheNew(const uchar *const url)
key_equals_string, hashtable_json_object_put);
cache->nsHt = create_hashtable(100, hash_from_string,
key_equals_string, hashtable_json_object_put);
+ dbgprintf("mmkubernetes: created cache mdht [%p] nsht [%p]\n",
+ cache->mdHt, cache->nsHt);
cache->cacheMtx = malloc(sizeof(pthread_mutex_t));
if (!cache->mdHt || !cache->nsHt || !cache->cacheMtx) {
free (cache);
@@ -797,6 +911,7 @@ cacheNew(const uchar *const url)
FINALIZE;
}
pthread_mutex_init(cache->cacheMtx, NULL);
+ cache->lastBusyTime = 0;
finalize_it:
return cache;
@@ -816,9 +931,10 @@ static void cacheFree(struct cache_s *cache)
BEGINnewActInst
struct cnfparamvals *pvals = NULL;
int i;
- FILE *fp;
+ FILE *fp = NULL;
char *rxstr = NULL;
char *srcMetadataPath = NULL;
+ char errStr[1024];
CODESTARTnewActInst
DBGPRINTF("newActInst (mmkubernetes)\n");
@@ -840,6 +956,7 @@ CODESTARTnewActInst
pData->de_dot = loadModConf->de_dot;
pData->allowUnsignedCerts = loadModConf->allowUnsignedCerts;
+ pData->busyRetryInterval = loadModConf->busyRetryInterval;
for(i = 0 ; i < actpblk.nParams ; ++i) {
if(!pvals[i].bUsed) {
continue;
@@ -863,7 +980,6 @@ CODESTARTnewActInst
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));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -872,6 +988,33 @@ CODESTARTnewActInst
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
+ }
+ } 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) {
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ iRet = RS_RET_NO_FILE_ACCESS;
+ LogError(0, iRet,
+ "error: 'tls.mycert' file %s couldn't be accessed: %s\n",
+ pData->myCertFile, errStr);
+ } else {
+ fclose(fp);
+ fp = NULL;
+ }
+ } 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) {
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ iRet = RS_RET_NO_FILE_ACCESS;
+ LogError(0, iRet,
+ "error: 'tls.myprivkey' file %s couldn't be accessed: %s\n",
+ pData->myPrivKeyFile, errStr);
+ } else {
+ fclose(fp);
+ fp = NULL;
}
} else if(!strcmp(actpblk.descr[i].name, "allowunsignedcerts")) {
pData->allowUnsignedCerts = pvals[i].val.d.n;
@@ -883,7 +1026,6 @@ CODESTARTnewActInst
pData->tokenFile = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)pData->tokenFile, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -892,6 +1034,7 @@ CODESTARTnewActInst
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
} else if(!strcmp(actpblk.descr[i].name, "annotation_match")) {
free_annotationmatch(&pData->annotation_match);
@@ -912,7 +1055,6 @@ CODESTARTnewActInst
pData->fnRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)pData->fnRulebase, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -921,6 +1063,7 @@ CODESTARTnewActInst
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
#if HAVE_LOADSAMPLESFROMSTRING == 1
} else if(!strcmp(modpblk.descr[i].name, "containerrules")) {
@@ -932,7 +1075,6 @@ CODESTARTnewActInst
pData->contRulebase = (uchar *) es_str2cstr(pvals[i].val.d.estr, NULL);
fp = fopen((const char*)pData->contRulebase, "r");
if(fp == NULL) {
- char errStr[1024];
rs_strerror_r(errno, errStr, sizeof(errStr));
iRet = RS_RET_NO_FILE_ACCESS;
LogError(0, iRet,
@@ -941,7 +1083,10 @@ CODESTARTnewActInst
ABORT_FINALIZE(iRet);
} else {
fclose(fp);
+ fp = NULL;
}
+ } else if(!strcmp(actpblk.descr[i].name, "busyretryinterval")) {
+ pData->busyRetryInterval = pvals[i].val.d.n;
} else {
dbgprintf("mmkubernetes: program error, non-handled "
"param '%s' in action() block\n", actpblk.descr[i].name);
@@ -982,6 +1127,10 @@ CODESTARTnewActInst
pData->dstMetadataPath = (uchar *) strdup((char *) loadModConf->dstMetadataPath);
if(pData->caCertFile == NULL && loadModConf->caCertFile)
pData->caCertFile = (uchar *) strdup((char *) loadModConf->caCertFile);
+ if(pData->myCertFile == NULL && loadModConf->myCertFile)
+ pData->myCertFile = (uchar *) strdup((char *) loadModConf->myCertFile);
+ if(pData->myPrivKeyFile == NULL && loadModConf->myPrivKeyFile)
+ pData->myPrivKeyFile = (uchar *) strdup((char *) loadModConf->myPrivKeyFile);
if(pData->token == NULL && loadModConf->token)
pData->token = (uchar *) strdup((char *) loadModConf->token);
if(pData->tokenFile == NULL && loadModConf->tokenFile)
@@ -1018,6 +1167,8 @@ CODESTARTnewActInst
CODE_STD_FINALIZERnewActInst
if(pvals != NULL)
cnfparamvalsDestruct(pvals, &actpblk);
+ if(fp)
+ fclose(fp);
free(rxstr);
free(srcMetadataPath);
ENDnewActInst
@@ -1061,6 +1212,8 @@ CODESTARTfreeCnf
free(pModConf->srcMetadataPath);
free(pModConf->dstMetadataPath);
free(pModConf->caCertFile);
+ free(pModConf->myCertFile);
+ free(pModConf->myPrivKeyFile);
free(pModConf->token);
free(pModConf->tokenFile);
free(pModConf->de_dot_separator);
@@ -1069,8 +1222,11 @@ CODESTARTfreeCnf
free(pModConf->contRules);
free(pModConf->contRulebase);
free_annotationmatch(&pModConf->annotation_match);
- for(i = 0; caches[i] != NULL; i++)
+ for(i = 0; caches[i] != NULL; i++) {
+ dbgprintf("mmkubernetes: freeing cache [%d] mdht [%p] nsht [%p]\n",
+ i, caches[i]->mdHt, caches[i]->nsHt);
cacheFree(caches[i]);
+ }
free(caches);
ENDfreeCnf
@@ -1082,6 +1238,8 @@ CODESTARTdbgPrintInstInfo
dbgprintf("\tsrcMetadataPath='%s'\n", pData->srcMetadataDescr->name);
dbgprintf("\tdstMetadataPath='%s'\n", pData->dstMetadataPath);
dbgprintf("\ttls.cacert='%s'\n", pData->caCertFile);
+ dbgprintf("\ttls.mycert='%s'\n", pData->myCertFile);
+ dbgprintf("\ttls.myprivkey='%s'\n", pData->myPrivKeyFile);
dbgprintf("\tallowUnsignedCerts='%d'\n", pData->allowUnsignedCerts);
dbgprintf("\ttoken='%s'\n", pData->token);
dbgprintf("\ttokenFile='%s'\n", pData->tokenFile);
@@ -1093,6 +1251,7 @@ CODESTARTdbgPrintInstInfo
dbgprintf("\tfilenamerules='%s'\n", pData->fnRules);
dbgprintf("\tcontainerrules='%s'\n", pData->contRules);
#endif
+ dbgprintf("\tbusyretryinterval='%d'\n", pData->busyRetryInterval);
ENDdbgPrintInstInfo
@@ -1206,6 +1365,24 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply)
struct json_object *jo;
long resp_code = 400;
+ if (pWrkrData->pData->cache->lastBusyTime) {
+ time_t now;
+ datetime.GetTime(&now);
+ now -= pWrkrData->pData->cache->lastBusyTime;
+ if (now < pWrkrData->pData->busyRetryInterval) {
+ LogMsg(0, RS_RET_RETRY, LOG_DEBUG,
+ "mmkubernetes: Waited [%ld] of [%d] seconds for the requested url [%s]\n",
+ now, pWrkrData->pData->busyRetryInterval, url);
+ ABORT_FINALIZE(RS_RET_RETRY);
+ } else {
+ LogMsg(0, RS_RET_OK, LOG_DEBUG,
+ "mmkubernetes: Cleared busy status after [%d] seconds - "
+ "will retry the requested url [%s]\n",
+ pWrkrData->pData->busyRetryInterval, url);
+ pWrkrData->pData->cache->lastBusyTime = 0;
+ }
+ }
+
/* query kubernetes for pod info */
ccode = curl_easy_setopt(pWrkrData->curlCtx, CURLOPT_URL, url);
if(ccode != CURLE_OK)
@@ -1238,17 +1415,23 @@ queryKB(wrkrInstanceData_t *pWrkrData, char *url, struct json_object **rply)
ABORT_FINALIZE(RS_RET_ERR);
}
if(resp_code == 404) {
- LogMsg(0, RS_RET_ERR, LOG_ERR,
+ LogMsg(0, RS_RET_NOT_FOUND, LOG_INFO,
"mmkubernetes: Not Found: the resource does not exist at url [%s]\n",
url);
- ABORT_FINALIZE(RS_RET_ERR);
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
if(resp_code == 429) {
- LogMsg(0, RS_RET_ERR, LOG_ERR,
+ if (pWrkrData->pData->busyRetryInterval) {
+ time_t now;
+ datetime.GetTime(&now);
+ pWrkrData->pData->cache->lastBusyTime = now;
+ }
+
+ LogMsg(0, RS_RET_RETRY, LOG_INFO,
"mmkubernetes: Too Many Requests: the server is too heavily loaded "
"to provide the data for the requested url [%s]\n",
url);
- ABORT_FINALIZE(RS_RET_ERR);
+ ABORT_FINALIZE(RS_RET_RETRY);
}
if(resp_code != 200) {
LogMsg(0, RS_RET_ERR, LOG_ERR,
@@ -1299,12 +1482,14 @@ BEGINdoAction
char *mdKey = NULL;
struct json_object *jMetadata = NULL, *jMetadataCopy = NULL, *jMsgMeta = NULL,
*jo = NULL;
- int add_ns_metadata = 0;
+ int add_pod_metadata = 1;
CODESTARTdoAction
CHKiRet_Hdlr(extractMsgMetadata(pMsg, pWrkrData->pData, &jMsgMeta)) {
ABORT_FINALIZE((iRet == RS_RET_NOT_FOUND) ? RS_RET_OK : iRet);
}
+ STATSCOUNTER_INC(pWrkrData->k8sRecordSeen, pWrkrData->mutK8sRecordSeen);
+
if (fjson_object_object_get_ex(jMsgMeta, "pod_name", &jo))
podName = json_object_get_string(jo);
if (fjson_object_object_get_ex(jMsgMeta, "namespace_name", &jo))
@@ -1347,28 +1532,49 @@ CODESTARTdoAction
}
iRet = queryKB(pWrkrData, url, &jReply);
free(url);
- /* todo: implement support for the .orphaned namespace */
- if (iRet != RS_RET_OK) {
+ if (iRet == RS_RET_NOT_FOUND) {
+ /* negative cache namespace - make a dummy empty namespace metadata object */
+ jNsMeta = json_object_new_object();
+ STATSCOUNTER_INC(pWrkrData->namespaceMetadataNotFound,
+ pWrkrData->mutNamespaceMetadataNotFound);
+ } else if (iRet == RS_RET_RETRY) {
+ /* server is busy - retry or error */
+ STATSCOUNTER_INC(pWrkrData->namespaceMetadataBusy,
+ pWrkrData->mutNamespaceMetadataBusy);
+ if (0 == pWrkrData->pData->busyRetryInterval) {
+ pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ add_pod_metadata = 0; /* don't cache pod metadata either - retry both */
+ } else if (iRet != RS_RET_OK) {
+ /* hard error - something the admin needs to fix e.g. network, config, auth */
json_object_put(jReply);
jReply = NULL;
+ STATSCOUNTER_INC(pWrkrData->namespaceMetadataError,
+ pWrkrData->mutNamespaceMetadataError);
pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
FINALIZE;
- }
-
- if(fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) {
+ } else if (fjson_object_object_get_ex(jReply, "metadata", &jNsMeta)) {
jNsMeta = json_object_get(jNsMeta);
parse_labels_annotations(jNsMeta, &pWrkrData->pData->annotation_match,
pWrkrData->pData->de_dot,
(const char *)pWrkrData->pData->de_dot_separator,
pWrkrData->pData->de_dot_separator_len);
- add_ns_metadata = 1;
+ STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess,
+ pWrkrData->mutNamespaceMetadataSuccess);
} else {
/* namespace with no metadata??? */
LogMsg(0, RS_RET_ERR, LOG_INFO,
"mmkubernetes: namespace [%s] has no metadata!\n", ns);
- jNsMeta = NULL;
+ /* negative cache namespace - make a dummy empty namespace metadata object */
+ jNsMeta = json_object_new_object();
+ STATSCOUNTER_INC(pWrkrData->namespaceMetadataSuccess,
+ pWrkrData->mutNamespaceMetadataSuccess);
}
+ if(jNsMeta) {
+ hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
+ }
json_object_put(jReply);
jReply = NULL;
}
@@ -1381,14 +1587,28 @@ CODESTARTdoAction
}
iRet = queryKB(pWrkrData, url, &jReply);
free(url);
- if(iRet != RS_RET_OK) {
- if(jNsMeta && add_ns_metadata) {
- hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
+ if (iRet == RS_RET_NOT_FOUND) {
+ /* negative cache pod - make a dummy empty pod metadata object */
+ iRet = RS_RET_OK;
+ STATSCOUNTER_INC(pWrkrData->podMetadataNotFound, pWrkrData->mutPodMetadataNotFound);
+ } else if (iRet == RS_RET_RETRY) {
+ /* server is busy - retry or error */
+ STATSCOUNTER_INC(pWrkrData->podMetadataBusy, pWrkrData->mutPodMetadataBusy);
+ if (0 == pWrkrData->pData->busyRetryInterval) {
+ pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
+ ABORT_FINALIZE(RS_RET_ERR);
}
+ add_pod_metadata = 0; /* do not cache so that we can retry */
+ iRet = RS_RET_OK;
+ } else if(iRet != RS_RET_OK) {
+ /* hard error - something the admin needs to fix e.g. network, config, auth */
json_object_put(jReply);
jReply = NULL;
+ STATSCOUNTER_INC(pWrkrData->podMetadataError, pWrkrData->mutPodMetadataError);
pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
FINALIZE;
+ } else {
+ STATSCOUNTER_INC(pWrkrData->podMetadataSuccess, pWrkrData->mutPodMetadataSuccess);
}
jo = json_object_new_object();
@@ -1435,11 +1655,9 @@ CODESTARTdoAction
json_object_object_add(jo, "container_id", json_object_get(jo2));
json_object_object_add(jMetadata, "docker", jo);
- hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata);
- mdKey = NULL;
- if(jNsMeta && add_ns_metadata) {
- hashtable_insert(pWrkrData->pData->cache->nsHt, strdup(ns), jNsMeta);
- ns = NULL;
+ if (add_pod_metadata) {
+ hashtable_insert(pWrkrData->pData->cache->mdHt, mdKey, jMetadata);
+ mdKey = NULL;
}
}
@@ -1450,6 +1668,11 @@ CODESTARTdoAction
* outside of the cache lock
*/
jMetadataCopy = json_tokener_parse(json_object_get_string(jMetadata));
+ if (!add_pod_metadata) {
+ /* jMetadata object was created from scratch and not cached */
+ json_object_put(jMetadata);
+ jMetadata = NULL;
+ }
pthread_mutex_unlock(pWrkrData->pData->cache->cacheMtx);
/* the +1 is there to skip the leading '$' */
msgAddJSON(pMsg, (uchar *) pWrkrData->pData->dstMetadataPath + 1, jMetadataCopy, 0, 0);
@@ -1470,7 +1693,9 @@ BEGINmodExit
CODESTARTmodExit
curl_global_cleanup();
+ objRelease(datetime, CORE_COMPONENT);
objRelease(regexp, LM_REGEXP_FILENAME);
+ objRelease(statsobj, CORE_COMPONENT);
ENDmodExit
@@ -1489,8 +1714,9 @@ CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
DBGPRINTF("mmkubernetes: module compiled with rsyslog version %s.\n", VERSION);
+ CHKiRet(objUse(statsobj, CORE_COMPONENT));
CHKiRet(objUse(regexp, LM_REGEXP_FILENAME));
-
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
/* CURL_GLOBAL_ALL initializes more than is needed but the
* libcurl documentation discourages use of other values
*/

View File

@ -0,0 +1,263 @@
From e8d64cbd15fa84907dc23f8b52d6f2f847b46fec Mon Sep 17 00:00:00 2001
From: Rich Megginson <rmeggins@redhat.com>
Date: Mon, 10 Sep 2018 17:25:38 -0600
Subject: [PATCH] imfile: support for endmsg.regex
This adds support for endmsg.regex. It is similar to
startmsg.regex except that it matches the line that denotes
the end of the message, rather than the start of the next message.
This is primarily for container log file use cases such as this:
date stdout P start of message
date stdout P middle of message
date stdout F end of message
The `F` means this is the line which contains the final part of
the message. The fully assembled message should be
`start of message middle of message end of message`.
`startmsg.regex="^[^ ]+ stdout F "` will match.
(cherry picked from commit c902a0938fe163b5351829d2b72001d024895c16)
(cherry picked from commit dd4a72c4d52d8da98ed6b86114868e1a450ccb41)
---
plugins/imfile/imfile.c | 44 ++++--
plugins/imptcp/imptcp.c | 10 +-
runtime/stream.c | 28 +++-
runtime/stream.h | 2 +-
4 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index 7767c9f02..87706082f 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -126,7 +126,9 @@ struct instanceConf_s {
sbool bRMStateOnDel;
uint8_t readMode;
uchar *startRegex;
- regex_t end_preg; /* compiled version of startRegex */
+ uchar *endRegex;
+ regex_t start_preg; /* compiled version of startRegex */
+ regex_t end_preg; /* compiled version of endRegex */
sbool discardTruncatedMsg;
sbool msgDiscardingError;
sbool escapeLF;
@@ -281,6 +283,7 @@ static struct cnfparamdescr inppdescr[] = {
{ "ruleset", eCmdHdlrString, 0 },
{ "readmode", eCmdHdlrInt, 0 },
{ "startmsg.regex", eCmdHdlrString, 0 },
+ { "endmsg.regex", eCmdHdlrString, 0 },
{ "discardtruncatedmsg", eCmdHdlrBinary, 0 },
{ "msgdiscardingerror", eCmdHdlrBinary, 0 },
{ "escapelf", eCmdHdlrBinary, 0 },
@@ -1421,6 +1424,7 @@ pollFileReal(act_obj_t *act, cstr_t **pCStr)
int64 strtOffs;
DEFiRet;
int nProcessed = 0;
+ regex_t *start_preg = NULL, *end_preg = NULL;
DBGPRINTF("pollFileReal enter, pStrm %p, name '%s'\n", act->pStrm, act->name);
DBGPRINTF("pollFileReal enter, edge %p\n", act->edge);
@@ -1432,15 +1436,18 @@ pollFileReal(act_obj_t *act, cstr_t **pCStr)
CHKiRet(openFile(act)); /* open file */
}
+ start_preg = (inst->startRegex == NULL) ? NULL : &inst->start_preg;
+ end_preg = (inst->endRegex == NULL) ? NULL : &inst->end_preg;
+
/* loop below will be exited when strmReadLine() returns EOF */
while(glbl.GetGlobalInputTermState() == 0) {
if(inst->maxLinesAtOnce != 0 && nProcessed >= inst->maxLinesAtOnce)
break;
- if(inst->startRegex == NULL) {
+ if((start_preg == NULL) && (end_preg == NULL)) {
CHKiRet(strm.ReadLine(act->pStrm, pCStr, inst->readMode, inst->escapeLF,
inst->trimLineOverBytes, &strtOffs));
} else {
- CHKiRet(strmReadMultiLine(act->pStrm, pCStr, &inst->end_preg,
+ CHKiRet(strmReadMultiLine(act->pStrm, pCStr, start_preg, end_preg,
inst->escapeLF, inst->discardTruncatedMsg, inst->msgDiscardingError, &strtOffs));
}
++nProcessed;
@@ -1506,6 +1513,7 @@ createInstance(instanceConf_t **const pinst)
inst->iPersistStateInterval = 0;
inst->readMode = 0;
inst->startRegex = NULL;
+ inst->endRegex = NULL;
inst->discardTruncatedMsg = 0;
inst->msgDiscardingError = 1;
inst->bRMStateOnDel = 1;
@@ -1713,6 +1721,8 @@ CODESTARTnewInpInst
inst->readMode = (sbool) pvals[i].val.d.n;
} else if(!strcmp(inppblk.descr[i].name, "startmsg.regex")) {
inst->startRegex = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(inppblk.descr[i].name, "endmsg.regex")) {
+ inst->endRegex = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(inppblk.descr[i].name, "discardtruncatedmsg")) {
inst->discardTruncatedMsg = (sbool) pvals[i].val.d.n;
} else if(!strcmp(inppblk.descr[i].name, "msgdiscardingerror")) {
@@ -1753,19 +1763,31 @@ CODESTARTnewInpInst
"param '%s'\n", inppblk.descr[i].name);
}
}
- if(inst->readMode != 0 && inst->startRegex != NULL) {
+ i = (inst->readMode > 0) ? 1 : 0;
+ i = (NULL != inst->startRegex) ? (i+1) : i;
+ i = (NULL != inst->endRegex) ? (i+1) : i;
+ if(i > 1) {
LogError(0, RS_RET_PARAM_NOT_PERMITTED,
- "readMode and startmsg.regex cannot be set "
- "at the same time --- remove one of them");
+ "only one of readMode or startmsg.regex or endmsg.regex can be set "
+ "at the same time");
ABORT_FINALIZE(RS_RET_PARAM_NOT_PERMITTED);
}
if(inst->startRegex != NULL) {
- const int errcode = regcomp(&inst->end_preg, (char*)inst->startRegex, REG_EXTENDED);
+ const int errcode = regcomp(&inst->start_preg, (char*)inst->startRegex, REG_EXTENDED);
+ if(errcode != 0) {
+ char errbuff[512];
+ regerror(errcode, &inst->start_preg, errbuff, sizeof(errbuff));
+ parser_errmsg("imfile: error in startmsg.regex expansion: %s", errbuff);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ }
+ if(inst->endRegex != NULL) {
+ const int errcode = regcomp(&inst->end_preg, (char*)inst->endRegex, REG_EXTENDED);
if(errcode != 0) {
char errbuff[512];
regerror(errcode, &inst->end_preg, errbuff, sizeof(errbuff));
- parser_errmsg("imfile: error in regex expansion: %s", errbuff);
+ parser_errmsg("imfile: error in endmsg.regex expansion: %s", errbuff);
ABORT_FINALIZE(RS_RET_ERR);
}
}
@@ -1970,9 +1992,13 @@ CODESTARTfreeCnf
free(inst->pszStateFile);
free(inst->pszFileName_forOldStateFile);
if(inst->startRegex != NULL) {
- regfree(&inst->end_preg);
+ regfree(&inst->start_preg);
free(inst->startRegex);
}
+ if(inst->endRegex != NULL) {
+ regfree(&inst->end_preg);
+ free(inst->endRegex);
+ }
del = inst;
inst = inst->next;
free(del);
diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c
index 9b6be0f40..a94b97f41 100644
--- a/plugins/imptcp/imptcp.c
+++ b/plugins/imptcp/imptcp.c
@@ -162,7 +162,7 @@ struct instanceConf_s {
int ratelimitInterval;
int ratelimitBurst;
uchar *startRegex;
- regex_t end_preg; /* compiled version of startRegex */
+ regex_t start_preg; /* compiled version of startRegex */
struct instanceConf_s *next;
};
@@ -961,7 +961,7 @@ processDataRcvd_regexFraming(ptcpsess_t *const __restrict__ pThis,
if(c == '\n') {
pThis->iCurrLine = pThis->iMsg;
} else {
- const int isMatch = !regexec(&inst->end_preg, (char*)pThis->pMsg+pThis->iCurrLine, 0, NULL, 0);
+ const int isMatch = !regexec(&inst->start_preg, (char*)pThis->pMsg+pThis->iCurrLine, 0, NULL, 0);
if(isMatch) {
DBGPRINTF("regex match (%d), framing line: %s\n", pThis->iCurrLine, pThis->pMsg);
strcpy((char*)pThis->pMsg_save, (char*) pThis->pMsg+pThis->iCurrLine);
@@ -2188,10 +2188,10 @@ CODESTARTnewInpInst
}
if(inst->startRegex != NULL) {
- const int errcode = regcomp(&inst->end_preg, (char*)inst->startRegex, REG_EXTENDED);
+ const int errcode = regcomp(&inst->start_preg, (char*)inst->startRegex, REG_EXTENDED);
if(errcode != 0) {
char errbuff[512];
- regerror(errcode, &inst->end_preg, errbuff, sizeof(errbuff));
+ regerror(errcode, &inst->start_preg, errbuff, sizeof(errbuff));
parser_errmsg("imptcp: error in framing.delimiter.regex expansion: %s", errbuff);
ABORT_FINALIZE(RS_RET_ERR);
}
@@ -2348,7 +2348,7 @@ CODESTARTfreeCnf
free(inst->pszInputName);
free(inst->dfltTZ);
if(inst->startRegex != NULL) {
- regfree(&inst->end_preg);
+ regfree(&inst->start_preg);
free(inst->startRegex);
}
del = inst;
diff --git a/runtime/stream.c b/runtime/stream.c
index 6b7e7028e..0f4197103 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -942,12 +942,12 @@ strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis)
/* read a multi-line message from a strm file.
* The multi-line message is terminated based on the user-provided
- * startRegex (Posix ERE). For performance reasons, the regex
+ * startRegex or endRegex (Posix ERE). For performance reasons, the regex
* must already have been compiled by the user.
* added 2015-05-12 rgerhards
*/
rsRetVal
-strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEscapeLF,
+strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *start_preg, regex_t *end_preg, const sbool bEscapeLF,
const sbool discardTruncatedMsg, const sbool msgDiscardingError, int64 *const strtOffs)
{
uchar c;
@@ -979,9 +979,14 @@ strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEs
cstrFinalize(thisLine);
/* we have a line, now let's assemble the message */
- const int isMatch = !regexec(preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0);
-
- if(isMatch) {
+ const int isStartMatch = start_preg ?
+ !regexec(start_preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0) :
+ 0;
+ const int isEndMatch = end_preg ?
+ !regexec(end_preg, (char*)rsCStrGetSzStrNoNULL(thisLine), 0, NULL, 0) :
+ 0;
+
+ if(isStartMatch) {
/* in this case, the *previous* message is complete and we are
* at the start of a new one.
*/
@@ -1047,6 +1052,19 @@ strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg, const sbool bEs
}
}
}
+ if(isEndMatch) {
+ /* in this case, the *current* message is complete and we are
+ * at the end of it.
+ */
+ if(pThis->ignoringMsg == 0) {
+ if(pThis->prevMsgSegment != NULL) {
+ finished = 1;
+ *ppCStr = pThis->prevMsgSegment;
+ pThis->prevMsgSegment= NULL;
+ }
+ }
+ pThis->ignoringMsg = 0;
+ }
cstrDestruct(&thisLine);
} while(finished == 0);
diff --git a/runtime/stream.h b/runtime/stream.h
index 71596879e..7dc597ff5 100644
--- a/runtime/stream.h
+++ b/runtime/stream.h
@@ -225,7 +225,7 @@ ENDinterface(strm)
/* prototypes */
PROTOTYPEObjClassInit(strm);
rsRetVal strmMultiFileSeek(strm_t *pThis, unsigned int fileNum, off64_t offs, off64_t *bytesDel);
-rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *preg,
+rsRetVal strmReadMultiLine(strm_t *pThis, cstr_t **ppCStr, regex_t *start_preg, regex_t *end_preg,
sbool bEscapeLF, sbool discardTruncatedMsg, sbool msgDiscardingError, int64 *const strtOffs);
int strmReadMultiLine_isTimedOut(const strm_t *const __restrict__ pThis);
void strmDebugOutBuf(const strm_t *const pThis);

View File

@ -0,0 +1,93 @@
diff -up ./plugins/imjournal/imjournal.c.default-tag ./plugins/imjournal/imjournal.c
--- ./plugins/imjournal/imjournal.c.default-tag 2018-05-17 08:50:11.416418022 -0400
+++ ./plugins/imjournal/imjournal.c 2018-05-17 08:53:02.884418022 -0400
@@ -78,6 +78,7 @@ static struct configSettings_s {
int bUseJnlPID;
char *usePid;
int bWorkAroundJournalBug;
+ char *dfltTag;
} cs;
static rsRetVal facilityHdlr(uchar **pp, void *pVal);
@@ -93,7 +94,8 @@ static struct cnfparamdescr modpdescr[]
{ "defaultfacility", eCmdHdlrString, 0 },
{ "usepidfromsystem", eCmdHdlrBinary, 0 },
{ "usepid", eCmdHdlrString, 0 },
- { "workaroundjournalbug", eCmdHdlrBinary, 0 }
+ { "workaroundjournalbug", eCmdHdlrBinary, 0 },
+ { "defaulttag", eCmdHdlrGetWord, 0 }
};
static struct cnfparamblk modpblk =
{ CNFPARAMBLK_VERSION,
@@ -104,6 +106,7 @@ static struct cnfparamblk modpblk =
#define DFLT_persiststateinterval 10
#define DFLT_SEVERITY pri2sev(LOG_NOTICE)
#define DFLT_FACILITY pri2fac(LOG_USER)
+#define DFLT_TAG "journal"
static int bLegacyCnfModGlobalsPermitted = 1;/* are legacy module-global config parameters permitted? */
@@ -268,7 +271,7 @@ readjournal(void)
/* Information from messages */
char *message = NULL;
- char *sys_iden;
+ char *sys_iden = NULL;
char *sys_iden_help = NULL;
char *c = NULL;
@@ -331,7 +334,7 @@ readjournal(void)
if (sd_journal_get_data(j, "SYSLOG_IDENTIFIER", &get, &length) >= 0) {
CHKiRet(sanitizeValue(((const char *)get) + 18, length - 18, &sys_iden));
} else {
- CHKmalloc(sys_iden = strdup("journal"));
+ CHKmalloc(sys_iden = strdup(cs.dfltTag));
}
/* trying to get PID, default is "SYSLOG_PID" property */
@@ -654,6 +657,11 @@ CODESTARTrunInput
"\"usepidfromsystem\" is depricated, use \"usepid\" instead");
}
+ if (cs.dfltTag == NULL) {
+ cs.dfltTag = strdup(DFLT_TAG);
+ }
+
+
if (cs.usePid && (strcmp(cs.usePid, "system") == 0)) {
pidFieldName = "_PID";
bPidFallBack = 0;
@@ -732,6 +740,7 @@ CODESTARTbeginCnfLoad
cs.bUseJnlPID = -1;
cs.usePid = NULL;
cs.bWorkAroundJournalBug = 0;
+ cs.dfltTag = NULL;
ENDbeginCnfLoad
@@ -754,6 +763,7 @@ BEGINfreeCnf
CODESTARTfreeCnf
free(cs.stateFile);
free(cs.usePid);
+ free(cs.dfltTag);
statsobj.Destruct(&(statsCounter.stats));
ENDfreeCnf
@@ -832,6 +842,8 @@ CODESTARTsetModCnf
cs.usePid = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if (!strcmp(modpblk.descr[i].name, "workaroundjournalbug")) {
cs.bWorkAroundJournalBug = (int) pvals[i].val.d.n;
+ } else if (!strcmp(modpblk.descr[i].name, "defaulttag")) {
+ cs.dfltTag = (char *)es_str2cstr(pvals[i].val.d.estr, NULL);
} else {
dbgprintf("imjournal: program error, non-handled "
"param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
@@ -799,6 +820,8 @@ CODEmodInit_QueryRegCFSLineHdlr
facilityHdlr, &cs.iDfltFacility, STD_LOADABLE_MODULE_ID));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalusepidfromsystem", 0, eCmdHdlrBinary,
NULL, &cs.bUseJnlPID, STD_LOADABLE_MODULE_ID));
+ CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournaldefaulttag", 0, eCmdHdlrGetWord,
+ NULL, &cs.dfltTag, STD_LOADABLE_MODULE_ID));
ENDmodInit
/* vim:set ai:
*/

View File

@ -0,0 +1,368 @@
From f85ef7aabcec84497a5eaf9670616b3402c79d9c Mon Sep 17 00:00:00 2001
From: Rainer Gerhards <rgerhards@adiscon.com>
Date: Sun, 23 Sep 2018 13:19:31 +0200
Subject: File rotation with imfile broken
Previously, truncation was only detected at end of file. Especially with
busy files that could cause loss of data and possibly also stall imfile
reading. The new code now also checks during each read. Obviously, there
is some additional overhead associated with that, but this is unavoidable.
It still is highly recommended NOT to turn on "reopenOnTruncate" in imfile.
Note that there are also inherant reliability issues. There is no way to
"fix" these, as they are caused by races between the process(es) who truncate
and rsyslog reading the file. But with the new code, the "problem window"
should be much smaller and, more importantly, imfile should not stall.
A change in the inode was not detected under all circumstances,
most importantly not in some logrotate cases.
Includes new tests made by Andre Lorbach. They now use the
logrotate tool natively to reproduce the issue.
---
runtime/rsyslog.h | 6 ++--
plugins/imfile/imfile.c | 17 +++-
runtime/stream.c | 122 ++++++++----
runtime/stream.h | 7 ++
4 files changed, 126 insertions(+), 36 deletions(-)
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 61d0af623..22a1c46d1 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -221,9 +221,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
/* begin regular error codes */
RS_RET_NOT_IMPLEMENTED = -7, /**< implementation is missing (probably internal error or lazyness ;)) */
RS_RET_OUT_OF_MEMORY = -6, /**< memory allocation failed */
- RS_RET_PROVIDED_BUFFER_TOO_SMALL = -50,
-/*< the caller provided a buffer, but the called function sees the size of this buffer is too small -
-operation not carried out */
+ RS_RET_PROVIDED_BUFFER_TOO_SMALL = -50, /*< the caller provided a buffer, but the called function sees
+ the size of this buffer is too small - operation not carried out */
+ RS_RET_FILE_TRUNCATED = -51, /**< (input) file was truncated, not an error but a status */
RS_RET_TRUE = -3, /**< to indicate a true state (can be used as TRUE, legacy) */
RS_RET_FALSE = -2, /**< to indicate a false state (can be used as FALSE, legacy) */
RS_RET_NO_IRET = -8, /**< This is a trick for the debuging system - it means no iRet is provided */
diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c
index f4a4ef9b7..6be8b2999 100644
--- a/plugins/imfile/imfile.c
+++ b/plugins/imfile/imfile.c
@@ -740,8 +740,19 @@ detect_updates(fs_edge_t *const edge)
act_obj_unlink(act);
restart = 1;
break;
+ } else if(fileInfo.st_ino != act->ino) {
+ DBGPRINTF("file '%s' inode changed from %llu to %llu, unlinking from "
+ "internal lists\n", act->name, (long long unsigned) act->ino,
+ (long long unsigned) fileInfo.st_ino);
+ if(act->pStrm != NULL) {
+ /* we do no need to re-set later, as act_obj_unlink
+ * will destroy the strm obj */
+ strmSet_checkRotation(act->pStrm, STRM_ROTATION_DO_NOT_CHECK);
+ }
+ act_obj_unlink(act);
+ restart = 1;
+ break;
}
- // TODO: add inode check for change notification!
}
@@ -993,10 +1004,10 @@ chk_active(const act_obj_t *act, const act_obj_t *const deleted)
/* unlink act object from linked list and then
* destruct it.
*/
-static void //ATTR_NONNULL()
+static void ATTR_NONNULL()
act_obj_unlink(act_obj_t *act)
{
- DBGPRINTF("act_obj_unlink %p: %s\n", act, act->name);
+ DBGPRINTF("act_obj_unlink %p: %s, pStrm %p\n", act, act->name, act->pStrm);
if(act->prev == NULL) {
act->edge->active = act->next;
} else {
diff --git a/runtime/stream.c b/runtime/stream.c
index 0f4197103..32a12b256 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -400,6 +400,7 @@ static rsRetVal strmOpenFile(strm_t *pThis)
CHKiRet(doPhysOpen(pThis));
pThis->iCurrOffs = 0;
+ pThis->iBufPtrMax = 0;
CHKiRet(getFileSize(pThis->pszCurrFName, &offset));
if(pThis->tOperationsMode == STREAMMODE_WRITE_APPEND) {
pThis->iCurrOffs = offset;
@@ -636,6 +637,78 @@ strmHandleEOF(strm_t *pThis)
RETiRet;
}
+
+/* helper to checkTruncation */
+static rsRetVal ATTR_NONNULL()
+rereadTruncated(strm_t *const pThis, const char *const reason)
+{
+ DEFiRet;
+
+ LogMsg(errno, RS_RET_FILE_TRUNCATED, LOG_WARNING, "file '%s': truncation detected, "
+ "(%s) - re-start reading from beginning",
+ pThis->pszCurrFName, reason);
+ DBGPRINTF("checkTruncation, file %s last buffer CHANGED\n", pThis->pszCurrFName);
+ CHKiRet(strmCloseFile(pThis));
+ CHKiRet(strmOpenFile(pThis));
+ iRet = RS_RET_FILE_TRUNCATED;
+
+finalize_it:
+ RETiRet;
+}
+/* helper to read:
+ * Check if file has been truncated since last read and, if so, re-set reading
+ * to begin of file. To detect truncation, we try to re-read the last block.
+ * If that does not succeed or different data than from the original read is
+ * returned, truncation is assumed.
+ * NOTE: this function must be called only if truncation is enabled AND
+ * when the previous read buffer still is valid (aka "before the next read").
+ * It is ok to call with a 0-size buffer, which we than assume as begin of
+ * reading. In that case, no truncation will be detected.
+ * rgerhards, 2018-09-20
+ */
+static rsRetVal ATTR_NONNULL()
+checkTruncation(strm_t *const pThis)
+{
+ DEFiRet;
+ int ret;
+ off64_t backseek;
+ assert(pThis->bReopenOnTruncate);
+
+ DBGPRINTF("checkTruncation, file %s, iBufPtrMax %zd\n", pThis->pszCurrFName, pThis->iBufPtrMax);
+ if(pThis->iBufPtrMax == 0) {
+ FINALIZE;
+ }
+
+ int currpos = lseek64(pThis->fd, 0, SEEK_CUR);
+ backseek = -1 * (off64_t) pThis->iBufPtrMax;
+ dbgprintf("checkTruncation in actual processing, currpos %d, backseek is %d\n", (int)currpos, (int) backseek);
+ ret = lseek64(pThis->fd, backseek, SEEK_CUR);
+ if(ret < 0) {
+ iRet = rereadTruncated(pThis, "cannot seek backward to begin of last block");
+ FINALIZE;
+ }
+dbgprintf("checkTruncation seek backwrds: %d\n", ret);
+currpos = lseek64(pThis->fd, 0, SEEK_CUR);
+dbgprintf("checkTruncation in actual processing, NEW currpos %d, backseek is %d\n", (int)currpos, (int) backseek);
+
+ const ssize_t lenRead = read(pThis->fd, pThis->pIOBuf_truncation, pThis->iBufPtrMax);
+ dbgprintf("checkTruncation proof-read: %d bytes\n", (int) lenRead);
+ if(lenRead < 0) {
+ iRet = rereadTruncated(pThis, "last block could not be re-read");
+ FINALIZE;
+ }
+
+ if(!memcmp(pThis->pIOBuf_truncation, pThis->pIOBuf, pThis->iBufPtrMax)) {
+ DBGPRINTF("checkTruncation, file %s last buffer unchanged\n", pThis->pszCurrFName);
+ } else {
+ iRet = rereadTruncated(pThis, "last block data different");
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* read the next buffer from disk
* rgerhards, 2008-02-13
*/
@@ -668,6 +741,13 @@ strmReadBuf(strm_t *pThis, int *padBytes)
toRead = (size_t) bytesLeft;
}
}
+ if(pThis->bReopenOnTruncate) {
+ rsRetVal localRet = checkTruncation(pThis);
+ if(localRet == RS_RET_FILE_TRUNCATED) {
+ continue;
+ }
+ CHKiRet(localRet);
+ }
iLenRead = read(pThis->fd, pThis->pIOBuf, toRead);
DBGOPRINT((obj_t*) pThis, "file %d read %ld bytes\n", pThis->fd, iLenRead);
/* end crypto */
@@ -1184,6 +1264,7 @@ static rsRetVal strmConstructFinalize(strm_t *pThis)
} else {
/* we work synchronously, so we need to alloc a fixed pIOBuf */
CHKmalloc(pThis->pIOBuf = (uchar*) MALLOC(pThis->sIOBufSize));
+ CHKmalloc(pThis->pIOBuf_truncation = (char*) MALLOC(pThis->sIOBufSize));
}
finalize_it:
@@ -1231,6 +1312,7 @@ CODESTARTobjDestruct(strm)
}
} else {
free(pThis->pIOBuf);
+ free(pThis->pIOBuf_truncation);
}
/* Finally, we can free the resources.
diff --git a/runtime/stream.c b/runtime/stream.c
index 2d494c612..5b52591ef 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -360,8 +360,8 @@ CheckFileChange(strm_t *pThis)
CHKiRet(strmSetCurrFName(pThis));
if(stat((char*) pThis->pszCurrFName, &statName) == -1)
ABORT_FINALIZE(RS_RET_IO_ERROR);
- DBGPRINTF("stream/after deserialize checking for file change on '%s', "
- "inode %u/%u, size/currOffs %llu/%llu\n",
+ DBGPRINTF("CheckFileChange: stream/after deserialize checking for file change "
+ "on '%s', inode %u/%u, size/currOffs %llu/%llu\n",
pThis->pszCurrFName, (unsigned) pThis->inode,
(unsigned) statName.st_ino,
(long long unsigned) statName.st_size,
@@ -574,8 +574,8 @@ strmNextFile(strm_t *pThis)
* circumstances). So starting as of now, we only check the inode number and
* a file change is detected only if the inode changes. -- rgerhards, 2011-01-10
*/
-static rsRetVal
-strmHandleEOFMonitor(strm_t *pThis)
+static rsRetVal ATTR_NONNULL()
+strmHandleEOFMonitor(strm_t *const pThis)
{
DEFiRet;
struct stat statName;
@@ -611,8 +611,8 @@ strmHandleEOFMonitor(strm_t *pThis)
* try to open the next one.
* rgerhards, 2008-02-13
*/
-static rsRetVal
-strmHandleEOF(strm_t *pThis)
+static rsRetVal ATTR_NONNULL()
+strmHandleEOF(strm_t *const pThis)
{
DEFiRet;
@@ -629,7 +629,13 @@ strmHandleEOF(strm_t *pThis)
CHKiRet(strmNextFile(pThis));
break;
case STREAMTYPE_FILE_MONITOR:
- CHKiRet(strmHandleEOFMonitor(pThis));
+ DBGOPRINT((obj_t*) pThis, "file '%s' (%d) EOF, rotationCheck %d\n",
+ pThis->pszCurrFName, pThis->fd, pThis->rotationCheck);
+ if(pThis->rotationCheck == STRM_ROTATION_DO_CHECK) {
+ CHKiRet(strmHandleEOFMonitor(pThis));
+ } else {
+ ABORT_FINALIZE(RS_RET_EOF);
+ }
break;
}
@@ -687,9 +693,6 @@ checkTruncation(strm_t *const pThis)
iRet = rereadTruncated(pThis, "cannot seek backward to begin of last block");
FINALIZE;
}
-dbgprintf("checkTruncation seek backwrds: %d\n", ret);
-currpos = lseek64(pThis->fd, 0, SEEK_CUR);
-dbgprintf("checkTruncation in actual processing, NEW currpos %d, backseek is %d\n", (int)currpos, (int) backseek);
const ssize_t lenRead = read(pThis->fd, pThis->pIOBuf_truncation, pThis->iBufPtrMax);
dbgprintf("checkTruncation proof-read: %d bytes\n", (int) lenRead);
@@ -861,7 +864,7 @@ static rsRetVal strmUnreadChar(strm_t *pThis, uchar c)
* a line, but following lines that are indented are part of the same log entry
*/
static rsRetVal
-strmReadLine(strm_t *pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF,
+strmReadLine(strm_t *const pThis, cstr_t **ppCStr, uint8_t mode, sbool bEscapeLF,
uint32_t trimLineOverBytes, int64 *const strtOffs)
{
uchar c;
@@ -2147,14 +2150,25 @@ DEFpropSetMeth(strm, cryprov, cryprov_if_t*)
DEFpropSetMeth(strm, cryprovData, void*)
/* sets timeout in seconds */
-void
+void ATTR_NONNULL()
strmSetReadTimeout(strm_t *const __restrict__ pThis, const int val)
{
+ ISOBJ_TYPE_assert(pThis, strm);
pThis->readTimeout = val;
}
-static rsRetVal strmSetbDeleteOnClose(strm_t *pThis, int val)
+void ATTR_NONNULL()
+strmSet_checkRotation(strm_t *const pThis, const int val) {
+ ISOBJ_TYPE_assert(pThis, strm);
+ assert(val == STRM_ROTATION_DO_CHECK || val == STRM_ROTATION_DO_NOT_CHECK);
+ pThis->rotationCheck = val;
+}
+
+
+static rsRetVal ATTR_NONNULL()
+strmSetbDeleteOnClose(strm_t *const pThis, const int val)
{
+ ISOBJ_TYPE_assert(pThis, strm);
pThis->bDeleteOnClose = val;
if(pThis->cryprov != NULL) {
pThis->cryprov->SetDeleteOnClose(pThis->cryprovFileData, pThis->bDeleteOnClose);
@@ -2162,15 +2176,19 @@ static rsRetVal strmSetbDeleteOnClose(strm_t *pThis, int val)
return RS_RET_OK;
}
-static rsRetVal strmSetiMaxFiles(strm_t *pThis, int iNewVal)
+static rsRetVal ATTR_NONNULL()
+strmSetiMaxFiles(strm_t *const pThis, const int iNewVal)
{
+ ISOBJ_TYPE_assert(pThis, strm);
pThis->iMaxFiles = iNewVal;
pThis->iFileNumDigits = getNumberDigits(iNewVal);
return RS_RET_OK;
}
-static rsRetVal strmSetFileNotFoundError(strm_t *pThis, int pFileNotFoundError)
+static rsRetVal ATTR_NONNULL()
+strmSetFileNotFoundError(strm_t *const pThis, const int pFileNotFoundError)
{
+ ISOBJ_TYPE_assert(pThis, strm);
pThis->fileNotFoundError = pFileNotFoundError;
return RS_RET_OK;
}
diff --git a/runtime/stream.h b/runtime/stream.h
index 7dc597ff5..e3d6c2372 100644
--- a/runtime/stream.h
+++ b/runtime/stream.h
@@ -124,6 +124,7 @@ typedef struct strm_s {
ino_t inode; /* current inode for files being monitored (undefined else) */
uchar *pszCurrFName; /* name of current file (if open) */
uchar *pIOBuf; /* the iobuffer currently in use to gather data */
+ char *pIOBuf_truncation; /* iobuffer used during trucation detection block re-reads */
size_t iBufPtrMax; /* current max Ptr in Buffer (if partial read!) */
size_t iBufPtr; /* pointer into current buffer */
int iUngetC; /* char set via UngetChar() call or -1 if none set */
diff --git a/runtime/stream.h b/runtime/stream.h
index e3d6c2372..f6f48378a 100644
--- a/runtime/stream.h
+++ b/runtime/stream.h
@@ -91,6 +91,10 @@ typedef enum { /* when extending, do NOT change existing modes! */
STREAMMODE_WRITE_APPEND = 4
} strmMode_t;
+/* settings for stream rotation (applies not to all processing modes!) */
+#define STRM_ROTATION_DO_CHECK 0
+#define STRM_ROTATION_DO_NOT_CHECK 1
+
#define STREAM_ASYNC_NUMBUFS 2 /* must be a power of 2 -- TODO: make configurable */
/* The strm_t data structure */
typedef struct strm_s {
@@ -114,6 +118,7 @@ typedef struct strm_s {
sbool bDisabled; /* should file no longer be written to? (currently set only if omfile file size limit fails) */
sbool bSync; /* sync this file after every write? */
sbool bReopenOnTruncate;
+ int rotationCheck; /* rotation check mode */
size_t sIOBufSize;/* size of IO buffer */
uchar *pszDir; /* Directory */
int lenDir;
@@ -234,5 +239,6 @@ void strmSetReadTimeout(strm_t *const __restrict__ pThis, const int val);
const uchar * ATTR_NONNULL() strmGetPrevLineSegment(strm_t *const pThis);
const uchar * ATTR_NONNULL() strmGetPrevMsgSegment(strm_t *const pThis);
int ATTR_NONNULL() strmGetPrevWasNL(const strm_t *const pThis);
+void ATTR_NONNULL() strmSet_checkRotation(strm_t *const pThis, const int val);
#endif /* #ifndef STREAM_H_INCLUDED */

View File

@ -0,0 +1,86 @@
From 1255a67fdec2fc44cd49b6ea8c463f4319910812 Mon Sep 17 00:00:00 2001
From: Jiri Vymazal <jvymazal@redhat.com>
Date: Wed, 27 Feb 2019 11:57:49 +0100
Subject: [PATCH] Enlarged msg offset types for bigger structured messages
using a large enough (dozens of kBs) structured message
it is possible to overflow the signed short type which leads
to rsyslog crash.
---
runtime/msg.c | 12 ++++++------
runtime/msg.h | 8 ++++----
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/runtime/msg.c b/runtime/msg.c
index b82c38b9ee..96306bbeab 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -839,7 +839,7 @@ msgBaseConstruct(smsg_t **ppThis)
pM->iFacility = LOG_INVLD;
pM->iLenPROGNAME = -1;
pM->offAfterPRI = 0;
- pM->offMSG = -1;
+ pM->offMSG = 0;
pM->iProtocolVersion = 0;
pM->msgFlags = 0;
pM->iLenRawMsg = 0;
@@ -2167,7 +2167,7 @@ MsgSetFlowControlType(smsg_t * const pMsg, flowControl_t eFlowCtl)
* rgerhards, 2009-06-16
*/
rsRetVal
-MsgSetAfterPRIOffs(smsg_t * const pMsg, short offs)
+MsgSetAfterPRIOffs(smsg_t * const pMsg, uint32_t offs)
{
assert(pMsg != NULL);
pMsg->offAfterPRI = offs;
@@ -2819,12 +2819,12 @@ void MsgSetHOSTNAME(smsg_t *pThis, const uchar* pszHOSTNAME, const int lenHOSTNA
* (exactly by one). This can happen if we have a message that does not
* contain any MSG part.
*/
-void MsgSetMSGoffs(smsg_t * const pMsg, short offs)
+void MsgSetMSGoffs(smsg_t * const pMsg, uint32_t offs)
{
ISOBJ_TYPE_assert(pMsg, msg);
pMsg->offMSG = offs;
- if(offs > pMsg->iLenRawMsg) {
- assert(offs - 1 == pMsg->iLenRawMsg);
+ if(offs > (uint32_t)pMsg->iLenRawMsg) {
+ assert((int)offs - 1 == pMsg->iLenRawMsg);
pMsg->iLenMSG = 0;
} else {
pMsg->iLenMSG = pMsg->iLenRawMsg - offs;
@@ -2920,7 +2920,7 @@ MsgSetRawMsg(smsg_t *const pThis, const char*const pszRawMsg, const size_t lenMs
memcpy(pThis->pszRawMsg, pszRawMsg, pThis->iLenRawMsg);
pThis->pszRawMsg[pThis->iLenRawMsg] = '\0'; /* this also works with truncation! */
/* correct other information */
- if(pThis->iLenRawMsg > pThis->offMSG)
+ if((uint32_t)pThis->iLenRawMsg > pThis->offMSG)
pThis->iLenMSG += deltaSize;
else
pThis->iLenMSG = 0;
diff --git a/runtime/msg.h b/runtime/msg.h
index 74439275b1..722cca6e8a 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -67,8 +67,8 @@ struct msg {
sbool bParseSuccess; /* set to reflect state of last executed higher level parser */
unsigned short iSeverity;/* the severity */
unsigned short iFacility;/* Facility code */
- short offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */
- short offMSG; /* offset at which the MSG part starts in pszRawMsg */
+ uint32_t offAfterPRI; /* offset, at which raw message WITHOUT PRI part starts in pszRawMsg */
+ uint32_t offMSG; /* offset at which the MSG part starts in pszRawMsg */
short iProtocolVersion;/* protocol version of message received 0 - legacy, 1 syslog-protocol) */
int msgFlags; /* flags associated with this message */
int iLenRawMsg; /* length of raw message */
@@ -194,8 +194,8 @@ void MsgSetRcvFromStr(smsg_t *const pMsg, const uchar* pszRcvFrom, const int, pr
rsRetVal MsgSetRcvFromIP(smsg_t *pMsg, prop_t*);
rsRetVal MsgSetRcvFromIPStr(smsg_t *const pThis, const uchar *psz, const int len, prop_t **ppProp);
void MsgSetHOSTNAME(smsg_t *pMsg, const uchar* pszHOSTNAME, const int lenHOSTNAME);
-rsRetVal MsgSetAfterPRIOffs(smsg_t *pMsg, short offs);
-void MsgSetMSGoffs(smsg_t *pMsg, short offs);
+rsRetVal MsgSetAfterPRIOffs(smsg_t *pMsg, uint32_t offs);
+void MsgSetMSGoffs(smsg_t *pMsg, uint32_t offs);
void MsgSetRawMsgWOSize(smsg_t *pMsg, char* pszRawMsg);
void ATTR_NONNULL() MsgSetRawMsg(smsg_t *const pThis, const char*const pszRawMsg, const size_t lenMsg);
rsRetVal MsgReplaceMSG(smsg_t *pThis, const uchar* pszMSG, int lenMSG);

View File

@ -0,0 +1,60 @@
From 920c28ff705aac74f389b4613815b14b9482e497 Mon Sep 17 00:00:00 2001
From: Jiri Vymazal <jvymazal@redhat.com>
Date: Mon, 21 Jan 2019 10:58:03 +0100
Subject: [PATCH] Added missing free() calls of received journal cursor
---
plugins/imjournal/imjournal.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
index a85e521003..f5c2be4b6e 100644
--- a/plugins/imjournal/imjournal.c
+++ b/plugins/imjournal/imjournal.c
@@ -442,8 +437,7 @@ readjournal(void)
if (cs.bWorkAroundJournalBug) {
/* save journal cursor (at this point we can be sure it is valid) */
- sd_journal_get_cursor(j, &c);
- if (c) {
+ if (!sd_journal_get_cursor(j, &c)) {
free(last_cursor);
last_cursor = c;
}
@@ -470,6 +471,7 @@ persistJournalState(void)
}
} else {
int ret;
+ free(last_cursor);
if ((ret = sd_journal_get_cursor(j, &last_cursor))) {
LogError(-ret, RS_RET_ERR, "imjournal: sd_journal_get_cursor() failed");
ABORT_FINALIZE(RS_RET_ERR);
@@ -630,6 +632,7 @@ loadJournalState(void)
iRet = RS_RET_ERR;
}
}
+ free(tmp_cursor);
}
} else {
LogError(0, RS_RET_IO_ERROR, "imjournal: "
@@ -843,6 +846,7 @@ BEGINfreeCnf
free(cs.stateFile);
free(cs.usePid);
free(cs.dfltTag);
+ free(last_cursor);
statsobj.Destruct(&(statsCounter.stats));
ENDfreeCnf
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
index f5c2be4b6e..7225fae1ab 100644
--- a/plugins/imjournal/imjournal.c
+++ b/plugins/imjournal/imjournal.c
@@ -474,6 +474,7 @@ persistJournalState(void)
free(last_cursor);
if ((ret = sd_journal_get_cursor(j, &last_cursor))) {
LogError(-ret, RS_RET_ERR, "imjournal: sd_journal_get_cursor() failed");
+ last_cursor = NULL;
ABORT_FINALIZE(RS_RET_ERR);
}
}

View File

@ -0,0 +1,136 @@
From 9c22b31cd639911a2faffad02f2ed9f7cc10b9e1 Mon Sep 17 00:00:00 2001
From: Jiri Vymazal <jvymazal@redhat.com>
Date: Fri, 15 Mar 2019 09:29:04 +0100
Subject: [PATCH] Fetching journal cursor only for valid journal
The sd_journal_get_cursor() got called regradless of previous
retcodes from other jorunal calls which flooded logs with journald
errors. Now skipping the call in case of previous journal call
non-zero result. Fixed success checking of get_cursor() call
to eliminate double-free possibility.
Also, making WorkAroundJournalBug true by default, as there were no
confirmed performance regressions for a quite long time.
---
plugins/imjournal/imjournal.c | 43 ++++++++++++++++++++++------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
index 7225fae1ab..5419762cf1 100644
--- a/plugins/imjournal/imjournal.c
+++ b/plugins/imjournal/imjournal.c
@@ -135,7 +135,7 @@ static char *last_cursor = NULL;
#define J_PROCESS_PERIOD 1024 /* Call sd_journal_process() every 1,024 records */
-static rsRetVal persistJournalState(void);
+static rsRetVal persistJournalState(int trySave);
static rsRetVal loadJournalState(void);
static rsRetVal openJournal(void) {
@@ -158,9 +158,9 @@ static rsRetVal openJournal(void) {
RETiRet;
}
-static void closeJournal(void) {
+static void closeJournal(int trySave) {
if (cs.stateFile) { /* can't persist without a state file */
- persistJournalState();
+ persistJournalState(trySave);
}
sd_journal_close(j);
j_inotify_fd = 0;
@@ -461,7 +461,7 @@ readjournal(void)
/* This function gets journal cursor and saves it into state file
*/
static rsRetVal
-persistJournalState(void)
+persistJournalState(int trySave)
{
DEFiRet;
FILE *sf; /* state file */
@@ -469,7 +470,7 @@ persistJournalState(void)
if (!last_cursor) {
ABORT_FINALIZE(RS_RET_OK);
}
- } else {
+ } else if (trySave) {
int ret;
free(last_cursor);
if ((ret = sd_journal_get_cursor(j, &last_cursor))) {
@@ -477,6 +478,8 @@ persistJournalState(void)
last_cursor = NULL;
ABORT_FINALIZE(RS_RET_ERR);
}
+ } else { /* not trying to get cursor out of invalid journal state */
+ ABORT_FINALIZE(RS_RET_OK);
}
/* we create a temporary name by adding a ".tmp"
@@ -535,14 +535,24 @@ pollJournal(void)
err = sd_journal_wait(j, POLL_TIMEOUT);
if (err == SD_JOURNAL_INVALIDATE) {
STATSCOUNTER_INC(statsCounter.ctrRotations, statsCounter.mutCtrRotations);
- closeJournal();
+ closeJournal(0);
iRet = openJournal();
if (iRet != RS_RET_OK) {
ABORT_FINALIZE(RS_RET_ERR);
}
- if (cs.stateFile) {
+ /* If we have locally saved cursor there is no need to read it from state file */
+ if (cs.bWorkAroundJournalBug && last_cursor)
+ {
+ if (sd_journal_seek_cursor(j, last_cursor) != 0) {
+ LogError(0, RS_RET_ERR, "imjournal: "
+ "couldn't seek to cursor `%s'\n", last_cursor);
+ iRet = RS_RET_ERR;
+ }
+ sd_journal_next(j);
+ }
+ else if (cs.stateFile) {
iRet = loadJournalState();
}
LogMsg(0, RS_RET_OK, LOG_NOTICE, "imjournal: journal reloaded...");
@@ -668,10 +680,9 @@ loadJournalState(void)
static void
tryRecover(void) {
- LogMsg(0, RS_RET_OK, LOG_INFO, "imjournal: trying to recover from unexpected "
- "journal error");
+ LogMsg(0, RS_RET_OK, LOG_INFO, "imjournal: trying to recover from journal error");
STATSCOUNTER_INC(statsCounter.ctrRecoveryAttempts, statsCounter.mutCtrRecoveryAttempts);
- closeJournal();
+ closeJournal(0);
srSleep(10, 0); // do not hammer machine with too-frequent retries
openJournal();
}
@@ -768,7 +779,7 @@ CODESTARTrunInput
if (cs.stateFile) { /* can't persist without a state file */
/* TODO: This could use some finer metric. */
if ((count % cs.iPersistStateInterval) == 0) {
- persistJournalState();
+ persistJournalState(1);
}
}
}
@@ -790,7 +801,7 @@ CODESTARTbeginCnfLoad
cs.iDfltFacility = DFLT_FACILITY;
cs.bUseJnlPID = -1;
cs.usePid = NULL;
- cs.bWorkAroundJournalBug = 0;
+ cs.bWorkAroundJournalBug = 1;
cs.dfltTag = NULL;
ENDbeginCnfLoad
@@ -860,7 +871,7 @@ ENDwillRun
/* close journal */
BEGINafterRun
CODESTARTafterRun
- closeJournal();
+ closeJournal(1);
ratelimitDestruct(ratelimiter);
ENDafterRun

View File

@ -0,0 +1,28 @@
From f53977817f352ef1c67178687cbfcee849f667fc Mon Sep 17 00:00:00 2001
From: Andre Lorbach <alorbach@adiscon.com>
Date: Tue, 9 Oct 2018 14:31:52 +0200
Subject: [PATCH] imrelp: Fixed issue with oldstyle configuration caused by
commit:
https://github.com/rsyslog/rsyslog/commit/32b71daa8aadb8f16fe0ca2945e54d593f47a824
Fixed by setting bEnableLstn in addInstance().
Closes https://github.com/rsyslog/rsyslog/issues/3106
---
plugins/imrelp/imrelp.c | 2 ++
1 files changed, 2 insertions(+)
diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c
index c2134e5165..076dd64900 100644
--- a/plugins/imrelp/imrelp.c
+++ b/plugins/imrelp/imrelp.c
@@ -346,6 +346,8 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal)
CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset));
}
inst->pBindRuleset = NULL;
+
+ inst->bEnableLstn = -1; /* all ok, ready to start up */
finalize_it:
free(pNewVal);
RETiRet;

View File

@ -0,0 +1,618 @@
From b15e6ab7242b25311a9e0dcf14187d21a80a44a6 Mon Sep 17 00:00:00 2001
From: Jiri Vymazal <jvymazal@redhat.com>
Date: Fri, 16 Aug 2019 15:01:11 +0200
Subject: [PATCH] Stricter GnuTLS operation
This commit adds to new flags which can be set to allow
1) checking of extendedKeyUsage certificate field
2) stricter checking of certificate name/adresses
---
plugins/imtcp/imtcp.c | 12 +++++++
runtime/netstrm.c | 22 +++++++++++++
runtime/netstrm.h | 5 ++-
runtime/netstrms.c | 47 +++++++++++++++++++++++++++
runtime/netstrms.h | 6 ++++
runtime/nsd.h | 7 ++--
runtime/nsd_gtls.c | 74 ++++++++++++++++++++++++++++++++++++++++---
runtime/nsd_gtls.h | 12 +++++++
runtime/nsd_ossl.c | 36 +++++++++++++++++++++
runtime/nsd_ptcp.c | 35 ++++++++++++++++++++
runtime/tcpsrv.c | 24 ++++++++++++++
runtime/tcpsrv.h | 7 +++-
tools/omfwd.c | 12 +++++++
13 files changed, 291 insertions(+), 8 deletions(-)
diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c
index 55245842d5..6b3401f8fe 100644
--- a/plugins/imtcp/imtcp.c
+++ b/plugins/imtcp/imtcp.c
@@ -131,6 +131,8 @@ struct modConfData_s {
int iTCPSessMax; /* max number of sessions */
int iTCPLstnMax; /* max number of sessions */
int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */
+ int iStrmDrvrExtendedCertCheck; /* verify also purpose OID in certificate extended field */
+ int iStrmDrvrSANPreference; /* ignore CN when any SAN set */
int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */
int maxFrameSize;
int bSuppOctetFram;
@@ -170,6 +172,8 @@ static struct cnfparamdescr modpdescr[] = {
{ "streamdriver.mode", eCmdHdlrNonNegInt, 0 },
{ "streamdriver.authmode", eCmdHdlrString, 0 },
{ "streamdriver.name", eCmdHdlrString, 0 },
+ { "streamdriver.CheckExtendedKeyPurpose", eCmdHdlrBinary, 0 },
+ { "streamdriver.PrioritizeSAN", eCmdHdlrBinary, 0 },
{ "permittedpeer", eCmdHdlrArray, 0 },
{ "keepalive", eCmdHdlrBinary, 0 },
{ "keepalive.probes", eCmdHdlrPositiveInt, 0 },
@@ -368,6 +372,8 @@ addListner(modConfData_t *modConf, instanceConf_t *inst)
CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, modConf->iTCPSessMax));
CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, modConf->iTCPLstnMax));
CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, modConf->iStrmDrvrMode));
+ CHKiRet(tcpsrv.SetDrvrCheckExtendedKeyUsage(pOurTcpsrv, modConf->iStrmDrvrExtendedCertCheck));
+ CHKiRet(tcpsrv.SetDrvrPrioritizeSAN(pOurTcpsrv, modConf->iStrmDrvrSANPreference));
CHKiRet(tcpsrv.SetUseFlowControl(pOurTcpsrv, modConf->bUseFlowControl));
CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, modConf->iAddtlFrameDelim));
CHKiRet(tcpsrv.SetMaxFrameSize(pOurTcpsrv, modConf->maxFrameSize));
@@ -479,6 +485,8 @@ CODESTARTbeginCnfLoad
loadModConf->iTCPLstnMax = 20;
loadModConf->bSuppOctetFram = 1;
loadModConf->iStrmDrvrMode = 0;
+ loadModConf->iStrmDrvrExtendedCertCheck = 0;
+ loadModConf->iStrmDrvrSANPreference = 0;
loadModConf->bUseFlowControl = 1;
loadModConf->bKeepAlive = 0;
loadModConf->iKeepAliveIntvl = 0;
@@ -560,6 +568,10 @@ CODESTARTsetModCnf
loadModConf->gnutlsPriorityString = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(modpblk.descr[i].name, "streamdriver.mode")) {
loadModConf->iStrmDrvrMode = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "streamdriver.CheckExtendedKeyPurpose")) {
+ loadModConf->iStrmDrvrExtendedCertCheck = (int) pvals[i].val.d.n;
+ } else if(!strcmp(modpblk.descr[i].name, "streamdriver.PrioritizeSAN")) {
+ loadModConf->iStrmDrvrSANPreference = (int) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "streamdriver.authmode")) {
loadModConf->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(modpblk.descr[i].name, "streamdriver.name")) {
diff --git a/runtime/netstrm.c b/runtime/netstrm.c
index e1df83edee..59aa135997 100644
--- a/runtime/netstrm.c
+++ b/runtime/netstrm.c
@@ -221,6 +221,26 @@ SetDrvrPermPeers(netstrm_t *pThis, permittedPeers_t *pPermPeers)
RETiRet;
}
+/* Mandate also verification of Extended key usage / purpose field */
+static rsRetVal
+SetDrvrCheckExtendedKeyUsage(netstrm_t *pThis, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, netstrm);
+ iRet = pThis->Drvr.SetCheckExtendedKeyUsage(pThis->pDrvrData, ChkExtendedKeyUsage);
+ RETiRet;
+}
+
+/* Mandate stricter name checking per RFC 6125 - ignoce CN if any SAN present */
+static rsRetVal
+SetDrvrPrioritizeSAN(netstrm_t *pThis, int prioritizeSan)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, netstrm);
+ iRet = pThis->Drvr.SetPrioritizeSAN(pThis->pDrvrData, prioritizeSan);
+ RETiRet;
+}
+
/* End of methods to shuffle autentication settings to the driver.
* -------------------------------------------------------------------------- */
@@ -405,6 +425,8 @@ CODESTARTobjQueryInterface(netstrm)
pIf->SetKeepAliveTime = SetKeepAliveTime;
pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
+ pIf->SetDrvrCheckExtendedKeyUsage = SetDrvrCheckExtendedKeyUsage;
+ pIf->SetDrvrPrioritizeSAN = SetDrvrPrioritizeSAN;
finalize_it:
ENDobjQueryInterface(netstrm)
diff --git a/runtime/netstrm.h b/runtime/netstrm.h
index 113585d0a5..08b58fd119 100644
--- a/runtime/netstrm.h
+++ b/runtime/netstrm.h
@@ -78,8 +78,11 @@ BEGINinterface(netstrm) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetKeepAliveTime)(netstrm_t *pThis, int keepAliveTime);
rsRetVal (*SetKeepAliveIntvl)(netstrm_t *pThis, int keepAliveIntvl);
rsRetVal (*SetGnutlsPriorityString)(netstrm_t *pThis, uchar *priorityString);
+ /* v12 -- two new binary flags added to gtls driver enabling stricter operation */
+ rsRetVal (*SetDrvrCheckExtendedKeyUsage)(netstrm_t *pThis, int ChkExtendedKeyUsage);
+ rsRetVal (*SetDrvrPrioritizeSAN)(netstrm_t *pThis, int prioritizeSan);
ENDinterface(netstrm)
-#define netstrmCURR_IF_VERSION 10 /* increment whenever you change the interface structure! */
+#define netstrmCURR_IF_VERSION 12 /* increment whenever you change the interface structure! */
/* interface version 3 added GetRemAddr()
* interface version 4 added EnableKeepAlive() -- rgerhards, 2009-06-02
* interface version 5 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06
diff --git a/runtime/netstrms.c b/runtime/netstrms.c
index bd6a06bd7f..a8c342b76b 100644
--- a/runtime/netstrms.c
+++ b/runtime/netstrms.c
@@ -279,6 +279,49 @@ GetDrvrMode(netstrms_t *pThis)
}
+/* set the driver cert extended key usage check setting -- jvymazal, 2019-08-16 */
+static rsRetVal
+SetDrvrCheckExtendedKeyUsage(netstrms_t *pThis, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, netstrms);
+ pThis->DrvrChkExtendedKeyUsage = ChkExtendedKeyUsage;
+ RETiRet;
+}
+
+
+/* return the driver cert extended key usage check setting
+ * jvymazal, 2019-08-16
+ */
+static int
+GetDrvrCheckExtendedKeyUsage(netstrms_t *pThis)
+{
+ ISOBJ_TYPE_assert(pThis, netstrms);
+ return pThis->DrvrChkExtendedKeyUsage;
+}
+
+
+/* set the driver name checking policy -- jvymazal, 2019-08-16 */
+static rsRetVal
+SetDrvrPrioritizeSAN(netstrms_t *pThis, int prioritizeSan)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, netstrms);
+ pThis->DrvrPrioritizeSan = prioritizeSan;
+ RETiRet;
+}
+
+
+/* return the driver name checking policy
+ * jvymazal, 2019-08-16
+ */
+static int
+GetDrvrPrioritizeSAN(netstrms_t *pThis)
+{
+ ISOBJ_TYPE_assert(pThis, netstrms);
+ return pThis->DrvrPrioritizeSan;
+}
+
/* create an instance of a netstrm object. It is initialized with default
* values. The current driver is used. The caller may set netstrm properties
* and must call ConstructFinalize().
@@ -337,6 +380,10 @@ CODESTARTobjQueryInterface(netstrms)
pIf->GetDrvrGnutlsPriorityString = GetDrvrGnutlsPriorityString;
pIf->SetDrvrPermPeers = SetDrvrPermPeers;
pIf->GetDrvrPermPeers = GetDrvrPermPeers;
+ pIf->SetDrvrCheckExtendedKeyUsage = SetDrvrCheckExtendedKeyUsage;
+ pIf->GetDrvrCheckExtendedKeyUsage = GetDrvrCheckExtendedKeyUsage;
+ pIf->SetDrvrPrioritizeSAN = SetDrvrPrioritizeSAN;
+ pIf->GetDrvrPrioritizeSAN = GetDrvrPrioritizeSAN;
finalize_it:
ENDobjQueryInterface(netstrms)
diff --git a/runtime/netstrms.h b/runtime/netstrms.h
index 440beb20c9..f21bd6a8e2 100644
--- a/runtime/netstrms.h
+++ b/runtime/netstrms.h
@@ -33,6 +33,8 @@ struct netstrms_s {
uchar *pDrvrName; /**< full base driver name (set when driver is loaded) */
int iDrvrMode; /**< current default driver mode */
uchar *pszDrvrAuthMode; /**< current driver authentication mode */
+ int DrvrChkExtendedKeyUsage; /**< if true, verify extended key usage in certs */
+ int DrvrPrioritizeSan; /**< if true, perform stricter checking of names in certs */
uchar *gnutlsPriorityString; /**< priorityString for connection */
permittedPeers_t *pPermPeers;/**< current driver's permitted peers */
@@ -58,6 +60,10 @@ BEGINinterface(netstrms) /* name must also be changed in ENDinterface macro! */
permittedPeers_t* (*GetDrvrPermPeers)(netstrms_t *pThis);
rsRetVal (*SetDrvrGnutlsPriorityString)(netstrms_t *pThis, uchar*);
uchar* (*GetDrvrGnutlsPriorityString)(netstrms_t *pThis);
+ rsRetVal (*SetDrvrCheckExtendedKeyUsage)(netstrms_t *pThis, int ChkExtendedKeyUsage);
+ int (*GetDrvrCheckExtendedKeyUsage)(netstrms_t *pThis);
+ rsRetVal (*SetDrvrPrioritizeSAN)(netstrms_t *pThis, int prioritizeSan);
+ int (*GetDrvrPrioritizeSAN)(netstrms_t *pThis);
ENDinterface(netstrms)
#define netstrmsCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/nsd.h b/runtime/nsd.h
index eab53ad6ae..f0cb5bd1aa 100644
--- a/runtime/nsd.h
+++ b/runtime/nsd.h
@@ -85,8 +85,11 @@ BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetKeepAliveProbes)(nsd_t *pThis, int keepAliveProbes);
rsRetVal (*SetKeepAliveTime)(nsd_t *pThis, int keepAliveTime);
rsRetVal (*SetGnutlsPriorityString)(nsd_t *pThis, uchar *gnutlsPriorityString);
+ /* v13 -- two new binary flags added to gtls driver enabling stricter operation */
+ rsRetVal (*SetCheckExtendedKeyUsage)(nsd_t *pThis, int ChkExtendedKeyUsage);
+ rsRetVal (*SetPrioritizeSAN)(nsd_t *pThis, int prioritizeSan);
ENDinterface(nsd)
-#define nsdCURR_IF_VERSION 11 /* increment whenever you change the interface structure! */
+#define nsdCURR_IF_VERSION 13 /* increment whenever you change the interface structure! */
/* interface version 4 added GetRemAddr()
* interface version 5 added EnableKeepAlive() -- rgerhards, 2009-06-02
* interface version 6 changed return of CheckConnection from void to rsRetVal -- alorbach, 2012-09-06
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index 56238b9cb4..a3662bedf4 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -1004,6 +1004,7 @@ gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt_t *pCert)
int iAltName;
size_t szAltNameLen;
int bFoundPositiveMatch;
+ int bHaveSAN = 0;
cstr_t *pStr = NULL;
cstr_t *pstrCN = NULL;
int gnuRet;
@@ -1023,6 +1024,7 @@ gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt_t *pCert)
if(gnuRet < 0)
break;
else if(gnuRet == GNUTLS_SAN_DNSNAME) {
+ bHaveSAN = 1;
dbgprintf("subject alt dnsName: '%s'\n", szAltName);
snprintf((char*)lnBuf, sizeof(lnBuf), "DNSname: %s; ", szAltName);
CHKiRet(rsCStrAppendStr(pStr, lnBuf));
@@ -1032,8 +1034,8 @@ gtlsChkPeerName(nsd_gtls_t *pThis, gnutls_x509_crt_t *pCert)
++iAltName;
}
- if(!bFoundPositiveMatch) {
- /* if we did not succeed so far, we try the CN part of the DN... */
+ /* Check also CN only if not configured per stricter RFC 6125 or no SAN present*/
+ if(!bFoundPositiveMatch && (!pThis->bSANpriority || !bHaveSAN)) {
CHKiRet(gtlsGetCN(pCert, &pstrCN));
if(pstrCN != NULL) { /* NULL if there was no CN present */
dbgprintf("gtls now checking auth for CN '%s'\n", cstrGetSzStrNoNULL(pstrCN));
@@ -1044,7 +1044,19 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
ABORT_FINALIZE(RS_RET_TLS_NO_CERT);
}
- CHKgnutls(gnutls_certificate_verify_peers2(pThis->sess, &stateCert));
+ if (pThis->dataTypeCheck == GTLS_NONE) {
+ CHKgnutls(gnutls_certificate_verify_peers2(pThis->sess, &stateCert));
+ } else { /* we have configured data to check in addition to cert */
+ gnutls_typed_vdata_st data;
+ data.type = GNUTLS_DT_KEY_PURPOSE_OID;
+ if (pThis->bIsInitiator) { /* client mode */
+ data.data = (uchar *)GNUTLS_KP_TLS_WWW_SERVER;
+ } else { /* server mode */
+ data.data = (uchar *)GNUTLS_KP_TLS_WWW_CLIENT;
+ }
+ data.size = ustrlen(data.data);
+ CHKgnutls(gnutls_certificate_verify_peers(pThis->sess, &data, 1, &stateCert));
+ }
if(stateCert & GNUTLS_CERT_INVALID) {
/* provide error details if we have them */
@@ -1188,6 +1205,8 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis)
pszErrCause = "insecure algorithm";
} else if(stateCert & GNUTLS_CERT_REVOKED) {
pszErrCause = "certificate revoked";
+ } else if(stateCert & GNUTLS_CERT_PURPOSE_MISMATCH) {
+ pszErrCause = "key purpose OID does not match";
} else {
pszErrCause = "GnuTLS returned no specific reason";
dbgprintf("GnuTLS returned no specific reason for GNUTLS_CERT_INVALID, certificate "
@@ -1499,6 +1516,53 @@ SetGnutlsPriorityString(nsd_t *pNsd, uchar *gnutlsPriorityString)
RETiRet;
}
+/* Set the driver cert extended key usage check setting
+ * 0 - ignore contents of extended key usage
+ * 1 - verify that cert contents is compatible with appropriate OID
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetCheckExtendedKeyUsage(nsd_t *pNsd, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
+
+ ISOBJ_TYPE_assert((pThis), nsd_gtls);
+ if(ChkExtendedKeyUsage != 0 && ChkExtendedKeyUsage != 1) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver ChkExtendedKeyUsage %d "
+ "not supported by gtls netstream driver", ChkExtendedKeyUsage);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+
+ pThis->dataTypeCheck = ChkExtendedKeyUsage;
+
+finalize_it:
+ RETiRet;
+}
+
+/* Set the driver name checking strictness
+ * 0 - less strict per RFC 5280, section 4.1.2.6 - either SAN or CN match is good
+ * 1 - more strict per RFC 6125 - if any SAN present it must match (CN is ignored)
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetPrioritizeSAN(nsd_t *pNsd, int prioritizeSan)
+{
+ DEFiRet;
+ nsd_gtls_t *pThis = (nsd_gtls_t*) pNsd;
+
+ ISOBJ_TYPE_assert((pThis), nsd_gtls);
+ if(prioritizeSan != 0 && prioritizeSan != 1) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver prioritizeSan %d "
+ "not supported by gtls netstream driver", prioritizeSan);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+
+ pThis->bSANpriority = prioritizeSan;
+
+finalize_it:
+ RETiRet;
+}
/* Provide access to the underlying OS socket. This is primarily
* useful for other drivers (like nsd_gtls) who utilize ourselfs
@@ -2124,6 +2188,8 @@ CODESTARTobjQueryInterface(nsd_gtls)
pIf->SetKeepAliveProbes = SetKeepAliveProbes;
pIf->SetKeepAliveTime = SetKeepAliveTime;
pIf->SetGnutlsPriorityString = SetGnutlsPriorityString;
+ pIf->SetCheckExtendedKeyUsage = SetCheckExtendedKeyUsage;
+ pIf->SetPrioritizeSAN = SetPrioritizeSAN;
finalize_it:
ENDobjQueryInterface(nsd_gtls)
diff --git a/runtime/nsd_gtls.h b/runtime/nsd_gtls.h
index 80a86f21d7..d73c0e6a4d 100644
--- a/runtime/nsd_gtls.h
+++ b/runtime/nsd_gtls.h
@@ -54,6 +54,11 @@ struct nsd_gtls_s {
GTLS_AUTH_CERTVALID = 2,
GTLS_AUTH_CERTANON = 3
} authMode;
+ enum {
+ GTLS_NONE = 0,
+ GTLS_PURPOSE = 1
+ } dataTypeCheck;
+ int bSANpriority; /* if true, we do stricter checking (if any SAN present we do not cehck CN) */
gtlsRtryCall_t rtryCall;/**< what must we retry? */
int bIsInitiator; /**< 0 if socket is the server end (listener), 1 if it is the initiator */
gnutls_session_t sess;
diff --git a/runtime/nsd_ossl.c b/runtime/nsd_ossl.c
index 0a474fd744..419e0e97ef 100644
--- a/runtime/nsd_ossl.c
+++ b/runtime/nsd_ossl.c
@@ -1864,6 +1864,40 @@ SetGnutlsPriorityString(__attribute__((unused)) nsd_t *pNsd, __attribute__((unus
RETiRet;
}
+/* Set the driver cert extended key usage check setting, for now it is empty wrapper.
+ * TODO: implement openSSL version
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetCheckExtendedKeyUsage(nsd_t __attribute__((unused)) *pNsd, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ if(ChkExtendedKeyUsage != 0) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver ChkExtendedKeyUsage %d "
+ "not supported by ossl netstream driver", ChkExtendedKeyUsage);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+finalize_it:
+ RETiRet;
+}
+
+/* Set the driver name checking strictness, for now it is empty wrapper.
+ * TODO: implement openSSL version
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetPrioritizeSAN(nsd_t __attribute__((unused)) *pNsd, int prioritizeSan)
+{
+ DEFiRet;
+ if(prioritizeSan != 0) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver prioritizeSan %d "
+ "not supported by ossl netstream driver", prioritizeSan);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+finalize_it:
+ RETiRet;
+}
+
/* queryInterface function */
BEGINobjQueryInterface(nsd_ossl)
CODESTARTobjQueryInterface(nsd_ossl)
@@ -1898,6 +1932,8 @@ CODESTARTobjQueryInterface(nsd_ossl)
pIf->SetKeepAliveProbes = SetKeepAliveProbes;
pIf->SetKeepAliveTime = SetKeepAliveTime;
pIf->SetGnutlsPriorityString = SetGnutlsPriorityString; /* we don't NEED this interface! */
+ pIf->SetCheckExtendedKeyUsage = SetCheckExtendedKeyUsage; /* we don't NEED this interface! */
+ pIf->SetPrioritizeSAN = SetPrioritizeSAN; /* we don't NEED this interface! */
finalize_it:
ENDobjQueryInterface(nsd_ossl)
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
index 68bed5b9ea..60c40ad444 100644
--- a/runtime/nsd_ptcp.c
+++ b/runtime/nsd_ptcp.c
@@ -150,6 +150,37 @@ SetMode(nsd_t __attribute__((unused)) *pNsd, int mode)
RETiRet;
}
+/* Set the driver cert extended key usage check setting, not supported in ptcp.
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetCheckExtendedKeyUsage(nsd_t __attribute__((unused)) *pNsd, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ if(ChkExtendedKeyUsage != 0) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver ChkExtendedKeyUsage %d "
+ "not supported by ptcp netstream driver", ChkExtendedKeyUsage);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+finalize_it:
+ RETiRet;
+}
+
+/* Set the driver name checking strictness, not supported in ptcp.
+ * jvymazal, 2019-08-16
+ */
+static rsRetVal
+SetPrioritizeSAN(nsd_t __attribute__((unused)) *pNsd, int prioritizeSan)
+{
+ DEFiRet;
+ if(prioritizeSan != 0) {
+ LogError(0, RS_RET_VALUE_NOT_SUPPORTED, "error: driver prioritizeSan %d "
+ "not supported by ptcp netstream driver", prioritizeSan);
+ ABORT_FINALIZE(RS_RET_VALUE_NOT_SUPPORTED);
+ }
+finalize_it:
+ RETiRet;
+}
/* Set the authentication mode. For us, the following is supported:
* anon - no certificate checks whatsoever (discouraged, but supported)
@@ -613,6 +644,8 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
CHKiRet(pNS->Drvr.Construct(&pNewNsd));
CHKiRet(pNS->Drvr.SetSock(pNewNsd, sock));
CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS)));
+ CHKiRet(pNS->Drvr.SetCheckExtendedKeyUsage(pNewNsd, netstrms.GetDrvrCheckExtendedKeyUsage(pNS)));
+ CHKiRet(pNS->Drvr.SetPrioritizeSAN(pNewNsd, netstrms.GetDrvrPrioritizeSAN(pNS)));
CHKiRet(pNS->Drvr.SetAuthMode(pNewNsd, netstrms.GetDrvrAuthMode(pNS)));
CHKiRet(pNS->Drvr.SetPermPeers(pNewNsd, netstrms.GetDrvrPermPeers(pNS)));
CHKiRet(pNS->Drvr.SetGnutlsPriorityString(pNewNsd, netstrms.GetDrvrGnutlsPriorityString(pNS)));
@@ -963,6 +996,8 @@ CODESTARTobjQueryInterface(nsd_ptcp)
pIf->SetKeepAliveIntvl = SetKeepAliveIntvl;
pIf->SetKeepAliveProbes = SetKeepAliveProbes;
pIf->SetKeepAliveTime = SetKeepAliveTime;
+ pIf->SetCheckExtendedKeyUsage = SetCheckExtendedKeyUsage;
+ pIf->SetPrioritizeSAN = SetPrioritizeSAN;
finalize_it:
ENDobjQueryInterface(nsd_ptcp)
diff --git a/runtime/tcpsrv.c b/runtime/tcpsrv.c
index d7ea2f9f00..43a6687b4a 100644
--- a/runtime/tcpsrv.c
+++ b/runtime/tcpsrv.c
@@ -1013,6 +1013,8 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis)
if(pThis->pszDrvrName != NULL)
CHKiRet(netstrms.SetDrvrName(pThis->pNS, pThis->pszDrvrName));
CHKiRet(netstrms.SetDrvrMode(pThis->pNS, pThis->iDrvrMode));
+ CHKiRet(netstrms.SetDrvrCheckExtendedKeyUsage(pThis->pNS, pThis->DrvrChkExtendedKeyUsage));
+ CHKiRet(netstrms.SetDrvrPrioritizeSAN(pThis->pNS, pThis->DrvrPrioritizeSan));
if(pThis->pszDrvrAuthMode != NULL)
CHKiRet(netstrms.SetDrvrAuthMode(pThis->pNS, pThis->pszDrvrAuthMode));
if(pThis->pPermPeers != NULL)
@@ -1405,6 +1407,26 @@ SetDrvrPermPeers(tcpsrv_t *pThis, permittedPeers_t *pPermPeers)
RETiRet;
}
+/* set the driver cert extended key usage check setting -- jvymazal, 2019-08-16 */
+static rsRetVal
+SetDrvrCheckExtendedKeyUsage(tcpsrv_t *pThis, int ChkExtendedKeyUsage)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+ pThis->DrvrChkExtendedKeyUsage = ChkExtendedKeyUsage;
+ RETiRet;
+}
+
+/* set the driver name checking policy -- jvymazal, 2019-08-16 */
+static rsRetVal
+SetDrvrPrioritizeSAN(tcpsrv_t *pThis, int prioritizeSan)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, tcpsrv);
+ pThis->DrvrPrioritizeSan = prioritizeSan;
+ RETiRet;
+}
+
/* End of methods to shuffle autentication settings to the driver.;
@@ -1522,6 +1544,8 @@ CODESTARTobjQueryInterface(tcpsrv)
pIf->SetLinuxLikeRatelimiters = SetLinuxLikeRatelimiters;
pIf->SetNotificationOnRemoteClose = SetNotificationOnRemoteClose;
pIf->SetPreserveCase = SetPreserveCase;
+ pIf->SetDrvrCheckExtendedKeyUsage = SetDrvrCheckExtendedKeyUsage;
+ pIf->SetDrvrPrioritizeSAN = SetDrvrPrioritizeSAN;
finalize_it:
ENDobjQueryInterface(tcpsrv)
diff --git a/runtime/tcpsrv.h b/runtime/tcpsrv.h
index 55aa8e9922..79b659013d 100644
--- a/runtime/tcpsrv.h
+++ b/runtime/tcpsrv.h
@@ -61,6 +61,8 @@ struct tcpsrv_s {
int iKeepAliveTime; /**< socket layer KEEPALIVE timeout */
netstrms_t *pNS; /**< pointer to network stream subsystem */
int iDrvrMode; /**< mode of the stream driver to use */
+ int DrvrChkExtendedKeyUsage; /**< if true, verify extended key usage in certs */
+ int DrvrPrioritizeSan; /**< if true, perform stricter checking of names in certs */
uchar *gnutlsPriorityString; /**< priority string for gnutls */
uchar *pszDrvrAuthMode; /**< auth mode of the stream driver to use */
uchar *pszDrvrName; /**< name of stream driver to use */
@@ -185,8 +187,11 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetGnutlsPriorityString)(tcpsrv_t*, uchar*);
/* added v21 -- Preserve case in fromhost, 2018-08-16 */
rsRetVal (*SetPreserveCase)(tcpsrv_t *pThis, int bPreserveCase);
+ /* added v23 -- Options for stricter driver behavior, 2019-08-16 */
+ rsRetVal (*SetDrvrCheckExtendedKeyUsage)(tcpsrv_t *pThis, int ChkExtendedKeyUsage);
+ rsRetVal (*SetDrvrPrioritizeSAN)(tcpsrv_t *pThis, int prioritizeSan);
ENDinterface(tcpsrv)
-#define tcpsrvCURR_IF_VERSION 21 /* increment whenever you change the interface structure! */
+#define tcpsrvCURR_IF_VERSION 23 /* increment whenever you change the interface structure! */
/* change for v4:
* - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10
* - SetInputName() added -- rgerhards, 2008-12-10
diff --git a/tools/omfwd.c b/tools/omfwd.c
index cdb74b8d22..96fa68752c 100644
--- a/tools/omfwd.c
+++ b/tools/omfwd.c
@@ -83,6 +83,8 @@ typedef struct _instanceData {
uchar *pszStrmDrvrAuthMode;
permittedPeers_t *pPermPeers;
int iStrmDrvrMode;
+ int iStrmDrvrExtendedCertCheck; /* verify also purpose OID in certificate extended field */
+ int iStrmDrvrSANPreference; /* ignore CN when any SAN set */
char *target;
char *address;
char *device;
@@ -189,6 +191,8 @@ static struct cnfparamdescr actpdescr[] = {
{ "streamdrivermode", eCmdHdlrInt, 0 },
{ "streamdriverauthmode", eCmdHdlrGetWord, 0 },
{ "streamdriverpermittedpeers", eCmdHdlrGetWord, 0 },
+ { "streamdriver.CheckExtendedKeyPurpose", eCmdHdlrBinary, 0 },
+ { "streamdriver.PrioritizeSAN", eCmdHdlrBinary, 0 },
{ "resendlastmsgonreconnect", eCmdHdlrBinary, 0 },
{ "udp.sendtoall", eCmdHdlrBinary, 0 },
{ "udp.senddelay", eCmdHdlrInt, 0 },
@@ -748,6 +752,8 @@ static rsRetVal TCPSendInit(void *pvData)
CHKiRet(netstrms.CreateStrm(pWrkrData->pNS, &pWrkrData->pNetstrm));
CHKiRet(netstrm.ConstructFinalize(pWrkrData->pNetstrm));
CHKiRet(netstrm.SetDrvrMode(pWrkrData->pNetstrm, pData->iStrmDrvrMode));
+ CHKiRet(netstrm.SetDrvrCheckExtendedKeyUsage(pWrkrData->pNetstrm, pData->iStrmDrvrExtendedCertCheck));
+ CHKiRet(netstrm.SetDrvrPrioritizeSAN(pWrkrData->pNetstrm, pData->iStrmDrvrSANPreference));
/* now set optional params, but only if they were actually configured */
if(pData->pszStrmDrvrAuthMode != NULL) {
CHKiRet(netstrm.SetDrvrAuthMode(pWrkrData->pNetstrm, pData->pszStrmDrvrAuthMode));
@@ -1119,6 +1125,8 @@ setInstParamDefaults(instanceData *pData)
pData->pszStrmDrvr = NULL;
pData->pszStrmDrvrAuthMode = NULL;
pData->iStrmDrvrMode = 0;
+ pData->iStrmDrvrExtendedCertCheck = 0;
+ pData->iStrmDrvrSANPreference = 0;
pData->iRebindInterval = 0;
pData->bKeepAlive = 0;
pData->iKeepAliveProbes = 0;
@@ -1220,6 +1228,10 @@ CODESTARTnewActInst
pData->pszStrmDrvr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "streamdrivermode")) {
pData->iStrmDrvrMode = pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "streamdriver.CheckExtendedKeyPurpose")) {
+ pData->iStrmDrvrExtendedCertCheck = pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "streamdriver.PrioritizeSAN")) {
+ pData->iStrmDrvrSANPreference = pvals[i].val.d.n;
} else if(!strcmp(actpblk.descr[i].name, "streamdriverauthmode")) {
pData->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "streamdriverpermittedpeers")) {

79
SOURCES/rsyslog.conf Normal file
View File

@ -0,0 +1,79 @@
# rsyslog configuration file
# For more information see /usr/share/doc/rsyslog-*/rsyslog_conf.html
# or latest version online at http://www.rsyslog.com/doc/rsyslog_conf.html
# If you experience problems, see http://www.rsyslog.com/doc/troubleshoot.html
#### MODULES ####
module(load="imuxsock" # provides support for local system logging (e.g. via logger command)
SysSock.Use="off") # Turn off message reception via local log socket;
# local messages are retrieved through imjournal now.
module(load="imjournal" # provides access to the systemd journal
StateFile="imjournal.state") # File to store the position in the journal
#module(load="imklog") # reads kernel messages (the same are read from journald)
#module(load"immark") # provides --MARK-- message capability
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
#module(load="imudp") # needs to be done just once
#input(type="imudp" port="514")
# Provides TCP syslog reception
# for parameters see http://www.rsyslog.com/doc/imtcp.html
#module(load="imtcp") # needs to be done just once
#input(type="imtcp" port="514")
#### GLOBAL DIRECTIVES ####
# Where to place auxiliary files
global(workDirectory="/var/lib/rsyslog")
# Use default timestamp format
module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat")
# Include all config files in /etc/rsyslog.d/
include(file="/etc/rsyslog.d/*.conf" mode="optional")
#### RULES ####
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none /var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/secure
# Log all the mail messages in one place.
mail.* -/var/log/maillog
# Log cron stuff
cron.* /var/log/cron
# Everybody gets emergency messages
*.emerg :omusrmsg:*
# Save news errors of level crit and higher in a special file.
uucp,news.crit /var/log/spooler
# Save boot messages also to boot.log
local7.* /var/log/boot.log
# ### sample forwarding rule ###
#action(type="omfwd"
# An on-disk queue is created for this action. If the remote host is
# down, messages are spooled to disk and sent when it is up again.
#queue.filename="fwdRule1" # unique name prefix for spool files
#queue.maxdiskspace="1g" # 1gb space limit (use as much as possible)
#queue.saveonshutdown="on" # save messages to disk on shutdown
#queue.type="LinkedList" # run asynchronously
#action.resumeRetryCount="-1" # infinite retries if host is down
# Remote Logging (we use TCP for reliable delivery)
# remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
#Target="remote_host" Port="XXX" Protocol="tcp")

12
SOURCES/rsyslog.log Normal file
View File

@ -0,0 +1,12 @@
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
missingok
sharedscripts
postrotate
/usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
endscript
}

View File

@ -0,0 +1,5 @@
# Options for rsyslogd
# Syslogd options are deprecated since rsyslog v3.
# If you want to use them, switch to compatibility mode 2 by "-c 2"
# See rsyslogd(8) for more details
SYSLOGD_OPTIONS=""

574
SPECS/rsyslog.spec Normal file
View File

@ -0,0 +1,574 @@
%define rsyslog_statedir %{_sharedstatedir}/%{name}
%define rsyslog_pkidir %{_sysconfdir}/pki/%{name}
%define rsyslog_docdir %{_docdir}/%{name}
Summary: Enhanced system logging and kernel message trapping daemon
Name: rsyslog
Version: 8.37.0
Release: 13%{?dist}
License: (GPLv3+ and ASL 2.0)
Group: System Environment/Daemons
ExcludeArch: i686
URL: http://www.rsyslog.com/
Source0: http://www.rsyslog.com/files/download/rsyslog/%{name}-%{version}.tar.gz
Source1: http://www.rsyslog.com/files/download/rsyslog/%{name}-doc-%{version}.tar.gz
Source2: rsyslog.conf
Source3: rsyslog.sysconfig
Source4: rsyslog.log
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: bison
BuildRequires: flex
BuildRequires: libcurl-devel
BuildRequires: libgcrypt-devel
BuildRequires: libfastjson-devel >= 0.99.8
BuildRequires: libestr-devel >= 0.1.9
BuildRequires: libtool
BuildRequires: libuuid-devel
BuildRequires: pkgconfig
BuildRequires: python3-docutils
# it depens on rhbz#1419228
BuildRequires: systemd-devel >= 219-39
BuildRequires: zlib-devel
Requires: logrotate >= 3.5.2
Requires: bash >= 2.0
Requires: libestr >= 0.1.9
Requires(post): systemd
Requires(preun): systemd
Requires(postun): systemd
Provides: syslog
Obsoletes: sysklogd < 1.5-11
# tweak the upstream service file to honour configuration from /etc/sysconfig/rsyslog
Patch0: rsyslog-8.32.0-service.patch
# imjournal: adds "journal" when tag/process name is missing
Patch1: rsyslog-8.37.0-rhbz1659898-imjournal-default-tag.patch
Patch2: rsyslog-8.37.0-rhbz1614179-imfile-symlink-support.patch
Patch3: rsyslog-8.37.0-rhbz1622768-kubernetes-404-handling.patch
Patch4: rsyslog-8.37.0-rhbz1627941-imfile-support-for-endmsg.regex.patch
Patch5: rsyslog-8.37.0-rhbz1674471-imfile-log-rotation.patch
Patch6: rsyslog-8.37.0-rhbz1677037-short-offMsg-overrun-crash.patch
Patch7: rsyslog-8.37.0-rhbz1614181-imtcp-imudp-preservecase-option.patch
Patch8: rsyslog-8.37.0-rhbz1716867-imjournal-memleak.patch
Patch9: rsyslog-8.37.0-rhbz1722165-imjournal-flooding-errors.patch
Patch10: rsyslog-8.37.0-rhbz1724218-imrelp-old-syntax.patch
Patch11: rsyslog-8.37.0-rhbz1733244-TLS-CC-compatibility.patch
%package crypto
Summary: Encryption support
Group: System Environment/Daemons
Requires: %name = %version-%release
%package doc
Summary: HTML Documentation for rsyslog
Group: Documentation
#no reason to have arched documentation
BuildArch: noarch
%package elasticsearch
Summary: ElasticSearch output module for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
%package gnutls
Summary: TLS protocol support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: gnutls-devel
%package gssapi
Summary: GSSAPI authentication and encryption support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: krb5-devel
%package kafka
Summary: Provides kafka support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: librdkafka-devel
%package mmaudit
Summary: Message modification module supporting Linux audit format
Group: System Environment/Daemons
Requires: %name = %version-%release
%package mmjsonparse
Summary: JSON enhanced logging support
Group: System Environment/Daemons
Requires: %name = %version-%release
%package mmkubernetes
Summary: Provides the mmkubernetes module
Group: System Environment/Daemons
Requires: %name = %version-%release
%package mmnormalize
Summary: Log normalization support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: liblognorm-devel
%package mmsnmptrapd
Summary: Message modification module for snmptrapd generated messages
Group: System Environment/Daemons
Requires: %name = %version-%release
%package mysql
Summary: MySQL support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: mariadb-connector-c-devel
%package pgsql
Summary: PostgresSQL support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: postgresql-devel
%package relp
Summary: RELP protocol support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
Requires: librelp >= 1.0.3
BuildRequires: librelp-devel >= 1.2.16
%package snmp
Summary: SNMP protocol support for rsyslog
Group: System Environment/Daemons
Requires: %name = %version-%release
BuildRequires: net-snmp-devel
%description
Rsyslog is an enhanced, multi-threaded syslog daemon. It supports MySQL,
syslog/TCP, RFC 3195, permitted sender lists, filtering on any message part,
and fine grain output format control. It is compatible with stock sysklogd
and can be used as a drop-in replacement. Rsyslog is simple to set up, with
advanced features suitable for enterprise-class, encryption-protected syslog
relay chains.
%description crypto
This package contains a module providing log file encryption and a
command line tool to process encrypted logs.
%description doc
This subpackage contains documentation for rsyslog.
%description elasticsearch
This module provides the capability for rsyslog to feed logs directly into
Elasticsearch.
%description gnutls
The rsyslog-gnutls package contains the rsyslog plugins that provide the
ability to receive syslog messages via upcoming syslog-transport-tls
IETF standard protocol.
%description gssapi
The rsyslog-gssapi package contains the rsyslog plugins which support GSSAPI
authentication and secure connections. GSSAPI is commonly used for Kerberos
authentication.
%description kafka
The rsyslog-kafka package provides modules for Apache Kafka input and output.
%description mmaudit
This module provides message modification supporting Linux audit format
in various settings.
%description mmjsonparse
This module provides the capability to recognize and parse JSON enhanced
syslog messages.
%description mmkubernetes
The rsyslog-mmkubernetes package provides module for adding kubernetes
container metadata.
%description mmnormalize
This module provides the capability to normalize log messages via liblognorm.
%description mmsnmptrapd
This message modification module takes messages generated from snmptrapd and
modifies them so that they look like they originated from the read originator.
%description mysql
The rsyslog-mysql package contains a dynamic shared object that will add
MySQL database support to rsyslog.
%description pgsql
The rsyslog-pgsql package contains a dynamic shared object that will add
PostgreSQL database support to rsyslog.
%description relp
The rsyslog-relp package contains the rsyslog plugins that provide
the ability to receive syslog messages via the reliable RELP
protocol.
%description snmp
The rsyslog-snmp package contains the rsyslog plugin that provides the
ability to send syslog messages as SNMPv1 and SNMPv2c traps.
%prep
# set up rsyslog-doc sources
%setup -q -a 1 -T -c
#regenerate the docs
#mv build/searchindex.js searchindex_backup.js
#sphinx-build -b html source build
#clean up
#mv searchindex_backup.js build/searchindex.js
rm -r LICENSE README.md source build/objects.inv
mv build doc
# set up rsyslog sources
%setup -q -D
%patch0 -p1 -b .service
%patch1 -p1 -b .default-tag
%patch2 -p1 -b .imfile-symlink
%patch3 -p1 -b .mmkubernetes-404
%patch4 -p1 -b .endmsg-regex
%patch5 -p1 -b .rotation-detection
%patch6 -p1 -b .short-offmsg-crash
%patch7 -p1 -b .preservecase-option
%patch8 -p1 -b .imjournal-memleak
%patch9 -p1 -b .imjournal-err-flood
%patch10 -p1 -b .imrelp-old-syntax
%patch11 -p1 -b .tls-CC
%build
%ifarch sparc64
#sparc64 need big PIE
export CFLAGS="$RPM_OPT_FLAGS -fPIE"
%else
export CFLAGS="$RPM_OPT_FLAGS -fpie"
%endif
export LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now"
sed -i 's/%{version}/%{version}-%{release}/g' configure.ac
autoreconf -if
%configure \
--prefix=/usr \
--disable-static \
--disable-testbench \
--enable-elasticsearch \
--enable-generate-man-pages \
--enable-gnutls \
--enable-gssapi-krb5 \
--enable-imdiag \
--enable-imfile \
--enable-imjournal \
--enable-imkafka \
--enable-impstats \
--enable-imptcp \
--enable-mail \
--enable-mmanon \
--enable-mmaudit \
--enable-mmcount \
--enable-mmjsonparse \
--enable-mmkubernetes \
--enable-mmnormalize \
--enable-mmsnmptrapd \
--enable-mmutf8fix \
--enable-mysql \
--enable-omjournal \
--enable-omkafka \
--enable-omprog \
--enable-omstdout \
--enable-omuxsock \
--enable-pgsql \
--enable-pmaixforwardedfrom \
--enable-pmcisconames \
--enable-pmlastmsg \
--enable-pmsnare \
--enable-relp \
--enable-snmp \
--enable-unlimited-select \
--enable-usertools
make
%install
make DESTDIR=%{buildroot} install
install -d -m 755 %{buildroot}%{_sysconfdir}/sysconfig
install -d -m 755 %{buildroot}%{_sysconfdir}/logrotate.d
install -d -m 755 %{buildroot}%{_sysconfdir}/rsyslog.d
install -d -m 700 %{buildroot}%{rsyslog_statedir}
install -d -m 700 %{buildroot}%{rsyslog_pkidir}
install -d -m 755 %{buildroot}%{rsyslog_docdir}/html
install -p -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/rsyslog.conf
install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/rsyslog
install -p -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/logrotate.d/syslog
install -p -m 644 plugins/ommysql/createDB.sql %{buildroot}%{rsyslog_docdir}/mysql-createDB.sql
install -p -m 644 plugins/ompgsql/createDB.sql %{buildroot}%{rsyslog_docdir}/pgsql-createDB.sql
install -p -m 644 contrib/mmkubernetes/*.rulebase %{buildroot}%{rsyslog_docdir}
# extract documentation
cp -r doc/* %{buildroot}%{rsyslog_docdir}/html
# get rid of libtool libraries
rm -f %{buildroot}%{_libdir}/rsyslog/*.la
# get rid of socket activation by default
sed -i '/^Alias/s/^/;/;/^Requires=syslog.socket/s/^/;/' %{buildroot}%{_unitdir}/rsyslog.service
# convert line endings from "\r\n" to "\n"
cat tools/recover_qi.pl | tr -d '\r' > %{buildroot}%{_bindir}/rsyslog-recover-qi.pl
%post
for n in /var/log/{messages,secure,maillog,spooler}
do
[ -f $n ] && continue
umask 066 && touch $n
done
%systemd_post rsyslog.service
%preun
%systemd_preun rsyslog.service
%postun
%systemd_postun_with_restart rsyslog.service
%files
%doc AUTHORS COPYING* ChangeLog
%exclude %{rsyslog_docdir}/html
%exclude %{rsyslog_docdir}/mysql-createDB.sql
%exclude %{rsyslog_docdir}/pgsql-createDB.sql
%dir %{_libdir}/rsyslog
%dir %{_sysconfdir}/rsyslog.d
%dir %{rsyslog_statedir}
%dir %{rsyslog_pkidir}
%{_sbindir}/rsyslogd
%attr(755,root,root) %{_bindir}/rsyslog-recover-qi.pl
%{_mandir}/man5/rsyslog.conf.5.gz
%{_mandir}/man8/rsyslogd.8.gz
%{_unitdir}/rsyslog.service
%config(noreplace) %{_sysconfdir}/rsyslog.conf
%config(noreplace) %{_sysconfdir}/sysconfig/rsyslog
%config(noreplace) %{_sysconfdir}/logrotate.d/syslog
# plugins
%{_libdir}/rsyslog/fmhash.so
%{_libdir}/rsyslog/fmhttp.so
%{_libdir}/rsyslog/imdiag.so
%{_libdir}/rsyslog/imfile.so
%{_libdir}/rsyslog/imjournal.so
%{_libdir}/rsyslog/imklog.so
%{_libdir}/rsyslog/immark.so
%{_libdir}/rsyslog/impstats.so
%{_libdir}/rsyslog/imptcp.so
%{_libdir}/rsyslog/imtcp.so
%{_libdir}/rsyslog/imudp.so
%{_libdir}/rsyslog/imuxsock.so
%{_libdir}/rsyslog/lmnet.so
%{_libdir}/rsyslog/lmnetstrms.so
%{_libdir}/rsyslog/lmnsd_ptcp.so
%{_libdir}/rsyslog/lmregexp.so
%{_libdir}/rsyslog/lmstrmsrv.so
%{_libdir}/rsyslog/lmtcpclt.so
%{_libdir}/rsyslog/lmtcpsrv.so
%{_libdir}/rsyslog/lmzlibw.so
%{_libdir}/rsyslog/mmanon.so
%{_libdir}/rsyslog/mmcount.so
%{_libdir}/rsyslog/mmexternal.so
%{_libdir}/rsyslog/mmutf8fix.so
%{_libdir}/rsyslog/omjournal.so
%{_libdir}/rsyslog/ommail.so
%{_libdir}/rsyslog/omprog.so
%{_libdir}/rsyslog/omstdout.so
%{_libdir}/rsyslog/omtesting.so
%{_libdir}/rsyslog/omuxsock.so
%{_libdir}/rsyslog/pmaixforwardedfrom.so
%{_libdir}/rsyslog/pmcisconames.so
%{_libdir}/rsyslog/pmlastmsg.so
%{_libdir}/rsyslog/pmsnare.so
%files crypto
%{_bindir}/rscryutil
%{_mandir}/man1/rscryutil.1.gz
%{_libdir}/rsyslog/lmcry_gcry.so
%files doc
%doc %{rsyslog_docdir}/html
%files elasticsearch
%{_libdir}/rsyslog/omelasticsearch.so
%files gssapi
%{_libdir}/rsyslog/lmgssutil.so
%{_libdir}/rsyslog/imgssapi.so
%{_libdir}/rsyslog/omgssapi.so
%files gnutls
%{_libdir}/rsyslog/lmnsd_gtls.so
%files kafka
%{_libdir}/rsyslog/imkafka.so
%{_libdir}/rsyslog/omkafka.so
%files mmaudit
%{_libdir}/rsyslog/mmaudit.so
%files mmjsonparse
%{_libdir}/rsyslog/mmjsonparse.so
%files mmkubernetes
%{_libdir}/rsyslog/mmkubernetes.so
%doc %{rsyslog_docdir}/k8s_filename.rulebase
%doc %{rsyslog_docdir}/k8s_container_name.rulebase
%files mmnormalize
%{_libdir}/rsyslog/mmnormalize.so
%files mmsnmptrapd
%{_libdir}/rsyslog/mmsnmptrapd.so
%files mysql
%doc %{rsyslog_docdir}/mysql-createDB.sql
%{_libdir}/rsyslog/ommysql.so
%files pgsql
%doc %{rsyslog_docdir}/pgsql-createDB.sql
%{_libdir}/rsyslog/ompgsql.so
%files relp
%{_libdir}/rsyslog/imrelp.so
%{_libdir}/rsyslog/omrelp.so
%files snmp
%{_libdir}/rsyslog/omsnmp.so
%changelog
* Fri Aug 30 2019 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-13
RHEL 8.1.0 ERRATUM
- added patch enabling stricter TLS certs checking conforming to
common criteria requirements
resolves: rhbz#1733244
* Mon Jul 22 2019 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-12
RHEL 8.1.0 ERRATUM
- edited imjournal memleak patch to not cause double-free crash
resolves: rhbz#1729995
- added patch calling journald API only when there are no
preceeding errors
resolves: rhbz#1722165
- added patch fixing imrelp module when invoked with old syntax
resolves: rhbz#1724218
* Wed Jun 05 2019 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-11
RHEL 8.1.0 ERRATUM
- fixed memory leak in imjournal by proper cursor releasing
resolves: rhbz#1716867
* Fri May 10 2019 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-10
RHEL 8.1.0 ERRATUM
- added option for imfile endmsg.regex
resolves: rhbz#1627941
- added patch enhancing imfile rotation detection
resolves: rhbz#1674471
- added patch fixing msgOffset datatype preventing crash on
message with too long other fields
resolves: rhbz#1677037
- added patch introducing "preservecase" option for imudp/imtcp
resolves: rhbz#1614181
* Mon Dec 17 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-9
RHEL 8.0.0 ERRATUM
- added back legacy option for imjournal default tag
resolves: rhbz#1659898
* Fri Dec 14 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-8
RHEL 8.0.0 ERRATUM
- fixes mmkubenetes handling 404 and 429 errors
resolves: rhbz#1622768
* Fri Oct 19 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-7
- removed version from docdir macro
resolves: rhbz#1638023
* Mon Aug 27 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-6
- updated patch for enhanced imfile symlink support
resolves: rhbz#1614179
* Fri Aug 10 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-5
- rebuild for rebased dependencies
- dependency cleanup and sorted sub-packages in spec
resolves: rhbz#1613880
* Fri Aug 10 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-4
- enabled mmkubernetes module
resolves: rhbz#1614432
resolves: rhbz#1614441
* Thu Aug 09 2018 Josef Ridky <jridky@redhat.com> - 8.37.0-3
- Rebuild for Net-SNMP
* Thu Aug 09 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-2
- added patch for enhanced imfile symlink support
resolves: rhbz#1614179
* Wed Aug 08 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.37.0-1
- rebase to 8.37.0
resolves: rhbz#1613880
resolves: rhbz#1564054
resolves: rhbz#1598218
- dropped invalid statefile patch - upstreamed
- dropped imjournal duplicates patch - upstreamed
resolves: rhbz#1544394
- renumbered default tag patch and fitted onto rebased version
* Fri Aug 03 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.36.0-4
- removed dependency on libee
resolves: rhbz#1612032
* Wed Aug 01 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.36.0-3
- dropped json_nonoverwrite patch as there is no reason for
keeping it
- renumbered rest of patches
- added release number to AC_INIT to have it in package error logs
* Mon Jul 16 2018 Charalampos Stratakis <cstratak@redhat.com> - 8.36.0-2
- Depend on python3-docutils
* Mon Jul 02 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.36.0-1
- changed PID file name to follow upstream
- removed config option to disable stdlog as it is now
disabled by default
* Thu Jun 28 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.36.0-1
- rebase to 8.36
- removed hiredis module
- removed omudpspoof module
resolves: rhbz#1593762
- finished converting config to new-style syntax
* Mon May 21 2018 Jiri Vymazal <jvymazal@redhat.com> - 8.35.0-1
- spec file cleanup
- enabled kafka and hiredis modules
resolves: rhbz#1542497
resolves: rhbz#1542504
- renamed patch fixing imjournal duplicating messages
resolves: rhbz#1544394
* Thu May 17 2018 Marek Tamaskovic <mtamasko@redhat.com> - 8.35.0-1
- rebase to 8.35
- rebased patches from 8.32 to 8.35
- fixed imjournal-duplicates
- fixed imjournal-default-tag
- fixed service patch
- fixed in upstream deserialize-property-name
* Fri Mar 23 2018 Radovan Sroka <rsroka@redhat.com> - 8.32.0-2
- rebuild, bumped release number
* Tue Feb 06 2018 Radovan Sroka <rsroka@redhat.com> - 8.32.0-1
- initial clean build with plugins from rhel7
- removed plugins:
- libdbi
- omruleset
- pmrfc3164sd
- imported from fedora26