From f1de428192a843d9c6c58da9689ebbd6727da9fe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 24 Aug 2025 14:08:01 +0200 Subject: [PATCH] omrelp: add TCP keepalive configuration --- doc/source/configuration/modules/omrelp.rst | 62 ++++++++++++++++++++- plugins/omrelp/omrelp.c | 29 +++++++++- tests/Makefile.am | 1 + tests/omrelp-keepalive.sh | 53 ++++++++++++++++++ 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100755 tests/omrelp-keepalive.sh diff --git a/doc/source/configuration/modules/omrelp.rst b/doc/source/configuration/modules/omrelp.rst index 4dfd3e96d..5cacefc45 100644 --- a/doc/source/configuration/modules/omrelp.rst +++ b/doc/source/configuration/modules/omrelp.rst @@ -148,6 +148,66 @@ balancers, which in turn forward messages to another physical target system. +KeepAlive +^^^^^^^^^ + +.. csv-table:: + :header: "type", "default", "mandatory", "|FmtObsoleteName| directive" + :widths: auto + :class: parameter-table + + "binary", "off", "no", "none" + +Enable or disable keep-alive packets at the TCP socket layer. By +default keep-alive is disabled. + + +KeepAlive.Probes +^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "type", "default", "mandatory", "|FmtObsoleteName| directive" + :widths: auto + :class: parameter-table + + "integer", "0", "no", "none" + +The number of keepalive probes to send before considering the +connection dead. The default, 0, uses the operating system defaults. +This only has an effect if keep-alive is enabled and may not be +available on all platforms. + + +KeepAlive.Interval +^^^^^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "type", "default", "mandatory", "|FmtObsoleteName| directive" + :widths: auto + :class: parameter-table + + "integer", "0", "no", "none" + +The interval between subsequent keepalive probes. The default, 0, +uses the operating system defaults. This only has an effect if +keep-alive is enabled and may not be available on all platforms. + + +KeepAlive.Time +^^^^^^^^^^^^^^ + +.. csv-table:: + :header: "type", "default", "mandatory", "|FmtObsoleteName| directive" + :widths: auto + :class: parameter-table + + "integer", "0", "no", "none" + +The idle time before the first keepalive probe is sent. The default, 0, +uses the operating system defaults. This only has an effect if +keep-alive is enabled and may not be available on all platforms. + + WindowSize ^^^^^^^^^^ @@ -374,7 +434,7 @@ manual `__. **Note: this is an expert parameter.** Do not use if you do not exactly know what you are doing. -tls.tlscfgcmd +tls.tlscfgcmd ^^^^^^^^^^^^^ .. csv-table:: diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index 6539b25f4..780501e4c 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -93,6 +93,10 @@ typedef struct _instanceData { #endif uchar *tplName; uchar *localClientIP; + sbool bKeepAlive; /* support keep-alive packets */ + int iKeepAliveProbes; + int iKeepAliveTime; + int iKeepAliveIntvl; struct { int nmemb; uchar **name; @@ -136,7 +140,9 @@ static struct cnfparamdescr actpdescr[] = { {"tls.tlscfgcmd", eCmdHdlrString, 0}, {"tls.permittedpeer", eCmdHdlrArray, 0}, {"port", eCmdHdlrGetWord, 0}, {"rebindinterval", eCmdHdlrInt, 0}, {"windowsize", eCmdHdlrInt, 0}, {"timeout", eCmdHdlrInt, 0}, - {"conn.timeout", eCmdHdlrInt, 0}, {"localclientip", eCmdHdlrGetWord, 0}, + {"conn.timeout", eCmdHdlrInt, 0}, {"keepalive", eCmdHdlrBinary, 0}, + {"keepalive.probes", eCmdHdlrInt, 0}, {"keepalive.time", eCmdHdlrInt, 0}, + {"keepalive.interval", eCmdHdlrInt, 0}, {"localclientip", eCmdHdlrGetWord, 0}, {"template", eCmdHdlrGetWord, 0}}; static struct cnfparamblk actpblk = {CNFPARAMBLK_VERSION, sizeof(actpdescr) / sizeof(struct cnfparamdescr), actpdescr}; @@ -210,6 +216,11 @@ static rsRetVal doCreateRelpClient(instanceData *pData, relpClt_t **pRelpClt) { ABORT_FINALIZE(RS_RET_RELP_ERR); } if (relpCltSetWindowSize(*pRelpClt, pData->sizeWindow) != RELP_RET_OK) ABORT_FINALIZE(RS_RET_RELP_ERR); +#if defined(HAVE_RELPCLTSETKEEPALIVE) + if (relpCltSetKeepAlive(*pRelpClt, pData->bKeepAlive, pData->iKeepAliveIntvl, pData->iKeepAliveProbes, + pData->iKeepAliveTime) != RELP_RET_OK) + ABORT_FINALIZE(RS_RET_RELP_ERR); +#endif if (pData->bEnableTLS) { if (relpCltEnableTLS(*pRelpClt) != RELP_RET_OK) ABORT_FINALIZE(RS_RET_RELP_ERR); if (pData->bEnableTLSZip) { @@ -282,6 +293,10 @@ BEGINcreateInstance #if defined(HAVE_RELPENGINESETTLSCFGCMD) pData->tlscfgcmd = NULL; #endif + pData->bKeepAlive = 0; + pData->iKeepAliveProbes = 0; + pData->iKeepAliveTime = 0; + pData->iKeepAliveIntvl = 0; pData->permittedPeers.nmemb = 0; ENDcreateInstance @@ -344,6 +359,10 @@ static void setInstParamDefaults(instanceData *pData) { #if defined(HAVE_RELPENGINESETTLSCFGCMD) pData->tlscfgcmd = NULL; #endif + pData->bKeepAlive = 0; + pData->iKeepAliveProbes = 0; + pData->iKeepAliveTime = 0; + pData->iKeepAliveIntvl = 0; pData->permittedPeers.name = NULL; pData->permittedPeers.nmemb = 0; } @@ -432,6 +451,14 @@ BEGINnewActInst pData->timeout = (unsigned)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "conn.timeout")) { pData->connTimeout = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "keepalive")) { + pData->bKeepAlive = (sbool)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "keepalive.probes")) { + pData->iKeepAliveProbes = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "keepalive.time")) { + pData->iKeepAliveTime = (int)pvals[i].val.d.n; + } else if (!strcmp(actpblk.descr[i].name, "keepalive.interval")) { + pData->iKeepAliveIntvl = (int)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "rebindinterval")) { pData->rebindInterval = (unsigned)pvals[i].val.d.n; } else if (!strcmp(actpblk.descr[i].name, "windowsize")) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 305b9abbd..d37ccedd2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2252,6 +2252,7 @@ EXTRA_DIST= \ omfwd-subtree-tpl.sh \ omfwd_fast_imuxsock.sh \ omfile_hup-vg.sh \ + omrelp-keepalive.sh \ omsendertrack-basic.sh \ omsendertrack-basic-vg.sh \ omsendertrack-statefile.sh \ diff --git a/tests/omrelp-keepalive.sh b/tests/omrelp-keepalive.sh new file mode 100755 index 000000000..1ad172164 --- /dev/null +++ b/tests/omrelp-keepalive.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# added 2024-08-07 by ChatGPT, released under ASL 2.0 +. ${srcdir:=.}/diag.sh init + +# ensure recent librelp with client keepalive support +if ! pkg-config --atleast-version=1.12.0 relp 2>/dev/null ; then + echo "SKIP: librelp without client keepalive support" + exit 77 +fi + +export PORT_RCVR="$(get_free_port)" + +generate_conf +add_conf ' +module(load="../plugins/imrelp/.libs/imrelp") +input(type="imrelp" port="'$PORT_RCVR'") + +template(name="outfmt" type="list") { + property(name="msg") + constant(value="\n") +} +:msg, contains, "msgnum:" action(type="omfile" template="outfmt" file="'$RSYSLOG_OUT_LOG'") +' +startup + +generate_conf 2 +add_conf ' +module(load="../plugins/omrelp/.libs/omrelp") +module(load="../plugins/imtcp/.libs/imtcp") +input(type="imtcp" port="0" listenPortFileName="'$RSYSLOG_DYNNAME'.tcpflood_port") +if $msg contains "msgnum:" then action(type="omrelp" target="127.0.0.1" port="'$PORT_RCVR'" keepalive="on" keepalive.probes="5" keepalive.time="60" keepalive.interval="15") +' 2 +startup 2 + +tcpflood -m1 -Ptcpflood_port +sleep 1 + +CLIENT_PID=$(cat $RSYSLOG_DYNNAME.2.pid) +if ss -tnpo | grep -E "pid=$CLIENT_PID" | grep -q keepalive; then + : +else + echo "keepalive not set" + error_exit 1 +fi + +shutdown_when_empty 2 +wait_shutdown 2 +shutdown_when_empty +wait_shutdown + +echo " msgnum:00000000:" | cmp - $RSYSLOG_OUT_LOG || error_exit 1 + +exit_test