This is an automated email from the ASF dual-hosted git repository. FreeAndNil pushed a commit to branch Feature/318-telnet-default in repository https://gitbox.apache.org/repos/asf/logging-log4net.git
commit 7ddebdd22de162cc9247ba5407435cae6cbba432 Author: Jan Friedrich <[email protected]> AuthorDate: Fri Sep 4 07:36:25 2026 +0200 listen on loopback by default in TelnetAppender #318 - The appender streams the rendered log to any client that connects, with no authentication and no encryption, and defaulted to every interface on port 23. - It now defaults to 127.0.0.1. Watching from another machine is opt-in: set listenAddress to 0.0.0.0 or ::. Every documented example already used loopback. - SocketHandler(port, sendTimeoutMillis) defaults the same way. Deliberate default flip: a deployment relying on the implicit all-interfaces bind loses remote access until it sets listenAddress. audit da18b6fd-f012 --- .../3.5.0/318-telnet-loopback-default.xml | 13 ++++++++++++ src/log4net.Tests/Appender/TelnetAppenderTest.cs | 17 +++++++++++---- src/log4net/Appender/TelnetAppender.cs | 24 ++++++++++++---------- .../configuration/appenders/telnetappender.adoc | 20 ++++++++++-------- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/changelog/3.5.0/318-telnet-loopback-default.xml b/src/changelog/3.5.0/318-telnet-loopback-default.xml new file mode 100644 index 00000000..2361c159 --- /dev/null +++ b/src/changelog/3.5.0/318-telnet-loopback-default.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="https://logging.apache.org/xml/ns" + xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" + type="changed"> + <issue id="318" link="https://github.com/apache/logging-log4net/pull/318"/> + <description format="asciidoc">`TelnetAppender` now listens on `127.0.0.1` by default instead of every + interface. The stream is unauthenticated and unencrypted, so any host that could reach the port + could read the application's log, and every documented example already used loopback. Watching the + log from another machine is now opt-in: set `listenAddress` to `0.0.0.0` or `::` to restore the old + behaviour. The `SocketHandler(port, sendTimeoutMillis)` constructor defaults the same way (audit + da18b6fd-f012, implemented by @FreeAndNil)</description> +</entry> diff --git a/src/log4net.Tests/Appender/TelnetAppenderTest.cs b/src/log4net.Tests/Appender/TelnetAppenderTest.cs index c0df92b4..9b0bb3b2 100644 --- a/src/log4net.Tests/Appender/TelnetAppenderTest.cs +++ b/src/log4net.Tests/Appender/TelnetAppenderTest.cs @@ -239,12 +239,21 @@ public void SendTimeoutMillisRejectsNegativeValuesButAllowsZero() } /// <summary> - /// The appender accepts connections on every interface unless told otherwise, which is the - /// behaviour it has always had. + /// The stream is unauthenticated, so an appender nobody configured an address for must not be + /// reachable from another machine. /// </summary> [Test] - public void ListenAddressDefaultsToEveryInterface() - => Assert.That(new TelnetAppender().ListenAddress, Is.EqualTo(IPAddress.Any)); + public void ListenAddressDefaultsToLoopback() + => Assert.That(new TelnetAppender().ListenAddress, Is.EqualTo(IPAddress.Loopback)); + + /// <summary> + /// Remote monitoring is still available, it just has to be asked for. + /// </summary> + [TestCase("::", TestName = "EveryIPv6InterfaceCanBeAskedFor")] + [TestCase("0.0.0.0", TestName = "EveryIPv4InterfaceCanBeAskedFor")] + public void EveryInterfaceCanBeAskedFor(string address) + => Assert.That(new TelnetAppender { ListenAddress = IPAddress.Parse(address) }.ListenAddress, + Is.EqualTo(IPAddress.Parse(address))); /// <summary> /// Binding to the loopback address has to keep the port unreachable from other machines, which diff --git a/src/log4net/Appender/TelnetAppender.cs b/src/log4net/Appender/TelnetAppender.cs index 903cd0d5..b38a9373 100644 --- a/src/log4net/Appender/TelnetAppender.cs +++ b/src/log4net/Appender/TelnetAppender.cs @@ -37,10 +37,11 @@ namespace log4net.Appender; /// <para> /// The TelnetAppender accepts socket connections and streams logging messages back to the client. /// The output is provided in a telnet-friendly way so that a log can be monitored over a TCP/IP socket. -/// This allows simple remote monitoring of application logging. /// </para> /// <para> -/// The default <see cref="Port"/> is 23 (the telnet port). +/// The default <see cref="Port"/> is 23 (the telnet port) and the default +/// <see cref="ListenAddress"/> is <see cref="IPAddress.Loopback"/>, so monitoring from another +/// machine has to be turned on deliberately. /// </para> /// <para> /// This appender is a diagnostic tool for trusted networks. As with any other appender @@ -57,20 +58,20 @@ public class TelnetAppender : AppenderSkeleton private SocketHandler? _handler; private int _listeningPort = 23; private int _sendTimeoutMillis = 5_000; - private IPAddress _listenAddress = IPAddress.Any; + private IPAddress _listenAddress = IPAddress.Loopback; /// <summary> /// Gets or sets the address to listen on. /// </summary> /// <value> - /// The local address to accept connections on. The default is <see cref="IPAddress.Any"/>, every - /// interface of the machine. + /// The local address to accept connections on. The default is <see cref="IPAddress.Loopback"/>, + /// the machine the application runs on. /// </value> /// <remarks> /// <para> - /// Set this to <see cref="IPAddress.Loopback"/> to accept connections only from the machine the - /// application runs on, which is what the diagnostic use this appender is meant for usually - /// needs. + /// The stream is unauthenticated and unencrypted, so reaching it from another machine is opt-in: + /// set this to <see cref="IPAddress.Any"/> or <see cref="IPAddress.IPv6Any"/> for that, and keep + /// untrusted parties away from the port. /// </para> /// </remarks> /// <exception cref="ArgumentNullException">The value specified is <see langword="null"/>.</exception> @@ -183,7 +184,7 @@ public override void ActivateOptions() try { LogLog.Debug(_declaringType, $"Creating SocketHandler to listen on [{_listenAddress}]:[{_listeningPort}]"); - _handler = new SocketHandler(_listenAddress, _listeningPort, _sendTimeoutMillis); + _handler = new(_listenAddress, _listeningPort, _sendTimeoutMillis); } catch (Exception ex) { @@ -325,11 +326,12 @@ public SocketHandler(int port) /// block before that client is disconnected, or 0 to block indefinitely</param> /// <remarks> /// <para> - /// Creates a socket handler on the specified local server port. + /// Creates a socket handler on the specified local server port, listening on + /// <see cref="IPAddress.Loopback"/>. /// </para> /// </remarks> public SocketHandler(int port, int sendTimeoutMillis) - : this(IPAddress.Any, port, sendTimeoutMillis) + : this(IPAddress.Loopback, port, sendTimeoutMillis) { } /// <summary> diff --git a/src/site/antora/modules/ROOT/pages/manual/configuration/appenders/telnetappender.adoc b/src/site/antora/modules/ROOT/pages/manual/configuration/appenders/telnetappender.adoc index 6751ca0c..adc29c1e 100644 --- a/src/site/antora/modules/ROOT/pages/manual/configuration/appenders/telnetappender.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/configuration/appenders/telnetappender.adoc @@ -51,10 +51,12 @@ The default is `23`, the telnet port. `listenAddress`:: The local address to accept connections on. -The default is `0.0.0.0`, every interface of the machine. +The default is `127.0.0.1`, the machine the application runs on, which is what diagnostic use +usually needs. + -Set it to `127.0.0.1` to accept connections only from the machine the application runs on, which is -what diagnostic use usually needs. +The stream is unauthenticated and unencrypted, so watching it from another machine is opt-in: set +this to `0.0.0.0` for every IPv4 interface, or `::` for every IPv6 one, and keep untrusted parties +away from the port. An IPv6 address may be given instead, and the listening socket follows its family. `sendTimeoutMillis`:: @@ -82,17 +84,17 @@ The appender therefore performs no authentication of its own. [WARNING] ==== -The connection is *unauthenticated* and *unencrypted*, and by default the appender listens on *all -network interfaces*. +The connection is *unauthenticated* and *unencrypted*. There is no option to require a credential or to enable TLS. Any client that can reach the port receives the full rendered log stream, including whatever the layout renders: user names, session identifiers, request parameters, stack traces. -Keeping untrusted parties away from the port is the operator's responsibility, exactly as it is -for a log file: +The appender listens on `127.0.0.1` only, so that stays on the local machine until you widen +`listenAddress`, and keeping untrusted parties away from the port is then the operator's +responsibility, exactly as it is for a log file: -* Set `listenAddress` to `127.0.0.1` unless clients on other machines really have to connect. -* Only enable this appender on a trusted network. +* Widen `listenAddress` only if clients on other machines really have to connect. +* Only do so on a trusted network. * Restrict access to the port with a host firewall or network policy. * Prefer it for local or short-lived diagnostics rather than as a permanent logging destination. ====
