Phase 4: syslog UDP ingestion source (D-0023) #4
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/syslog-source"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What does this PR do?
Implements the general syslog UDP ingestion source (Phase 4, D-0023), serving SWAG/nginx first and future senders (MikroTik RouterOS remote logging, other LAN hosts).
Viegard.Sources.Syslog:SyslogUdpSource: thin UDP receive loop; per-source health including drop counters.SyslogDatagramHandler(testable guardrail core): fail-closed source-IP allowlist (no allowlist, no listener), datagram size cap, per-source token-bucket rate cap, replacement-character UTF-8 decoding so hostile bytes can never throw.SyslogEnvelopeParser: RFC 3164 (pid tags, year inference with December/January wrap) and RFC 5424; unparseable input degrades to a message-only envelope, never an exception.NginxAccessLogParser: standard combined format plus the Viegardhost=/rt=extension; malformed or hostile request lines yield partial fields.SyslogEventNormalizer:nginx_access-tagged lines becomeHttpRequestEventwith IP/host/URI/User-Agent entity refs; everything else becomes a genericSyslogEventwhose origin identity is the peer IP, with the claimed hostname carried as untrusted data.HttpRequestEventandSyslogEventpayloads.docs/swag-syslog-setup.md: sanitized SWAG-side nginx configuration guide (log_format viegard, syslogaccess_log/error_logtargets, firewall note, keep-file-logs guidance).Fixes #
How was this tested?
dotnet build Viegard.slnx- 0 errors, 0 warningsdotnet test Viegard.slnx- 130/130 pass (31 new: envelope parsing incl. hostile content verbatim, nginx parsing incl. injection-text-in-UA as data and IPv6, allowlist/size/rate guardrails with FakeTimeProvider, spoofed-hostname handling, fail-closed DTO validation)HttpRequestEvent(nginx access line) and a genericSyslogEvent(hostile "ignore previous instructions" message, treated purely as data), both persisted and queued for correlationChecklist
- Viegard.Sources.Syslog: - SyslogUdpSource: thin UDP loop; per-source health incl. drop counters - SyslogDatagramHandler (testable core): fail-closed source-IP allowlist, datagram size cap, per-source token-bucket rate cap, replacement-character decoding so hostile bytes never throw - SyslogEnvelopeParser: RFC 3164 (incl. pid tags, year inference with Dec/Jan wrap) and RFC 5424; garbage degrades to message-only - NginxAccessLogParser: combined format + Viegard host=/rt= extension; malformed/hostile request lines yield partial fields, never throw - SyslogEventNormalizer: nginx_access tags -> HttpRequestEvent with IP/host/URI/UA entity refs; everything else -> generic SyslogEvent keyed to peer IP (claimed hostname untrusted) - Options validation: enabled listener requires non-empty allowlist - Domain: HttpRequestEvent + SyslogEvent payloads - PipelineHost: syslog registration (off by default); debug log on successful ingestion - docs/swag-syslog-setup.md: sanitized SWAG nginx configuration guide - Tests: 130 passing (31 new incl. spoofed-hostname handling, injection text as data, rate-limit recovery with FakeTimeProvider) Verified end-to-end: live UDP datagrams to the running host produced a normalized HttpRequestEvent (nginx line) and generic SyslogEvent (hostile message) queued for correlation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>