Skip to content

Commit 5a09173

Browse files
committed
Fix: Akka.Remote should not shutdown on invalid TLS traffic (#7939)
When TLS is enabled, invalid traffic (like HTTP requests) hitting the Akka.Remote port would cause the entire ActorSystem to shut down with exit code 79. This was due to overly aggressive TLS handshake failure handling introduced in #7839. Changes: - Modified TcpTransport to only trigger CoordinatedShutdown for client-side TLS handshake failures (outbound connections we initiate) - Server-side TLS failures (incoming invalid connections) now just log a warning and reject the connection without shutting down - Added test to verify servers remain running when invalid traffic hits the TLS port This makes Akka.Remote resilient to port scanners, misconfigured clients, or malicious traffic while maintaining strict security for legitimate connections. Fixes #7938
1 parent e7bf0c7 commit 5a09173

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

src/core/Akka.Remote.Tests/Transport/DotNettyTlsHandshakeFailureSpec.cs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
using System;
99
using System.IO;
10+
using System.Net.Sockets;
1011
using System.Security.Cryptography.X509Certificates;
12+
using System.Text;
1113
using System.Threading.Tasks;
1214
using Akka.Actor;
1315
using Akka.Configuration;
@@ -28,13 +30,13 @@ public DotNettyTlsHandshakeFailureSpec(ITestOutputHelper output) : base(Configur
2830
{
2931
}
3032

31-
private static Config CreateConfig(bool enableSsl, string certPath, string certPassword, bool suppressValidation = true)
33+
private static Config CreateConfig(bool enableSsl, string certPath, string certPassword, bool suppressValidation = true, int port = 0)
3234
{
3335
var baseConfig = ConfigurationFactory.ParseString(@"akka {
3436
loglevel = DEBUG
3537
actor.provider = ""Akka.Remote.RemoteActorRefProvider,Akka.Remote""
3638
remote.dot-netty.tcp {
37-
port = 0
39+
port = " + port + @"
3840
hostname = ""127.0.0.1""
3941
enable-ssl = " + (enableSsl ? "on" : "off") + @"
4042
log-transport = off
@@ -147,7 +149,66 @@ await AwaitAssertAsync(async () =>
147149
}
148150
}
149151

152+
[Fact(DisplayName = "Server should NOT shutdown when invalid traffic (like HTTP) hits TLS port")]
153+
public async Task Server_side_invalid_traffic_should_not_shutdown_server()
154+
{
155+
// This test addresses issue https://github.com/akkadotnet/akka.net/issues/7938
156+
// When invalid traffic (like HTTP requests) hits a TLS-enabled port,
157+
// the server should reject the connection but NOT shut down
158+
ActorSystem server = null;
159+
160+
try
161+
{
162+
// Start server with TLS enabled on a specific port
163+
var port = 15557; // Use a fixed port for this test
164+
var serverConfig = CreateConfig(true, ValidCertPath, Password, suppressValidation: true, port: port);
165+
server = ActorSystem.Create("ServerSystem", serverConfig);
166+
167+
var serverEcho = server.ActorOf(Props.Create(() => new EchoActor()), "echo");
168+
169+
// Ensure the server is ready by waiting for the remote transport to be bound
170+
var serverAddress = RARP.For(server).Provider.DefaultAddress;
171+
Assert.NotNull(serverAddress);
172+
Assert.Equal(port, serverAddress.Port.Value);
173+
174+
// Send invalid HTTP traffic to the TLS port (simulating the issue)
175+
try
176+
{
177+
using var tcpClient = new TcpClient();
178+
await tcpClient.ConnectAsync("127.0.0.1", port);
179+
180+
// Send an HTTP OPTIONS request (as described in the bug report)
181+
var httpRequest = Encoding.UTF8.GetBytes("OPTIONS / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
182+
await tcpClient.GetStream().WriteAsync(httpRequest, 0, httpRequest.Length);
183+
await tcpClient.GetStream().FlushAsync();
150184

185+
// Connection should be closed by server after rejecting invalid TLS
186+
tcpClient.Close();
187+
}
188+
catch
189+
{
190+
// Connection might be closed by server, that's expected
191+
}
192+
193+
// Verify the server hasn't initiated shutdown
194+
// If it was going to shut down due to TLS failure, it would have done so immediately
195+
await AwaitConditionAsync(() => !server.WhenTerminated.IsCompleted,
196+
TimeSpan.FromSeconds(3), TimeSpan.FromMilliseconds(100));
197+
198+
// CRITICAL ASSERTION: Server should NOT have shut down
199+
Assert.False(server.WhenTerminated.IsCompleted,
200+
"Server should NOT shut down after receiving invalid HTTP traffic on TLS port");
201+
202+
// Also verify the system is still functional
203+
var testActor = server.ActorOf(Props.Empty, "test-actor");
204+
Assert.NotNull(testActor);
205+
}
206+
finally
207+
{
208+
if (server != null)
209+
Shutdown(server, TimeSpan.FromSeconds(10));
210+
}
211+
}
151212

152213
private sealed class EchoActor : ReceiveActor
153214
{

src/core/Akka.Remote/Transport/DotNetty/TcpTransport.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,20 @@ public override void UserEventTriggered(IChannelHandlerContext context, object e
9292
context.Channel.LocalAddress, context.Channel.RemoteAddress,
9393
context.Channel.Id, detailedError);
9494

95-
// Shutdown the ActorSystem on TLS handshake failure
96-
var cs = CoordinatedShutdown.Get(Transport.System);
97-
cs.Run(new TlsHandshakeFailureReason($"TLS handshake failed on channel [{context.Channel.LocalAddress}->{context.Channel.RemoteAddress}](Id={context.Channel.Id})"));
95+
// Only shutdown the ActorSystem if this is a client-side failure
96+
// Server-side failures (incoming connections) should just reject the connection
97+
if (isClient)
98+
{
99+
// Client-side: We initiated the connection and TLS failed - this is critical
100+
var cs = CoordinatedShutdown.Get(Transport.System);
101+
cs.Run(new TlsHandshakeFailureReason($"TLS handshake failed on outbound connection to [{context.Channel.RemoteAddress}]"));
102+
}
103+
else
104+
{
105+
// Server-side: Someone connected to us with invalid TLS - just reject them
106+
Log.Warning("Rejected incoming connection from [{0}] due to TLS handshake failure. This is likely invalid or malicious traffic.",
107+
context.Channel.RemoteAddress);
108+
}
98109

99110
context.CloseAsync();
100111
return; // don't pass to next handlers

0 commit comments

Comments
 (0)