Skip to content

Tweak diagnostics #1241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 53 additions & 15 deletions src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,65 @@
using System.Diagnostics;
using System.ComponentModel;
using System.Diagnostics;

namespace Renci.SshNet.Abstractions
{
internal static class DiagnosticAbstraction
/// <summary>
/// Provides access to the <see cref="System.Diagnostics"/> internals of SSH.NET.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static class DiagnosticAbstraction
{
private static readonly SourceSwitch SourceSwitch = new SourceSwitch("SshNetSwitch");

public static bool IsEnabled(TraceEventType traceEventType)
{
return SourceSwitch.ShouldTrace(traceEventType);
}

private static readonly TraceSource Loggging =
#if DEBUG
new TraceSource("SshNet.Logging", SourceLevels.All);
#else
new TraceSource("SshNet.Logging");
#endif // DEBUG
/// <summary>
/// The <see cref="TraceSource"/> instance used by SSH.NET.
/// </summary>
/// <remarks>
/// <para>
/// Configuration on .NET Core must be done programmatically, e.g.
/// <code>
/// DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose");
/// DiagnosticAbstraction.Source.Listeners.Remove("Default");
/// DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener());
/// DiagnosticAbstraction.Source.Listeners.Add(new TextWriterTraceListener("trace.log"));
/// </code>
/// </para>
/// <para>
/// On .NET Framework, it is possible to configure via App.config, e.g.
/// <code>
/// <![CDATA[
/// <configuration>
/// <system.diagnostics>
/// <trace autoflush="true"/>
/// <sources>
/// <source name="SshNet.Logging" switchValue="Verbose">
/// <listeners>
/// <remove name="Default" />
/// <add name="console"
/// type="System.Diagnostics.ConsoleTraceListener" />
/// <add name="logFile"
/// type="System.Diagnostics.TextWriterTraceListener"
/// initializeData="SshNetTrace.log" />
/// </listeners>
/// </source>
/// </sources>
/// </system.diagnostics>
/// </configuration>
/// ]]>
/// </code>
/// </para>
/// </remarks>
public static readonly TraceSource Source = new TraceSource("SshNet.Logging");
#endif

/// <summary>
/// Logs a message to <see cref="Source"/> at the <see cref="TraceEventType.Verbose"/>
/// level.
/// </summary>
/// <param name="text">The message to log.</param>
[Conditional("DEBUG")]
public static void Log(string text)
{
Loggging.TraceEvent(TraceEventType.Verbose,
Source.TraceEvent(TraceEventType.Verbose,
System.Environment.CurrentManagedThreadId,
text);
}
Expand Down
8 changes: 8 additions & 0 deletions src/Renci.SshNet/Messages/Authentication/FailureMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,13 @@ internal override void Process(Session session)
{
session.OnUserAuthenticationFailureReceived(this);
}

/// <inheritdoc/>
public override string ToString()
{
#pragma warning disable MA0089 // Optimize string method usage
return $"SSH_MSG_USERAUTH_FAILURE {string.Join(",", AllowedAuthentications)} ({nameof(PartialSuccess)}:{PartialSuccess})";
#pragma warning restore MA0089 // Optimize string method usage
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,11 @@ protected override void SaveData()
WriteBinaryString(PublicKeyAlgorithmName);
WriteBinaryString(PublicKeyData);
}

/// <inheritdoc/>
public override string ToString()
{
return $"SSH_MSG_USERAUTH_PK_OK ({Ascii.GetString(PublicKeyAlgorithmName)})";
}
}
}
6 changes: 6 additions & 0 deletions src/Renci.SshNet/Messages/Authentication/RequestMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,11 @@ internal override void Process(Session session)
{
throw new NotImplementedException();
}

/// <inheritdoc/>
public override string ToString()
{
return $"SSH_MSG_USERAUTH_REQUEST ({MethodName})";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,11 @@ protected override void SaveData()
WriteBinaryString(Signature);
}
}

/// <inheritdoc/>
public override string ToString()
{
return $"{base.ToString()} {Ascii.GetString(PublicKeyAlgorithmName)} {(Signature != null ? "with" : "without")} signature.";
}
}
}
4 changes: 2 additions & 2 deletions src/Renci.SshNet/Renci.SshNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
<DefineConstants>FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
Expand All @@ -18,6 +18,6 @@
</ItemGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<DefineConstants>FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP</DefineConstants>
</PropertyGroup>
</Project>
26 changes: 22 additions & 4 deletions src/Renci.SshNet/Security/KeyExchange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,9 @@ public Cipher CreateServerCipher()

serverKey = GenerateSessionKey(SharedKey, ExchangeHash, serverKey, _serverCipherInfo.KeySize / 8);

DiagnosticAbstraction.Log(string.Format("[{0}] Creating server cipher (Name:{1},Key:{2},IV:{3})",
DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server cipher.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentServerEncryption,
Session.ToHex(serverKey),
Session.ToHex(serverVector)));
Session.ConnectionInfo.CurrentServerEncryption));

// Create server cipher
return _serverCipherInfo.Cipher(serverKey, serverVector);
Expand All @@ -210,6 +208,10 @@ public Cipher CreateClientCipher()

clientKey = GenerateSessionKey(SharedKey, ExchangeHash, clientKey, _clientCipherInfo.KeySize / 8);

DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client cipher.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentClientEncryption));

// Create client cipher
return _clientCipherInfo.Cipher(clientKey, clientVector);
}
Expand All @@ -230,6 +232,10 @@ public HashAlgorithm CreateServerHash()
Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'F', sessionId)),
_serverHashInfo.KeySize / 8);

DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server hmac algorithm.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentServerHmacAlgorithm));

return _serverHashInfo.HashAlgorithm(serverKey);
}

Expand All @@ -249,6 +255,10 @@ public HashAlgorithm CreateClientHash()
Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'E', sessionId)),
_clientHashInfo.KeySize / 8);

DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client hmac algorithm.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentClientHmacAlgorithm));

return _clientHashInfo.HashAlgorithm(clientKey);
}

Expand All @@ -265,6 +275,10 @@ public Compressor CreateCompressor()
return null;
}

DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client compressor.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentClientCompressionAlgorithm));

var compressor = _compressionType.CreateInstance<Compressor>();

compressor.Init(Session);
Expand All @@ -285,6 +299,10 @@ public Compressor CreateDecompressor()
return null;
}

DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server decompressor.",
Session.ToHex(Session.SessionId),
Session.ConnectionInfo.CurrentServerCompressionAlgorithm));

var decompressor = _decompressionType.CreateInstance<Compressor>();

decompressor.Init(Session);
Expand Down
6 changes: 4 additions & 2 deletions src/Renci.SshNet/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ public void Connect()
ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString();
ConnectionInfo.ClientVersion = ClientVersion;

DiagnosticAbstraction.Log(string.Format("Server version '{0}' on '{1}'.", serverIdentification.ProtocolVersion, serverIdentification.SoftwareVersion));
DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification));

if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99")))
{
Expand Down Expand Up @@ -728,7 +728,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken)
ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString();
ConnectionInfo.ClientVersion = ClientVersion;

DiagnosticAbstraction.Log(string.Format("Server version '{0}' on '{1}'.", serverIdentification.ProtocolVersion, serverIdentification.SoftwareVersion));
DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification));

if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99")))
{
Expand Down Expand Up @@ -1397,6 +1397,8 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message)

ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name;

DiagnosticAbstraction.Log(string.Format("[{0}] Performing {1} key exchange.", ToHex(SessionId), ConnectionInfo.CurrentKeyExchangeAlgorithm));

_keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived;

// Start the algorithm implementation
Expand Down