[*] Clients identifizieren: < /strong> basierend auf den Parametern der Verbindungszeichenfolge. (Ich bin nur über die Verbindungszeichenfolge auf clientseitige Identifikation beschränkt). Ausführungszeit), der Proxy sollte Ergebnisse aus einer gespeicherten Datei zurückgeben, anstatt die tatsächliche Datenbank zu treffen. Server TLS -Handshakes und führt eine Roh -Byte -Weiterleitung durch. Ich begegne jedoch auf anhaltende Probleme, wenn ich mich mit .NET SQLConnection oder SQLCMD -n -c (Erzwingen der Verschlüsselung erzwingen). Problem:
Bei Verwendung eines SQL -Clients mit Encrypt = true in der Verbindungszeichenfolge, um über den Proxy eine Verbindung herzustellen, kann der Client konsequent eine Verbindung und Auswürfe herstellen Der folgende Fehler: < /p>
---> system.io.ioException: erhielt einen unerwarteten EOF- oder 0-Bytes aus dem Transportstrom. < /p>
< /blockquote>
Die Proxy -Protokolle zeigen konsistent: < /p>
Code: Select all
Minimal TLS Proxy listening on port 14330
HandleClientAsync: Client connection accepted.
HandleClientAsync: Forwarding FULL Server Prelogin Response (Hex): ...
HandleClientAsync: FULL Server prelogin response forwarded to client.
HandleClientAsync: Starting client TLS handshake.
TLS handshake failed: Received an unexpected EOF or 0 bytes from the transport stream.
< /code>
Interessanterweise [b]openssl s_client -connect 127.0.0.1:14330 -tls1_2
Ich habe umfangreiche Debugging -Bemühungen unternommen, einschließlich: < /p>
direkt weiterleiten die vollständige Server -Prelogin -Antwort an den Client. li>
vereinfachtes TdstlsStream zu Rohpass-Through. >
[*] SSLPROTOCOLS.TLS12 für Client- und Server -TLS -Handshakes ausdrücklich festgelegt. [/b]
[*] Behinderter Nagle -Algorithmus auf Sockets. Erfassungen des Netzwerkverkehrs. Br />
Code: Select all
openssl s_client
Code: Select all
SqlConnection
Das System.IndexoutoFrangeException , das ursprünglich im Client beobachtet wurde, indem das vollständige Server-Prelogin weitergeleitet wurde Antwort, aber der TLS -Handshake -Versagen bleibt bestehen. > (minimaltlsproxy.cs - HandleClientAsync -Methode):
Code: Select all
private async Task HandleClientAsync(TcpClient client)
{
FileLogger.Log("HandleClientAsync: Client connection accepted.");
using (client)
{
client.NoDelay = true;
NetworkStream clientNetStream = client.GetStream();
SslStream clientSslStream = new SslStream(clientNetStream, false);
SslStream sslUpstreamStream = null;
// Start Client TLS Handshake IMMEDIATELY
try
{
FileLogger.Log("HandleClientAsync: Starting client TLS handshake (EARLY START).");
DateTime clientHandshakeStart = DateTime.Now;
await clientSslStream.AuthenticateAsServerAsync(_serverCertificate, false, SslProtocols.Tls12, false);
TimeSpan clientHandshakeDuration = DateTime.Now - clientHandshakeStart;
Console.WriteLine($"Client TLS handshake completed in {clientHandshakeDuration.TotalMilliseconds} ms.");
FileLogger.Log($"Client TLS handshake completed in {clientHandshakeDuration.TotalMilliseconds} ms.");
FileLogger.Log("HandleClientAsync: Client TLS handshake completed.");
}
catch (Exception ex)
{
Console.WriteLine("TLS handshake failed: " + ex.Message);
FileLogger.Log("TLS handshake failed: " + ex.Message);
return;
}
byte[] clientPreloginPacket = await ReadTdsPacketAsync(clientNetStream);
if (clientPreloginPacket != null)
{
TcpClient upstreamClient = new TcpClient();
Stream upstreamStream = null;
try
{
await upstreamClient.ConnectAsync(_targetServer, _targetPort);
upstreamStream = upstreamClient.GetStream();
upstreamClient.NoDelay = true;
await upstreamStream.WriteAsync(clientPreloginPacket, 0, clientPreloginPacket.Length);
await upstreamStream.FlushAsync();
byte[] serverPreloginPacket = await ReadTdsPacketAsync(upstreamStream);
if (serverPreloginPacket != null)
{
FileLogger.Log($"HandleClientAsync: Forwarding FULL Server Prelogin Response (Hex): {BitConverter.ToString(serverPreloginPacket).Replace('-', ' ')}");
await clientNetStream.WriteAsync(serverPreloginPacket, 0, serverPreloginPacket.Length);
await clientNetStream.FlushAsync();
FileLogger.Log("HandleClientAsync: FULL Server prelogin response forwarded to client.");
}
}
finally
{
upstreamClient?.Close();
upstreamStream?.Dispose();
}
}
sslUpstreamStream = null;
NetworkStream upstreamNetStream = null;
TcpClient upstreamClientForForwarding = new TcpClient();
try
{
await upstreamClientForForwarding.ConnectAsync(_targetServer, _targetPort);
upstreamNetStream = upstreamClientForForwarding.GetStream();
sslUpstreamStream = new SslStream(upstreamNetStream, false, (sender, certificate, chain, sslPolicyErrors) => true);
DateTime upstreamHandshakeStart = DateTime.Now;
await sslUpstreamStream.AuthenticateAsClientAsync(_targetServer, null, SslProtocols.Tls12, false);
TimeSpan upstreamHandshakeDuration = DateTime.Now - upstreamHandshakeStart;
Console.WriteLine($"Upstream TLS handshake completed in {upstreamHandshakeDuration.TotalMilliseconds} ms.");
FileLogger.Log($"Upstream TLS handshake completed in {upstreamHandshakeDuration.TotalMilliseconds} ms.");
FileLogger.Log("HandleClientAsync: Upstream TLS handshake completed.");
// Begin bidirectional forwarding - RAW BYTE FORWARDING
Task clientToServer = ForwardTrafficAsync(clientSslStream, sslUpstreamStream, "CLIENT -> SERVER");
Task serverToClient = ForwardTrafficAsync(upstreamSslStream, clientSslStream, "SERVER -> CLIENT");
await Task.WhenAll(clientToServer, serverToClient);
}
catch (Exception ex)
{
Console.WriteLine("Upstream connection/TLS failed: " + ex.Message);
FileLogger.Log("Upstream connection/TLS failed: " + ex.Message);
}
finally
{
upstreamClientForForwarding?.Close();
upstreamNetStream?.Dispose();
sslUpstreamStream?.Dispose();
}
}
}
Code: Select all
///
/// Forwards traffic between two streams (Simplified version - basic byte forwarding) - WITH GRANULAR TIMING LOGS.
///
private async Task ForwardTrafficAsync(Stream source, Stream destination, string direction)
{
byte[] buffer = new byte[4096];
try
{
while (true)
{
DateTime readStart = DateTime.Now; // Timestamp before ReadAsync
int bytesRead = await source.ReadAsync(buffer, 0, buffer.Length);
TimeSpan readDuration = DateTime.Now - readStart; // Duration of ReadAsync
FileLogger.Log($"{direction} - ReadAsync - Read {bytesRead} bytes in {readDuration.TotalMilliseconds} ms."); // Log ReadAsync timing
if (bytesRead == 0)
{
string msg = $"{direction} connection closed by remote endpoint.";
Console.WriteLine(msg);
FileLogger.Log(msg);
break;
}
DateTime writeStart = DateTime.Now; // Timestamp before WriteAsync
await destination.WriteAsync(buffer, 0, bytesRead);
DateTime flushStart = DateTime.Now; // Timestamp before FlushAsync
await destination.FlushAsync();
TimeSpan writeDuration = DateTime.Now - writeStart; // Duration of WriteAsync+FlushAsync
FileLogger.Log($"{direction} - WriteAsync+FlushAsync - Wrote {bytesRead} bytes in {writeDuration.TotalMilliseconds} ms."); // Log WriteAsync+FlushAsync timing
}
}
catch (Exception ex)
{
string err = $"Forwarding error ({direction}): {ex.Message}";
Console.WriteLine(err);
FileLogger.Log(err);
}
}
Code: Select all
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SqlProxyExample
{
///
/// Custom stream that strips the TDS header to expose raw TLS records.
/// This implementation assumes one TLS record per TDS packet.
/// For writing, it encapsulates TLS bytes into a TDS packet.
/// **SIMPLIFIED VERSION - RAW PASS-THROUGH FOR TESTING - WITH ENHANCED LOGGING**
///
public class TdsTlsStream : Stream
{
private readonly Stream _baseStream;
public TdsTlsStream(Stream baseStream)
{
_baseStream = baseStream;
FileLogger.Log("TdsTlsStream: Using SIMPLIFIED RAW PASS-THROUGH VERSION with ENHANCED LOGGING for testing."); // Added log
}
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => false;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length => _baseStream.Length; // Or throw new NotSupportedException();
public override long Position { get => _baseStream.Position; set => _baseStream.Position = value; } // Or throw new NotSupportedException();
public override void Flush() => _baseStream.Flush();
public override int Read(byte[] buffer, int offset, int count)
{
FileLogger.Log($"TdsTlsStream.Read (SIMPLIFIED - LOGGED): Reading {count} bytes from base stream.");
DateTime startTime = DateTime.Now; // Log start time
int read = _baseStream.Read(buffer, offset, count);
TimeSpan duration = DateTime.Now - startTime; // Log duration
FileLogger.Log($"TdsTlsStream.Read (SIMPLIFIED - LOGGED): Read {read} bytes in {duration.TotalMilliseconds} ms.");
return read;
}
public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
FileLogger.Log($"TdsTlsStream.ReadAsync (SIMPLIFIED - LOGGED): Reading {count} bytes from base stream.");
DateTime startTime = DateTime.Now; // Log start time
int read = await _baseStream.ReadAsync(buffer, offset, count, cancellationToken);
TimeSpan duration = DateTime.Now - startTime; // Log duration
FileLogger.Log($"TdsTlsStream.ReadAsync (SIMPLIFIED - LOGGED): Read {read} bytes in {duration.TotalMilliseconds} ms.");
return read;
}
public override void Write(byte[] buffer, int offset, int count)
{
FileLogger.Log($"TdsTlsStream.Write (SIMPLIFIED - LOGGED): Writing {count} bytes to base stream.");
DateTime startTime = DateTime.Now; // Log start time
_baseStream.Write(buffer, offset, count);
TimeSpan duration = DateTime.Now - startTime; // Log duration
FileLogger.Log($"TdsTlsStream.Write (SIMPLIFIED - LOGGED): Written {count} bytes in {duration.TotalMilliseconds} ms.");
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
FileLogger.Log($"TdsTlsStream.WriteAsync (SIMPLIFIED - LOGGED): Writing {count} bytes to base stream.");
DateTime startTime = DateTime.Now; // Log start time
await _baseStream.WriteAsync(buffer, offset, count, cancellationToken);
TimeSpan duration = DateTime.Now - startTime; // Log duration
FileLogger.Log($"TdsTlsStream.WriteAsync (SIMPLIFIED - LOGGED): Written {count} bytes in {duration.TotalMilliseconds} ms.");
}
public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin); // Or throw new NotSupportedException();
public override void SetLength(long value) => _baseStream.SetLength(value); // Or throw new NotSupportedException();
}
}
Ich suche Expertenberatung aus der Stack Overflow -Community, insbesondere diejenigen, die vertraut sind : < /p>
.NET Networking, SSLStream, Netzwerkstream und Asynchronous -Programmierung. Sensitivitäten. > Spezifische Fragen: < /strong> < /p>
Warum ist der .NET -SQL -Client (SQLConnection, SQLCMD -n -c) fehl Vervollständigen Sie den TLS -Handschlag durch den Proxy mit "unerwarteten EOF" oder Verbindungsabbruchfehlern, während OpenSSL S_Client einwandfrei funktioniert? oder ineffizient in der TLS -Handhabungs- oder Weiterleitung von Proxy -Code des minimalen Proxycode, die diese Probleme für SQL -Clients verursachen könnte? Subtile Anforderungen des .NET -SQL -Clients, wenn Sie über Proxies mit tls einherstellen, dass ich möglicherweise fehlt? Gibt es über Verbindungszeichenfolge, abfragebasierte Antwortrouting) alternative, robustere oder einfachere Ansätze, um diese Ziele zu erreichen, anstatt einen benutzerdefinierten TDS-Proxy von Grund auf neu zu erstellen? Vielleicht wäre die Verwendung vorhandener Reverse -Proxy -Lösungen oder anderer .NET -Netzwerktechniken zuverlässiger? Debugging -Schritte oder alternative Ansätze wären sehr geschätzt!
Vielen Dank für Ihre Zeit und Ihr Fachwissen.