FreeAndNil commented on PR #324:
URL: https://github.com/apache/logging-log4net/pull/324#issuecomment-6121984337

   Implementation plan for #324, kept here for the record. Revised after the 
merge so that it describes the change as it landed.
   
   <details>
   <summary>Plan</summary>
   
   # PR #324: the sinks cluster (f015, f042, f037)
   
   ## Context
   
   Continuing the remediation of the 2026-08-29 scan after #323, with three 
findings from scan
   `da18b6fd`, all about what leaves the process:
   
   - **f015**, MEDIUM, `UdpAppender`: a rendered event over the datagram limit 
makes `Send` throw, the
     event is lost, and `OnlyOnceErrorHandler` reports only the first loss. 
Event loss is this
     project's main risk class, so it goes first.
   - **f042**, LOW, `XmlHierarchyConfigurator`: with `debug="true"` the 
configurator echoes every
     configured value, passwords and connection strings included.
   - **f037**, LOW, `SmtpPickupDirAppender`: the file ends with a lone dot but 
body lines are not dot
     stuffed, so a logged line that is only a dot can end the mail early for a 
dot-honouring agent.
   
   None of the three is a vulnerability. Outcome: three commits on a new 
branch, each with a
   regression test, a changelog entry and, where a property or a file format 
changes, the Antora
   page.
   
   ## Branch
   
   Changelog entries go in `src/changelog/3.5.0/324-*.xml` with
   `<issue id="324" 
link="https://github.com/apache/logging-log4net/pull/324"/>`.
   
   ## Commit 1: f015, oversize datagram truncated instead of dropped
   
   **Measure first.** Send a datagram over the limit through a `UdpClient` on 
loopback and record the
   threshold: 65507 bytes are sent, 65508 fail. That is the IPv4 UDP payload 
maximum, and an IPv6
   packet would carry 20 bytes more, which is not worth a second limit. The 
numbers go into the PR
   body.
   
   `src/log4net/Appender/UdpAppender.cs`:
   
   - New `public int MaxDatagramSize` property, default 65507, validated in its 
setter rather than in
     `ActivateOptions`, range 512 to 65507 as two private constants, via
     `SystemInfo.CreateArgumentOutOfRangeException`. The remarks say why it 
cannot be raised.
   - New `private protected byte[] GetDatagramBytes(string message)`: encode 
with `Encoding`; return
     as is when it fits. Otherwise a private `GetTruncatedBytes` runs the 
message through
     `Encoding.GetEncoder().Convert` with `flush: false` into a budget of 
`MaxDatagramSize` minus the
     marker length, writing into the oversize encoding itself, which is the one 
buffer already long
     enough. `Convert` never splits a character and, unflushed, holds back a 
trailing high surrogate
     rather than emitting the replacement character. Append the marker 
`...[truncated]` and report
     the truncation with the byte counts through `ErrorHandler`.
   - `Append` calls it instead of `Encoding.GetBytes(...)`.
   
   `src/log4net/Appender/RemoteSyslogAppender.cs`: `Append` runs the finished 
`builder.ToString()`
   through the same helper before enqueueing. Its `Encoding` is ASCII and 
`AppendMessage` has already
   escaped everything outside 0x20 to 0x7E, so the marker stays inside the RFC 
3164 range.
   
   Tests, `src/log4net.Tests/Appender/UdpAppenderTest.cs` (new) and an addition 
to
   `RemoteSyslogAppenderTest.cs`:
   
   - `GetDatagramBytes` is `private protected`, so drive it by reflection from 
a small `Encode`
     helper in the fixture; no socket needed for the size cases. Cover: the 
default is 65507; 511
     and 65508 throw `ArgumentOutOfRangeException`; a message that fits is 
byte-for-byte unchanged; a
     message of exactly the limit is unchanged and nothing is reported; an 
oversize one comes back at
     `MaxDatagramSize` bytes, ends in the marker and is reported once through a
     `RecordingErrorHandler`; a two-byte encoding is cut on a character 
boundary (513 bytes hold the
     14 byte marker and 249 characters); a surrogate pair straddling the cut is 
not split, asserted
     as no replacement character, ordinal.
   - The syslog case goes through the existing `ExecuteAppend` helper in 
`RemoteSyslogAppenderTest`,
     which gains an optional `maxDatagramSize`, asserting one datagram of 
exactly the limit ending in
     the marker.
   - Wrap the expected `ErrorHandler`/`LogLog` output in
     `LogLog.ExecuteWithoutEmittingInternalMessages` so the suite stays quiet.
   - Revert the production change and watch each new test fail.
   
   Docs: a paragraph on
   
`src/site/antora/modules/ROOT/pages/manual/configuration/appenders/udpappender.adoc`
 (the page has
   no property table) with the default, the lower bound and why it cannot be 
raised, and a bullet on
   `remotesyslogappender.adoc` naming the inherited property.
   
   Changelog `324-udp-oversize-truncation.xml`, `type="fixed"`, credit
   `(audit da18b6fd-f015, fixed by @FreeAndNil)`.
   
   ## Commit 2: f042, no secret values in the configuration debug echo
   
   Share one redaction rule rather than growing a second one:
   
   - Move `RedactConnectionString`, `DiagnosticKeywords` and `RedactedValue` 
out of
     `src/log4net/Appender/AdoNetAppender.cs:829-886` into a new internal 
static helper,
     `src/log4net/Util/Redact.cs`, as `Redact.ConnectionString`, the keyword 
allowlist and an
     internal `RedactedValue` constant. `AdoNetAppender` keeps calling it, so 
its behaviour is
     unchanged, and it loses its `System.Data.Common` using.
   - Add to that helper a `Value(string name, object? value)` that returns the 
masked form when the
     configured parameter name contains a secret-bearing fragment 
(case-insensitive: `password`,
     `pwd`, `passphrase`, `secret`, `token`, `credential`, `apikey`), and 
routes a name that **ends
     with** `connectionstring` through the allowlist redaction so the server 
part stays visible for
     troubleshooting. Ends with, not contains: `ConnectionType` and 
`ConnectionStringName` are
     diagnostics, not secrets, and are the first things read when configuration 
fails. A null value
     passes through as null, everything else unchanged.
   - Apply it at the nine `SetParameter` message sites in
     `src/log4net/Repository/Hierarchy/XmlHierarchyConfigurator.cs`: the two 
`Debug` value paths,
     the failed-conversion `Warn`, the four setter-exception `Error` paths and 
the two `Debug` object
     paths, always keyed by the configured `name`. The `Error` paths matter 
most: they are emitted
     even without `debug="true"`. Property names and types keep being logged. 
No other site echoes a
     raw configuration value or the config XML.
   
   Test, `src/log4net.Tests/Config/RedactTest.cs`, `[NonParallelizable]` since 
it mutates
   `LogLog.InternalDebugging`, with a `Configure` helper that turns internal 
debugging on inside
   `LogLog.ExecuteWithoutEmittingInternalMessages`, captures with 
`LogLog.LogReceivedAdapter`,
   configures a repository from an XML string and restores the flag in 
`finally`. Three tests: a
   password-named parameter on an SMTP appender is absent while the property 
name and a non-secret
   value are still present; a connection string keeps the server name and loses 
the password; the
   connection type and the connection string name survive. `Does.Not.Contain` 
is culture sensitive,
   so use `!Contains.Substring(secret).Using(StringComparison.Ordinal)`. Revert 
and watch it fail.
   
   Docs: one sentence in the internal debugging entry of `manual/faq.adoc`, 
since that is the
   documented first troubleshooting step: a value whose name reads as a secret 
is replaced with
   `*****`, the property is still named.
   
   Changelog `324-config-debug-secret-values.xml`, `type="fixed"`, credit
   `(audit da18b6fd-f042, fixed by @FreeAndNil)`.
   
   ## Commit 3: f037, drop the lone-dot terminator from the pickup file
   
   Decided: remove the hazard rather than encode around it. A pickup file is an 
RFC 822 message, not a
   DATA stream, so the terminator buys nothing and no dot stuffing is needed 
once it is gone. An agent
   that expects SMTP DATA framing is not a supported consumer, and the page 
says so.
   
   `src/log4net/Appender/SmtpPickupDirAppender.cs:171`: delete 
`writer.WriteLine(".");` and keep the
   preceding `writer.WriteLine();` so the file still ends with a newline. Two 
lines of comment saying
   why there is no terminator.
   
   Test in `src/log4net.Tests/Appender/SmtpPickupDirAppenderTest.cs`,
   `ALoggedDotIsTheOnlyDotLineInTheFile`: log an event that is only a dot and 
one after it, close the
   logger, then assert the written file holds exactly one bare-dot line and the 
second event, with
   the silent error handler still empty. Use `using AutoTempFolder folder = 
new();` as a local and
   close the appender before the scope ends. Revert and watch it fail.
   
   Docs: a paragraph in `smtppickupdirappender.adoc` stating the file is a 
plain RFC 822 message read
   to its end, with no SMTP DATA terminator and no dot stuffing.
   
   Changelog `324-pickup-dir-dot-terminator.xml`, `type="changed"` (the written 
file format changes),
   credit `(audit da18b6fd-f037, implemented by @FreeAndNil)`.
   
   ## Verification, after every commit
   
   ```
   dotnet build src/log4net.sln                                              # 
0 warnings, both TFMs
   dotnet build src/log4net.Tests/log4net.Tests.csproj -f net462 
-p:TargetFrameworks=net462
   dotnet test src/log4net.Tests/log4net.Tests.csproj -f net10.0             # 
413 at the end
   dotnet test src/log4net.Ext.Mail.Tests/log4net.Ext.Mail.Tests.csproj      # 
50
   ```
   
   Redirect build output to a file and read the whole file.
   
   ## Around the work
   
   - Stage and propose a commit message, one file per commit in 
`.git/plans/324/`, then wait. No
     commits are made here.
   - Cite findings as `audit da18b6fd-fNNN`.
   - Read the scan's own patches for the three findings before writing each 
test; its tests have
     more than once been better than ours.
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to