Ensure osslChkPeerAuth starts with a null peer-certificate pointer and
frees any retrieved X509 certificate so OpenSSL allocations from
SSL_get_peer_certificate do not leak after TLS handshakes.
* imtcp: include peer ports in runtime log messages
Ensure tcpsrv and session diagnostics report the sender's source port alongside the existing host/IP fields so administrators can pinpoint connections precisely. This updates imtcp connection notices, close/error paths, and framing warnings to use a consistent "host (ip:port)" style already present in TLS mismatch logs.
With the help of AI-Agent: Codex
Admins often report "gibberish" when a TLS-enabled sender connects to a
plain imtcp port. Making the mismatch explicit reduces operator confusion
and support churn, and points directly to remediation.
Impact: logs one explicit error per mismatched connection; no change to
parsing or transport on plain listeners.
Before/After: before, ClientHello bytes were ingested as binary with no
hint; after, imtcp detects a TLS ClientHello on ptcp and logs a clear
message with a troubleshooting URL.
Technically, we add a small per-session probe in tcps_sess_t and sample
the first 5 bytes of new sessions. If the record header matches a TLS
handshake (type 0x16, version 0x03.00–0x04, length 40–16384) and the
listener is plain TCP (streamDriver.mode=0), we emit a single error and
disable further probing for that session. The probe is called from
DataRcvd() and returns RS_RET_SERVER_NO_TLS when triggered; the session
is otherwise left untouched.
Runtime: introduce RS_RET_SERVER_NO_TLS (-2465) to tag the condition.
Docs: add imtcp troubleshooting section and a dedicated FAQ page.
Tests/tools: add test imtcp-tls-gibberish.sh and extend tcpflood with
-H to send only a ClientHello (OpenSSL and GnuTLS paths tolerate early
termination and non-blocking I/O for this mode).
Handle post-handshake KeyUpdate by driving a minimal non-blocking read when the
TLS library requests READ during Send(). This prevents stalls when servers send
TLS 1.3 KeyUpdate and aligns behavior with RFC 8446 §4.6.3.
- nsd_ossl.c: SSL_ERROR_WANT_READ => small SSL_read(), then retry write
- nsd_gtls.c: E_AGAIN/E_INTERRUPTED with READ direction => small gnutls_record_recv(), then retry write
Backward-compatible and only active when the TLS stack signals a need to read.
closes: https://github.com/rsyslog/rsyslog/issues/5627
most importantly, header file now includes comments that enable
tooltip-like behaviour in IDEs. Also includes antipaterns, which
is useful for developers and hopefully also for AI to detect
them e.g. in code reviews (and get it right in AI-generated code).
This moves NetworkNamespace functionality into
the net module. This allows the same code to
be reused across multiple tools and plugins.
The first usage is with omfwd, which is changed
to use the common net implementation. Note
the net implementation is based on the original
omfwd implementation. Subsequent PRs will be
opened for integrating this into omuxsock and
imtcp.
The original test case tcp_forwarding_ns_tpl.sh
was broken due to use of single quotes rather
than double quotes, thus preventing the proper
port number argument to be passed to the
listener. Note this test must be run as
root.
Development has occurred across Fedora41 and
Fedora42, which uses glibc 2.40 and glibc2.41
respectively. The valgrind suppressions are
updated to handle new glibc issues
accordingly.
Four new functions are callable through the
net module. These allow one to save a handle
to the current namespace, switch to a new
namespace by name, and restore the namespace
from the saved handle. A fourth higher
level wrapper is used to open a socket in
a named network namespace, and handles the
invocation of the lower level functions.
Ideally this would be the only public
function, however it simplifies integration
into imtcp in the future (which doesn't
directly open sockets). This may change
in the future as network namespaces are
integrated into more modules and plugins.
Signed-off-by: Billie Alsup <balsup@cisco.com>
Adds the ability to remove unnecessary spaces from genrated json
to conserve space, e.g. on disk.
Maintainer edit: this replaces orginal PR which was too hard to
rebase. This was caused by too-slow reaction of the rsyslog team.
see also: https://github.com/rsyslog/rsyslog/pull/2925
(this is the original PR)
closes: https://github.com/rsyslog/rsyslog/issues/2913
Some deployments need to disambiguate multiple senders sharing an IP,
for example autossh or similar tunnel setups. Exposing the source port
improves observability and lets pipelines key on a stable tuple.
Impact: new property/JSON field; tcps_sess IF v4; out-of-tree modules
must rebuild.
Before: messages exposed fromhost and fromhost-ip only.
After: messages also expose fromhost-port and jsonmesg includes it.
Introduce PROP_FROMHOST_PORT and wire it through msg.{h,c}. For TCP,
capture the remote port on accept, store it in tcps_sess, and attach it
to the msg on submit. For other inputs, resolveDNS derives the port from
the sockaddr when available; local inputs return an empty string. Add a
getter, duplication and destructor handling, and name<->ID mapping. Add
the field to jsonmesg output. Update docs, lexer keywords, and the
external plugin interface doc (property is modifiable). Bump
tcps_sessCURR_IF_VERSION to 4 and add SetHostPort() to the interface.
Include a focused test (fromhost-port.sh) that verifies the property.
Non-technical rationale: allow identification by (fromhost-ip,
fromhost-port) where IP alone is shared across systems (e.g., autossh).
With help from AI-Agents: ChatGPT
Fix compilation issues on macOS/Darwin systems and enhance cross-platform
compatibility for BSD variants:
- Add Darwin-specific pthread_setname_np call in tcpsrv.c with enhanced
platform-specific conditional compilation
- macOS (__APPLE__): Single parameter, returns int
- FreeBSD/NetBSD: Two parameters, returns void
- Linux/glibc (default): Two parameters, returns int
This prevents compilation failures across all BSD systems where the
function signature and return type differ, while maintaining existing
compatibility with macOS and Linux systems.
- Add _PATH_UTMP fallback definition in omusrmsg.c for systems
without paths.h or missing _PATH_UTMP definition
- Remove trailing empty line in cfsysline.c for consistency
The change adds proper platform-specific conditional compilation
with clear documentation for each variant and maintains error
checking where the return value is available.
Impact: Fixes build regressions on Darwin and BSD systems while
preserving backward compatibility with existing platforms.
Refs: https://github.com/rsyslog/rsyslog/pull/6069
Refs: https://github.com/rsyslog/rsyslog/pull/5635
Refs: https://github.com/Homebrew/homebrew-core/issues/221869
Refs: https://github.com/Homebrew/homebrew-core/issues/226378
Harden default endpoints for cloud-native use: make health/metrics
scrapes proxy-friendly and allow locking them down with Basic Auth.
This aligns imhttp with common Kubernetes/Prometheus patterns and
supports metrics-only deployments.
Impact: /metrics now exports full rsyslog stats with Content-Length;
health and metrics can be gated via htpasswd; unified 500 on failures.
Technical details:
- Add module params: healthCheckBasicAuthFile and metricsBasicAuthFile.
When set, attach a Basic Auth handler that reads an htpasswd file;
reuse the same handler for per-input endpoints by passing the file via
cbdata.
- Rework Prometheus handler to collect data through statsobj in
Prometheus format. Accumulate lines into a growable buffer with
overflow checks, append an imhttp_up gauge, then reply with an
explicit Content-Length and close the connection.
- Fix metrics buffer termination to use a single NUL byte; prevent a
leak when buffer growth fails; consolidate error paths so the buffer is
freed and a single HTTP 500 is emitted.
- Docs: describe new auth options, clarify default paths, document that
metrics responses carry Content-Length, and add examples (including
metrics-only setups).
Before/After: metrics previously exposed a minimal body without auth;
now they export full rsyslog stats with optional Basic Auth and a
Content-Length header.
Improve maintainability and robustness of the TCP server by clarifying
locking/ownership, tightening invariants, and simplifying queueing.
Also fix a long-standing pragma macro typo across the tree.
Impact: Internal behavior only. EPOLL re-arm now occurs while holding
pSess->mut; starvation cap counts only successful reads.
Before/After:
Before: EPOLL re-arm happened after leaving the critical section; read
starvation cap counted loop iterations; closeSess() sometimes unlocked;
select_* helpers used on non-epoll path; enqueueWork() returned status.
After: EPOLLONESHOT is re-armed before unlocking; starvation cap counts
only RS_RET_OK reads; closeSess() never unlocks; poll_* helpers replace
select_*; enqueueWork() is void (best-effort).
Technical details:
- Replace notifyReArm() with rearmIoEvent() (EPOLL_CTL_MOD with
EPOLLONESHOT|EPOLLET; asserts efd/sock; logs on failure).
- doReceive(): explicit state machine; would-block path re-arms before
unlock; close path unlocks then calls closeSess(); starvation handoff
enqueues without re-arming.
- Initialize ioDirection for listener and session descriptors; add
assert(sock >= 0) and widespread ATTR_NONNULL annotations.
- startWrkrPool(): single finalize rollback (cancel/join partial
threads; destroy cond/mutex); stopWrkrPool(): destroy cond/mutex.
- enqueueWork(): FIFO append under lock and cond signal; returns void.
- Cleanup hardening on construct failure: free ppLstn, ppLstnPort,
ppioDescrPtr; free fromHostIP on SessAccept() error.
- Non-epoll: rename select_Add/Poll/IsReady -> poll_*; RunPoll() uses
poll_* and sets sane ioDirection defaults.
- Typo fix: standardize PRAGMA_IGNORE_Wswitch_enum in header and all
users (action.c, rainerscript.c, template.c, tcpsrv.c).
Work towards full completion of the module’s interface as it exits PoC.
The new name senderid (formerly: template) matches intent (identify a
sender, not an output format) and avoids confusion. Also make state
persistence safer via atomic writes.
Merged a bit pre-completion in order to get a static analyzer fix
into the main code base. Some additional cleanup PR will follow.
State is much cleaner now than in PoC.
Impact: Configs must use senderid=; statefile is now required. Tests
and docs updated.
Before/After: action(... template="name") -> action(... senderid="name").
Technical details:
- Replace the config parameter and instance field; drop legacy template
parsing in parseSelectorAct. The module now reads only senderid=.
- Enforce required statefile (descriptor + runtime) and cache a temp
path "<statefile>.tmp" to ensure rename() is atomic. Provide a
one-time fallback build if the cache is missing (e.g., reload flow).
- Add built-in template "StdOmSenderTrack-senderid" yielding
"%fromhost-ip%" and use it as the default senderid template.
- Improve memory ownership (free cached temp path/default template) and
keep existing locking/queue semantics unchanged.
- Update tests to use senderid= and prune PoC doc note accordingly.
see also: https://github.com/rsyslog/rsyslog/issues/5599
Multiple intermediate CAs were not honored because strtok() modified
the original config value at the first comma. This led to only the
first file being considered. This change preserves the original value
and validates files using a duplicate buffer.
Impact: Users can reliably specify multiple CA intermediates via
NetstreamDriverCAExtraFiles; TLS chains that require intermediates
now validate as expected. Tests added.
Before: parsing mutated the stored string, effectively truncating at
the first comma and ignoring subsequent CA files.
After: we strdup() for validation, leave the original string intact,
and set it only if all files are accessible. Error handling follows
existing RS_RET patterns; temporary buffer is freed on all paths.
Additionally, add a test (OpenSSL backend) that generates a root,
two intermediates, and leaf certs on both client and server. The test
verifies chains with openssl, aligns CN/PermittedPeer, and exercises
a full send/receive path to guard against regressions. Makefile is
updated to include the new test in TESTS and EXTRA_DIST.
Fixes: https://github.com/rsyslog/rsyslog/issues/5207
While at the time of merge I was confident it would fix a data race,
the root cause has now surfaced to be a simple state advancement
(single-threaded) bug. See commit c5fd73499 for details. As such
I revert this patch. it caused no harm, but complicates code, adds
a bit of computation and is no longer needed.
I cannot 100% outrule it might have addressed some edge cases.
I know an environment where we can verify this within the next
month or so. If, unexpectedly, this shows regressions, we can
re-enable the patch. But I am 99.99% sure it is not needed.
see also: https://github.com/rsyslog/rsyslog/pull/5806
see also: https://github.com/rsyslog/rsyslog/pull/5993
inQueue guarded against double-queuing of descriptors.
The server uses EPOLLONESHOT and only one dispatcher, so
a descriptor is enqueued at most once before being
processed. The extra flag and atomic helpers are dead
code. Removing them simplifies queue management.
AI-Agent: ChatGPT
Static analysis cleanup to remove a possible read of uninitialized data.
This reduces undefined behavior risk with negligible overhead and aligns
with best practices for network address handling.
Impact: No functional change expected on correct systems; on buggy
getpeername() implementations we now return -1 instead of a random port.
Before: addr could contain garbage when getpeername() failed/partially
filled it, leading to spurious port extraction.
After: addr is zero-initialized; if family/port are not set we keep
*port at -1 and treat it as "no remote port".
Technically, GetRemotePort() now zeroes the local sockaddr_storage
before calling getpeername(). This prevents subsequent AF_INET/AF_INET6
parsing from reading uninitialized fields. No changes to RS_RET codes,
queues, OMODTX, or HUP semantics. No tests/docs touched.
This fixes a real-world segfault seen in production. The loop could
continue after closing a session and touch freed state on EPOLL builds.
The change makes the termination explicit to prevent crashes.
Impact: prevents segfaults in rare error paths; loop ends earlier after
a close, which may skip remaining iteration work for that session.
Before/After: before, the read/error branch could continue after
closeSess() and use freed pioDescr/pSess; after, we set do_run=0 and
exit the loop, avoiding any further dereference.
Technical: closeSess() on EPOLL removes the fd from epoll and frees the
io descriptor; callers must not access pioDescr or pSess after return.
We now set do_run=0 right after CHKiRet(closeSess(...)) in the read/
error path, matching the documented contract that both pointers become
invalid. We also improve closeSess() documentation to state pre/post
conditions, unlocking behavior, and epoll semantics, and fix a comment
typo ("epoll_Ctl"). No API/ABI change; action queues and stats are
unchanged. HUP and OMODTX semantics are unaffected.
Trailing semicolons in atomic helper macros caused double
semicolons when the macros expanded, producing build warnings.
Macros now omit semicolons and call sites add them explicitly.
STATSCOUNTER_DEF updated to terminate the generated mutex line.
AI-Agent: ChatGPT
Replace opaque/variadic callback usage with explicit, type-safe function
signatures to reduce undefined behavior and clarify intent.
Adapter helpers bridge the existing APIs without raw variadic casts, enabling
the transition incrementally. Callback setup sites are standardized for
consistent readability. This tightens the contract on callbacks, eases future
refactoring, and makes their roles more self-documenting.
Inspired by https://github.com/rsyslog/rsyslog/pull/5882
With AI support: Codex, Gemini
- Replaced function pointer casting with direct handler calls for type safety
- Fixes crashes (BUS errors) on ARM64 macOS 14+ due to strict calling conventions
- Root cause identified by ThreadSanitizer
- Eliminates undefined behavior, improves code safety
This commit fixes a race condition that could occur when two threads tried to close the same TCP session simultaneously. This could lead to an "epoll_ctl failed: Bad file descriptor" error message.
The fix introduces an atomic flag `being_closed` to the `tcps_sess_t` struct. This flag is used to ensure that the session-closing logic is executed only once per session.
This commit also corrects the logic of the atomic check to prevent the race condition correctly.
This commit fixes a race condition that could occur when two threads tried to close the same TCP session simultaneously. This could lead to an "epoll_ctl failed: Bad file descriptor" error message.
The fix introduces an atomic flag `being_closed` to the `tcps_sess_t` struct. This flag is used to ensure that the session-closing logic is executed only once per session.
This patch adds a robust, optional mechanism for handling "headerless" input—
log messages that do not conform to traditional syslog formatting.
- **Headerless detection (opt-in)**
- Controlled by the new `detect.headerless` boolean (default: off)
- Detects messages with **no PRI** and **no valid timestamp**
- Excludes structured inputs (e.g. JSON starting with `{` or `[`) as
before
- Injects default `hostname` and `tag` values
- Flags message internally as `HEADERLESS_MSG` for further processing
- **Fallback processing options**
- `headerless.ruleset`: route headerless messages to a dedicated ruleset
- `headerless.errorfile`: optionally store raw input to a file
- `headerless.drop`: discard headerless messages early if desired
- **Thread-safe HUP signal handling**
- New `doHUPParser` entry point allows safe log rotation for error file
- Follows standard reopen-on-write pattern post-HUP
- **Testing & Maintenance**
- Adds two test cases: `pmrfc3164-headerless.sh` and `pmrfc3164-drop.sh`
- Extends documentation for all new parameters
- Cleans up code formatting, includes, and bumps copyright
Some environments produce mixed or malformed input streams. This patch enables
early, lightweight detection of non-syslog input, with customizable recovery
and routing strategies. It avoids unnecessary parsing work and gives operators
better tools to isolate or discard garbage input—without breaking legacy behavior.
Introduce a new lifecycle callback—`checkParserInst`—to perform
configuration sanity checks on parser instances immediately after they’re
created. This establishes a standardized validation point (similar to
`checkCnf` in other module types) without altering existing parser logic.
By wiring `checkParserInst` into:
- the module template (macros for definition and registration),
- the module loader (`doModInit`) with graceful fallback,
- the runtime configuration flow (`rsconf.c`) just after
`newParserInst`,
and by providing empty stubs in all current parser modules (contrib and
plugins), we now have a clear, uniform spot to add parser-specific
validation rules in subsequent patches. This improves future
maintainability and robustness of parser configuration handling.
Add OpenSSL equivalent of existing GnuTLS PrioritizeSAN functionality
implemented in commit 937e278fdf51c3e21ebd3acf05f9d1b8649ce2c5
https://docs.openssl.org/1.1.1/man3/X509_check_host
> The X509_CHECK_FLAG_NEVER_CHECK_SUBJECT flag causes the function to
> never consider the subject DN even if the certificate contains no
> subject alternative names of the right type (DNS name or email address
> as appropriate); the default is to use the subject DN when no
> corresponding subject alternative names are present.
0x10100004L corresponds to OpenSSL 1.1.0-pre4 in which
X509_CHECK_FLAG_NEVER_CHECK_SUBJECT first appeared.
When no TLS certificate or key is configured for forwarding actions,
repeated connection attempts produced the same warning messages over and
over. gtlsInitCred() and gtlsAddOurCert() now log these warnings only
during the initial setup